Skip to content

Commit ae2b56b

Browse files
committed
CLI calradio
1 parent 6a9a7ee commit ae2b56b

File tree

6 files changed

+207
-146
lines changed

6 files changed

+207
-146
lines changed

src/madflight/cli/cli_RclCalibrate.h

Lines changed: 136 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,18 @@
33
#include "../hal/hal.h"
44
#include "../imu/imu.h"
55

6-
//this class assumes rcl.update() is called in the background... (i.e. in imu_loop())
7-
8-
void rcl_cal_imu_loop() {
9-
rcl.update();
10-
}
11-
126
class RclCalibrate {
137

148
public:
159
static void calibrate() {
16-
imu.onUpdate = rcl_cal_imu_loop;
1710
RclCalibrate *cal = new RclCalibrate();
18-
cal->_calibrate();
11+
if(!cal->_calibrate()) {
12+
Serial.println("\n==== Radio Calibration Aborted ====");
13+
}
1914
}
2015

2116
struct stick_t{
22-
uint8_t ch; //stick channel
17+
int8_t ch = -1; //stick channel (0-based, -1 is not assigned)
2318
uint16_t left_pull; //spwm at left/pull position
2419
uint16_t mid; //pwm at center position
2520
uint16_t right_push; //pwm at right/push position
@@ -35,23 +30,47 @@ class RclCalibrate {
3530
stick_t arm; //arm switch
3631
stick_t flt; //flightmode switch
3732

38-
bool ignore[RCL_MAX_CH] = {}; //channels to ignore
39-
int16_t pc[RCL_MAX_CH] = {}; //temp value
40-
int16_t arm_last; //temp value
33+
bool assigned_ch[RCL_MAX_CH] = {}; //channels which were assigned a function
34+
int16_t prev_pwm[RCL_MAX_CH] = {}; //previous pwm values
35+
int16_t prev_arm; //previous arm value
36+
37+
//update rcl, yield and check for cancel, return false if 'q' was pressed
38+
bool do_events(bool *event_key = nullptr) {
39+
rcl.update();
40+
41+
taskYIELD();
42+
43+
while(Serial.available()) {
44+
//set event_key flag
45+
if(event_key) *event_key = true;
46+
47+
//exit if 'q' was pressed
48+
char c = Serial.read();
49+
if(c=='q' || c=='Q') {
50+
//empty receive buffer
51+
while(Serial.available()) Serial.read();
52+
return false;
53+
}
54+
}
55+
56+
return true;
57+
}
4158

42-
void prompt(const char *msg) {
59+
//wait for key, returns false if 'q' was pressed
60+
bool prompt(const char *msg) {
4361
Serial.println(msg);
4462

45-
//empty buffer
63+
//empty receive buffer
4664
while(Serial.available()) Serial.read();
4765

48-
//wait for enter
66+
//wait for event
67+
bool event_key = false;
4968
for(;;) {
50-
if(Serial.available()) {
51-
char c = Serial.read();
52-
if ( c=='\r' || c=='\n' ) return;
53-
}
69+
if(!do_events(&event_key)) return false;;
70+
if(event_key) break;
5471
}
72+
73+
return true;
5574
}
5675

5776
void printpwm() {
@@ -75,45 +94,36 @@ void setVal(int16_t *p, int16_t v) {
7594
}
7695
}
7796

78-
void setPc() {
97+
void set_prev_pwm() {
7998
for(int i=0;i<cfg.rcl_num_ch;i++) {
80-
pc[i] = rcl.pwm[i];
81-
}
82-
}
83-
84-
void armToggleInit() {
85-
arm_last = rcl.pwm[arm.ch];
86-
}
87-
88-
bool armToggled() {
89-
return (abs((int16_t)rcl.pwm[arm.ch] - arm_last) > 500);
90-
}
91-
92-
void armToggleWait() {
93-
armToggleInit();
94-
for(;;) {
95-
if(armToggled()) return;
96-
taskYIELD();
99+
prev_pwm[i] = rcl.pwm[i];
97100
}
98101
}
99102

100-
void findStick(stick_t &stk) {
103+
//returns false if 'q' was pressed
104+
bool findStick(stick_t &stk) {
101105
int16_t pmin[cfg.rcl_num_ch]={};
102106
setVal(pmin,9999);
103107
uint32_t tmin[cfg.rcl_num_ch]={};
104108
int16_t pmax[cfg.rcl_num_ch]={};
105109
uint32_t tmax[cfg.rcl_num_ch]={};
106-
armToggleInit();
110+
int16_t prev_arm = rcl.pwm[arm.ch];
107111

108112
//for each channel: record pwm_min and pwm_max, and record timestamps
109-
for(int c = 0; ; c++) {
110-
if(ignore[c]) c++; //skip known channels
111-
if(c>=cfg.rcl_num_ch) c=0;
112-
int16_t p = rcl.pwm[c];
113-
if(pmin[c] > p) {pmin[c] = p; tmin[c] = micros();}
114-
if(pmax[c] < p) {pmax[c] = p; tmax[c] = micros();}
115-
if(armToggled()) break;
116-
taskYIELD();
113+
//until armed switch toggle or key press
114+
bool event_key = false;
115+
int c = 0;
116+
while(1) {
117+
if(!do_events(&event_key)) return false; //quit
118+
119+
c++;
120+
if(c >= cfg.rcl_num_ch) c=0;
121+
if(!assigned_ch[c]) { //skip assigned channels
122+
int16_t p = rcl.pwm[c];
123+
if(pmin[c] > p) {pmin[c] = p; tmin[c] = micros();}
124+
if(pmax[c] < p) {pmax[c] = p; tmax[c] = micros();}
125+
if(event_key || (arm.ch >= 0 && abs((int16_t)rcl.pwm[arm.ch] - prev_arm) > 500)) break;
126+
}
117127
}
118128

119129
//find channel with max difference between pwm_min and pwm_max
@@ -138,61 +148,90 @@ void findStick(stick_t &stk) {
138148
stk.left_pull = pmax[stk.ch];
139149
stk.right_push = pmin[stk.ch];
140150
}
141-
ignore[stk.ch] = true; //ignore this channel from now on
151+
assigned_ch[stk.ch] = true; //assigned_ch this channel from now on
152+
153+
return true;
142154
}
143155

144156
protected:
145-
void _calibrate() {
146-
int c;
157+
bool _calibrate() {
147158
Serial.println("\n==== Radio Calibration ====");
148-
while(!rcl.connected()) {
149-
Serial.println("Connect radio to continue...");
150-
delay(500);
159+
160+
//check connected
161+
if(!rcl.connected()) {
162+
Serial.println("ERROR: radio not connected. Connect and try again");
163+
return false;
151164
}
152165

153-
Serial.println("Switch to ARMED (if already armed, toggle until calibration done, then restart 'calradio' DISARMED)");
154-
setPc();
155-
for(c=0;;c++) {
156-
if(c>=cfg.rcl_num_ch) c=0;
157-
if(abs((int16_t)rcl.pwm[c] - pc[c]) > 500) break;
158-
taskYIELD();
166+
Serial.println("During calibration type 'q' to quit");
167+
168+
//prompt DISARMED
169+
if(!prompt("\n--- Step 1: Start Calibration ---\nCENTER all sticks (including throttle), armed swich to DISARMED, then press ENTER to continue")) return false;
170+
171+
//get armed switch
172+
Serial.println("\n--- Step 2: Arm Switch Calibration ---\nSwitch to ARMED, or press enter for no arm switch");
173+
bool event_key = false;
174+
set_prev_pwm();
175+
int c = 0;
176+
while(1) {
177+
c++;
178+
if(c >= cfg.rcl_num_ch) c = 0;
179+
if(abs((int16_t)rcl.pwm[c] - prev_pwm[c]) > 500) break;
180+
if(!do_events(&event_key)) return false;
181+
if(event_key) break;
159182
}
160-
arm.ch = c;
161-
int16_t arm_v1 = pc[c];
162-
int16_t arm_v2 = rcl.pwm[c];
163-
164-
int16_t arm_armed = arm_v2;
165-
int16_t arm_disarmed = arm_v1;
166-
if(abs(arm_disarmed - arm_armed) < 100) arm_disarmed = arm_v2;
167-
if(arm_disarmed < arm_armed) {
168-
arm.min = (arm_disarmed+arm_armed)/2;
169-
arm.max = 2500;
183+
if(event_key) {
184+
//no armed channel - can't arm!
185+
arm.ch = -1;
186+
arm.min = 0;
187+
arm.max = 0;
170188
}else{
171-
arm.min = 500;
172-
arm.max = (arm_disarmed+arm_armed)/2;
189+
arm.ch = c;
190+
int16_t arm_v1 = prev_pwm[c];
191+
int16_t arm_v2 = rcl.pwm[c];
192+
int16_t arm_armed = arm_v2;
193+
int16_t arm_disarmed = arm_v1;
194+
if(abs(arm_disarmed - arm_armed) < 100) arm_disarmed = arm_v2;
195+
if(arm_disarmed < arm_armed) {
196+
arm.min = (arm_disarmed+arm_armed)/2;
197+
arm.max = 2500;
198+
}else{
199+
arm.min = 500;
200+
arm.max = (arm_disarmed+arm_armed)/2;
201+
}
202+
assigned_ch[arm.ch] = true;
173203
}
174-
Serial.printf("==> ARMED: ch=%d from=%d to=%d\n", arm.ch+1, arm.min, arm.max);
175-
ignore[arm.ch]=true;
176-
177-
Serial.println("THROTTLE: First pull throttle idle, then full throttle, then back to center, then toggle arm switch");
178-
findStick(thr);
179-
Serial.printf("==> THROTTLE: ch=%d pull=%d mid=%d push=%d\n", rol.ch+1, rol.left_pull, rol.mid, rol.right_push);
180-
181-
Serial.println("PITCH: First pull stick back, then push forward, then back to center, then toggle arm switch");
182-
findStick(pit);
183-
Serial.printf("==> PITCH: ch=%d pull=%d mid=%d push=%d\n", pit.ch+1, pit.left_pull, pit.mid, pit.right_push);
184-
185-
Serial.println("ROLL: First move stick left, then right, then back to center, then toggle arm switch");
186-
findStick(rol);
187-
Serial.printf("==> ROLL: ch=%d left=%d mid=%d right=%d\n", rol.ch+1, rol.left_pull, rol.mid, rol.right_push);
188-
189-
Serial.println("YAW: First move stick left, then right, then back to center, then toggle arm switch");
190-
findStick(yaw);
191-
Serial.printf("==> YAW: ch=%d left=%d mid=%d right=%d\n", yaw.ch+1, yaw.left_pull, yaw.mid, yaw.right_push);
192-
193-
Serial.println("Select min and max flight modes, then toggle arm switch");
194-
findStick(flt);
195-
Serial.printf("==> FLIGHTMODE: ch=%d from=%d to=%d\n", flt.ch+1, flt.min, flt.max);
204+
Serial.printf("==> Arm Switch: ch=%d from=%d to=%d\n", arm.ch+1, arm.min, arm.max);
205+
206+
//get throttle
207+
Serial.println("\n--- Step 3: Throttle Stick Calibration ---\nFirst pull throttle idle, then full throttle, then back to center, then toggle arm switch or press enter");
208+
if(!findStick(thr)) return false;
209+
Serial.printf("==> Throttle: ch=%d pull=%d mid=%d push=%d\n", rol.ch+1, rol.left_pull, rol.mid, rol.right_push);
210+
211+
//get pitch
212+
Serial.println("\n--- Step 4: Pitch Stick Calibration ---\nFirst pull pitch stick back, then push forward, then back to center, then toggle arm switch or press enter");
213+
if(!findStick(pit)) return false;
214+
Serial.printf("==> Pitch: ch=%d pull=%d mid=%d push=%d\n", pit.ch+1, pit.left_pull, pit.mid, pit.right_push);
215+
216+
//get roll
217+
Serial.println("\n--- Step 5: Roll Stick Calibration ---\nFirst move roll stick left, then right, then back to center, then toggle arm switch or press enter");
218+
if(!findStick(rol)) return false;
219+
Serial.printf(" ==> Roll: ch=%d left=%d mid=%d right=%d\n", rol.ch+1, rol.left_pull, rol.mid, rol.right_push);
220+
221+
//get yaw
222+
Serial.println("\n--- Step 6: Yaw Stick Calibration ---\nFirst move yaw stick left, then right, then back to center, then toggle arm switch or press enter");
223+
if(!findStick(yaw)) return false;
224+
Serial.printf(" ==> Yaw: ch=%d left=%d mid=%d right=%d\n", yaw.ch+1, yaw.left_pull, yaw.mid, yaw.right_push);
225+
226+
//get flight mode
227+
Serial.println("\n--- Step 7: Flight Mode Switch Calibration ---\nSelect min and max flight modes, then toggle arm switch or press enter");
228+
Serial.println(" -or- Press 'q' for no flight mode switch");
229+
if(!findStick(flt)) {
230+
flt.ch = -1;
231+
flt.min = 0;
232+
flt.max = 0;
233+
}
234+
Serial.printf(" ==> Flight Mode Switch: ch=%d from=%d to=%d\n", flt.ch+1, flt.min, flt.max);
196235

197236
//set config
198237
cfg.rcl_thr_ch = thr.ch + 1;
@@ -223,9 +262,11 @@ void _calibrate() {
223262
cfg.rcl_flt_min = flt.min;
224263
cfg.rcl_flt_max = flt.max;
225264

226-
rcl.setup(); //restart rc to reload config
265+
Serial.println();
266+
rcl.setup(); //restart rcl to reload config (outputs RCL messages)
227267

228-
Serial.printf("Radio calibration completed! Now use 'pradio' to check, 'cwrite' to save config, or reboot to restart with old config.\n");
268+
Serial.printf("\n=== Radio Calibration Completed ===\nNow use 'prcl' to check, 'cwrite' to save config, or reboot to restart with old config.\n");
269+
return true;
229270
}
230271

231272
};

src/madflight/rcl/RclGizmoSbus.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ class RclGizmoSbus : public RclGizmo {
3030
uint16_t sbusChannels[16];
3131
bool sbusFailSafe;
3232
bool sbusLostFrame;
33-
if(!sbus.read(sbusChannels, &sbusFailSafe, &sbusLostFrame)) return false;
33+
int packet_cnt = sbus.read(sbusChannels, &sbusFailSafe, &sbusLostFrame);
34+
if(packet_cnt == 0) return false;
3435

3536
//sBus scaling below is for Taranis-Plus and X4R-SB
3637
float scale = 0.615;

src/madflight/rcl/rcl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class Rcl {
6060
void calibrate(); //interactive calibration
6161
bool telem_statustext(uint8_t severity, char *text); //send MAVLink status text
6262

63-
uint16_t pwm[RCL_MAX_CH] = {}; //pwm channel data. values: 988-2012
63+
uint16_t pwm[RCL_MAX_CH + 1] = {}; //pwm channel data. regular range: 988-2012, pwm[RCL_MAX_CH] is used for non assigned sticks
6464

6565
float throttle = 0; //throttle stick value 0.0 (zero throttle/stick back) to 1.0 (full throttle/stick forward)
6666
float roll = 0; //roll stick value -1.0 (left) to 1.0 (right)
@@ -71,6 +71,7 @@ class Rcl {
7171
uint8_t flightmode = 0; //flightmode 0 to 5
7272

7373
private:
74+
int _getCh(int ch); //normalize 1-based parameter channel to 0-RCL_MAX_CH, where RCL_MAX_CH is used for invalid channels
7475
float _ChannelNormalize(int val, int min, int center, int max, int deadband);
7576
void _setupStick(int stickno, int ch, int left_pull, int mid, int right_push);
7677

0 commit comments

Comments
 (0)