2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
29 #include "blackbox/blackbox.h"
30 #include "blackbox/blackbox_fielddefs.h"
32 #include "build/build_config.h"
34 #include "common/axis.h"
35 #include "common/maths.h"
36 #include "common/utils.h"
38 #include "config/feature.h"
40 #include "drivers/time.h"
42 #include "config/config.h"
43 #include "fc/controlrate_profile.h"
44 #include "fc/rc_controls.h"
47 #include "flight/pid.h"
48 #include "flight/pid_init.h"
50 #include "io/beeper.h"
51 #include "io/ledstrip.h"
52 #include "io/pidaudio.h"
57 #include "pg/pg_ids.h"
62 #include "rc_adjustments.h"
64 #define ADJUSTMENT_RANGE_COUNT_INVALID -1
66 PG_REGISTER_ARRAY(adjustmentRange_t
, MAX_ADJUSTMENT_RANGE_COUNT
, adjustmentRanges
, PG_ADJUSTMENT_RANGE_CONFIG
, 2);
68 uint8_t pidAudioPositionToModeMap
[7] = {
69 // on a pot with a center detent, it's easy to have center area for off/default, then three positions to the left and three to the right.
70 // current implementation yields RC values as below.
72 PID_AUDIO_PIDSUM_X
, // 900 - ~1071 - Min
73 PID_AUDIO_PIDSUM_Y
, // ~1071 - ~1242
74 PID_AUDIO_PIDSUM_XY
, // ~1242 - ~1414
75 PID_AUDIO_OFF
, // ~1414 - ~1585 - Center
76 PID_AUDIO_OFF
, // ~1585 - ~1757
77 PID_AUDIO_OFF
, // ~1757 - ~1928
78 PID_AUDIO_OFF
, // ~1928 - 2100 - Max
80 // Note: Last 3 positions are currently pending implementations and use PID_AUDIO_OFF for now.
83 STATIC_UNIT_TESTED
int stepwiseAdjustmentCount
= ADJUSTMENT_RANGE_COUNT_INVALID
;
84 STATIC_UNIT_TESTED timedAdjustmentState_t stepwiseAdjustments
[MAX_ADJUSTMENT_RANGE_COUNT
];
86 STATIC_UNIT_TESTED
int continuosAdjustmentCount
;
87 STATIC_UNIT_TESTED continuosAdjustmentState_t continuosAdjustments
[MAX_ADJUSTMENT_RANGE_COUNT
];
89 static void blackboxLogInflightAdjustmentEvent(adjustmentFunction_e adjustmentFunction
, int32_t newValue
)
92 UNUSED(adjustmentFunction
);
95 if (blackboxConfig()->device
) {
96 flightLogEvent_inflightAdjustment_t eventData
;
97 eventData
.adjustmentFunction
= adjustmentFunction
;
98 eventData
.newValue
= newValue
;
99 eventData
.floatFlag
= false;
100 blackboxLogEvent(FLIGHT_LOG_EVENT_INFLIGHT_ADJUSTMENT
, (flightLogEventData_t
*)&eventData
);
105 // sync with adjustmentFunction_e
106 static const adjustmentConfig_t defaultAdjustmentConfigs
[ADJUSTMENT_FUNCTION_COUNT
- 1] = {
108 .adjustmentFunction
= ADJUSTMENT_RC_RATE
,
109 .mode
= ADJUSTMENT_MODE_STEP
,
110 .data
= { .step
= 1 }
112 .adjustmentFunction
= ADJUSTMENT_RC_EXPO
,
113 .mode
= ADJUSTMENT_MODE_STEP
,
114 .data
= { .step
= 1 }
116 .adjustmentFunction
= ADJUSTMENT_THROTTLE_EXPO
,
117 .mode
= ADJUSTMENT_MODE_STEP
,
118 .data
= { .step
= 1 }
120 .adjustmentFunction
= ADJUSTMENT_PITCH_ROLL_RATE
,
121 .mode
= ADJUSTMENT_MODE_STEP
,
122 .data
= { .step
= 1 }
124 .adjustmentFunction
= ADJUSTMENT_YAW_RATE
,
125 .mode
= ADJUSTMENT_MODE_STEP
,
126 .data
= { .step
= 1 }
128 .adjustmentFunction
= ADJUSTMENT_PITCH_ROLL_P
,
129 .mode
= ADJUSTMENT_MODE_STEP
,
130 .data
= { .step
= 1 }
132 .adjustmentFunction
= ADJUSTMENT_PITCH_ROLL_I
,
133 .mode
= ADJUSTMENT_MODE_STEP
,
134 .data
= { .step
= 1 }
136 .adjustmentFunction
= ADJUSTMENT_PITCH_ROLL_D
,
137 .mode
= ADJUSTMENT_MODE_STEP
,
138 .data
= { .step
= 1 }
140 .adjustmentFunction
= ADJUSTMENT_YAW_P
,
141 .mode
= ADJUSTMENT_MODE_STEP
,
142 .data
= { .step
= 1 }
144 .adjustmentFunction
= ADJUSTMENT_YAW_I
,
145 .mode
= ADJUSTMENT_MODE_STEP
,
146 .data
= { .step
= 1 }
148 .adjustmentFunction
= ADJUSTMENT_YAW_D
,
149 .mode
= ADJUSTMENT_MODE_STEP
,
150 .data
= { .step
= 1 }
152 .adjustmentFunction
= ADJUSTMENT_RATE_PROFILE
,
153 .mode
= ADJUSTMENT_MODE_SELECT
,
154 .data
= { .switchPositions
= 3 }
156 .adjustmentFunction
= ADJUSTMENT_PITCH_RATE
,
157 .mode
= ADJUSTMENT_MODE_STEP
,
158 .data
= { .step
= 1 }
160 .adjustmentFunction
= ADJUSTMENT_ROLL_RATE
,
161 .mode
= ADJUSTMENT_MODE_STEP
,
162 .data
= { .step
= 1 }
164 .adjustmentFunction
= ADJUSTMENT_PITCH_P
,
165 .mode
= ADJUSTMENT_MODE_STEP
,
166 .data
= { .step
= 1 }
168 .adjustmentFunction
= ADJUSTMENT_PITCH_I
,
169 .mode
= ADJUSTMENT_MODE_STEP
,
170 .data
= { .step
= 1 }
172 .adjustmentFunction
= ADJUSTMENT_PITCH_D
,
173 .mode
= ADJUSTMENT_MODE_STEP
,
174 .data
= { .step
= 1 }
176 .adjustmentFunction
= ADJUSTMENT_ROLL_P
,
177 .mode
= ADJUSTMENT_MODE_STEP
,
178 .data
= { .step
= 1 }
180 .adjustmentFunction
= ADJUSTMENT_ROLL_I
,
181 .mode
= ADJUSTMENT_MODE_STEP
,
182 .data
= { .step
= 1 }
184 .adjustmentFunction
= ADJUSTMENT_ROLL_D
,
185 .mode
= ADJUSTMENT_MODE_STEP
,
186 .data
= { .step
= 1 }
188 .adjustmentFunction
= ADJUSTMENT_RC_RATE_YAW
,
189 .mode
= ADJUSTMENT_MODE_STEP
,
190 .data
= { .step
= 1 }
192 .adjustmentFunction
= ADJUSTMENT_PITCH_ROLL_F
,
193 .mode
= ADJUSTMENT_MODE_STEP
,
194 .data
= { .step
= 1 }
196 .adjustmentFunction
= ADJUSTMENT_FEEDFORWARD_TRANSITION
,
197 .mode
= ADJUSTMENT_MODE_STEP
,
198 .data
= { .step
= 1 }
200 .adjustmentFunction
= ADJUSTMENT_HORIZON_STRENGTH
,
201 .mode
= ADJUSTMENT_MODE_SELECT
,
202 .data
= { .switchPositions
= 255 }
204 .adjustmentFunction
= ADJUSTMENT_PID_AUDIO
,
205 .mode
= ADJUSTMENT_MODE_SELECT
,
206 .data
= { .switchPositions
= ARRAYLEN(pidAudioPositionToModeMap
) }
208 .adjustmentFunction
= ADJUSTMENT_PITCH_F
,
209 .mode
= ADJUSTMENT_MODE_STEP
,
210 .data
= { .step
= 1 }
212 .adjustmentFunction
= ADJUSTMENT_ROLL_F
,
213 .mode
= ADJUSTMENT_MODE_STEP
,
214 .data
= { .step
= 1 }
216 .adjustmentFunction
= ADJUSTMENT_YAW_F
,
217 .mode
= ADJUSTMENT_MODE_STEP
,
218 .data
= { .step
= 1 }
220 .adjustmentFunction
= ADJUSTMENT_OSD_PROFILE
,
221 .mode
= ADJUSTMENT_MODE_SELECT
,
222 .data
= { .switchPositions
= 3 }
224 .adjustmentFunction
= ADJUSTMENT_LED_PROFILE
,
225 .mode
= ADJUSTMENT_MODE_SELECT
,
226 .data
= { .switchPositions
= 3 }
230 #if defined(USE_OSD) && defined(USE_OSD_ADJUSTMENTS)
231 static const char * const adjustmentLabels
[] = {
267 static int adjustmentRangeNameIndex
= 0;
268 static int adjustmentRangeValue
= -1;
271 static int applyStepAdjustment(controlRateConfig_t
*controlRateConfig
, uint8_t adjustmentFunction
, int delta
)
273 beeperConfirmationBeeps(delta
> 0 ? 2 : 1);
275 switch (adjustmentFunction
) {
276 case ADJUSTMENT_RC_RATE
:
277 case ADJUSTMENT_ROLL_RC_RATE
:
278 newValue
= constrain((int)controlRateConfig
->rcRates
[FD_ROLL
] + delta
, 1, CONTROL_RATE_CONFIG_RC_RATES_MAX
);
279 controlRateConfig
->rcRates
[FD_ROLL
] = newValue
;
280 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_RC_RATE
, newValue
);
281 if (adjustmentFunction
== ADJUSTMENT_ROLL_RC_RATE
) {
284 // fall through for combined ADJUSTMENT_RC_EXPO
286 case ADJUSTMENT_PITCH_RC_RATE
:
287 newValue
= constrain((int)controlRateConfig
->rcRates
[FD_PITCH
] + delta
, 1, CONTROL_RATE_CONFIG_RC_RATES_MAX
);
288 controlRateConfig
->rcRates
[FD_PITCH
] = newValue
;
289 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_RC_RATE
, newValue
);
291 case ADJUSTMENT_RC_EXPO
:
292 case ADJUSTMENT_ROLL_RC_EXPO
:
293 newValue
= constrain((int)controlRateConfig
->rcExpo
[FD_ROLL
] + delta
, 0, CONTROL_RATE_CONFIG_RC_EXPO_MAX
);
294 controlRateConfig
->rcExpo
[FD_ROLL
] = newValue
;
295 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_RC_EXPO
, newValue
);
296 if (adjustmentFunction
== ADJUSTMENT_ROLL_RC_EXPO
) {
299 // fall through for combined ADJUSTMENT_RC_EXPO
301 case ADJUSTMENT_PITCH_RC_EXPO
:
302 newValue
= constrain((int)controlRateConfig
->rcExpo
[FD_PITCH
] + delta
, 0, CONTROL_RATE_CONFIG_RC_EXPO_MAX
);
303 controlRateConfig
->rcExpo
[FD_PITCH
] = newValue
;
304 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_RC_EXPO
, newValue
);
306 case ADJUSTMENT_THROTTLE_EXPO
:
307 newValue
= constrain((int)controlRateConfig
->thrExpo8
+ delta
, 0, 100); // FIXME magic numbers repeated in cli.c
308 controlRateConfig
->thrExpo8
= newValue
;
310 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_THROTTLE_EXPO
, newValue
);
312 case ADJUSTMENT_PITCH_ROLL_RATE
:
313 case ADJUSTMENT_PITCH_RATE
:
314 newValue
= constrain((int)controlRateConfig
->rates
[FD_PITCH
] + delta
, 0, CONTROL_RATE_CONFIG_RATE_MAX
);
315 controlRateConfig
->rates
[FD_PITCH
] = newValue
;
316 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_RATE
, newValue
);
317 if (adjustmentFunction
== ADJUSTMENT_PITCH_RATE
) {
320 // fall through for combined ADJUSTMENT_PITCH_ROLL_RATE
322 case ADJUSTMENT_ROLL_RATE
:
323 newValue
= constrain((int)controlRateConfig
->rates
[FD_ROLL
] + delta
, 0, CONTROL_RATE_CONFIG_RATE_MAX
);
324 controlRateConfig
->rates
[FD_ROLL
] = newValue
;
325 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_RATE
, newValue
);
327 case ADJUSTMENT_YAW_RATE
:
328 newValue
= constrain((int)controlRateConfig
->rates
[FD_YAW
] + delta
, 0, CONTROL_RATE_CONFIG_RATE_MAX
);
329 controlRateConfig
->rates
[FD_YAW
] = newValue
;
330 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_RATE
, newValue
);
332 case ADJUSTMENT_PITCH_ROLL_P
:
333 case ADJUSTMENT_PITCH_P
:
334 newValue
= constrain((int)currentPidProfile
->pid
[PID_PITCH
].P
+ delta
, 0, 200); // FIXME magic numbers repeated in cli.c
335 currentPidProfile
->pid
[PID_PITCH
].P
= newValue
;
336 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_P
, newValue
);
338 if (adjustmentFunction
== ADJUSTMENT_PITCH_P
) {
341 // fall through for combined ADJUSTMENT_PITCH_ROLL_P
343 case ADJUSTMENT_ROLL_P
:
344 newValue
= constrain((int)currentPidProfile
->pid
[PID_ROLL
].P
+ delta
, 0, 200); // FIXME magic numbers repeated in cli.c
345 currentPidProfile
->pid
[PID_ROLL
].P
= newValue
;
346 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_P
, newValue
);
348 case ADJUSTMENT_PITCH_ROLL_I
:
349 case ADJUSTMENT_PITCH_I
:
350 newValue
= constrain((int)currentPidProfile
->pid
[PID_PITCH
].I
+ delta
, 0, 200); // FIXME magic numbers repeated in cli.c
351 currentPidProfile
->pid
[PID_PITCH
].I
= newValue
;
352 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_I
, newValue
);
353 if (adjustmentFunction
== ADJUSTMENT_PITCH_I
) {
356 // fall through for combined ADJUSTMENT_PITCH_ROLL_I
358 case ADJUSTMENT_ROLL_I
:
359 newValue
= constrain((int)currentPidProfile
->pid
[PID_ROLL
].I
+ delta
, 0, 200); // FIXME magic numbers repeated in cli.c
360 currentPidProfile
->pid
[PID_ROLL
].I
= newValue
;
361 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_I
, newValue
);
363 case ADJUSTMENT_PITCH_ROLL_D
:
364 case ADJUSTMENT_PITCH_D
:
365 newValue
= constrain((int)currentPidProfile
->pid
[PID_PITCH
].D
+ delta
, 0, 200); // FIXME magic numbers repeated in cli.c
366 currentPidProfile
->pid
[PID_PITCH
].D
= newValue
;
367 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_D
, newValue
);
368 if (adjustmentFunction
== ADJUSTMENT_PITCH_D
) {
371 // fall through for combined ADJUSTMENT_PITCH_ROLL_D
373 case ADJUSTMENT_ROLL_D
:
374 newValue
= constrain((int)currentPidProfile
->pid
[PID_ROLL
].D
+ delta
, 0, 200); // FIXME magic numbers repeated in cli.c
375 currentPidProfile
->pid
[PID_ROLL
].D
= newValue
;
376 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_D
, newValue
);
378 case ADJUSTMENT_YAW_P
:
379 newValue
= constrain((int)currentPidProfile
->pid
[PID_YAW
].P
+ delta
, 0, 200); // FIXME magic numbers repeated in cli.c
380 currentPidProfile
->pid
[PID_YAW
].P
= newValue
;
381 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_P
, newValue
);
383 case ADJUSTMENT_YAW_I
:
384 newValue
= constrain((int)currentPidProfile
->pid
[PID_YAW
].I
+ delta
, 0, 200); // FIXME magic numbers repeated in cli.c
385 currentPidProfile
->pid
[PID_YAW
].I
= newValue
;
386 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_I
, newValue
);
388 case ADJUSTMENT_YAW_D
:
389 newValue
= constrain((int)currentPidProfile
->pid
[PID_YAW
].D
+ delta
, 0, 200); // FIXME magic numbers repeated in cli.c
390 currentPidProfile
->pid
[PID_YAW
].D
= newValue
;
391 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_D
, newValue
);
393 case ADJUSTMENT_RC_RATE_YAW
:
394 newValue
= constrain((int)controlRateConfig
->rcRates
[FD_YAW
] + delta
, 1, CONTROL_RATE_CONFIG_RC_RATES_MAX
);
395 controlRateConfig
->rcRates
[FD_YAW
] = newValue
;
396 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_RC_RATE_YAW
, newValue
);
398 case ADJUSTMENT_PITCH_ROLL_F
:
399 case ADJUSTMENT_PITCH_F
:
400 newValue
= constrain(currentPidProfile
->pid
[PID_PITCH
].F
+ delta
, 0, 2000);
401 currentPidProfile
->pid
[PID_PITCH
].F
= newValue
;
402 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_F
, newValue
);
404 if (adjustmentFunction
== ADJUSTMENT_PITCH_F
) {
407 // fall through for combined ADJUSTMENT_PITCH_ROLL_F
409 case ADJUSTMENT_ROLL_F
:
410 newValue
= constrain(currentPidProfile
->pid
[PID_ROLL
].F
+ delta
, 0, 2000);
411 currentPidProfile
->pid
[PID_ROLL
].F
= newValue
;
412 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_F
, newValue
);
414 case ADJUSTMENT_YAW_F
:
415 newValue
= constrain(currentPidProfile
->pid
[PID_YAW
].F
+ delta
, 0, 2000);
416 currentPidProfile
->pid
[PID_YAW
].F
= newValue
;
417 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_F
, newValue
);
419 case ADJUSTMENT_FEEDFORWARD_TRANSITION
:
420 newValue
= constrain(currentPidProfile
->feedforwardTransition
+ delta
, 1, 100); // FIXME magic numbers repeated in cli.c
421 currentPidProfile
->feedforwardTransition
= newValue
;
422 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_FEEDFORWARD_TRANSITION
, newValue
);
432 static int applyAbsoluteAdjustment(controlRateConfig_t
*controlRateConfig
, adjustmentFunction_e adjustmentFunction
, int value
)
436 switch (adjustmentFunction
) {
437 case ADJUSTMENT_RC_RATE
:
438 case ADJUSTMENT_ROLL_RC_RATE
:
439 newValue
= constrain(value
, 1, CONTROL_RATE_CONFIG_RC_RATES_MAX
);
440 controlRateConfig
->rcRates
[FD_ROLL
] = newValue
;
441 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_RC_RATE
, newValue
);
442 if (adjustmentFunction
== ADJUSTMENT_ROLL_RC_RATE
) {
445 // fall through for combined ADJUSTMENT_RC_EXPO
447 case ADJUSTMENT_PITCH_RC_RATE
:
448 newValue
= constrain(value
, 1, CONTROL_RATE_CONFIG_RC_RATES_MAX
);
449 controlRateConfig
->rcRates
[FD_PITCH
] = newValue
;
450 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_RC_RATE
, newValue
);
452 case ADJUSTMENT_RC_EXPO
:
453 case ADJUSTMENT_ROLL_RC_EXPO
:
454 newValue
= constrain(value
, 1, CONTROL_RATE_CONFIG_RC_EXPO_MAX
);
455 controlRateConfig
->rcExpo
[FD_ROLL
] = newValue
;
456 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_RC_EXPO
, newValue
);
457 if (adjustmentFunction
== ADJUSTMENT_ROLL_RC_EXPO
) {
460 // fall through for combined ADJUSTMENT_RC_EXPO
462 case ADJUSTMENT_PITCH_RC_EXPO
:
463 newValue
= constrain(value
, 0, CONTROL_RATE_CONFIG_RC_EXPO_MAX
);
464 controlRateConfig
->rcExpo
[FD_PITCH
] = newValue
;
465 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_RC_EXPO
, newValue
);
467 case ADJUSTMENT_THROTTLE_EXPO
:
468 newValue
= constrain(value
, 0, 100); // FIXME magic numbers repeated in cli.c
469 controlRateConfig
->thrExpo8
= newValue
;
471 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_THROTTLE_EXPO
, newValue
);
473 case ADJUSTMENT_PITCH_ROLL_RATE
:
474 case ADJUSTMENT_PITCH_RATE
:
475 newValue
= constrain(value
, 0, CONTROL_RATE_CONFIG_RATE_MAX
);
476 controlRateConfig
->rates
[FD_PITCH
] = newValue
;
477 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_RATE
, newValue
);
478 if (adjustmentFunction
== ADJUSTMENT_PITCH_RATE
) {
481 // fall through for combined ADJUSTMENT_PITCH_ROLL_RATE
483 case ADJUSTMENT_ROLL_RATE
:
484 newValue
= constrain(value
, 0, CONTROL_RATE_CONFIG_RATE_MAX
);
485 controlRateConfig
->rates
[FD_ROLL
] = newValue
;
486 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_RATE
, newValue
);
488 case ADJUSTMENT_YAW_RATE
:
489 newValue
= constrain(value
, 0, CONTROL_RATE_CONFIG_RATE_MAX
);
490 controlRateConfig
->rates
[FD_YAW
] = newValue
;
491 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_RATE
, newValue
);
493 case ADJUSTMENT_PITCH_ROLL_P
:
494 case ADJUSTMENT_PITCH_P
:
495 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
496 currentPidProfile
->pid
[PID_PITCH
].P
= newValue
;
497 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_P
, newValue
);
499 if (adjustmentFunction
== ADJUSTMENT_PITCH_P
) {
502 // fall through for combined ADJUSTMENT_PITCH_ROLL_P
504 case ADJUSTMENT_ROLL_P
:
505 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
506 currentPidProfile
->pid
[PID_ROLL
].P
= newValue
;
507 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_P
, newValue
);
509 case ADJUSTMENT_PITCH_ROLL_I
:
510 case ADJUSTMENT_PITCH_I
:
511 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
512 currentPidProfile
->pid
[PID_PITCH
].I
= newValue
;
513 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_I
, newValue
);
514 if (adjustmentFunction
== ADJUSTMENT_PITCH_I
) {
517 // fall through for combined ADJUSTMENT_PITCH_ROLL_I
519 case ADJUSTMENT_ROLL_I
:
520 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
521 currentPidProfile
->pid
[PID_ROLL
].I
= newValue
;
522 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_I
, newValue
);
524 case ADJUSTMENT_PITCH_ROLL_D
:
525 case ADJUSTMENT_PITCH_D
:
526 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
527 currentPidProfile
->pid
[PID_PITCH
].D
= newValue
;
528 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_D
, newValue
);
529 if (adjustmentFunction
== ADJUSTMENT_PITCH_D
) {
532 // fall through for combined ADJUSTMENT_PITCH_ROLL_D
534 case ADJUSTMENT_ROLL_D
:
535 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
536 currentPidProfile
->pid
[PID_ROLL
].D
= newValue
;
537 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_D
, newValue
);
539 case ADJUSTMENT_YAW_P
:
540 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
541 currentPidProfile
->pid
[PID_YAW
].P
= newValue
;
542 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_P
, newValue
);
544 case ADJUSTMENT_YAW_I
:
545 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
546 currentPidProfile
->pid
[PID_YAW
].I
= newValue
;
547 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_I
, newValue
);
549 case ADJUSTMENT_YAW_D
:
550 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
551 currentPidProfile
->pid
[PID_YAW
].D
= newValue
;
552 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_D
, newValue
);
554 case ADJUSTMENT_RC_RATE_YAW
:
555 newValue
= constrain(value
, 1, CONTROL_RATE_CONFIG_RC_RATES_MAX
);
556 controlRateConfig
->rcRates
[FD_YAW
] = newValue
;
557 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_RC_RATE_YAW
, newValue
);
559 case ADJUSTMENT_PITCH_ROLL_F
:
560 case ADJUSTMENT_PITCH_F
:
561 newValue
= constrain(value
, 0, 2000);
562 currentPidProfile
->pid
[PID_PITCH
].F
= newValue
;
563 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_F
, newValue
);
565 if (adjustmentFunction
== ADJUSTMENT_PITCH_F
) {
568 // fall through for combined ADJUSTMENT_PITCH_ROLL_F
570 case ADJUSTMENT_ROLL_F
:
571 newValue
= constrain(value
, 0, 2000);
572 currentPidProfile
->pid
[PID_ROLL
].F
= newValue
;
573 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_F
, newValue
);
575 case ADJUSTMENT_YAW_F
:
576 newValue
= constrain(value
, 0, 2000);
577 currentPidProfile
->pid
[PID_YAW
].F
= newValue
;
578 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_F
, newValue
);
580 case ADJUSTMENT_FEEDFORWARD_TRANSITION
:
581 newValue
= constrain(value
, 1, 100); // FIXME magic numbers repeated in cli.c
582 currentPidProfile
->feedforwardTransition
= newValue
;
583 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_FEEDFORWARD_TRANSITION
, newValue
);
593 static uint8_t applySelectAdjustment(adjustmentFunction_e adjustmentFunction
, uint8_t position
)
597 switch (adjustmentFunction
) {
598 case ADJUSTMENT_RATE_PROFILE
:
599 if (getCurrentControlRateProfileIndex() != position
) {
600 changeControlRateProfile(position
);
601 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_RATE_PROFILE
, position
);
603 beeps
= position
+ 1;
606 case ADJUSTMENT_HORIZON_STRENGTH
:
608 uint8_t newValue
= constrain(position
, 0, 200); // FIXME magic numbers repeated in serial_cli.c
609 if (currentPidProfile
->pid
[PID_LEVEL
].D
!= newValue
) {
610 beeps
= ((newValue
- currentPidProfile
->pid
[PID_LEVEL
].D
) / 8) + 1;
611 currentPidProfile
->pid
[PID_LEVEL
].D
= newValue
;
612 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_HORIZON_STRENGTH
, position
);
616 case ADJUSTMENT_PID_AUDIO
:
619 pidAudioModes_e newMode
= pidAudioPositionToModeMap
[position
];
620 if (newMode
!= pidAudioGetMode()) {
621 pidAudioSetMode(newMode
);
626 case ADJUSTMENT_OSD_PROFILE
:
627 #ifdef USE_OSD_PROFILES
628 if (getCurrentOsdProfileIndex() != (position
+ 1)) {
629 changeOsdProfileIndex(position
+1);
633 case ADJUSTMENT_LED_PROFILE
:
635 if (getLedProfile() != position
) {
636 setLedProfile(position
);
646 beeperConfirmationBeeps(beeps
);
652 #define ADJUSTMENT_FUNCTION_CONFIG_INDEX_OFFSET 1
654 static void calcActiveAdjustmentRanges(void)
656 adjustmentRange_t defaultAdjustmentRange
;
657 memset(&defaultAdjustmentRange
, 0, sizeof(defaultAdjustmentRange
));
659 stepwiseAdjustmentCount
= 0;
660 continuosAdjustmentCount
= 0;
661 for (int i
= 0; i
< MAX_ADJUSTMENT_RANGE_COUNT
; i
++) {
662 const adjustmentRange_t
* const adjustmentRange
= adjustmentRanges(i
);
663 if (memcmp(adjustmentRange
, &defaultAdjustmentRange
, sizeof(defaultAdjustmentRange
)) != 0) {
664 const adjustmentConfig_t
*adjustmentConfig
= &defaultAdjustmentConfigs
[adjustmentRange
->adjustmentConfig
- ADJUSTMENT_FUNCTION_CONFIG_INDEX_OFFSET
];
665 if (adjustmentRange
->adjustmentCenter
== 0 && adjustmentConfig
->mode
!= ADJUSTMENT_MODE_SELECT
) {
666 timedAdjustmentState_t
*adjustmentState
= &stepwiseAdjustments
[stepwiseAdjustmentCount
++];
667 adjustmentState
->adjustmentRangeIndex
= i
;
668 adjustmentState
->timeoutAt
= 0;
669 adjustmentState
->ready
= true;
671 continuosAdjustmentState_t
*adjustmentState
= &continuosAdjustments
[continuosAdjustmentCount
++];
672 adjustmentState
->adjustmentRangeIndex
= i
;
673 adjustmentState
->lastRcData
= 0;
679 #define VALUE_DISPLAY_LATENCY_MS 2000
681 #if defined(USE_OSD) && defined(USE_OSD_ADJUSTMENTS)
682 static void updateOsdAdjustmentData(int newValue
, adjustmentFunction_e adjustmentFunction
)
684 static timeMs_t lastValueChangeMs
;
686 timeMs_t currentTimeMs
= millis();
688 && adjustmentFunction
!= ADJUSTMENT_RATE_PROFILE
// Rate profile already has an OSD element
689 #ifdef USE_OSD_PROFILES
690 && adjustmentFunction
!= ADJUSTMENT_OSD_PROFILE
693 adjustmentRangeNameIndex
= adjustmentFunction
;
694 adjustmentRangeValue
= newValue
;
696 lastValueChangeMs
= currentTimeMs
;
699 if (cmp32(currentTimeMs
, lastValueChangeMs
+ VALUE_DISPLAY_LATENCY_MS
) >= 0) {
700 adjustmentRangeNameIndex
= 0;
705 #define RESET_FREQUENCY_2HZ (1000 / 2)
707 static void processStepwiseAdjustments(controlRateConfig_t
*controlRateConfig
, const bool canUseRxData
)
709 const timeMs_t now
= millis();
711 for (int index
= 0; index
< stepwiseAdjustmentCount
; index
++) {
712 timedAdjustmentState_t
*adjustmentState
= &stepwiseAdjustments
[index
];
713 const adjustmentRange_t
*const adjustmentRange
= adjustmentRanges(adjustmentState
->adjustmentRangeIndex
);
714 const adjustmentConfig_t
*adjustmentConfig
= &defaultAdjustmentConfigs
[adjustmentRange
->adjustmentConfig
- ADJUSTMENT_FUNCTION_CONFIG_INDEX_OFFSET
];
715 const adjustmentFunction_e adjustmentFunction
= adjustmentConfig
->adjustmentFunction
;
717 if (!isRangeActive(adjustmentRange
->auxChannelIndex
, &adjustmentRange
->range
) ||
718 adjustmentFunction
== ADJUSTMENT_NONE
) {
719 adjustmentState
->timeoutAt
= 0;
724 if (cmp32(now
, adjustmentState
->timeoutAt
) >= 0) {
725 adjustmentState
->timeoutAt
= now
+ RESET_FREQUENCY_2HZ
;
726 adjustmentState
->ready
= true;
733 const uint8_t channelIndex
= NON_AUX_CHANNEL_COUNT
+ adjustmentRange
->auxSwitchChannelIndex
;
735 if (adjustmentConfig
->mode
== ADJUSTMENT_MODE_STEP
) {
737 if (rcData
[channelIndex
] > rxConfig()->midrc
+ 200) {
738 delta
= adjustmentConfig
->data
.step
;
739 } else if (rcData
[channelIndex
] < rxConfig()->midrc
- 200) {
740 delta
= -adjustmentConfig
->data
.step
;
742 // returning the switch to the middle immediately resets the ready state
743 adjustmentState
->ready
= true;
744 adjustmentState
->timeoutAt
= now
+ RESET_FREQUENCY_2HZ
;
747 if (!adjustmentState
->ready
) {
751 int newValue
= applyStepAdjustment(controlRateConfig
, adjustmentFunction
, delta
);
755 pidInitConfig(currentPidProfile
);
757 adjustmentState
->ready
= false;
759 #if defined(USE_OSD) && defined(USE_OSD_ADJUSTMENTS)
760 updateOsdAdjustmentData(newValue
, adjustmentConfig
->adjustmentFunction
);
768 static void setConfigDirtyIfNotPermanent(const channelRange_t
*range
)
770 if (!(range
->startStep
== MIN_MODE_RANGE_STEP
&& range
->endStep
== MAX_MODE_RANGE_STEP
)) {
771 // Only set the configuration dirty if this range is NOT permanently enabled (and the config thus never used).
776 static void processContinuosAdjustments(controlRateConfig_t
*controlRateConfig
)
778 for (int i
= 0; i
< continuosAdjustmentCount
; i
++) {
779 continuosAdjustmentState_t
*adjustmentState
= &continuosAdjustments
[i
];
780 const adjustmentRange_t
* const adjustmentRange
= adjustmentRanges(adjustmentState
->adjustmentRangeIndex
);
781 const uint8_t channelIndex
= NON_AUX_CHANNEL_COUNT
+ adjustmentRange
->auxSwitchChannelIndex
;
782 const adjustmentConfig_t
*adjustmentConfig
= &defaultAdjustmentConfigs
[adjustmentRange
->adjustmentConfig
- ADJUSTMENT_FUNCTION_CONFIG_INDEX_OFFSET
];
783 const adjustmentFunction_e adjustmentFunction
= adjustmentConfig
->adjustmentFunction
;
785 if (isRangeActive(adjustmentRange
->auxChannelIndex
, &adjustmentRange
->range
) &&
786 adjustmentFunction
!= ADJUSTMENT_NONE
) {
788 if (rcData
[channelIndex
] != adjustmentState
->lastRcData
) {
791 if (adjustmentConfig
->mode
== ADJUSTMENT_MODE_SELECT
) {
792 int switchPositions
= adjustmentConfig
->data
.switchPositions
;
793 if (adjustmentFunction
== ADJUSTMENT_RATE_PROFILE
&& systemConfig()->rateProfile6PosSwitch
) {
796 const uint16_t rangeWidth
= (2100 - 900) / switchPositions
;
797 const uint8_t position
= (constrain(rcData
[channelIndex
], 900, 2100 - 1) - 900) / rangeWidth
;
798 newValue
= applySelectAdjustment(adjustmentFunction
, position
);
800 setConfigDirtyIfNotPermanent(&adjustmentRange
->range
);
802 // If setting is defined for step adjustment and center value has been specified, apply values directly (scaled) from aux channel
803 if (adjustmentRange
->adjustmentCenter
&&
804 (adjustmentConfig
->mode
== ADJUSTMENT_MODE_STEP
)) {
805 int value
= (((rcData
[channelIndex
] - PWM_RANGE_MIDDLE
) * adjustmentRange
->adjustmentScale
) / (PWM_RANGE_MIDDLE
- PWM_RANGE_MIN
)) + adjustmentRange
->adjustmentCenter
;
807 newValue
= applyAbsoluteAdjustment(controlRateConfig
, adjustmentFunction
, value
);
809 setConfigDirtyIfNotPermanent(&adjustmentRange
->range
);
811 pidInitConfig(currentPidProfile
);
814 #if defined(USE_OSD) && defined(USE_OSD_ADJUSTMENTS)
815 updateOsdAdjustmentData(newValue
, adjustmentConfig
->adjustmentFunction
);
819 adjustmentState
->lastRcData
= rcData
[channelIndex
];
822 adjustmentState
->lastRcData
= 0;
827 void processRcAdjustments(controlRateConfig_t
*controlRateConfig
)
829 const bool canUseRxData
= rxIsReceivingSignal();
831 // Recalculate the new active adjustments if required
832 if (stepwiseAdjustmentCount
== ADJUSTMENT_RANGE_COUNT_INVALID
) {
833 calcActiveAdjustmentRanges();
836 processStepwiseAdjustments(controlRateConfig
, canUseRxData
);
839 processContinuosAdjustments(controlRateConfig
);
842 #if defined(USE_OSD) && defined(USE_OSD_ADJUSTMENTS)
843 // Hide the element if there is no change
844 updateOsdAdjustmentData(-1, 0);
848 #if defined(USE_OSD) && defined(USE_OSD_ADJUSTMENTS)
849 const char *getAdjustmentsRangeName(void)
851 if (adjustmentRangeNameIndex
> 0) {
852 return &adjustmentLabels
[adjustmentRangeNameIndex
- 1][0];
858 int getAdjustmentsRangeValue(void)
860 return adjustmentRangeValue
;
864 void activeAdjustmentRangeReset(void)
866 stepwiseAdjustmentCount
= ADJUSTMENT_RANGE_COUNT_INVALID
;