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 #if defined(USE_FEEDFORWARD)
420 case ADJUSTMENT_FEEDFORWARD_TRANSITION
:
421 newValue
= constrain(currentPidProfile
->feedforward_transition
+ delta
, 1, 100); // FIXME magic numbers repeated in cli.c
422 currentPidProfile
->feedforward_transition
= newValue
;
423 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_FEEDFORWARD_TRANSITION
, newValue
);
434 static int applyAbsoluteAdjustment(controlRateConfig_t
*controlRateConfig
, adjustmentFunction_e adjustmentFunction
, int value
)
438 switch (adjustmentFunction
) {
439 case ADJUSTMENT_RC_RATE
:
440 case ADJUSTMENT_ROLL_RC_RATE
:
441 newValue
= constrain(value
, 1, CONTROL_RATE_CONFIG_RC_RATES_MAX
);
442 controlRateConfig
->rcRates
[FD_ROLL
] = newValue
;
443 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_RC_RATE
, newValue
);
444 if (adjustmentFunction
== ADJUSTMENT_ROLL_RC_RATE
) {
447 // fall through for combined ADJUSTMENT_RC_EXPO
449 case ADJUSTMENT_PITCH_RC_RATE
:
450 newValue
= constrain(value
, 1, CONTROL_RATE_CONFIG_RC_RATES_MAX
);
451 controlRateConfig
->rcRates
[FD_PITCH
] = newValue
;
452 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_RC_RATE
, newValue
);
454 case ADJUSTMENT_RC_EXPO
:
455 case ADJUSTMENT_ROLL_RC_EXPO
:
456 newValue
= constrain(value
, 1, CONTROL_RATE_CONFIG_RC_EXPO_MAX
);
457 controlRateConfig
->rcExpo
[FD_ROLL
] = newValue
;
458 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_RC_EXPO
, newValue
);
459 if (adjustmentFunction
== ADJUSTMENT_ROLL_RC_EXPO
) {
462 // fall through for combined ADJUSTMENT_RC_EXPO
464 case ADJUSTMENT_PITCH_RC_EXPO
:
465 newValue
= constrain(value
, 0, CONTROL_RATE_CONFIG_RC_EXPO_MAX
);
466 controlRateConfig
->rcExpo
[FD_PITCH
] = newValue
;
467 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_RC_EXPO
, newValue
);
469 case ADJUSTMENT_THROTTLE_EXPO
:
470 newValue
= constrain(value
, 0, 100); // FIXME magic numbers repeated in cli.c
471 controlRateConfig
->thrExpo8
= newValue
;
473 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_THROTTLE_EXPO
, newValue
);
475 case ADJUSTMENT_PITCH_ROLL_RATE
:
476 case ADJUSTMENT_PITCH_RATE
:
477 newValue
= constrain(value
, 0, CONTROL_RATE_CONFIG_RATE_MAX
);
478 controlRateConfig
->rates
[FD_PITCH
] = newValue
;
479 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_RATE
, newValue
);
480 if (adjustmentFunction
== ADJUSTMENT_PITCH_RATE
) {
483 // fall through for combined ADJUSTMENT_PITCH_ROLL_RATE
485 case ADJUSTMENT_ROLL_RATE
:
486 newValue
= constrain(value
, 0, CONTROL_RATE_CONFIG_RATE_MAX
);
487 controlRateConfig
->rates
[FD_ROLL
] = newValue
;
488 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_RATE
, newValue
);
490 case ADJUSTMENT_YAW_RATE
:
491 newValue
= constrain(value
, 0, CONTROL_RATE_CONFIG_RATE_MAX
);
492 controlRateConfig
->rates
[FD_YAW
] = newValue
;
493 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_RATE
, newValue
);
495 case ADJUSTMENT_PITCH_ROLL_P
:
496 case ADJUSTMENT_PITCH_P
:
497 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
498 currentPidProfile
->pid
[PID_PITCH
].P
= newValue
;
499 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_P
, newValue
);
501 if (adjustmentFunction
== ADJUSTMENT_PITCH_P
) {
504 // fall through for combined ADJUSTMENT_PITCH_ROLL_P
506 case ADJUSTMENT_ROLL_P
:
507 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
508 currentPidProfile
->pid
[PID_ROLL
].P
= newValue
;
509 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_P
, newValue
);
511 case ADJUSTMENT_PITCH_ROLL_I
:
512 case ADJUSTMENT_PITCH_I
:
513 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
514 currentPidProfile
->pid
[PID_PITCH
].I
= newValue
;
515 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_I
, newValue
);
516 if (adjustmentFunction
== ADJUSTMENT_PITCH_I
) {
519 // fall through for combined ADJUSTMENT_PITCH_ROLL_I
521 case ADJUSTMENT_ROLL_I
:
522 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
523 currentPidProfile
->pid
[PID_ROLL
].I
= newValue
;
524 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_I
, newValue
);
526 case ADJUSTMENT_PITCH_ROLL_D
:
527 case ADJUSTMENT_PITCH_D
:
528 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
529 currentPidProfile
->pid
[PID_PITCH
].D
= newValue
;
530 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_D
, newValue
);
531 if (adjustmentFunction
== ADJUSTMENT_PITCH_D
) {
534 // fall through for combined ADJUSTMENT_PITCH_ROLL_D
536 case ADJUSTMENT_ROLL_D
:
537 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
538 currentPidProfile
->pid
[PID_ROLL
].D
= newValue
;
539 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_D
, newValue
);
541 case ADJUSTMENT_YAW_P
:
542 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
543 currentPidProfile
->pid
[PID_YAW
].P
= newValue
;
544 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_P
, newValue
);
546 case ADJUSTMENT_YAW_I
:
547 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
548 currentPidProfile
->pid
[PID_YAW
].I
= newValue
;
549 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_I
, newValue
);
551 case ADJUSTMENT_YAW_D
:
552 newValue
= constrain(value
, 0, 200); // FIXME magic numbers repeated in cli.c
553 currentPidProfile
->pid
[PID_YAW
].D
= newValue
;
554 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_D
, newValue
);
556 case ADJUSTMENT_RC_RATE_YAW
:
557 newValue
= constrain(value
, 1, CONTROL_RATE_CONFIG_RC_RATES_MAX
);
558 controlRateConfig
->rcRates
[FD_YAW
] = newValue
;
559 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_RC_RATE_YAW
, newValue
);
561 case ADJUSTMENT_PITCH_ROLL_F
:
562 case ADJUSTMENT_PITCH_F
:
563 newValue
= constrain(value
, 0, 2000);
564 currentPidProfile
->pid
[PID_PITCH
].F
= newValue
;
565 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_PITCH_F
, newValue
);
567 if (adjustmentFunction
== ADJUSTMENT_PITCH_F
) {
570 // fall through for combined ADJUSTMENT_PITCH_ROLL_F
572 case ADJUSTMENT_ROLL_F
:
573 newValue
= constrain(value
, 0, 2000);
574 currentPidProfile
->pid
[PID_ROLL
].F
= newValue
;
575 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_ROLL_F
, newValue
);
577 case ADJUSTMENT_YAW_F
:
578 newValue
= constrain(value
, 0, 2000);
579 currentPidProfile
->pid
[PID_YAW
].F
= newValue
;
580 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_YAW_F
, newValue
);
582 #if defined(USE_FEEDFORWARD)
583 case ADJUSTMENT_FEEDFORWARD_TRANSITION
:
584 newValue
= constrain(value
, 1, 100); // FIXME magic numbers repeated in cli.c
585 currentPidProfile
->feedforward_transition
= newValue
;
586 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_FEEDFORWARD_TRANSITION
, newValue
);
597 static uint8_t applySelectAdjustment(adjustmentFunction_e adjustmentFunction
, uint8_t position
)
601 switch (adjustmentFunction
) {
602 case ADJUSTMENT_RATE_PROFILE
:
603 if (getCurrentControlRateProfileIndex() != position
) {
604 changeControlRateProfile(position
);
605 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_RATE_PROFILE
, position
);
607 beeps
= position
+ 1;
610 case ADJUSTMENT_HORIZON_STRENGTH
:
612 uint8_t newValue
= constrain(position
, 0, 200); // FIXME magic numbers repeated in serial_cli.c
613 if (currentPidProfile
->pid
[PID_LEVEL
].D
!= newValue
) {
614 beeps
= ((newValue
- currentPidProfile
->pid
[PID_LEVEL
].D
) / 8) + 1;
615 currentPidProfile
->pid
[PID_LEVEL
].D
= newValue
;
616 blackboxLogInflightAdjustmentEvent(ADJUSTMENT_HORIZON_STRENGTH
, position
);
620 case ADJUSTMENT_PID_AUDIO
:
623 pidAudioModes_e newMode
= pidAudioPositionToModeMap
[position
];
624 if (newMode
!= pidAudioGetMode()) {
625 pidAudioSetMode(newMode
);
630 case ADJUSTMENT_OSD_PROFILE
:
631 #ifdef USE_OSD_PROFILES
632 if (getCurrentOsdProfileIndex() != (position
+ 1)) {
633 changeOsdProfileIndex(position
+1);
637 case ADJUSTMENT_LED_PROFILE
:
639 if (getLedProfile() != position
) {
640 setLedProfile(position
);
650 beeperConfirmationBeeps(beeps
);
656 #define ADJUSTMENT_FUNCTION_CONFIG_INDEX_OFFSET 1
658 static void calcActiveAdjustmentRanges(void)
660 adjustmentRange_t defaultAdjustmentRange
;
661 memset(&defaultAdjustmentRange
, 0, sizeof(defaultAdjustmentRange
));
663 stepwiseAdjustmentCount
= 0;
664 continuosAdjustmentCount
= 0;
665 for (int i
= 0; i
< MAX_ADJUSTMENT_RANGE_COUNT
; i
++) {
666 const adjustmentRange_t
* const adjustmentRange
= adjustmentRanges(i
);
667 if (memcmp(adjustmentRange
, &defaultAdjustmentRange
, sizeof(defaultAdjustmentRange
)) != 0) {
668 const adjustmentConfig_t
*adjustmentConfig
= &defaultAdjustmentConfigs
[adjustmentRange
->adjustmentConfig
- ADJUSTMENT_FUNCTION_CONFIG_INDEX_OFFSET
];
669 if (adjustmentRange
->adjustmentCenter
== 0 && adjustmentConfig
->mode
!= ADJUSTMENT_MODE_SELECT
) {
670 timedAdjustmentState_t
*adjustmentState
= &stepwiseAdjustments
[stepwiseAdjustmentCount
++];
671 adjustmentState
->adjustmentRangeIndex
= i
;
672 adjustmentState
->timeoutAt
= 0;
673 adjustmentState
->ready
= true;
675 continuosAdjustmentState_t
*adjustmentState
= &continuosAdjustments
[continuosAdjustmentCount
++];
676 adjustmentState
->adjustmentRangeIndex
= i
;
677 adjustmentState
->lastRcData
= 0;
683 #define VALUE_DISPLAY_LATENCY_MS 2000
685 #if defined(USE_OSD) && defined(USE_OSD_ADJUSTMENTS)
686 static void updateOsdAdjustmentData(int newValue
, adjustmentFunction_e adjustmentFunction
)
688 static timeMs_t lastValueChangeMs
;
690 timeMs_t currentTimeMs
= millis();
692 && adjustmentFunction
!= ADJUSTMENT_RATE_PROFILE
// Rate profile already has an OSD element
693 #ifdef USE_OSD_PROFILES
694 && adjustmentFunction
!= ADJUSTMENT_OSD_PROFILE
697 adjustmentRangeNameIndex
= adjustmentFunction
;
698 adjustmentRangeValue
= newValue
;
700 lastValueChangeMs
= currentTimeMs
;
703 if (cmp32(currentTimeMs
, lastValueChangeMs
+ VALUE_DISPLAY_LATENCY_MS
) >= 0) {
704 adjustmentRangeNameIndex
= 0;
709 #define RESET_FREQUENCY_2HZ (1000 / 2)
711 static void processStepwiseAdjustments(controlRateConfig_t
*controlRateConfig
, const bool canUseRxData
)
713 const timeMs_t now
= millis();
715 for (int index
= 0; index
< stepwiseAdjustmentCount
; index
++) {
716 timedAdjustmentState_t
*adjustmentState
= &stepwiseAdjustments
[index
];
717 const adjustmentRange_t
*const adjustmentRange
= adjustmentRanges(adjustmentState
->adjustmentRangeIndex
);
718 const adjustmentConfig_t
*adjustmentConfig
= &defaultAdjustmentConfigs
[adjustmentRange
->adjustmentConfig
- ADJUSTMENT_FUNCTION_CONFIG_INDEX_OFFSET
];
719 const adjustmentFunction_e adjustmentFunction
= adjustmentConfig
->adjustmentFunction
;
721 if (!isRangeActive(adjustmentRange
->auxChannelIndex
, &adjustmentRange
->range
) ||
722 adjustmentFunction
== ADJUSTMENT_NONE
) {
723 adjustmentState
->timeoutAt
= 0;
728 if (cmp32(now
, adjustmentState
->timeoutAt
) >= 0) {
729 adjustmentState
->timeoutAt
= now
+ RESET_FREQUENCY_2HZ
;
730 adjustmentState
->ready
= true;
737 const uint8_t channelIndex
= NON_AUX_CHANNEL_COUNT
+ adjustmentRange
->auxSwitchChannelIndex
;
739 if (adjustmentConfig
->mode
== ADJUSTMENT_MODE_STEP
) {
741 if (rcData
[channelIndex
] > rxConfig()->midrc
+ 200) {
742 delta
= adjustmentConfig
->data
.step
;
743 } else if (rcData
[channelIndex
] < rxConfig()->midrc
- 200) {
744 delta
= -adjustmentConfig
->data
.step
;
746 // returning the switch to the middle immediately resets the ready state
747 adjustmentState
->ready
= true;
748 adjustmentState
->timeoutAt
= now
+ RESET_FREQUENCY_2HZ
;
751 if (!adjustmentState
->ready
) {
755 int newValue
= applyStepAdjustment(controlRateConfig
, adjustmentFunction
, delta
);
759 pidInitConfig(currentPidProfile
);
761 adjustmentState
->ready
= false;
763 #if defined(USE_OSD) && defined(USE_OSD_ADJUSTMENTS)
764 updateOsdAdjustmentData(newValue
, adjustmentConfig
->adjustmentFunction
);
772 static void setConfigDirtyIfNotPermanent(const channelRange_t
*range
)
774 if (!(range
->startStep
== MIN_MODE_RANGE_STEP
&& range
->endStep
== MAX_MODE_RANGE_STEP
)) {
775 // Only set the configuration dirty if this range is NOT permanently enabled (and the config thus never used).
780 static void processContinuosAdjustments(controlRateConfig_t
*controlRateConfig
)
782 for (int i
= 0; i
< continuosAdjustmentCount
; i
++) {
783 continuosAdjustmentState_t
*adjustmentState
= &continuosAdjustments
[i
];
784 const adjustmentRange_t
* const adjustmentRange
= adjustmentRanges(adjustmentState
->adjustmentRangeIndex
);
785 const uint8_t channelIndex
= NON_AUX_CHANNEL_COUNT
+ adjustmentRange
->auxSwitchChannelIndex
;
786 const adjustmentConfig_t
*adjustmentConfig
= &defaultAdjustmentConfigs
[adjustmentRange
->adjustmentConfig
- ADJUSTMENT_FUNCTION_CONFIG_INDEX_OFFSET
];
787 const adjustmentFunction_e adjustmentFunction
= adjustmentConfig
->adjustmentFunction
;
789 if (isRangeActive(adjustmentRange
->auxChannelIndex
, &adjustmentRange
->range
) &&
790 adjustmentFunction
!= ADJUSTMENT_NONE
) {
792 if (rcData
[channelIndex
] != adjustmentState
->lastRcData
) {
795 if (adjustmentConfig
->mode
== ADJUSTMENT_MODE_SELECT
) {
796 int switchPositions
= adjustmentConfig
->data
.switchPositions
;
797 if (adjustmentFunction
== ADJUSTMENT_RATE_PROFILE
&& systemConfig()->rateProfile6PosSwitch
) {
800 const uint16_t rangeWidth
= (2100 - 900) / switchPositions
;
801 const uint8_t position
= (constrain(rcData
[channelIndex
], 900, 2100 - 1) - 900) / rangeWidth
;
802 newValue
= applySelectAdjustment(adjustmentFunction
, position
);
804 setConfigDirtyIfNotPermanent(&adjustmentRange
->range
);
806 // If setting is defined for step adjustment and center value has been specified, apply values directly (scaled) from aux channel
807 if (adjustmentRange
->adjustmentCenter
&&
808 (adjustmentConfig
->mode
== ADJUSTMENT_MODE_STEP
)) {
809 int value
= (((rcData
[channelIndex
] - PWM_RANGE_MIDDLE
) * adjustmentRange
->adjustmentScale
) / (PWM_RANGE_MIDDLE
- PWM_RANGE_MIN
)) + adjustmentRange
->adjustmentCenter
;
811 newValue
= applyAbsoluteAdjustment(controlRateConfig
, adjustmentFunction
, value
);
813 setConfigDirtyIfNotPermanent(&adjustmentRange
->range
);
815 pidInitConfig(currentPidProfile
);
818 #if defined(USE_OSD) && defined(USE_OSD_ADJUSTMENTS)
819 updateOsdAdjustmentData(newValue
, adjustmentConfig
->adjustmentFunction
);
823 adjustmentState
->lastRcData
= rcData
[channelIndex
];
826 adjustmentState
->lastRcData
= 0;
831 void processRcAdjustments(controlRateConfig_t
*controlRateConfig
)
833 const bool canUseRxData
= rxIsReceivingSignal();
835 // Recalculate the new active adjustments if required
836 if (stepwiseAdjustmentCount
== ADJUSTMENT_RANGE_COUNT_INVALID
) {
837 calcActiveAdjustmentRanges();
840 processStepwiseAdjustments(controlRateConfig
, canUseRxData
);
843 processContinuosAdjustments(controlRateConfig
);
846 #if defined(USE_OSD) && defined(USE_OSD_ADJUSTMENTS)
847 // Hide the element if there is no change
848 updateOsdAdjustmentData(-1, 0);
852 #if defined(USE_OSD) && defined(USE_OSD_ADJUSTMENTS)
853 const char *getAdjustmentsRangeName(void)
855 if (adjustmentRangeNameIndex
> 0) {
856 return &adjustmentLabels
[adjustmentRangeNameIndex
- 1][0];
862 int getAdjustmentsRangeValue(void)
864 return adjustmentRangeValue
;
868 void activeAdjustmentRangeReset(void)
870 stepwiseAdjustmentCount
= ADJUSTMENT_RANGE_COUNT_INVALID
;