2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
24 FILE_COMPILE_FOR_SPEED
26 #include "blackbox/blackbox.h"
28 #include "build/debug.h"
30 #include "common/maths.h"
31 #include "common/axis.h"
32 #include "common/color.h"
33 #include "common/utils.h"
34 #include "common/filter.h"
36 #include "drivers/light_led.h"
37 #include "drivers/serial.h"
38 #include "drivers/time.h"
39 #include "drivers/system.h"
40 #include "drivers/pwm_output.h"
42 #include "sensors/sensors.h"
43 #include "sensors/diagnostics.h"
44 #include "sensors/boardalignment.h"
45 #include "sensors/acceleration.h"
46 #include "sensors/barometer.h"
47 #include "sensors/compass.h"
48 #include "sensors/pitotmeter.h"
49 #include "sensors/gyro.h"
50 #include "sensors/battery.h"
51 #include "sensors/rangefinder.h"
52 #include "sensors/opflow.h"
53 #include "sensors/esc_sensor.h"
55 #include "fc/fc_core.h"
57 #include "fc/config.h"
58 #include "fc/controlrate_profile.h"
59 #include "fc/rc_adjustments.h"
60 #include "fc/rc_smoothing.h"
61 #include "fc/rc_controls.h"
62 #include "fc/rc_curves.h"
63 #include "fc/rc_modes.h"
64 #include "fc/runtime_config.h"
66 #include "io/beeper.h"
67 #include "io/dashboard.h"
69 #include "io/serial.h"
70 #include "io/statusindicator.h"
71 #include "io/asyncfatfs/asyncfatfs.h"
72 #include "io/piniobox.h"
74 #include "msp/msp_serial.h"
76 #include "navigation/navigation.h"
81 #include "scheduler/scheduler.h"
83 #include "telemetry/telemetry.h"
85 #include "flight/mixer.h"
86 #include "flight/servos.h"
87 #include "flight/pid.h"
88 #include "flight/imu.h"
89 #include "flight/rate_dynamics.h"
91 #include "flight/failsafe.h"
92 #include "flight/power_limits.h"
94 #include "config/feature.h"
95 #include "common/vector.h"
96 #include "programming/pid.h"
106 #define EMERGENCY_ARMING_TIME_WINDOW_MS 10000
107 #define EMERGENCY_ARMING_COUNTER_STEP_MS 1000
108 #define EMERGENCY_ARMING_MIN_ARM_COUNT 10
110 timeDelta_t cycleTime
= 0; // this is the number in micro second to achieve a full loop, it can differ a little and is taken into account in the PID loop
111 static timeUs_t flightTime
= 0;
112 static timeUs_t armTime
= 0;
114 EXTENDED_FASTRAM
float dT
;
116 int16_t headFreeModeHold
;
118 uint8_t motorControlEnable
= false;
120 static bool isRXDataNew
;
121 static disarmReason_t lastDisarmReason
= DISARM_NONE
;
122 timeUs_t lastDisarmTimeUs
= 0;
124 static bool prearmWasReset
= false; // Prearm must be reset (RC Mode not active) before arming is possible
125 static timeMs_t prearmActivationTime
= 0;
127 bool areSensorsCalibrating(void)
130 if (sensors(SENSOR_BARO
) && !baroIsCalibrationComplete()) {
136 if (sensors(SENSOR_MAG
) && !compassIsCalibrationComplete()) {
142 if (sensors(SENSOR_PITOT
) && !pitotIsCalibrationComplete()) {
147 if (!navIsCalibrationComplete()) {
151 if (!accIsCalibrationComplete() && sensors(SENSOR_ACC
)) {
155 if (!gyroIsCalibrationComplete()) {
162 int16_t getAxisRcCommand(int16_t rawData
, int16_t rate
, int16_t deadband
)
164 int16_t stickDeflection
;
166 stickDeflection
= constrain(rawData
- PWM_RANGE_MIDDLE
, -500, 500);
167 stickDeflection
= applyDeadbandRescaled(stickDeflection
, deadband
, -500, 500);
169 return rcLookup(stickDeflection
, rate
);
172 static void updateArmingStatus(void)
174 if (ARMING_FLAG(ARMED
)) {
177 /* CHECK: Run-time calibration */
178 static bool calibratingFinishedBeep
= false;
179 if (areSensorsCalibrating()) {
180 ENABLE_ARMING_FLAG(ARMING_DISABLED_SENSORS_CALIBRATING
);
181 calibratingFinishedBeep
= false;
184 DISABLE_ARMING_FLAG(ARMING_DISABLED_SENSORS_CALIBRATING
);
186 if (!calibratingFinishedBeep
) {
187 calibratingFinishedBeep
= true;
188 beeper(BEEPER_RUNTIME_CALIBRATION_DONE
);
192 /* CHECK: RX signal */
193 if (!failsafeIsReceivingRxData()) {
194 ENABLE_ARMING_FLAG(ARMING_DISABLED_RC_LINK
);
197 DISABLE_ARMING_FLAG(ARMING_DISABLED_RC_LINK
);
200 /* CHECK: Throttle */
201 if (!armingConfig()->fixed_wing_auto_arm
) {
202 // Don't want this check if fixed_wing_auto_arm is in use - machine arms on throttle > LOW
203 if (throttleStickIsLow()) {
204 DISABLE_ARMING_FLAG(ARMING_DISABLED_THROTTLE
);
206 ENABLE_ARMING_FLAG(ARMING_DISABLED_THROTTLE
);
210 /* CHECK: pitch / roll sticks centered when NAV_LAUNCH_MODE enabled */
211 if (isNavLaunchEnabled()) {
212 if (isRollPitchStickDeflected(rcControlsConfig()->control_deadband
)) {
213 ENABLE_ARMING_FLAG(ARMING_DISABLED_ROLLPITCH_NOT_CENTERED
);
215 DISABLE_ARMING_FLAG(ARMING_DISABLED_ROLLPITCH_NOT_CENTERED
);
220 if (!STATE(SMALL_ANGLE
)) {
221 ENABLE_ARMING_FLAG(ARMING_DISABLED_NOT_LEVEL
);
224 DISABLE_ARMING_FLAG(ARMING_DISABLED_NOT_LEVEL
);
227 /* CHECK: CPU load */
228 if (isSystemOverloaded()) {
229 ENABLE_ARMING_FLAG(ARMING_DISABLED_SYSTEM_OVERLOADED
);
232 DISABLE_ARMING_FLAG(ARMING_DISABLED_SYSTEM_OVERLOADED
);
235 /* CHECK: Navigation safety */
236 if (navigationIsBlockingArming(NULL
) != NAV_ARMING_BLOCKER_NONE
) {
237 ENABLE_ARMING_FLAG(ARMING_DISABLED_NAVIGATION_UNSAFE
);
240 DISABLE_ARMING_FLAG(ARMING_DISABLED_NAVIGATION_UNSAFE
);
245 if (sensors(SENSOR_MAG
) && !STATE(COMPASS_CALIBRATED
)) {
246 ENABLE_ARMING_FLAG(ARMING_DISABLED_COMPASS_NOT_CALIBRATED
);
249 DISABLE_ARMING_FLAG(ARMING_DISABLED_COMPASS_NOT_CALIBRATED
);
255 sensors(SENSOR_ACC
) &&
256 !STATE(ACCELEROMETER_CALIBRATED
) &&
257 // Require ACC calibration only if any of the setting might require it
259 isModeActivationConditionPresent(BOXNAVPOSHOLD
) ||
260 isModeActivationConditionPresent(BOXNAVRTH
) ||
261 isModeActivationConditionPresent(BOXNAVWP
) ||
262 isModeActivationConditionPresent(BOXANGLE
) ||
263 isModeActivationConditionPresent(BOXHORIZON
) ||
264 isModeActivationConditionPresent(BOXNAVALTHOLD
) ||
265 isModeActivationConditionPresent(BOXHEADINGHOLD
) ||
266 isModeActivationConditionPresent(BOXNAVLAUNCH
) ||
267 isModeActivationConditionPresent(BOXTURNASSIST
) ||
268 isModeActivationConditionPresent(BOXNAVCOURSEHOLD
) ||
269 isModeActivationConditionPresent(BOXSOARING
) ||
270 failsafeConfig()->failsafe_procedure
!= FAILSAFE_PROCEDURE_DROP_IT
274 ENABLE_ARMING_FLAG(ARMING_DISABLED_ACCELEROMETER_NOT_CALIBRATED
);
277 DISABLE_ARMING_FLAG(ARMING_DISABLED_ACCELEROMETER_NOT_CALIBRATED
);
281 if (!isHardwareHealthy()) {
282 ENABLE_ARMING_FLAG(ARMING_DISABLED_HARDWARE_FAILURE
);
285 DISABLE_ARMING_FLAG(ARMING_DISABLED_HARDWARE_FAILURE
);
288 /* CHECK: BOXFAILSAFE */
289 if (IS_RC_MODE_ACTIVE(BOXFAILSAFE
)) {
290 ENABLE_ARMING_FLAG(ARMING_DISABLED_BOXFAILSAFE
);
293 DISABLE_ARMING_FLAG(ARMING_DISABLED_BOXFAILSAFE
);
296 /* CHECK: BOXKILLSWITCH */
297 if (IS_RC_MODE_ACTIVE(BOXKILLSWITCH
)) {
298 ENABLE_ARMING_FLAG(ARMING_DISABLED_BOXKILLSWITCH
);
301 DISABLE_ARMING_FLAG(ARMING_DISABLED_BOXKILLSWITCH
);
304 /* CHECK: Do not allow arming if Servo AutoTrim is enabled */
305 if (IS_RC_MODE_ACTIVE(BOXAUTOTRIM
)) {
306 ENABLE_ARMING_FLAG(ARMING_DISABLED_SERVO_AUTOTRIM
);
309 DISABLE_ARMING_FLAG(ARMING_DISABLED_SERVO_AUTOTRIM
);
313 /* CHECK: Don't arm if the DShot beeper was used recently, as there is a minimum delay before sending the next DShot command */
314 if (micros() - getLastDshotBeeperCommandTimeUs() < getDShotBeaconGuardDelayUs()) {
315 ENABLE_ARMING_FLAG(ARMING_DISABLED_DSHOT_BEEPER
);
317 DISABLE_ARMING_FLAG(ARMING_DISABLED_DSHOT_BEEPER
);
320 DISABLE_ARMING_FLAG(ARMING_DISABLED_DSHOT_BEEPER
);
323 if (isModeActivationConditionPresent(BOXPREARM
)) {
324 if (IS_RC_MODE_ACTIVE(BOXPREARM
)) {
325 if (prearmWasReset
&& (armingConfig()->prearmTimeoutMs
== 0 || millis() - prearmActivationTime
< armingConfig()->prearmTimeoutMs
)) {
326 DISABLE_ARMING_FLAG(ARMING_DISABLED_NO_PREARM
);
328 ENABLE_ARMING_FLAG(ARMING_DISABLED_NO_PREARM
);
331 prearmWasReset
= true;
332 prearmActivationTime
= millis();
333 ENABLE_ARMING_FLAG(ARMING_DISABLED_NO_PREARM
);
336 DISABLE_ARMING_FLAG(ARMING_DISABLED_NO_PREARM
);
339 /* CHECK: Arming switch */
340 // If arming is disabled and the ARM switch is on
341 // Note that this should be last check so all other blockers could be cleared correctly
342 // if blocking modes are linked to the same RC channel
343 if (isArmingDisabled() && IS_RC_MODE_ACTIVE(BOXARM
)) {
344 ENABLE_ARMING_FLAG(ARMING_DISABLED_ARM_SWITCH
);
345 } else if (!IS_RC_MODE_ACTIVE(BOXARM
)) {
346 DISABLE_ARMING_FLAG(ARMING_DISABLED_ARM_SWITCH
);
349 if (isArmingDisabled()) {
359 static bool emergencyArmingCanOverrideArmingDisabled(void)
361 uint32_t armingPrevention
= armingFlags
& ARMING_DISABLED_ALL_FLAGS
;
362 armingPrevention
&= ~ARMING_DISABLED_EMERGENCY_OVERRIDE
;
363 return armingPrevention
== 0;
366 static bool emergencyArmingIsEnabled(void)
368 return emergencyArmingUpdate(IS_RC_MODE_ACTIVE(BOXARM
), false) && emergencyArmingCanOverrideArmingDisabled();
371 static void processPilotAndFailSafeActions(float dT
)
373 if (failsafeShouldApplyControlInput()) {
374 // Failsafe will apply rcCommand for us
375 failsafeApplyControlInput();
378 // Compute ROLL PITCH and YAW command
379 rcCommand
[ROLL
] = getAxisRcCommand(rxGetChannelValue(ROLL
), FLIGHT_MODE(MANUAL_MODE
) ? currentControlRateProfile
->manual
.rcExpo8
: currentControlRateProfile
->stabilized
.rcExpo8
, rcControlsConfig()->deadband
);
380 rcCommand
[PITCH
] = getAxisRcCommand(rxGetChannelValue(PITCH
), FLIGHT_MODE(MANUAL_MODE
) ? currentControlRateProfile
->manual
.rcExpo8
: currentControlRateProfile
->stabilized
.rcExpo8
, rcControlsConfig()->deadband
);
381 rcCommand
[YAW
] = -getAxisRcCommand(rxGetChannelValue(YAW
), FLIGHT_MODE(MANUAL_MODE
) ? currentControlRateProfile
->manual
.rcYawExpo8
: currentControlRateProfile
->stabilized
.rcYawExpo8
, rcControlsConfig()->yaw_deadband
);
383 // Apply manual control rates
384 if (FLIGHT_MODE(MANUAL_MODE
)) {
385 rcCommand
[ROLL
] = rcCommand
[ROLL
] * currentControlRateProfile
->manual
.rates
[FD_ROLL
] / 100L;
386 rcCommand
[PITCH
] = rcCommand
[PITCH
] * currentControlRateProfile
->manual
.rates
[FD_PITCH
] / 100L;
387 rcCommand
[YAW
] = rcCommand
[YAW
] * currentControlRateProfile
->manual
.rates
[FD_YAW
] / 100L;
389 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 0, rcCommand
[ROLL
]);
390 rcCommand
[ROLL
] = applyRateDynamics(rcCommand
[ROLL
], ROLL
, dT
);
391 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 1, rcCommand
[ROLL
]);
393 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 2, rcCommand
[PITCH
]);
394 rcCommand
[PITCH
] = applyRateDynamics(rcCommand
[PITCH
], PITCH
, dT
);
395 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 3, rcCommand
[PITCH
]);
397 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 4, rcCommand
[YAW
]);
398 rcCommand
[YAW
] = applyRateDynamics(rcCommand
[YAW
], YAW
, dT
);
399 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 5, rcCommand
[YAW
]);
403 //Compute THROTTLE command
404 rcCommand
[THROTTLE
] = throttleStickMixedValue();
406 // Signal updated rcCommand values to Failsafe system
407 failsafeUpdateRcCommandValues();
409 if (FLIGHT_MODE(HEADFREE_MODE
)) {
410 const float radDiff
= degreesToRadians(DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
) - headFreeModeHold
);
411 const float cosDiff
= cos_approx(radDiff
);
412 const float sinDiff
= sin_approx(radDiff
);
413 const int16_t rcCommand_PITCH
= rcCommand
[PITCH
] * cosDiff
+ rcCommand
[ROLL
] * sinDiff
;
414 rcCommand
[ROLL
] = rcCommand
[ROLL
] * cosDiff
- rcCommand
[PITCH
] * sinDiff
;
415 rcCommand
[PITCH
] = rcCommand_PITCH
;
420 void disarm(disarmReason_t disarmReason
)
422 if (ARMING_FLAG(ARMED
)) {
423 lastDisarmReason
= disarmReason
;
424 lastDisarmTimeUs
= micros();
425 DISABLE_ARMING_FLAG(ARMED
);
428 if (feature(FEATURE_BLACKBOX
)) {
433 if (FLIGHT_MODE(TURTLE_MODE
)) {
434 sendDShotCommand(DSHOT_CMD_SPIN_DIRECTION_NORMAL
);
435 DISABLE_FLIGHT_MODE(TURTLE_MODE
);
439 logicConditionReset();
441 #ifdef USE_PROGRAMMING_FRAMEWORK
442 programmingPidReset();
445 beeper(BEEPER_DISARMING
); // emit disarm tone
447 prearmWasReset
= false;
451 timeUs_t
getLastDisarmTimeUs(void) {
452 return lastDisarmTimeUs
;
455 disarmReason_t
getDisarmReason(void)
457 return lastDisarmReason
;
460 bool emergencyArmingUpdate(bool armingSwitchIsOn
, bool forceArm
)
462 if (ARMING_FLAG(ARMED
)) {
466 static timeMs_t timeout
= 0;
467 static int8_t counter
= 0;
469 timeMs_t currentTimeMs
= millis();
471 if (timeout
&& currentTimeMs
> timeout
) {
472 timeout
+= EMERGENCY_ARMING_COUNTER_STEP_MS
;
473 counter
-= counter
? 1 : 0;
479 if (armingSwitchIsOn
) {
480 if (!timeout
&& toggle
) {
481 timeout
= currentTimeMs
+ EMERGENCY_ARMING_TIME_WINDOW_MS
;
490 counter
= EMERGENCY_ARMING_MIN_ARM_COUNT
;
493 return counter
>= EMERGENCY_ARMING_MIN_ARM_COUNT
;
496 #define TELEMETRY_FUNCTION_MASK (FUNCTION_TELEMETRY_FRSKY | FUNCTION_TELEMETRY_HOTT | FUNCTION_TELEMETRY_SMARTPORT | FUNCTION_TELEMETRY_LTM | FUNCTION_TELEMETRY_MAVLINK | FUNCTION_TELEMETRY_IBUS)
498 void releaseSharedTelemetryPorts(void) {
499 serialPort_t
*sharedPort
= findSharedSerialPort(TELEMETRY_FUNCTION_MASK
, FUNCTION_MSP
);
501 mspSerialReleasePortIfAllocated(sharedPort
);
502 sharedPort
= findNextSharedSerialPort(TELEMETRY_FUNCTION_MASK
, FUNCTION_MSP
);
508 updateArmingStatus();
510 if (ARMING_FLAG(ARMED
)) {
515 if (STATE(MULTIROTOR
) && IS_RC_MODE_ACTIVE(BOXTURTLE
) && !FLIGHT_MODE(TURTLE_MODE
) &&
516 emergencyArmingCanOverrideArmingDisabled() && isMotorProtocolDshot()
518 sendDShotCommand(DSHOT_CMD_SPIN_DIRECTION_REVERSED
);
519 ENABLE_ARMING_FLAG(ARMED
);
520 enableFlightMode(TURTLE_MODE
);
525 #ifdef USE_PROGRAMMING_FRAMEWORK
526 if (!isArmingDisabled() || emergencyArmingIsEnabled() || LOGIC_CONDITION_GLOBAL_FLAG(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_ARMING_SAFETY
)) {
528 if (!isArmingDisabled() || emergencyArmingIsEnabled()) {
530 // If nav_extra_arming_safety was bypassed we always
531 // allow bypassing it even without the sticks set
532 // in the correct position to allow re-arming quickly
533 // in case of a mid-air accidental disarm.
534 bool usedBypass
= false;
535 navigationIsBlockingArming(&usedBypass
);
537 ENABLE_STATE(NAV_EXTRA_ARMING_SAFETY_BYPASSED
);
540 lastDisarmReason
= DISARM_NONE
;
542 ENABLE_ARMING_FLAG(ARMED
);
543 ENABLE_ARMING_FLAG(WAS_EVER_ARMED
);
544 //It is required to inform the mixer that arming was executed and it has to switch to the FORWARD direction
545 ENABLE_STATE(SET_REVERSIBLE_MOTORS_FORWARD
);
546 logicConditionReset();
548 #ifdef USE_PROGRAMMING_FRAMEWORK
549 programmingPidReset();
552 headFreeModeHold
= DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
);
554 resetHeadingHoldTarget(DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
));
557 if (feature(FEATURE_BLACKBOX
)) {
558 serialPort_t
*sharedBlackboxAndMspPort
= findSharedSerialPort(FUNCTION_BLACKBOX
, FUNCTION_MSP
);
559 if (sharedBlackboxAndMspPort
) {
560 mspSerialReleasePortIfAllocated(sharedBlackboxAndMspPort
);
566 //beep to indicate arming
567 if (navigationPositionEstimateIsHealthy()) {
568 beeper(BEEPER_ARMING_GPS_FIX
);
570 beeper(BEEPER_ARMING
);
578 if (!ARMING_FLAG(ARMED
)) {
579 beeperConfirmationBeeps(1);
583 void processRx(timeUs_t currentTimeUs
)
585 // Calculate RPY channel data
586 calculateRxChannelsAndUpdateFailsafe(currentTimeUs
);
588 // in 3D mode, we need to be able to disarm by switch at any time
589 if (feature(FEATURE_REVERSIBLE_MOTORS
)) {
590 if (!IS_RC_MODE_ACTIVE(BOXARM
)) {
591 disarm(DISARM_SWITCH_3D
);
595 updateRSSI(currentTimeUs
);
597 // Update failsafe monitoring system
598 if (currentTimeUs
> FAILSAFE_POWER_ON_DELAY_US
&& !failsafeIsMonitoring()) {
599 failsafeStartMonitoring();
602 failsafeUpdateState();
604 const bool throttleIsLow
= throttleStickIsLow();
606 // When armed and motors aren't spinning, do beeps periodically
607 if (ARMING_FLAG(ARMED
) && feature(FEATURE_MOTOR_STOP
) && !STATE(FIXED_WING_LEGACY
)) {
608 static bool armedBeeperOn
= false;
611 beeper(BEEPER_ARMED
);
612 armedBeeperOn
= true;
613 } else if (armedBeeperOn
) {
615 armedBeeperOn
= false;
619 processRcStickPositions(throttleIsLow
);
621 updateActivatedModes();
628 bool canUseRxData
= rxIsReceivingSignal() && !FLIGHT_MODE(FAILSAFE_MODE
);
629 updateAdjustmentStates(canUseRxData
);
630 processRcAdjustments(CONST_CAST(controlRateConfig_t
*, currentControlRateProfile
), canUseRxData
);
633 bool canUseHorizonMode
= true;
635 if ((IS_RC_MODE_ACTIVE(BOXANGLE
) || failsafeRequiresAngleMode() || navigationRequiresAngleMode()) && sensors(SENSOR_ACC
)) {
636 // bumpless transfer to Level mode
637 canUseHorizonMode
= false;
639 if (!FLIGHT_MODE(ANGLE_MODE
)) {
640 ENABLE_FLIGHT_MODE(ANGLE_MODE
);
643 DISABLE_FLIGHT_MODE(ANGLE_MODE
); // failsafe support
646 if (IS_RC_MODE_ACTIVE(BOXHORIZON
) && canUseHorizonMode
) {
648 DISABLE_FLIGHT_MODE(ANGLE_MODE
);
650 if (!FLIGHT_MODE(HORIZON_MODE
)) {
651 ENABLE_FLIGHT_MODE(HORIZON_MODE
);
654 DISABLE_FLIGHT_MODE(HORIZON_MODE
);
657 if (FLIGHT_MODE(ANGLE_MODE
) || FLIGHT_MODE(HORIZON_MODE
)) {
664 if (IS_RC_MODE_ACTIVE(BOXFLAPERON
) && STATE(FLAPERON_AVAILABLE
)) {
665 if (!FLIGHT_MODE(FLAPERON
)) {
666 ENABLE_FLIGHT_MODE(FLAPERON
);
669 DISABLE_FLIGHT_MODE(FLAPERON
);
672 /* Turn assistant mode */
673 if (IS_RC_MODE_ACTIVE(BOXTURNASSIST
)) {
674 if (!FLIGHT_MODE(TURN_ASSISTANT
)) {
675 ENABLE_FLIGHT_MODE(TURN_ASSISTANT
);
678 DISABLE_FLIGHT_MODE(TURN_ASSISTANT
);
681 if (sensors(SENSOR_ACC
)) {
682 if (IS_RC_MODE_ACTIVE(BOXHEADINGHOLD
)) {
683 if (!FLIGHT_MODE(HEADING_MODE
)) {
684 resetHeadingHoldTarget(DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
));
685 ENABLE_FLIGHT_MODE(HEADING_MODE
);
688 DISABLE_FLIGHT_MODE(HEADING_MODE
);
693 if (sensors(SENSOR_ACC
) || sensors(SENSOR_MAG
)) {
694 if (IS_RC_MODE_ACTIVE(BOXHEADFREE
)) {
695 if (!FLIGHT_MODE(HEADFREE_MODE
)) {
696 ENABLE_FLIGHT_MODE(HEADFREE_MODE
);
699 DISABLE_FLIGHT_MODE(HEADFREE_MODE
);
701 if (IS_RC_MODE_ACTIVE(BOXHEADADJ
)) {
702 headFreeModeHold
= DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
); // acquire new heading
707 // Handle passthrough mode
708 if (STATE(FIXED_WING_LEGACY
)) {
709 if ((IS_RC_MODE_ACTIVE(BOXMANUAL
) && !navigationRequiresAngleMode() && !failsafeRequiresAngleMode()) || // Normal activation of passthrough
710 (!ARMING_FLAG(ARMED
) && areSensorsCalibrating())){ // Backup - if we are not armed - enforce passthrough while calibrating
711 ENABLE_FLIGHT_MODE(MANUAL_MODE
);
713 DISABLE_FLIGHT_MODE(MANUAL_MODE
);
717 /* In airmode Iterm should be prevented to grow when Low thottle and Roll + Pitch Centered.
718 This is needed to prevent Iterm winding on the ground, but keep full stabilisation on 0 throttle while in air
719 Low Throttle + roll and Pitch centered is assuming the copter is on the ground. Done to prevent complex air/ground detections */
721 if (!ARMING_FLAG(ARMED
)) {
722 DISABLE_STATE(ANTI_WINDUP_DEACTIVATED
);
725 const rollPitchStatus_e rollPitchStatus
= calculateRollPitchCenterStatus();
727 // In MANUAL mode we reset integrators prevent I-term wind-up (PID output is not used in MANUAL)
728 if (FLIGHT_MODE(MANUAL_MODE
) || !ARMING_FLAG(ARMED
)) {
729 DISABLE_STATE(ANTI_WINDUP
);
730 pidResetErrorAccumulators();
732 else if (rcControlsConfig()->airmodeHandlingType
== STICK_CENTER
) {
734 if (STATE(AIRMODE_ACTIVE
) && !failsafeIsActive()) {
735 if ((rollPitchStatus
== CENTERED
) || (feature(FEATURE_MOTOR_STOP
) && !STATE(FIXED_WING_LEGACY
))) {
736 ENABLE_STATE(ANTI_WINDUP
);
739 DISABLE_STATE(ANTI_WINDUP
);
743 DISABLE_STATE(ANTI_WINDUP
);
744 pidResetErrorAccumulators();
748 DISABLE_STATE(ANTI_WINDUP
);
751 else if (rcControlsConfig()->airmodeHandlingType
== STICK_CENTER_ONCE
) {
753 if (STATE(AIRMODE_ACTIVE
) && !failsafeIsActive()) {
754 if ((rollPitchStatus
== CENTERED
) && !STATE(ANTI_WINDUP_DEACTIVATED
)) {
755 ENABLE_STATE(ANTI_WINDUP
);
758 DISABLE_STATE(ANTI_WINDUP
);
762 DISABLE_STATE(ANTI_WINDUP
);
763 pidResetErrorAccumulators();
767 DISABLE_STATE(ANTI_WINDUP
);
768 if (rollPitchStatus
!= CENTERED
) {
769 ENABLE_STATE(ANTI_WINDUP_DEACTIVATED
);
773 else if (rcControlsConfig()->airmodeHandlingType
== THROTTLE_THRESHOLD
) {
774 DISABLE_STATE(ANTI_WINDUP
);
775 //This case applies only to MR when Airmode management is throttle threshold activated
776 if (throttleIsLow
&& !STATE(AIRMODE_ACTIVE
)) {
777 pidResetErrorAccumulators();
780 //---------------------------------------------------------
781 if (mixerConfig()->platformType
== PLATFORM_AIRPLANE
) {
782 DISABLE_FLIGHT_MODE(HEADFREE_MODE
);
785 #if defined(USE_AUTOTUNE_FIXED_WING) || defined(USE_AUTOTUNE_MULTIROTOR)
786 autotuneUpdateState();
790 if (feature(FEATURE_TELEMETRY
)) {
791 if ((!telemetryConfig()->telemetry_switch
&& ARMING_FLAG(ARMED
)) ||
792 (telemetryConfig()->telemetry_switch
&& IS_RC_MODE_ACTIVE(BOXTELEMETRY
))) {
794 releaseSharedTelemetryPorts();
796 // the telemetry state must be checked immediately so that shared serial ports are released.
797 telemetryCheckState();
798 mspSerialAllocatePorts();
805 // Function for loop trigger
806 void FAST_CODE
taskGyro(timeUs_t currentTimeUs
) {
807 UNUSED(currentTimeUs
);
808 // getTaskDeltaTime() returns delta time frozen at the moment of entering the scheduler. currentTime is frozen at the very same point.
809 // To make busy-waiting timeout work we need to account for time spent within busy-waiting loop
810 const timeDelta_t currentDeltaTime
= getTaskDeltaTime(TASK_SELF
);
812 /* Update actual hardware readings */
816 if (sensors(SENSOR_OPFLOW
)) {
817 opflowGyroUpdateCallback(currentDeltaTime
);
822 static float calculateThrottleTiltCompensationFactor(uint8_t throttleTiltCompensationStrength
)
824 if (throttleTiltCompensationStrength
) {
825 float tiltCompFactor
= 1.0f
/ constrainf(calculateCosTiltAngle(), 0.6f
, 1.0f
); // max tilt about 50 deg
826 return 1.0f
+ (tiltCompFactor
- 1.0f
) * (throttleTiltCompensationStrength
/ 100.f
);
832 void taskMainPidLoop(timeUs_t currentTimeUs
)
834 cycleTime
= getTaskDeltaTime(TASK_SELF
);
835 dT
= (float)cycleTime
* 0.000001f
;
837 if (ARMING_FLAG(ARMED
) && (!STATE(FIXED_WING_LEGACY
) || !isNavLaunchEnabled() || (isNavLaunchEnabled() && fixedWingLaunchStatus() >= FW_LAUNCH_DETECTED
))) {
838 flightTime
+= cycleTime
;
839 armTime
+= cycleTime
;
843 if (!ARMING_FLAG(ARMED
)) {
846 processDelayedSave();
851 imuUpdateAccelerometer();
852 imuUpdateAttitude(currentTimeUs
);
854 processPilotAndFailSafeActions(dT
);
856 updateArmingStatus();
858 if (rxConfig()->rcFilterFrequency
) {
859 rcInterpolationApply(isRXDataNew
, currentTimeUs
);
863 updateWaypointsAndNavigationMode();
867 updatePositionEstimator();
868 applyWaypointNavigationAndAltitudeHold();
870 // Apply throttle tilt compensation
871 if (!STATE(FIXED_WING_LEGACY
)) {
872 int16_t thrTiltCompStrength
= 0;
874 if (navigationRequiresThrottleTiltCompensation()) {
875 thrTiltCompStrength
= 100;
877 else if (systemConfig()->throttle_tilt_compensation_strength
&& (FLIGHT_MODE(ANGLE_MODE
) || FLIGHT_MODE(HORIZON_MODE
))) {
878 thrTiltCompStrength
= systemConfig()->throttle_tilt_compensation_strength
;
881 if (thrTiltCompStrength
) {
882 rcCommand
[THROTTLE
] = constrain(getThrottleIdleValue()
883 + (rcCommand
[THROTTLE
] - getThrottleIdleValue()) * calculateThrottleTiltCompensationFactor(thrTiltCompStrength
),
884 getThrottleIdleValue(),
885 motorConfig()->maxthrottle
);
889 // FIXME: throttle pitch comp for FW
892 #ifdef USE_POWER_LIMITS
893 powerLimiterApply(&rcCommand
[THROTTLE
]);
896 // Calculate stabilisation
901 if (isMixerUsingServos()) {
903 processServoAutotrim(dT
);
906 //Servos should be filtered or written only when mixer is using servos or special feaures are enabled
909 if (!ARMING_FLAG(SIMULATOR_MODE
)) {
910 if (isServoOutputEnabled()) {
914 if (motorControlEnable
) {
919 if (isServoOutputEnabled()) {
923 if (motorControlEnable
) {
927 // Check if landed, FW and MR
928 if (STATE(ALTITUDE_CONTROL
)) {
929 updateLandingStatus(US2MS(currentTimeUs
));
933 if (!cliMode
&& feature(FEATURE_BLACKBOX
)) {
934 blackboxUpdate(micros());
939 // This function is called in a busy-loop, everything called from here should do it's own
940 // scheduling and avoid doing heavy calculations
941 void taskRunRealtimeCallbacks(timeUs_t currentTimeUs
)
943 UNUSED(currentTimeUs
);
950 pwmCompleteMotorUpdate();
953 #ifdef USE_ESC_SENSOR
954 escSensorUpdate(currentTimeUs
);
958 bool taskUpdateRxCheck(timeUs_t currentTimeUs
, timeDelta_t currentDeltaTime
)
960 UNUSED(currentDeltaTime
);
962 return rxUpdateCheck(currentTimeUs
, currentDeltaTime
);
965 void taskUpdateRxMain(timeUs_t currentTimeUs
)
967 processRx(currentTimeUs
);
972 float getFlightTime()
974 return US2S(flightTime
);
979 return US2S(armTime
);
982 void fcReboot(bool bootLoader
)
984 // stop motor/servo outputs
988 // extra delay before reboot to give ESCs chance to reset
992 systemResetToBootloader();