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-
126class RclCalibrate {
137
148public:
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
5776void 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
144156protected:
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 ---\n CENTER 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 ---\n Switch 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 ---\n First 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 ---\n First 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 ---\n First 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 ---\n First 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 ---\n Select 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 ===\n Now use 'prcl' to check, 'cwrite' to save config, or reboot to restart with old config.\n " );
269+ return true ;
229270}
230271
231272};
0 commit comments