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 #include "blackbox/blackbox.h"
26 #include "build/debug.h"
28 #include "common/maths.h"
29 #include "common/axis.h"
30 #include "common/color.h"
31 #include "common/utils.h"
32 #include "common/filter.h"
34 #include "drivers/light_led.h"
35 #include "drivers/serial.h"
36 #include "drivers/time.h"
37 #include "drivers/system.h"
38 #include "drivers/pwm_output.h"
40 #include "sensors/sensors.h"
41 #include "sensors/diagnostics.h"
42 #include "sensors/boardalignment.h"
43 #include "sensors/acceleration.h"
44 #include "sensors/barometer.h"
45 #include "sensors/compass.h"
46 #include "sensors/pitotmeter.h"
47 #include "sensors/gyro.h"
48 #include "sensors/battery.h"
49 #include "sensors/rangefinder.h"
50 #include "sensors/opflow.h"
51 #include "sensors/esc_sensor.h"
53 #include "fc/fc_core.h"
55 #include "fc/config.h"
56 #include "fc/controlrate_profile.h"
57 #include "fc/multifunction.h"
58 #include "fc/rc_adjustments.h"
59 #include "fc/rc_smoothing.h"
60 #include "fc/rc_controls.h"
61 #include "fc/rc_curves.h"
62 #include "fc/rc_modes.h"
63 #include "fc/runtime_config.h"
65 #include "io/beeper.h"
66 #include "io/dashboard.h"
68 #include "io/serial.h"
69 #include "io/statusindicator.h"
70 #include "io/asyncfatfs/asyncfatfs.h"
71 #include "io/piniobox.h"
73 #include "msp/msp_serial.h"
75 #include "navigation/navigation.h"
80 #include "scheduler/scheduler.h"
82 #include "telemetry/telemetry.h"
84 #include "flight/mixer_profile.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
109 #define EMERGENCY_INFLIGHT_REARM_TIME_WINDOW_MS 5000
111 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
112 static timeUs_t flightTime
= 0;
113 static timeUs_t armTime
= 0;
115 EXTENDED_FASTRAM
float dT
;
117 int16_t headFreeModeHold
;
119 uint8_t motorControlEnable
= false;
121 static bool isRXDataNew
;
122 static disarmReason_t lastDisarmReason
= DISARM_NONE
;
123 timeUs_t lastDisarmTimeUs
= 0;
124 timeMs_t emergRearmStabiliseTimeout
= 0;
126 static bool prearmWasReset
= false; // Prearm must be reset (RC Mode not active) before arming is possible
127 static timeMs_t prearmActivationTime
= 0;
129 static bool isAccRequired(void) {
130 return isModeActivationConditionPresent(BOXNAVPOSHOLD
) ||
131 isModeActivationConditionPresent(BOXNAVRTH
) ||
132 isModeActivationConditionPresent(BOXNAVWP
) ||
133 isModeActivationConditionPresent(BOXANGLE
) ||
134 isModeActivationConditionPresent(BOXHORIZON
) ||
135 isModeActivationConditionPresent(BOXNAVALTHOLD
) ||
136 isModeActivationConditionPresent(BOXHEADINGHOLD
) ||
137 isModeActivationConditionPresent(BOXNAVLAUNCH
) ||
138 isModeActivationConditionPresent(BOXTURNASSIST
) ||
139 isModeActivationConditionPresent(BOXNAVCOURSEHOLD
) ||
140 isModeActivationConditionPresent(BOXSOARING
) ||
141 failsafeConfig()->failsafe_procedure
!= FAILSAFE_PROCEDURE_DROP_IT
;
144 bool areSensorsCalibrating(void)
147 if (sensors(SENSOR_BARO
) && !baroIsCalibrationComplete()) {
153 if (sensors(SENSOR_MAG
) && !compassIsCalibrationComplete()) {
159 if (sensors(SENSOR_PITOT
) && !pitotIsCalibrationComplete()) {
164 if (!navIsCalibrationComplete() && isAccRequired()) {
168 if (!accIsCalibrationComplete() && sensors(SENSOR_ACC
) && isAccRequired()) {
172 if (!gyroIsCalibrationComplete()) {
179 int16_t getAxisRcCommand(int16_t rawData
, int16_t rate
, int16_t deadband
)
181 int16_t stickDeflection
= 0;
183 #if defined(SITL_BUILD) // Workaround due to strange bug in GCC > 10.2 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108914
184 const int16_t value
= rawData
- PWM_RANGE_MIDDLE
;
186 stickDeflection
= -500;
187 } else if (value
> 500) {
188 stickDeflection
= 500;
190 stickDeflection
= value
;
193 stickDeflection
= constrain(rawData
- PWM_RANGE_MIDDLE
, -500, 500);
196 stickDeflection
= applyDeadbandRescaled(stickDeflection
, deadband
, -500, 500);
197 return rcLookup(stickDeflection
, rate
);
200 static void updateArmingStatus(void)
202 if (ARMING_FLAG(ARMED
)) {
205 /* CHECK: Run-time calibration */
206 static bool calibratingFinishedBeep
= false;
207 if (areSensorsCalibrating()) {
208 ENABLE_ARMING_FLAG(ARMING_DISABLED_SENSORS_CALIBRATING
);
209 calibratingFinishedBeep
= false;
212 DISABLE_ARMING_FLAG(ARMING_DISABLED_SENSORS_CALIBRATING
);
214 if (!calibratingFinishedBeep
) {
215 calibratingFinishedBeep
= true;
216 beeper(BEEPER_RUNTIME_CALIBRATION_DONE
);
220 /* CHECK: RX signal */
221 if (!failsafeIsReceivingRxData()) {
222 ENABLE_ARMING_FLAG(ARMING_DISABLED_RC_LINK
);
225 DISABLE_ARMING_FLAG(ARMING_DISABLED_RC_LINK
);
228 /* CHECK: Throttle */
229 if (!armingConfig()->fixed_wing_auto_arm
) {
230 // Don't want this check if fixed_wing_auto_arm is in use - machine arms on throttle > LOW
231 if (throttleStickIsLow()) {
232 DISABLE_ARMING_FLAG(ARMING_DISABLED_THROTTLE
);
234 ENABLE_ARMING_FLAG(ARMING_DISABLED_THROTTLE
);
238 /* CHECK: pitch / roll sticks centered when NAV_LAUNCH_MODE enabled */
239 if (isNavLaunchEnabled()) {
240 if (isRollPitchStickDeflected(rcControlsConfig()->control_deadband
)) {
241 ENABLE_ARMING_FLAG(ARMING_DISABLED_ROLLPITCH_NOT_CENTERED
);
243 DISABLE_ARMING_FLAG(ARMING_DISABLED_ROLLPITCH_NOT_CENTERED
);
248 if (!STATE(SMALL_ANGLE
)) {
249 ENABLE_ARMING_FLAG(ARMING_DISABLED_NOT_LEVEL
);
252 DISABLE_ARMING_FLAG(ARMING_DISABLED_NOT_LEVEL
);
255 /* CHECK: CPU load */
256 if (isSystemOverloaded()) {
257 ENABLE_ARMING_FLAG(ARMING_DISABLED_SYSTEM_OVERLOADED
);
260 DISABLE_ARMING_FLAG(ARMING_DISABLED_SYSTEM_OVERLOADED
);
263 /* CHECK: Navigation safety */
264 if (navigationIsBlockingArming(NULL
) != NAV_ARMING_BLOCKER_NONE
) {
265 ENABLE_ARMING_FLAG(ARMING_DISABLED_NAVIGATION_UNSAFE
);
268 DISABLE_ARMING_FLAG(ARMING_DISABLED_NAVIGATION_UNSAFE
);
273 if (sensors(SENSOR_MAG
) && !STATE(COMPASS_CALIBRATED
)) {
274 ENABLE_ARMING_FLAG(ARMING_DISABLED_COMPASS_NOT_CALIBRATED
);
277 DISABLE_ARMING_FLAG(ARMING_DISABLED_COMPASS_NOT_CALIBRATED
);
283 sensors(SENSOR_ACC
) &&
284 !STATE(ACCELEROMETER_CALIBRATED
) &&
285 // Require ACC calibration only if any of the setting might require it
288 ENABLE_ARMING_FLAG(ARMING_DISABLED_ACCELEROMETER_NOT_CALIBRATED
);
291 DISABLE_ARMING_FLAG(ARMING_DISABLED_ACCELEROMETER_NOT_CALIBRATED
);
295 if (!isHardwareHealthy()) {
296 ENABLE_ARMING_FLAG(ARMING_DISABLED_HARDWARE_FAILURE
);
299 DISABLE_ARMING_FLAG(ARMING_DISABLED_HARDWARE_FAILURE
);
302 /* CHECK: BOXFAILSAFE */
303 if (IS_RC_MODE_ACTIVE(BOXFAILSAFE
)) {
304 ENABLE_ARMING_FLAG(ARMING_DISABLED_BOXFAILSAFE
);
307 DISABLE_ARMING_FLAG(ARMING_DISABLED_BOXFAILSAFE
);
310 /* CHECK: BOXKILLSWITCH */
311 if (IS_RC_MODE_ACTIVE(BOXKILLSWITCH
)) {
312 ENABLE_ARMING_FLAG(ARMING_DISABLED_BOXKILLSWITCH
);
315 DISABLE_ARMING_FLAG(ARMING_DISABLED_BOXKILLSWITCH
);
318 /* CHECK: Do not allow arming if Servo AutoTrim is enabled */
319 if (IS_RC_MODE_ACTIVE(BOXAUTOTRIM
)) {
320 ENABLE_ARMING_FLAG(ARMING_DISABLED_SERVO_AUTOTRIM
);
323 DISABLE_ARMING_FLAG(ARMING_DISABLED_SERVO_AUTOTRIM
);
327 /* CHECK: Don't arm if the DShot beeper was used recently, as there is a minimum delay before sending the next DShot command */
328 if (micros() - getLastDshotBeeperCommandTimeUs() < getDShotBeaconGuardDelayUs()) {
329 ENABLE_ARMING_FLAG(ARMING_DISABLED_DSHOT_BEEPER
);
331 DISABLE_ARMING_FLAG(ARMING_DISABLED_DSHOT_BEEPER
);
334 DISABLE_ARMING_FLAG(ARMING_DISABLED_DSHOT_BEEPER
);
337 if (isModeActivationConditionPresent(BOXPREARM
)) {
338 if (IS_RC_MODE_ACTIVE(BOXPREARM
)) {
339 if (prearmWasReset
&& (armingConfig()->prearmTimeoutMs
== 0 || millis() - prearmActivationTime
< armingConfig()->prearmTimeoutMs
)) {
340 DISABLE_ARMING_FLAG(ARMING_DISABLED_NO_PREARM
);
342 ENABLE_ARMING_FLAG(ARMING_DISABLED_NO_PREARM
);
345 prearmWasReset
= true;
346 prearmActivationTime
= millis();
347 ENABLE_ARMING_FLAG(ARMING_DISABLED_NO_PREARM
);
350 DISABLE_ARMING_FLAG(ARMING_DISABLED_NO_PREARM
);
353 /* CHECK: Arming switch */
354 // If arming is disabled and the ARM switch is on
355 // Note that this should be last check so all other blockers could be cleared correctly
356 // if blocking modes are linked to the same RC channel
357 if (isArmingDisabled() && IS_RC_MODE_ACTIVE(BOXARM
)) {
358 ENABLE_ARMING_FLAG(ARMING_DISABLED_ARM_SWITCH
);
359 } else if (!IS_RC_MODE_ACTIVE(BOXARM
)) {
360 DISABLE_ARMING_FLAG(ARMING_DISABLED_ARM_SWITCH
);
363 if (isArmingDisabled()) {
373 static bool emergencyArmingCanOverrideArmingDisabled(void)
375 uint32_t armingPrevention
= armingFlags
& ARMING_DISABLED_ALL_FLAGS
;
376 armingPrevention
&= ~ARMING_DISABLED_EMERGENCY_OVERRIDE
;
377 return armingPrevention
== 0;
380 static bool emergencyArmingIsEnabled(void)
382 return emergencyArmingUpdate(IS_RC_MODE_ACTIVE(BOXARM
), false) && emergencyArmingCanOverrideArmingDisabled();
385 static void processPilotAndFailSafeActions(float dT
)
387 if (failsafeShouldApplyControlInput()) {
388 // Failsafe will apply rcCommand for us
389 failsafeApplyControlInput();
392 // Compute ROLL PITCH and YAW command
393 rcCommand
[ROLL
] = getAxisRcCommand(rxGetChannelValue(ROLL
), FLIGHT_MODE(MANUAL_MODE
) ? currentControlRateProfile
->manual
.rcExpo8
: currentControlRateProfile
->stabilized
.rcExpo8
, rcControlsConfig()->deadband
);
394 rcCommand
[PITCH
] = getAxisRcCommand(rxGetChannelValue(PITCH
), FLIGHT_MODE(MANUAL_MODE
) ? currentControlRateProfile
->manual
.rcExpo8
: currentControlRateProfile
->stabilized
.rcExpo8
, rcControlsConfig()->deadband
);
395 rcCommand
[YAW
] = -getAxisRcCommand(rxGetChannelValue(YAW
), FLIGHT_MODE(MANUAL_MODE
) ? currentControlRateProfile
->manual
.rcYawExpo8
: currentControlRateProfile
->stabilized
.rcYawExpo8
, rcControlsConfig()->yaw_deadband
);
397 // Apply manual control rates
398 if (FLIGHT_MODE(MANUAL_MODE
)) {
399 rcCommand
[ROLL
] = rcCommand
[ROLL
] * currentControlRateProfile
->manual
.rates
[FD_ROLL
] / 100L;
400 rcCommand
[PITCH
] = rcCommand
[PITCH
] * currentControlRateProfile
->manual
.rates
[FD_PITCH
] / 100L;
401 rcCommand
[YAW
] = rcCommand
[YAW
] * currentControlRateProfile
->manual
.rates
[FD_YAW
] / 100L;
403 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 0, rcCommand
[ROLL
]);
404 rcCommand
[ROLL
] = applyRateDynamics(rcCommand
[ROLL
], ROLL
, dT
);
405 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 1, rcCommand
[ROLL
]);
407 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 2, rcCommand
[PITCH
]);
408 rcCommand
[PITCH
] = applyRateDynamics(rcCommand
[PITCH
], PITCH
, dT
);
409 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 3, rcCommand
[PITCH
]);
411 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 4, rcCommand
[YAW
]);
412 rcCommand
[YAW
] = applyRateDynamics(rcCommand
[YAW
], YAW
, dT
);
413 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 5, rcCommand
[YAW
]);
417 //Compute THROTTLE command
418 rcCommand
[THROTTLE
] = throttleStickMixedValue();
420 // Signal updated rcCommand values to Failsafe system
421 failsafeUpdateRcCommandValues();
423 if (FLIGHT_MODE(HEADFREE_MODE
)) {
424 const float radDiff
= degreesToRadians(DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
) - headFreeModeHold
);
425 const float cosDiff
= cos_approx(radDiff
);
426 const float sinDiff
= sin_approx(radDiff
);
427 const int16_t rcCommand_PITCH
= rcCommand
[PITCH
] * cosDiff
+ rcCommand
[ROLL
] * sinDiff
;
428 rcCommand
[ROLL
] = rcCommand
[ROLL
] * cosDiff
- rcCommand
[PITCH
] * sinDiff
;
429 rcCommand
[PITCH
] = rcCommand_PITCH
;
434 void disarm(disarmReason_t disarmReason
)
436 if (ARMING_FLAG(ARMED
)) {
437 lastDisarmReason
= disarmReason
;
438 lastDisarmTimeUs
= micros();
439 DISABLE_ARMING_FLAG(ARMED
);
440 DISABLE_STATE(IN_FLIGHT_EMERG_REARM
);
443 if (feature(FEATURE_BLACKBOX
)) {
448 if (FLIGHT_MODE(TURTLE_MODE
)) {
449 sendDShotCommand(DSHOT_CMD_SPIN_DIRECTION_NORMAL
);
450 DISABLE_FLIGHT_MODE(TURTLE_MODE
);
454 logicConditionReset();
456 #ifdef USE_PROGRAMMING_FRAMEWORK
457 programmingPidReset();
460 beeper(BEEPER_DISARMING
); // emit disarm tone
462 prearmWasReset
= false;
466 timeUs_t
getLastDisarmTimeUs(void) {
467 return lastDisarmTimeUs
;
470 disarmReason_t
getDisarmReason(void)
472 return lastDisarmReason
;
475 bool emergencyArmingUpdate(bool armingSwitchIsOn
, bool forceArm
)
477 if (ARMING_FLAG(ARMED
)) {
481 static timeMs_t timeout
= 0;
482 static int8_t counter
= 0;
484 timeMs_t currentTimeMs
= millis();
486 if (timeout
&& currentTimeMs
> timeout
) {
487 timeout
+= EMERGENCY_ARMING_COUNTER_STEP_MS
;
488 counter
-= counter
? 1 : 0;
494 if (armingSwitchIsOn
) {
495 if (!timeout
&& toggle
) {
496 timeout
= currentTimeMs
+ EMERGENCY_ARMING_TIME_WINDOW_MS
;
505 counter
= EMERGENCY_ARMING_MIN_ARM_COUNT
;
508 return counter
>= EMERGENCY_ARMING_MIN_ARM_COUNT
;
511 bool emergInflightRearmEnabled(void)
513 /* Emergency rearm allowed within 5s timeout period after disarm if craft still flying */
514 timeMs_t currentTimeMs
= millis();
515 emergRearmStabiliseTimeout
= 0;
517 if ((lastDisarmReason
!= DISARM_SWITCH
&& lastDisarmReason
!= DISARM_KILLSWITCH
) ||
518 (currentTimeMs
> US2MS(lastDisarmTimeUs
) + EMERGENCY_INFLIGHT_REARM_TIME_WINDOW_MS
)) {
522 // allow emergency rearm if MR has vertical speed at least 1.5 sec after disarm indicating still flying
523 bool mcDisarmVertVelCheck
= STATE(MULTIROTOR
) && (currentTimeMs
> US2MS(lastDisarmTimeUs
) + 1500) && fabsf(getEstimatedActualVelocity(Z
)) > 100.0f
;
525 if (isProbablyStillFlying() || mcDisarmVertVelCheck
) {
526 emergRearmStabiliseTimeout
= currentTimeMs
+ 5000; // activate Angle mode for 5s after rearm to help stabilise craft
527 ENABLE_STATE(IN_FLIGHT_EMERG_REARM
);
531 return false; // craft doesn't appear to be flying, don't allow emergency rearm
536 updateArmingStatus();
538 if (ARMING_FLAG(ARMED
)) {
543 #ifdef USE_MULTI_FUNCTIONS
544 const bool turtleIsActive
= IS_RC_MODE_ACTIVE(BOXTURTLE
) || MULTI_FUNC_FLAG(MF_TURTLE_MODE
);
546 const bool turtleIsActive
= IS_RC_MODE_ACTIVE(BOXTURTLE
);
548 if (STATE(MULTIROTOR
) && turtleIsActive
&& !FLIGHT_MODE(TURTLE_MODE
) && emergencyArmingCanOverrideArmingDisabled() && isMotorProtocolDshot()) {
549 sendDShotCommand(DSHOT_CMD_SPIN_DIRECTION_REVERSED
);
550 ENABLE_ARMING_FLAG(ARMED
);
551 enableFlightMode(TURTLE_MODE
);
556 #ifdef USE_PROGRAMMING_FRAMEWORK
557 if (emergInflightRearmEnabled() || !isArmingDisabled() || emergencyArmingIsEnabled() ||
558 LOGIC_CONDITION_GLOBAL_FLAG(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_ARMING_SAFETY
)) {
560 if (emergInflightRearmEnabled() || !isArmingDisabled() || emergencyArmingIsEnabled()) {
562 // If nav_extra_arming_safety was bypassed we always
563 // allow bypassing it even without the sticks set
564 // in the correct position to allow re-arming quickly
565 // in case of a mid-air accidental disarm.
566 bool usedBypass
= false;
567 navigationIsBlockingArming(&usedBypass
);
569 ENABLE_STATE(NAV_EXTRA_ARMING_SAFETY_BYPASSED
);
572 lastDisarmReason
= DISARM_NONE
;
574 ENABLE_ARMING_FLAG(ARMED
);
575 ENABLE_ARMING_FLAG(WAS_EVER_ARMED
);
576 //It is required to inform the mixer that arming was executed and it has to switch to the FORWARD direction
577 ENABLE_STATE(SET_REVERSIBLE_MOTORS_FORWARD
);
579 if (!STATE(IN_FLIGHT_EMERG_REARM
)) {
580 resetLandingDetectorActiveState(); // reset landing detector after arming to avoid false detection before flight
581 logicConditionReset();
582 #ifdef USE_PROGRAMMING_FRAMEWORK
583 programmingPidReset();
587 headFreeModeHold
= DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
);
589 resetHeadingHoldTarget(DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
));
592 if (feature(FEATURE_BLACKBOX
)) {
593 serialPort_t
*sharedBlackboxAndMspPort
= findSharedSerialPort(FUNCTION_BLACKBOX
, FUNCTION_MSP
);
594 if (sharedBlackboxAndMspPort
) {
595 mspSerialReleasePortIfAllocated(sharedBlackboxAndMspPort
);
601 //beep to indicate arming
602 if (navigationPositionEstimateIsHealthy()) {
603 beeper(BEEPER_ARMING_GPS_FIX
);
605 beeper(BEEPER_ARMING
);
613 if (!ARMING_FLAG(ARMED
)) {
614 beeperConfirmationBeeps(1);
618 #define TELEMETRY_FUNCTION_MASK (FUNCTION_TELEMETRY_HOTT | FUNCTION_TELEMETRY_SMARTPORT | FUNCTION_TELEMETRY_LTM | FUNCTION_TELEMETRY_MAVLINK | FUNCTION_TELEMETRY_IBUS)
620 void releaseSharedTelemetryPorts(void) {
621 serialPort_t
*sharedPort
= findSharedSerialPort(TELEMETRY_FUNCTION_MASK
, FUNCTION_MSP
);
623 mspSerialReleasePortIfAllocated(sharedPort
);
624 sharedPort
= findNextSharedSerialPort(TELEMETRY_FUNCTION_MASK
, FUNCTION_MSP
);
628 void processRx(timeUs_t currentTimeUs
)
630 // Calculate RPY channel data
631 calculateRxChannelsAndUpdateFailsafe(currentTimeUs
);
633 // in 3D mode, we need to be able to disarm by switch at any time
634 if (feature(FEATURE_REVERSIBLE_MOTORS
)) {
635 if (!IS_RC_MODE_ACTIVE(BOXARM
)) {
636 disarm(DISARM_SWITCH_3D
);
640 updateRSSI(currentTimeUs
);
642 // Update failsafe monitoring system
643 if (currentTimeUs
> FAILSAFE_POWER_ON_DELAY_US
&& !failsafeIsMonitoring()) {
644 failsafeStartMonitoring();
647 failsafeUpdateState();
649 const bool throttleIsLow
= throttleStickIsLow();
651 // When armed and motors aren't spinning, do beeps periodically
652 if (ARMING_FLAG(ARMED
) && ifMotorstopFeatureEnabled() && !STATE(FIXED_WING_LEGACY
)) {
653 static bool armedBeeperOn
= false;
656 beeper(BEEPER_ARMED
);
657 armedBeeperOn
= true;
658 } else if (armedBeeperOn
) {
660 armedBeeperOn
= false;
664 processRcStickPositions(throttleIsLow
);
666 updateActivatedModes();
673 bool canUseRxData
= rxIsReceivingSignal() && !FLIGHT_MODE(FAILSAFE_MODE
);
674 updateAdjustmentStates(canUseRxData
);
675 processRcAdjustments(CONST_CAST(controlRateConfig_t
*, currentControlRateProfile
), canUseRxData
);
678 // Angle mode forced on briefly after emergency inflight rearm to help stabilise attitude (currently limited to MR)
679 bool emergRearmAngleEnforce
= STATE(MULTIROTOR
) && emergRearmStabiliseTimeout
> US2MS(currentTimeUs
);
680 bool autoEnableAngle
= failsafeRequiresAngleMode() || navigationRequiresAngleMode() || emergRearmAngleEnforce
;
681 bool canUseHorizonMode
= true;
683 if (sensors(SENSOR_ACC
) && (IS_RC_MODE_ACTIVE(BOXANGLE
) || autoEnableAngle
)) {
684 // bumpless transfer to Level mode
685 canUseHorizonMode
= false;
687 if (!FLIGHT_MODE(ANGLE_MODE
)) {
688 ENABLE_FLIGHT_MODE(ANGLE_MODE
);
691 DISABLE_FLIGHT_MODE(ANGLE_MODE
); // failsafe support
694 if (IS_RC_MODE_ACTIVE(BOXHORIZON
) && canUseHorizonMode
) {
696 DISABLE_FLIGHT_MODE(ANGLE_MODE
);
698 if (!FLIGHT_MODE(HORIZON_MODE
)) {
699 ENABLE_FLIGHT_MODE(HORIZON_MODE
);
702 DISABLE_FLIGHT_MODE(HORIZON_MODE
);
705 if (FLIGHT_MODE(ANGLE_MODE
) || FLIGHT_MODE(HORIZON_MODE
)) {
712 if (IS_RC_MODE_ACTIVE(BOXFLAPERON
) && STATE(FLAPERON_AVAILABLE
)) {
713 if (!FLIGHT_MODE(FLAPERON
)) {
714 ENABLE_FLIGHT_MODE(FLAPERON
);
717 DISABLE_FLIGHT_MODE(FLAPERON
);
720 /* Turn assistant mode */
721 if (IS_RC_MODE_ACTIVE(BOXTURNASSIST
)) {
722 if (!FLIGHT_MODE(TURN_ASSISTANT
)) {
723 ENABLE_FLIGHT_MODE(TURN_ASSISTANT
);
726 DISABLE_FLIGHT_MODE(TURN_ASSISTANT
);
729 if (sensors(SENSOR_ACC
)) {
730 if (IS_RC_MODE_ACTIVE(BOXHEADINGHOLD
)) {
731 if (!FLIGHT_MODE(HEADING_MODE
)) {
732 resetHeadingHoldTarget(DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
));
733 ENABLE_FLIGHT_MODE(HEADING_MODE
);
736 DISABLE_FLIGHT_MODE(HEADING_MODE
);
741 if (sensors(SENSOR_ACC
) || sensors(SENSOR_MAG
)) {
742 if (IS_RC_MODE_ACTIVE(BOXHEADFREE
) && STATE(MULTIROTOR
)) {
743 if (!FLIGHT_MODE(HEADFREE_MODE
)) {
744 ENABLE_FLIGHT_MODE(HEADFREE_MODE
);
747 DISABLE_FLIGHT_MODE(HEADFREE_MODE
);
749 if (IS_RC_MODE_ACTIVE(BOXHEADADJ
) && STATE(MULTIROTOR
)) {
750 headFreeModeHold
= DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
); // acquire new heading
755 // Handle passthrough mode
756 if (STATE(FIXED_WING_LEGACY
)) {
757 if ((IS_RC_MODE_ACTIVE(BOXMANUAL
) && !navigationRequiresAngleMode() && !failsafeRequiresAngleMode()) || // Normal activation of passthrough
758 (!ARMING_FLAG(ARMED
) && areSensorsCalibrating())){ // Backup - if we are not armed - enforce passthrough while calibrating
759 ENABLE_FLIGHT_MODE(MANUAL_MODE
);
761 DISABLE_FLIGHT_MODE(MANUAL_MODE
);
764 DISABLE_FLIGHT_MODE(MANUAL_MODE
);
767 /* In airmode Iterm should be prevented to grow when Low thottle and Roll + Pitch Centered.
768 This is needed to prevent Iterm winding on the ground, but keep full stabilisation on 0 throttle while in air
769 Low Throttle + roll and Pitch centered is assuming the copter is on the ground. Done to prevent complex air/ground detections */
771 if (!ARMING_FLAG(ARMED
)) {
772 DISABLE_STATE(ANTI_WINDUP_DEACTIVATED
);
775 const rollPitchStatus_e rollPitchStatus
= calculateRollPitchCenterStatus();
777 // In MANUAL mode we reset integrators prevent I-term wind-up (PID output is not used in MANUAL)
778 if (FLIGHT_MODE(MANUAL_MODE
) || !ARMING_FLAG(ARMED
)) {
779 DISABLE_STATE(ANTI_WINDUP
);
780 pidResetErrorAccumulators();
782 else if (rcControlsConfig()->airmodeHandlingType
== STICK_CENTER
) {
784 if (STATE(AIRMODE_ACTIVE
)) {
785 if ((rollPitchStatus
== CENTERED
) || (ifMotorstopFeatureEnabled() && !STATE(FIXED_WING_LEGACY
))) {
786 ENABLE_STATE(ANTI_WINDUP
);
789 DISABLE_STATE(ANTI_WINDUP
);
793 DISABLE_STATE(ANTI_WINDUP
);
794 pidResetErrorAccumulators();
798 DISABLE_STATE(ANTI_WINDUP
);
801 else if (rcControlsConfig()->airmodeHandlingType
== STICK_CENTER_ONCE
) {
803 if (STATE(AIRMODE_ACTIVE
)) {
804 if ((rollPitchStatus
== CENTERED
) && !STATE(ANTI_WINDUP_DEACTIVATED
)) {
805 ENABLE_STATE(ANTI_WINDUP
);
808 DISABLE_STATE(ANTI_WINDUP
);
812 DISABLE_STATE(ANTI_WINDUP
);
813 pidResetErrorAccumulators();
817 DISABLE_STATE(ANTI_WINDUP
);
818 if (rollPitchStatus
!= CENTERED
) {
819 ENABLE_STATE(ANTI_WINDUP_DEACTIVATED
);
823 else if (rcControlsConfig()->airmodeHandlingType
== THROTTLE_THRESHOLD
) {
824 DISABLE_STATE(ANTI_WINDUP
);
825 //This case applies only to MR when Airmode management is throttle threshold activated
826 if (throttleIsLow
&& !STATE(AIRMODE_ACTIVE
)) {
827 pidResetErrorAccumulators();
830 //---------------------------------------------------------
831 if (currentMixerConfig
.platformType
== PLATFORM_AIRPLANE
) {
832 DISABLE_FLIGHT_MODE(HEADFREE_MODE
);
835 #if defined(USE_AUTOTUNE_FIXED_WING) || defined(USE_AUTOTUNE_MULTIROTOR)
836 autotuneUpdateState();
840 if (feature(FEATURE_TELEMETRY
)) {
841 if ((!telemetryConfig()->telemetry_switch
&& ARMING_FLAG(ARMED
)) ||
842 (telemetryConfig()->telemetry_switch
&& IS_RC_MODE_ACTIVE(BOXTELEMETRY
))) {
844 releaseSharedTelemetryPorts();
846 // the telemetry state must be checked immediately so that shared serial ports are released.
847 telemetryCheckState();
848 mspSerialAllocatePorts();
854 // Function for loop trigger
855 void FAST_CODE
taskGyro(timeUs_t currentTimeUs
) {
856 UNUSED(currentTimeUs
);
857 // getTaskDeltaTime() returns delta time frozen at the moment of entering the scheduler. currentTime is frozen at the very same point.
858 // To make busy-waiting timeout work we need to account for time spent within busy-waiting loop
859 const timeDelta_t currentDeltaTime
= getTaskDeltaTime(TASK_SELF
);
861 /* Update actual hardware readings */
865 if (sensors(SENSOR_OPFLOW
)) {
866 opflowGyroUpdateCallback(currentDeltaTime
);
871 static void applyThrottleTiltCompensation(void)
873 if (STATE(MULTIROTOR
)) {
874 int16_t thrTiltCompStrength
= 0;
876 if (navigationRequiresThrottleTiltCompensation()) {
877 thrTiltCompStrength
= 100;
879 else if (systemConfig()->throttle_tilt_compensation_strength
&& (FLIGHT_MODE(ANGLE_MODE
) || FLIGHT_MODE(HORIZON_MODE
))) {
880 thrTiltCompStrength
= systemConfig()->throttle_tilt_compensation_strength
;
883 if (thrTiltCompStrength
) {
884 const int throttleIdleValue
= getThrottleIdleValue();
885 float tiltCompFactor
= 1.0f
/ constrainf(calculateCosTiltAngle(), 0.6f
, 1.0f
); // max tilt about 50 deg
886 tiltCompFactor
= 1.0f
+ (tiltCompFactor
- 1.0f
) * (thrTiltCompStrength
/ 100.f
);
888 rcCommand
[THROTTLE
] = setDesiredThrottle(throttleIdleValue
+ (rcCommand
[THROTTLE
] - throttleIdleValue
) * tiltCompFactor
, false);
893 void taskMainPidLoop(timeUs_t currentTimeUs
)
896 cycleTime
= getTaskDeltaTime(TASK_SELF
);
897 dT
= (float)cycleTime
* 0.000001f
;
899 if (ARMING_FLAG(ARMED
) && (!STATE(FIXED_WING_LEGACY
) || !isNavLaunchEnabled() || (isNavLaunchEnabled() && fixedWingLaunchStatus() >= FW_LAUNCH_DETECTED
))) {
900 flightTime
+= cycleTime
;
901 armTime
+= cycleTime
;
905 if (!ARMING_FLAG(ARMED
)) {
908 processDelayedSave();
911 if (armTime
> 1 * USECS_PER_SEC
) { // reset in flight emerg rearm flag 1 sec after arming once it's served its purpose
912 DISABLE_STATE(IN_FLIGHT_EMERG_REARM
);
915 #if defined(SITL_BUILD)
921 imuUpdateAccelerometer();
922 imuUpdateAttitude(currentTimeUs
);
924 #if defined(SITL_BUILD)
928 processPilotAndFailSafeActions(dT
);
930 updateArmingStatus();
932 if (rxConfig()->rcFilterFrequency
) {
933 rcInterpolationApply(isRXDataNew
, currentTimeUs
);
937 updateWaypointsAndNavigationMode();
941 updatePositionEstimator();
942 applyWaypointNavigationAndAltitudeHold();
944 // Apply throttle tilt compensation
945 applyThrottleTiltCompensation();
947 #ifdef USE_POWER_LIMITS
948 powerLimiterApply(&rcCommand
[THROTTLE
]);
951 // Calculate stabilisation
956 if (isMixerUsingServos()) {
958 processServoAutotrim(dT
);
961 //Servos should be filtered or written only when mixer is using servos or special feaures are enabled
964 if (!ARMING_FLAG(SIMULATOR_MODE_HITL
)) {
965 if (isServoOutputEnabled()) {
969 if (motorControlEnable
) {
974 if (isServoOutputEnabled()) {
978 if (motorControlEnable
) {
982 // Check if landed, FW and MR
983 if (STATE(ALTITUDE_CONTROL
)) {
984 updateLandingStatus(US2MS(currentTimeUs
));
988 if (!cliMode
&& feature(FEATURE_BLACKBOX
)) {
989 blackboxUpdate(micros());
994 // This function is called in a busy-loop, everything called from here should do it's own
995 // scheduling and avoid doing heavy calculations
996 void taskRunRealtimeCallbacks(timeUs_t currentTimeUs
)
998 UNUSED(currentTimeUs
);
1005 pwmCompleteMotorUpdate();
1008 #ifdef USE_ESC_SENSOR
1009 escSensorUpdate(currentTimeUs
);
1013 bool taskUpdateRxCheck(timeUs_t currentTimeUs
, timeDelta_t currentDeltaTime
)
1015 UNUSED(currentDeltaTime
);
1017 return rxUpdateCheck(currentTimeUs
, currentDeltaTime
);
1020 void taskUpdateRxMain(timeUs_t currentTimeUs
)
1022 processRx(currentTimeUs
);
1027 float getFlightTime(void)
1029 return US2S(flightTime
);
1032 float getArmTime(void)
1034 return US2S(armTime
);
1037 void fcReboot(bool bootLoader
)
1039 // stop motor/servo outputs
1043 // extra delay before reboot to give ESCs chance to reset
1047 systemResetToBootloader();