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"
41 #include "drivers/accgyro/accgyro_bno055.h"
43 #include "sensors/sensors.h"
44 #include "sensors/diagnostics.h"
45 #include "sensors/boardalignment.h"
46 #include "sensors/acceleration.h"
47 #include "sensors/barometer.h"
48 #include "sensors/compass.h"
49 #include "sensors/pitotmeter.h"
50 #include "sensors/gyro.h"
51 #include "sensors/battery.h"
52 #include "sensors/rangefinder.h"
53 #include "sensors/opflow.h"
54 #include "sensors/esc_sensor.h"
56 #include "fc/fc_core.h"
58 #include "fc/config.h"
59 #include "fc/controlrate_profile.h"
60 #include "fc/rc_adjustments.h"
61 #include "fc/rc_smoothing.h"
62 #include "fc/rc_controls.h"
63 #include "fc/rc_curves.h"
64 #include "fc/rc_modes.h"
65 #include "fc/runtime_config.h"
67 #include "io/beeper.h"
68 #include "io/dashboard.h"
70 #include "io/serial.h"
71 #include "io/statusindicator.h"
72 #include "io/asyncfatfs/asyncfatfs.h"
73 #include "io/piniobox.h"
75 #include "msp/msp_serial.h"
77 #include "navigation/navigation.h"
82 #include "scheduler/scheduler.h"
84 #include "telemetry/telemetry.h"
86 #include "flight/mixer.h"
87 #include "flight/servos.h"
88 #include "flight/pid.h"
89 #include "flight/imu.h"
90 #include "flight/secondary_imu.h"
91 #include "flight/rate_dynamics.h"
93 #include "flight/failsafe.h"
94 #include "flight/power_limits.h"
96 #include "config/feature.h"
97 #include "common/vector.h"
98 #include "programming/pid.h"
100 // June 2013 V2.2-dev
108 #define EMERGENCY_ARMING_TIME_WINDOW_MS 10000
109 #define EMERGENCY_ARMING_COUNTER_STEP_MS 100
111 typedef struct emergencyArmingState_s
{
112 bool armingSwitchWasOn
;
113 // Each entry in the queue is an offset from start,
114 // in 0.1s increments. This lets us represent up to 25.5s
115 // so it will work fine as long as the window for the triggers
116 // is smaller (see EMERGENCY_ARMING_TIME_WINDOW_MS). First
117 // entry of the queue is implicit.
121 } emergencyArmingState_t
;
123 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
124 static timeUs_t flightTime
= 0;
125 static timeUs_t armTime
= 0;
127 EXTENDED_FASTRAM
float dT
;
129 int16_t headFreeModeHold
;
131 uint8_t motorControlEnable
= false;
133 static bool isRXDataNew
;
134 static disarmReason_t lastDisarmReason
= DISARM_NONE
;
135 timeUs_t lastDisarmTimeUs
= 0;
136 static emergencyArmingState_t emergencyArming
;
138 static bool prearmWasReset
= false; // Prearm must be reset (RC Mode not active) before arming is possible
139 static timeMs_t prearmActivationTime
= 0;
141 bool areSensorsCalibrating(void)
144 if (sensors(SENSOR_BARO
) && !baroIsCalibrationComplete()) {
150 if (sensors(SENSOR_MAG
) && !compassIsCalibrationComplete()) {
156 if (sensors(SENSOR_PITOT
) && !pitotIsCalibrationComplete()) {
161 if (!navIsCalibrationComplete()) {
165 if (!accIsCalibrationComplete() && sensors(SENSOR_ACC
)) {
169 if (!gyroIsCalibrationComplete()) {
176 int16_t getAxisRcCommand(int16_t rawData
, int16_t rate
, int16_t deadband
)
178 int16_t stickDeflection
;
180 stickDeflection
= constrain(rawData
- PWM_RANGE_MIDDLE
, -500, 500);
181 stickDeflection
= applyDeadbandRescaled(stickDeflection
, deadband
, -500, 500);
183 return rcLookup(stickDeflection
, rate
);
186 static void updateArmingStatus(void)
188 if (ARMING_FLAG(ARMED
)) {
191 /* CHECK: Run-time calibration */
192 static bool calibratingFinishedBeep
= false;
193 if (areSensorsCalibrating()) {
194 ENABLE_ARMING_FLAG(ARMING_DISABLED_SENSORS_CALIBRATING
);
195 calibratingFinishedBeep
= false;
198 DISABLE_ARMING_FLAG(ARMING_DISABLED_SENSORS_CALIBRATING
);
200 if (!calibratingFinishedBeep
) {
201 calibratingFinishedBeep
= true;
202 beeper(BEEPER_RUNTIME_CALIBRATION_DONE
);
206 /* CHECK: RX signal */
207 if (!failsafeIsReceivingRxData()) {
208 ENABLE_ARMING_FLAG(ARMING_DISABLED_RC_LINK
);
211 DISABLE_ARMING_FLAG(ARMING_DISABLED_RC_LINK
);
214 /* CHECK: Throttle */
215 if (!armingConfig()->fixed_wing_auto_arm
) {
216 // Don't want this check if fixed_wing_auto_arm is in use - machine arms on throttle > LOW
217 if (calculateThrottleStatus(THROTTLE_STATUS_TYPE_RC
) != THROTTLE_LOW
) {
218 ENABLE_ARMING_FLAG(ARMING_DISABLED_THROTTLE
);
220 DISABLE_ARMING_FLAG(ARMING_DISABLED_THROTTLE
);
224 /* CHECK: pitch / roll sticks centered when NAV_LAUNCH_MODE enabled */
225 if (isNavLaunchEnabled()) {
226 if (isRollPitchStickDeflected()) {
227 ENABLE_ARMING_FLAG(ARMING_DISABLED_ROLLPITCH_NOT_CENTERED
);
229 DISABLE_ARMING_FLAG(ARMING_DISABLED_ROLLPITCH_NOT_CENTERED
);
234 if (!STATE(SMALL_ANGLE
)) {
235 ENABLE_ARMING_FLAG(ARMING_DISABLED_NOT_LEVEL
);
238 DISABLE_ARMING_FLAG(ARMING_DISABLED_NOT_LEVEL
);
241 /* CHECK: CPU load */
242 if (isSystemOverloaded()) {
243 ENABLE_ARMING_FLAG(ARMING_DISABLED_SYSTEM_OVERLOADED
);
246 DISABLE_ARMING_FLAG(ARMING_DISABLED_SYSTEM_OVERLOADED
);
249 /* CHECK: Navigation safety */
250 if (navigationIsBlockingArming(NULL
) != NAV_ARMING_BLOCKER_NONE
) {
251 ENABLE_ARMING_FLAG(ARMING_DISABLED_NAVIGATION_UNSAFE
);
254 DISABLE_ARMING_FLAG(ARMING_DISABLED_NAVIGATION_UNSAFE
);
259 if (sensors(SENSOR_MAG
) && !STATE(COMPASS_CALIBRATED
)) {
260 ENABLE_ARMING_FLAG(ARMING_DISABLED_COMPASS_NOT_CALIBRATED
);
263 DISABLE_ARMING_FLAG(ARMING_DISABLED_COMPASS_NOT_CALIBRATED
);
268 if (sensors(SENSOR_ACC
) && !STATE(ACCELEROMETER_CALIBRATED
)) {
269 ENABLE_ARMING_FLAG(ARMING_DISABLED_ACCELEROMETER_NOT_CALIBRATED
);
272 DISABLE_ARMING_FLAG(ARMING_DISABLED_ACCELEROMETER_NOT_CALIBRATED
);
276 if (!isHardwareHealthy()) {
277 ENABLE_ARMING_FLAG(ARMING_DISABLED_HARDWARE_FAILURE
);
280 DISABLE_ARMING_FLAG(ARMING_DISABLED_HARDWARE_FAILURE
);
283 /* CHECK: BOXFAILSAFE */
284 if (IS_RC_MODE_ACTIVE(BOXFAILSAFE
)) {
285 ENABLE_ARMING_FLAG(ARMING_DISABLED_BOXFAILSAFE
);
288 DISABLE_ARMING_FLAG(ARMING_DISABLED_BOXFAILSAFE
);
291 /* CHECK: BOXKILLSWITCH */
292 if (IS_RC_MODE_ACTIVE(BOXKILLSWITCH
)) {
293 ENABLE_ARMING_FLAG(ARMING_DISABLED_BOXKILLSWITCH
);
296 DISABLE_ARMING_FLAG(ARMING_DISABLED_BOXKILLSWITCH
);
299 /* CHECK: Do not allow arming if Servo AutoTrim is enabled */
300 if (IS_RC_MODE_ACTIVE(BOXAUTOTRIM
)) {
301 ENABLE_ARMING_FLAG(ARMING_DISABLED_SERVO_AUTOTRIM
);
304 DISABLE_ARMING_FLAG(ARMING_DISABLED_SERVO_AUTOTRIM
);
308 /* CHECK: Don't arm if the DShot beeper was used recently, as there is a minimum delay before sending the next DShot command */
309 if (micros() - getLastDshotBeeperCommandTimeUs() < getDShotBeaconGuardDelayUs()) {
310 ENABLE_ARMING_FLAG(ARMING_DISABLED_DSHOT_BEEPER
);
312 DISABLE_ARMING_FLAG(ARMING_DISABLED_DSHOT_BEEPER
);
315 DISABLE_ARMING_FLAG(ARMING_DISABLED_DSHOT_BEEPER
);
318 if (isModeActivationConditionPresent(BOXPREARM
)) {
319 if (IS_RC_MODE_ACTIVE(BOXPREARM
)) {
320 if (prearmWasReset
&& (armingConfig()->prearmTimeoutMs
== 0 || millis() - prearmActivationTime
< armingConfig()->prearmTimeoutMs
)) {
321 DISABLE_ARMING_FLAG(ARMING_DISABLED_NO_PREARM
);
323 ENABLE_ARMING_FLAG(ARMING_DISABLED_NO_PREARM
);
326 prearmWasReset
= true;
327 prearmActivationTime
= millis();
328 ENABLE_ARMING_FLAG(ARMING_DISABLED_NO_PREARM
);
331 DISABLE_ARMING_FLAG(ARMING_DISABLED_NO_PREARM
);
334 /* CHECK: Arming switch */
335 // If arming is disabled and the ARM switch is on
336 // Note that this should be last check so all other blockers could be cleared correctly
337 // if blocking modes are linked to the same RC channel
338 if (isArmingDisabled() && IS_RC_MODE_ACTIVE(BOXARM
)) {
339 ENABLE_ARMING_FLAG(ARMING_DISABLED_ARM_SWITCH
);
340 } else if (!IS_RC_MODE_ACTIVE(BOXARM
)) {
341 DISABLE_ARMING_FLAG(ARMING_DISABLED_ARM_SWITCH
);
344 if (isArmingDisabled()) {
354 static bool emergencyArmingIsTriggered(void)
356 int threshold
= (EMERGENCY_ARMING_TIME_WINDOW_MS
/ EMERGENCY_ARMING_COUNTER_STEP_MS
);
357 return emergencyArming
.queueCount
== ARRAYLEN(emergencyArming
.queue
) + 1 &&
358 emergencyArming
.queue
[ARRAYLEN(emergencyArming
.queue
) - 1] < threshold
&&
359 emergencyArming
.start
>= millis() - EMERGENCY_ARMING_TIME_WINDOW_MS
;
362 static bool emergencyArmingCanOverrideArmingDisabled(void)
364 uint32_t armingPrevention
= armingFlags
& ARMING_DISABLED_ALL_FLAGS
;
365 armingPrevention
&= ~ARMING_DISABLED_EMERGENCY_OVERRIDE
;
366 return armingPrevention
== 0;
369 static bool emergencyArmingIsEnabled(void)
371 return emergencyArmingIsTriggered() && emergencyArmingCanOverrideArmingDisabled();
374 void annexCode(float dT
)
376 if (failsafeShouldApplyControlInput()) {
377 // Failsafe will apply rcCommand for us
378 failsafeApplyControlInput();
381 // Compute ROLL PITCH and YAW command
382 rcCommand
[ROLL
] = getAxisRcCommand(rxGetChannelValue(ROLL
), FLIGHT_MODE(MANUAL_MODE
) ? currentControlRateProfile
->manual
.rcExpo8
: currentControlRateProfile
->stabilized
.rcExpo8
, rcControlsConfig()->deadband
);
383 rcCommand
[PITCH
] = getAxisRcCommand(rxGetChannelValue(PITCH
), FLIGHT_MODE(MANUAL_MODE
) ? currentControlRateProfile
->manual
.rcExpo8
: currentControlRateProfile
->stabilized
.rcExpo8
, rcControlsConfig()->deadband
);
384 rcCommand
[YAW
] = -getAxisRcCommand(rxGetChannelValue(YAW
), FLIGHT_MODE(MANUAL_MODE
) ? currentControlRateProfile
->manual
.rcYawExpo8
: currentControlRateProfile
->stabilized
.rcYawExpo8
, rcControlsConfig()->yaw_deadband
);
386 // Apply manual control rates
387 if (FLIGHT_MODE(MANUAL_MODE
)) {
388 rcCommand
[ROLL
] = rcCommand
[ROLL
] * currentControlRateProfile
->manual
.rates
[FD_ROLL
] / 100L;
389 rcCommand
[PITCH
] = rcCommand
[PITCH
] * currentControlRateProfile
->manual
.rates
[FD_PITCH
] / 100L;
390 rcCommand
[YAW
] = rcCommand
[YAW
] * currentControlRateProfile
->manual
.rates
[FD_YAW
] / 100L;
392 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 0, rcCommand
[ROLL
]);
393 rcCommand
[ROLL
] = applyRateDynamics(rcCommand
[ROLL
], ROLL
, dT
);
394 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 1, rcCommand
[ROLL
]);
396 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 2, rcCommand
[PITCH
]);
397 rcCommand
[PITCH
] = applyRateDynamics(rcCommand
[PITCH
], PITCH
, dT
);
398 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 3, rcCommand
[PITCH
]);
400 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 4, rcCommand
[YAW
]);
401 rcCommand
[YAW
] = applyRateDynamics(rcCommand
[YAW
], YAW
, dT
);
402 DEBUG_SET(DEBUG_RATE_DYNAMICS
, 5, rcCommand
[YAW
]);
406 //Compute THROTTLE command
407 rcCommand
[THROTTLE
] = throttleStickMixedValue();
409 // Signal updated rcCommand values to Failsafe system
410 failsafeUpdateRcCommandValues();
412 if (FLIGHT_MODE(HEADFREE_MODE
)) {
413 const float radDiff
= degreesToRadians(DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
) - headFreeModeHold
);
414 const float cosDiff
= cos_approx(radDiff
);
415 const float sinDiff
= sin_approx(radDiff
);
416 const int16_t rcCommand_PITCH
= rcCommand
[PITCH
] * cosDiff
+ rcCommand
[ROLL
] * sinDiff
;
417 rcCommand
[ROLL
] = rcCommand
[ROLL
] * cosDiff
- rcCommand
[PITCH
] * sinDiff
;
418 rcCommand
[PITCH
] = rcCommand_PITCH
;
422 updateArmingStatus();
425 void disarm(disarmReason_t disarmReason
)
427 if (ARMING_FLAG(ARMED
)) {
428 lastDisarmReason
= disarmReason
;
429 lastDisarmTimeUs
= micros();
430 DISABLE_ARMING_FLAG(ARMED
);
433 if (feature(FEATURE_BLACKBOX
)) {
438 if (FLIGHT_MODE(TURTLE_MODE
)) {
439 sendDShotCommand(DSHOT_CMD_SPIN_DIRECTION_NORMAL
);
440 DISABLE_FLIGHT_MODE(TURTLE_MODE
);
444 logicConditionReset();
446 #ifdef USE_PROGRAMMING_FRAMEWORK
447 programmingPidReset();
450 beeper(BEEPER_DISARMING
); // emit disarm tone
452 prearmWasReset
= false;
456 timeUs_t
getLastDisarmTimeUs(void) {
457 return lastDisarmTimeUs
;
460 disarmReason_t
getDisarmReason(void)
462 return lastDisarmReason
;
465 void emergencyArmingUpdate(bool armingSwitchIsOn
)
467 if (armingSwitchIsOn
== emergencyArming
.armingSwitchWasOn
) {
470 if (armingSwitchIsOn
) {
471 timeMs_t now
= millis();
472 if (emergencyArming
.queueCount
== 0) {
473 emergencyArming
.queueCount
= 1;
474 emergencyArming
.start
= now
;
476 while (emergencyArming
.start
< now
- EMERGENCY_ARMING_TIME_WINDOW_MS
|| emergencyArmingIsTriggered()) {
477 if (emergencyArming
.queueCount
> 1) {
478 uint8_t delta
= emergencyArming
.queue
[0];
479 emergencyArming
.start
+= delta
* EMERGENCY_ARMING_COUNTER_STEP_MS
;
480 for (int ii
= 0; ii
< emergencyArming
.queueCount
- 2; ii
++) {
481 emergencyArming
.queue
[ii
] = emergencyArming
.queue
[ii
+ 1] - delta
;
483 emergencyArming
.queueCount
--;
485 emergencyArming
.start
= now
;
488 uint8_t delta
= (now
- emergencyArming
.start
) / EMERGENCY_ARMING_COUNTER_STEP_MS
;
490 emergencyArming
.queue
[emergencyArming
.queueCount
- 1] = delta
;
491 emergencyArming
.queueCount
++;
495 emergencyArming
.armingSwitchWasOn
= !emergencyArming
.armingSwitchWasOn
;
498 #define TELEMETRY_FUNCTION_MASK (FUNCTION_TELEMETRY_FRSKY | FUNCTION_TELEMETRY_HOTT | FUNCTION_TELEMETRY_SMARTPORT | FUNCTION_TELEMETRY_LTM | FUNCTION_TELEMETRY_MAVLINK | FUNCTION_TELEMETRY_IBUS)
500 void releaseSharedTelemetryPorts(void) {
501 serialPort_t
*sharedPort
= findSharedSerialPort(TELEMETRY_FUNCTION_MASK
, FUNCTION_MSP
);
503 mspSerialReleasePortIfAllocated(sharedPort
);
504 sharedPort
= findNextSharedSerialPort(TELEMETRY_FUNCTION_MASK
, FUNCTION_MSP
);
510 #ifdef USE_MULTI_MISSION
511 setMultiMissionOnArm();
513 updateArmingStatus();
518 IS_RC_MODE_ACTIVE(BOXTURTLE
) &&
519 emergencyArmingCanOverrideArmingDisabled() &&
520 isMotorProtocolDshot() &&
521 !ARMING_FLAG(ARMED
) &&
522 !FLIGHT_MODE(TURTLE_MODE
)
524 sendDShotCommand(DSHOT_CMD_SPIN_DIRECTION_REVERSED
);
525 ENABLE_ARMING_FLAG(ARMED
);
526 enableFlightMode(TURTLE_MODE
);
531 #ifdef USE_PROGRAMMING_FRAMEWORK
533 !isArmingDisabled() ||
534 emergencyArmingIsEnabled() ||
535 LOGIC_CONDITION_GLOBAL_FLAG(LOGIC_CONDITION_GLOBAL_FLAG_OVERRIDE_ARMING_SAFETY
)
539 !isArmingDisabled() ||
540 emergencyArmingIsEnabled()
543 if (ARMING_FLAG(ARMED
)) {
547 // If nav_extra_arming_safety was bypassed we always
548 // allow bypassing it even without the sticks set
549 // in the correct position to allow re-arming quickly
550 // in case of a mid-air accidental disarm.
551 bool usedBypass
= false;
552 navigationIsBlockingArming(&usedBypass
);
554 ENABLE_STATE(NAV_EXTRA_ARMING_SAFETY_BYPASSED
);
557 lastDisarmReason
= DISARM_NONE
;
559 ENABLE_ARMING_FLAG(ARMED
);
560 ENABLE_ARMING_FLAG(WAS_EVER_ARMED
);
561 //It is required to inform the mixer that arming was executed and it has to switch to the FORWARD direction
562 ENABLE_STATE(SET_REVERSIBLE_MOTORS_FORWARD
);
563 logicConditionReset();
565 #ifdef USE_PROGRAMMING_FRAMEWORK
566 programmingPidReset();
569 headFreeModeHold
= DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
);
571 resetHeadingHoldTarget(DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
));
574 if (feature(FEATURE_BLACKBOX
)) {
575 serialPort_t
*sharedBlackboxAndMspPort
= findSharedSerialPort(FUNCTION_BLACKBOX
, FUNCTION_MSP
);
576 if (sharedBlackboxAndMspPort
) {
577 mspSerialReleasePortIfAllocated(sharedBlackboxAndMspPort
);
583 //beep to indicate arming
584 if (navigationPositionEstimateIsHealthy()) {
585 beeper(BEEPER_ARMING_GPS_FIX
);
587 beeper(BEEPER_ARMING
);
595 if (!ARMING_FLAG(ARMED
)) {
596 beeperConfirmationBeeps(1);
600 void processRx(timeUs_t currentTimeUs
)
602 // Calculate RPY channel data
603 calculateRxChannelsAndUpdateFailsafe(currentTimeUs
);
605 // in 3D mode, we need to be able to disarm by switch at any time
606 if (feature(FEATURE_REVERSIBLE_MOTORS
)) {
607 if (!IS_RC_MODE_ACTIVE(BOXARM
)) {
608 disarm(DISARM_SWITCH_3D
);
612 updateRSSI(currentTimeUs
);
614 // Update failsafe monitoring system
615 if (currentTimeUs
> FAILSAFE_POWER_ON_DELAY_US
&& !failsafeIsMonitoring()) {
616 failsafeStartMonitoring();
619 failsafeUpdateState();
621 const throttleStatus_e throttleStatus
= calculateThrottleStatus(THROTTLE_STATUS_TYPE_RC
);
623 // When armed and motors aren't spinning, do beeps periodically
624 if (ARMING_FLAG(ARMED
) && feature(FEATURE_MOTOR_STOP
) && !STATE(FIXED_WING_LEGACY
)) {
625 static bool armedBeeperOn
= false;
627 if (throttleStatus
== THROTTLE_LOW
) {
628 beeper(BEEPER_ARMED
);
629 armedBeeperOn
= true;
630 } else if (armedBeeperOn
) {
632 armedBeeperOn
= false;
636 processRcStickPositions(throttleStatus
);
638 updateActivatedModes();
645 bool canUseRxData
= rxIsReceivingSignal() && !FLIGHT_MODE(FAILSAFE_MODE
);
646 updateAdjustmentStates(canUseRxData
);
647 processRcAdjustments(CONST_CAST(controlRateConfig_t
*, currentControlRateProfile
), canUseRxData
);
650 bool canUseHorizonMode
= true;
652 if ((IS_RC_MODE_ACTIVE(BOXANGLE
) || failsafeRequiresAngleMode() || navigationRequiresAngleMode()) && sensors(SENSOR_ACC
)) {
653 // bumpless transfer to Level mode
654 canUseHorizonMode
= false;
656 if (!FLIGHT_MODE(ANGLE_MODE
)) {
657 ENABLE_FLIGHT_MODE(ANGLE_MODE
);
660 DISABLE_FLIGHT_MODE(ANGLE_MODE
); // failsafe support
663 if (IS_RC_MODE_ACTIVE(BOXHORIZON
) && canUseHorizonMode
) {
665 DISABLE_FLIGHT_MODE(ANGLE_MODE
);
667 if (!FLIGHT_MODE(HORIZON_MODE
)) {
668 ENABLE_FLIGHT_MODE(HORIZON_MODE
);
671 DISABLE_FLIGHT_MODE(HORIZON_MODE
);
674 if (FLIGHT_MODE(ANGLE_MODE
) || FLIGHT_MODE(HORIZON_MODE
)) {
681 if (IS_RC_MODE_ACTIVE(BOXFLAPERON
) && STATE(FLAPERON_AVAILABLE
)) {
682 if (!FLIGHT_MODE(FLAPERON
)) {
683 ENABLE_FLIGHT_MODE(FLAPERON
);
686 DISABLE_FLIGHT_MODE(FLAPERON
);
689 /* Turn assistant mode */
690 if (IS_RC_MODE_ACTIVE(BOXTURNASSIST
)) {
691 if (!FLIGHT_MODE(TURN_ASSISTANT
)) {
692 ENABLE_FLIGHT_MODE(TURN_ASSISTANT
);
695 DISABLE_FLIGHT_MODE(TURN_ASSISTANT
);
698 if (sensors(SENSOR_ACC
)) {
699 if (IS_RC_MODE_ACTIVE(BOXHEADINGHOLD
)) {
700 if (!FLIGHT_MODE(HEADING_MODE
)) {
701 resetHeadingHoldTarget(DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
));
702 ENABLE_FLIGHT_MODE(HEADING_MODE
);
705 DISABLE_FLIGHT_MODE(HEADING_MODE
);
710 if (sensors(SENSOR_ACC
) || sensors(SENSOR_MAG
)) {
711 if (IS_RC_MODE_ACTIVE(BOXHEADFREE
)) {
712 if (!FLIGHT_MODE(HEADFREE_MODE
)) {
713 ENABLE_FLIGHT_MODE(HEADFREE_MODE
);
716 DISABLE_FLIGHT_MODE(HEADFREE_MODE
);
718 if (IS_RC_MODE_ACTIVE(BOXHEADADJ
)) {
719 headFreeModeHold
= DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
); // acquire new heading
724 // Handle passthrough mode
725 if (STATE(FIXED_WING_LEGACY
)) {
726 if ((IS_RC_MODE_ACTIVE(BOXMANUAL
) && !navigationRequiresAngleMode() && !failsafeRequiresAngleMode()) || // Normal activation of passthrough
727 (!ARMING_FLAG(ARMED
) && areSensorsCalibrating())){ // Backup - if we are not armed - enforce passthrough while calibrating
728 ENABLE_FLIGHT_MODE(MANUAL_MODE
);
730 DISABLE_FLIGHT_MODE(MANUAL_MODE
);
734 /* In airmode Iterm should be prevented to grow when Low thottle and Roll + Pitch Centered.
735 This is needed to prevent Iterm winding on the ground, but keep full stabilisation on 0 throttle while in air
736 Low Throttle + roll and Pitch centered is assuming the copter is on the ground. Done to prevent complex air/ground detections */
738 if (!ARMING_FLAG(ARMED
)) {
739 DISABLE_STATE(ANTI_WINDUP_DEACTIVATED
);
742 const rollPitchStatus_e rollPitchStatus
= calculateRollPitchCenterStatus();
744 // In MANUAL mode we reset integrators prevent I-term wind-up (PID output is not used in MANUAL)
745 if (FLIGHT_MODE(MANUAL_MODE
) || !ARMING_FLAG(ARMED
)) {
746 DISABLE_STATE(ANTI_WINDUP
);
747 pidResetErrorAccumulators();
749 else if (rcControlsConfig()->airmodeHandlingType
== STICK_CENTER
) {
750 if (throttleStatus
== THROTTLE_LOW
) {
751 if (STATE(AIRMODE_ACTIVE
) && !failsafeIsActive()) {
752 if ((rollPitchStatus
== CENTERED
) || (feature(FEATURE_MOTOR_STOP
) && !STATE(FIXED_WING_LEGACY
))) {
753 ENABLE_STATE(ANTI_WINDUP
);
756 DISABLE_STATE(ANTI_WINDUP
);
760 DISABLE_STATE(ANTI_WINDUP
);
761 pidResetErrorAccumulators();
765 DISABLE_STATE(ANTI_WINDUP
);
768 else if (rcControlsConfig()->airmodeHandlingType
== STICK_CENTER_ONCE
) {
769 if (throttleStatus
== THROTTLE_LOW
) {
770 if (STATE(AIRMODE_ACTIVE
) && !failsafeIsActive()) {
771 if ((rollPitchStatus
== CENTERED
) && !STATE(ANTI_WINDUP_DEACTIVATED
)) {
772 ENABLE_STATE(ANTI_WINDUP
);
775 DISABLE_STATE(ANTI_WINDUP
);
779 DISABLE_STATE(ANTI_WINDUP
);
780 pidResetErrorAccumulators();
784 DISABLE_STATE(ANTI_WINDUP
);
785 if (rollPitchStatus
!= CENTERED
) {
786 ENABLE_STATE(ANTI_WINDUP_DEACTIVATED
);
790 else if (rcControlsConfig()->airmodeHandlingType
== THROTTLE_THRESHOLD
) {
791 DISABLE_STATE(ANTI_WINDUP
);
792 //This case applies only to MR when Airmode management is throttle threshold activated
793 if (throttleStatus
== THROTTLE_LOW
&& !STATE(AIRMODE_ACTIVE
)) {
794 pidResetErrorAccumulators();
797 //---------------------------------------------------------
798 if (mixerConfig()->platformType
== PLATFORM_AIRPLANE
) {
799 DISABLE_FLIGHT_MODE(HEADFREE_MODE
);
802 #if defined(USE_AUTOTUNE_FIXED_WING) || defined(USE_AUTOTUNE_MULTIROTOR)
803 autotuneUpdateState();
807 if (feature(FEATURE_TELEMETRY
)) {
808 if ((!telemetryConfig()->telemetry_switch
&& ARMING_FLAG(ARMED
)) ||
809 (telemetryConfig()->telemetry_switch
&& IS_RC_MODE_ACTIVE(BOXTELEMETRY
))) {
811 releaseSharedTelemetryPorts();
813 // the telemetry state must be checked immediately so that shared serial ports are released.
814 telemetryCheckState();
815 mspSerialAllocatePorts();
822 // Function for loop trigger
823 void FAST_CODE
taskGyro(timeUs_t currentTimeUs
) {
824 UNUSED(currentTimeUs
);
825 // getTaskDeltaTime() returns delta time frozen at the moment of entering the scheduler. currentTime is frozen at the very same point.
826 // To make busy-waiting timeout work we need to account for time spent within busy-waiting loop
827 const timeDelta_t currentDeltaTime
= getTaskDeltaTime(TASK_SELF
);
829 /* Update actual hardware readings */
833 if (sensors(SENSOR_OPFLOW
)) {
834 opflowGyroUpdateCallback(currentDeltaTime
);
839 static float calculateThrottleTiltCompensationFactor(uint8_t throttleTiltCompensationStrength
)
841 if (throttleTiltCompensationStrength
) {
842 float tiltCompFactor
= 1.0f
/ constrainf(calculateCosTiltAngle(), 0.6f
, 1.0f
); // max tilt about 50 deg
843 return 1.0f
+ (tiltCompFactor
- 1.0f
) * (throttleTiltCompensationStrength
/ 100.f
);
849 void taskMainPidLoop(timeUs_t currentTimeUs
)
851 cycleTime
= getTaskDeltaTime(TASK_SELF
);
852 dT
= (float)cycleTime
* 0.000001f
;
854 if (ARMING_FLAG(ARMED
) && (!STATE(FIXED_WING_LEGACY
) || !isNavLaunchEnabled() || (isNavLaunchEnabled() && fixedWingLaunchStatus() >= FW_LAUNCH_DETECTED
))) {
855 flightTime
+= cycleTime
;
856 armTime
+= cycleTime
;
859 if (!ARMING_FLAG(ARMED
)) {
865 imuUpdateAccelerometer();
866 imuUpdateAttitude(currentTimeUs
);
870 if (rxConfig()->rcFilterFrequency
) {
871 rcInterpolationApply(isRXDataNew
);
875 updateWaypointsAndNavigationMode();
880 updatePositionEstimator();
881 applyWaypointNavigationAndAltitudeHold();
883 // Apply throttle tilt compensation
884 if (!STATE(FIXED_WING_LEGACY
)) {
885 int16_t thrTiltCompStrength
= 0;
887 if (navigationRequiresThrottleTiltCompensation()) {
888 thrTiltCompStrength
= 100;
890 else if (systemConfig()->throttle_tilt_compensation_strength
&& (FLIGHT_MODE(ANGLE_MODE
) || FLIGHT_MODE(HORIZON_MODE
))) {
891 thrTiltCompStrength
= systemConfig()->throttle_tilt_compensation_strength
;
894 if (thrTiltCompStrength
) {
895 rcCommand
[THROTTLE
] = constrain(getThrottleIdleValue()
896 + (rcCommand
[THROTTLE
] - getThrottleIdleValue()) * calculateThrottleTiltCompensationFactor(thrTiltCompStrength
),
897 getThrottleIdleValue(),
898 motorConfig()->maxthrottle
);
902 // FIXME: throttle pitch comp for FW
905 #ifdef USE_POWER_LIMITS
906 powerLimiterApply(&rcCommand
[THROTTLE
]);
909 // Calculate stabilisation
914 hilUpdateControlState();
915 motorControlEnable
= false;
921 if (isMixerUsingServos()) {
923 processServoAutotrim(dT
);
926 //Servos should be filtered or written only when mixer is using servos or special feaures are enabled
927 if (isServoOutputEnabled()) {
931 if (motorControlEnable
) {
935 // Check if landed, FW and MR
936 if (STATE(ALTITUDE_CONTROL
)) {
937 updateLandingStatus();
941 if (!cliMode
&& feature(FEATURE_BLACKBOX
)) {
942 blackboxUpdate(micros());
947 // This function is called in a busy-loop, everything called from here should do it's own
948 // scheduling and avoid doing heavy calculations
949 void taskRunRealtimeCallbacks(timeUs_t currentTimeUs
)
951 UNUSED(currentTimeUs
);
958 pwmCompleteMotorUpdate();
961 #ifdef USE_ESC_SENSOR
962 escSensorUpdate(currentTimeUs
);
966 bool taskUpdateRxCheck(timeUs_t currentTimeUs
, timeDelta_t currentDeltaTime
)
968 UNUSED(currentDeltaTime
);
970 return rxUpdateCheck(currentTimeUs
, currentDeltaTime
);
973 void taskUpdateRxMain(timeUs_t currentTimeUs
)
975 processRx(currentTimeUs
);
980 float getFlightTime()
982 return US2S(flightTime
);
987 return US2S(armTime
);
990 void fcReboot(bool bootLoader
)
992 // stop motor/servo outputs
996 // extra delay before reboot to give ESCs chance to reset
1000 systemResetToBootloader();