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/>.
26 #include "scheduler/scheduler.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/sensor.h"
35 #include "drivers/accgyro.h"
36 #include "drivers/compass.h"
37 #include "drivers/light_led.h"
39 #include "drivers/gpio.h"
40 #include "drivers/system.h"
41 #include "drivers/serial.h"
42 #include "drivers/timer.h"
43 #include "drivers/pwm_rx.h"
44 #include "drivers/gyro_sync.h"
46 #include "sensors/sensors.h"
47 #include "sensors/boardalignment.h"
48 #include "sensors/sonar.h"
49 #include "sensors/compass.h"
50 #include "sensors/acceleration.h"
51 #include "sensors/barometer.h"
52 #include "sensors/gyro.h"
53 #include "sensors/battery.h"
55 #include "io/beeper.h"
56 #include "io/display.h"
57 #include "io/escservo.h"
58 #include "io/rc_controls.h"
59 #include "io/rc_curves.h"
60 #include "io/gimbal.h"
62 #include "io/ledstrip.h"
63 #include "io/serial.h"
64 #include "io/serial_cli.h"
65 #include "io/serial_msp.h"
66 #include "io/statusindicator.h"
71 #include "telemetry/telemetry.h"
72 #include "blackbox/blackbox.h"
74 #include "flight/mixer.h"
75 #include "flight/pid.h"
76 #include "flight/imu.h"
77 #include "flight/hil.h"
78 #include "flight/failsafe.h"
79 #include "flight/navigation_rewrite.h"
81 #include "config/runtime_config.h"
82 #include "config/config.h"
83 #include "config/config_profile.h"
84 #include "config/config_master.h"
94 /* VBAT monitoring interval (in microseconds) - 1s*/
95 #define VBATINTERVAL (6 * 3500)
96 /* IBat monitoring interval (in microseconds) - 6 default looptimes */
97 #define IBATINTERVAL (6 * 3500)
98 #define GYRO_WATCHDOG_DELAY 100 // Watchdog for boards without interrupt for gyro
100 uint16_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
105 int16_t headFreeModeHold
;
107 uint8_t motorControlEnable
= false;
109 int16_t telemTemperature1
; // gyro sensor temperature
110 static uint32_t disarmAt
; // Time of automatic disarm when "Don't spin the motors when armed" is enabled and auto_disarm_delay is nonzero
112 extern uint32_t currentTime
;
114 static bool isRXDataNew
;
119 if (sensors(SENSOR_BARO
) && !isBaroCalibrationComplete()) {
124 // Note: compass calibration is handled completely differently, outside of the main loop, see f.CALIBRATE_MAG
126 return (!isAccelerationCalibrationComplete() && sensors(SENSOR_ACC
)) || (!isGyroCalibrationComplete());
131 int32_t tmp
, tmp2
, axis
;
133 for (axis
= 0; axis
< 3; axis
++) {
134 tmp
= MIN(ABS(rcData
[axis
] - masterConfig
.rxConfig
.midrc
), 500);
135 if (axis
== ROLL
|| axis
== PITCH
) {
136 if (currentProfile
->rcControlsConfig
.deadband
) {
137 if (tmp
> currentProfile
->rcControlsConfig
.deadband
) {
138 tmp
-= currentProfile
->rcControlsConfig
.deadband
;
145 rcCommand
[axis
] = lookupPitchRollRC
[tmp2
] + (tmp
- tmp2
* 100) * (lookupPitchRollRC
[tmp2
+ 1] - lookupPitchRollRC
[tmp2
]) / 100;
146 } else if (axis
== YAW
) {
147 if (currentProfile
->rcControlsConfig
.yaw_deadband
) {
148 if (tmp
> currentProfile
->rcControlsConfig
.yaw_deadband
) {
149 tmp
-= currentProfile
->rcControlsConfig
.yaw_deadband
;
155 rcCommand
[axis
] = (lookupYawRC
[tmp2
] + (tmp
- tmp2
* 100) * (lookupYawRC
[tmp2
+ 1] - lookupYawRC
[tmp2
]) / 100) * -masterConfig
.yaw_control_direction
;
158 if (rcData
[axis
] < masterConfig
.rxConfig
.midrc
)
159 rcCommand
[axis
] = -rcCommand
[axis
];
162 tmp
= constrain(rcData
[THROTTLE
], masterConfig
.rxConfig
.mincheck
, PWM_RANGE_MAX
);
163 tmp
= (uint32_t)(tmp
- masterConfig
.rxConfig
.mincheck
) * PWM_RANGE_MIN
/ (PWM_RANGE_MAX
- masterConfig
.rxConfig
.mincheck
); // [MINCHECK;2000] -> [0;1000]
165 rcCommand
[THROTTLE
] = lookupThrottleRC
[tmp2
] + (tmp
- tmp2
* 100) * (lookupThrottleRC
[tmp2
+ 1] - lookupThrottleRC
[tmp2
]) / 100; // [0;1000] -> expo -> [MINTHROTTLE;MAXTHROTTLE]
167 if (FLIGHT_MODE(HEADFREE_MODE
)) {
168 float radDiff
= degreesToRadians(DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
) - headFreeModeHold
);
169 float cosDiff
= cos_approx(radDiff
);
170 float sinDiff
= sin_approx(radDiff
);
171 int16_t rcCommand_PITCH
= rcCommand
[PITCH
] * cosDiff
+ rcCommand
[ROLL
] * sinDiff
;
172 rcCommand
[ROLL
] = rcCommand
[ROLL
] * cosDiff
- rcCommand
[PITCH
] * sinDiff
;
173 rcCommand
[PITCH
] = rcCommand_PITCH
;
176 if (ARMING_FLAG(ARMED
)) {
179 if (IS_RC_MODE_ACTIVE(BOXARM
) == 0) {
180 ENABLE_ARMING_FLAG(OK_TO_ARM
);
183 if (!STATE(SMALL_ANGLE
)) {
184 DISABLE_ARMING_FLAG(OK_TO_ARM
);
187 if (isCalibrating() || isSystemOverloaded()) {
189 DISABLE_ARMING_FLAG(OK_TO_ARM
);
193 if (naivationBlockArming()) {
194 DISABLE_ARMING_FLAG(OK_TO_ARM
);
198 if (ARMING_FLAG(OK_TO_ARM
)) {
207 // Read out gyro temperature. can use it for something somewhere. maybe get MCU temperature instead? lots of fun possibilities.
208 if (gyro
.temperature
)
209 gyro
.temperature(&telemTemperature1
);
214 if (ARMING_FLAG(ARMED
)) {
215 DISABLE_ARMING_FLAG(ARMED
);
218 if (feature(FEATURE_BLACKBOX
)) {
223 beeper(BEEPER_DISARMING
); // emit disarm tone
227 #define TELEMETRY_FUNCTION_MASK (FUNCTION_TELEMETRY_FRSKY | FUNCTION_TELEMETRY_HOTT | FUNCTION_TELEMETRY_SMARTPORT | FUNCTION_TELEMETRY_LTM)
229 void releaseSharedTelemetryPorts(void) {
230 serialPort_t
*sharedPort
= findSharedSerialPort(TELEMETRY_FUNCTION_MASK
, FUNCTION_MSP
);
232 mspReleasePortIfAllocated(sharedPort
);
233 sharedPort
= findNextSharedSerialPort(TELEMETRY_FUNCTION_MASK
, FUNCTION_MSP
);
239 if (ARMING_FLAG(OK_TO_ARM
)) {
240 if (ARMING_FLAG(ARMED
)) {
243 if (IS_RC_MODE_ACTIVE(BOXFAILSAFE
)) {
246 if (!ARMING_FLAG(PREVENT_ARMING
)) {
247 ENABLE_ARMING_FLAG(ARMED
);
248 ENABLE_ARMING_FLAG(WAS_EVER_ARMED
);
249 headFreeModeHold
= DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
);
252 if (feature(FEATURE_BLACKBOX
)) {
253 serialPort_t
*sharedBlackboxAndMspPort
= findSharedSerialPort(FUNCTION_BLACKBOX
, FUNCTION_MSP
);
254 if (sharedBlackboxAndMspPort
) {
255 mspReleasePortIfAllocated(sharedBlackboxAndMspPort
);
260 disarmAt
= millis() + masterConfig
.auto_disarm_delay
* 1000; // start disarm timeout, will be extended when throttle is nonzero
262 //beep to indicate arming
264 if (navigationPositionEstimateIsHealthy())
265 beeper(BEEPER_ARMING_GPS_FIX
);
267 beeper(BEEPER_ARMING
);
269 beeper(BEEPER_ARMING
);
276 if (!ARMING_FLAG(ARMED
)) {
277 beeperConfirmationBeeps(1);
281 void applyMagHold(void)
283 int16_t dif
= DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
) - magHold
;
293 dif
*= masterConfig
.yaw_control_direction
;
295 if (STATE(SMALL_ANGLE
)) {
296 rcCommand
[YAW
] = dif
* currentProfile
->pidProfile
.P8
[PIDMAG
] / 30;
300 void updateMagHold(void)
303 int navHeadingState
= naivationGetHeadingControlState();
304 // NAV will prevent MAG_MODE from activating, but require heading control
305 if (navHeadingState
!= NAV_HEADING_CONTROL_NONE
) {
306 // Apply maghold only if heading control is in auto mode
307 if (navHeadingState
== NAV_HEADING_CONTROL_AUTO
) {
313 if (ABS(rcCommand
[YAW
]) < 15 && FLIGHT_MODE(MAG_MODE
)) {
317 magHold
= DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
);
323 static bool armedBeeperOn
= false;
325 calculateRxChannelsAndUpdateFailsafe(currentTime
);
327 // in 3D mode, we need to be able to disarm by switch at any time
328 if (feature(FEATURE_3D
)) {
329 if (!IS_RC_MODE_ACTIVE(BOXARM
))
333 updateRSSI(currentTime
);
335 if (feature(FEATURE_FAILSAFE
)) {
337 if (currentTime
> FAILSAFE_POWER_ON_DELAY_US
&& !failsafeIsMonitoring()) {
338 failsafeStartMonitoring();
341 failsafeUpdateState();
344 throttleStatus_e throttleStatus
= calculateThrottleStatus(&masterConfig
.rxConfig
, masterConfig
.flight3DConfig
.deadband3d_throttle
);
346 // When armed and motors aren't spinning, do beeps and then disarm
347 // board after delay so users without buzzer won't lose fingers.
348 // mixTable constrains motor commands, so checking throttleStatus is enough
349 if (ARMING_FLAG(ARMED
)
350 && feature(FEATURE_MOTOR_STOP
)
351 && !STATE(FIXED_WING
)
353 if (isUsingSticksForArming()) {
354 if (throttleStatus
== THROTTLE_LOW
) {
355 if (masterConfig
.auto_disarm_delay
!= 0
356 && (int32_t)(disarmAt
- millis()) < 0
358 // auto-disarm configured and delay is over
360 armedBeeperOn
= false;
362 // still armed; do warning beeps while armed
363 beeper(BEEPER_ARMED
);
364 armedBeeperOn
= true;
367 // throttle is not low
368 if (masterConfig
.auto_disarm_delay
!= 0) {
369 // extend disarm time
370 disarmAt
= millis() + masterConfig
.auto_disarm_delay
* 1000;
375 armedBeeperOn
= false;
379 // arming is via AUX switch; beep while throttle low
380 if (throttleStatus
== THROTTLE_LOW
) {
381 beeper(BEEPER_ARMED
);
382 armedBeeperOn
= true;
383 } else if (armedBeeperOn
) {
385 armedBeeperOn
= false;
390 processRcStickPositions(&masterConfig
.rxConfig
, throttleStatus
, masterConfig
.disarm_kill_switch
);
392 updateActivatedModes(currentProfile
->modeActivationConditions
);
395 updateAdjustmentStates(currentProfile
->adjustmentRanges
);
396 processRcAdjustments(currentControlRateProfile
, &masterConfig
.rxConfig
);
399 bool canUseHorizonMode
= true;
401 if ((IS_RC_MODE_ACTIVE(BOXANGLE
) || (feature(FEATURE_FAILSAFE
) && failsafeIsActive()) || naivationRequiresAngleMode()) && sensors(SENSOR_ACC
)) {
402 // bumpless transfer to Level mode
403 canUseHorizonMode
= false;
405 if (!FLIGHT_MODE(ANGLE_MODE
)) {
406 ENABLE_FLIGHT_MODE(ANGLE_MODE
);
409 DISABLE_FLIGHT_MODE(ANGLE_MODE
); // failsafe support
412 if (IS_RC_MODE_ACTIVE(BOXHORIZON
) && canUseHorizonMode
) {
414 DISABLE_FLIGHT_MODE(ANGLE_MODE
);
416 if (!FLIGHT_MODE(HORIZON_MODE
)) {
417 ENABLE_FLIGHT_MODE(HORIZON_MODE
);
420 DISABLE_FLIGHT_MODE(HORIZON_MODE
);
423 if (FLIGHT_MODE(ANGLE_MODE
) || FLIGHT_MODE(HORIZON_MODE
)) {
429 /* Heading lock mode */
430 if (IS_RC_MODE_ACTIVE(BOXHEADINGLOCK
)) {
431 if (!FLIGHT_MODE(HEADING_LOCK
)) {
432 ENABLE_FLIGHT_MODE(HEADING_LOCK
);
435 DISABLE_FLIGHT_MODE(HEADING_LOCK
);
439 if (sensors(SENSOR_ACC
) || sensors(SENSOR_MAG
)) {
440 if (IS_RC_MODE_ACTIVE(BOXMAG
)) {
441 if (!FLIGHT_MODE(MAG_MODE
)) {
442 ENABLE_FLIGHT_MODE(MAG_MODE
);
443 magHold
= DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
);
446 DISABLE_FLIGHT_MODE(MAG_MODE
);
448 if (IS_RC_MODE_ACTIVE(BOXHEADFREE
)) {
449 if (!FLIGHT_MODE(HEADFREE_MODE
)) {
450 ENABLE_FLIGHT_MODE(HEADFREE_MODE
);
453 DISABLE_FLIGHT_MODE(HEADFREE_MODE
);
455 if (IS_RC_MODE_ACTIVE(BOXHEADADJ
)) {
456 headFreeModeHold
= DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
); // acquire new heading
461 // Navigation may override PASSTHRU_MODE
462 if (IS_RC_MODE_ACTIVE(BOXPASSTHRU
) && !naivationRequiresAngleMode()) {
463 ENABLE_FLIGHT_MODE(PASSTHRU_MODE
);
465 DISABLE_FLIGHT_MODE(PASSTHRU_MODE
);
468 /* In airmode Iterm should be prevented to grow when Low thottle and Roll + Pitch Centered.
469 This is needed to prevent Iterm winding on the ground, but keep full stabilisation on 0 throttle while in air
470 Low Throttle + roll and Pitch centered is assuming the copter is on the ground. Done to prevent complex air/ground detections */
471 if (FLIGHT_MODE(PASSTHRU_MODE
) || !ARMING_FLAG(ARMED
)) {
472 /* In PASSTHRU mode anti-windup must be explicitly enabled to prevent I-term wind-up (PID output is not used in PASSTHRU) */
473 //ENABLE_STATE(ANTI_WINDUP);
474 pidResetErrorAccumulators();
477 if (throttleStatus
== THROTTLE_LOW
) {
478 if (IS_RC_MODE_ACTIVE(BOXAIRMODE
) && !failsafeIsActive() && ARMING_FLAG(ARMED
)) {
479 rollPitchStatus_e rollPitchStatus
= calculateRollPitchCenterStatus(&masterConfig
.rxConfig
);
481 // ANTI_WINDUP at centred stick with MOTOR_STOP is needed on MRs and not needed on FWs
482 if ((rollPitchStatus
== CENTERED
) || (feature(FEATURE_MOTOR_STOP
) && !STATE(FIXED_WING
))) {
483 ENABLE_STATE(ANTI_WINDUP
);
486 DISABLE_STATE(ANTI_WINDUP
);
490 pidResetErrorAccumulators();
493 ENABLE_STATE(PID_ATTENUATE
);
496 DISABLE_STATE(PID_ATTENUATE
);
497 DISABLE_STATE(ANTI_WINDUP
);
501 if (masterConfig
.mixerMode
== MIXER_FLYING_WING
|| masterConfig
.mixerMode
== MIXER_AIRPLANE
|| masterConfig
.mixerMode
== MIXER_CUSTOM_AIRPLANE
) {
502 DISABLE_FLIGHT_MODE(HEADFREE_MODE
);
506 if (feature(FEATURE_TELEMETRY
)) {
507 if ((!masterConfig
.telemetryConfig
.telemetry_switch
&& ARMING_FLAG(ARMED
)) ||
508 (masterConfig
.telemetryConfig
.telemetry_switch
&& IS_RC_MODE_ACTIVE(BOXTELEMETRY
))) {
510 releaseSharedTelemetryPorts();
512 // the telemetry state must be checked immediately so that shared serial ports are released.
513 telemetryCheckState();
514 mspAllocateSerialPorts();
521 void filterRc(bool isRXDataNew
)
523 static int16_t lastCommand
[4] = { 0, 0, 0, 0 };
524 static int16_t deltaRC
[4] = { 0, 0, 0, 0 };
525 static int16_t factor
, rcInterpolationFactor
;
526 static biquad_t filteredCycleTimeState
;
527 static bool filterInitialised
;
528 uint16_t filteredCycleTime
;
529 uint16_t rxRefreshRate
;
531 // Set RC refresh rate for sampling and channels to filter
532 initRxRefreshRate(&rxRefreshRate
);
534 // Calculate average cycle time (1Hz LPF on cycle time)
535 if (!filterInitialised
) {
536 filterInitBiQuad(1, &filteredCycleTimeState
, 0);
537 filterInitialised
= true;
540 filteredCycleTime
= filterApplyBiQuad((float) cycleTime
, &filteredCycleTimeState
);
542 rcInterpolationFactor
= rxRefreshRate
/ filteredCycleTime
+ 1;
545 for (int channel
=0; channel
< 4; channel
++) {
546 deltaRC
[channel
] = rcCommand
[channel
] - (lastCommand
[channel
] - deltaRC
[channel
] * factor
/ rcInterpolationFactor
);
547 lastCommand
[channel
] = rcCommand
[channel
];
550 factor
= rcInterpolationFactor
- 1;
555 // Interpolate steps of rcCommand
557 for (int channel
=0; channel
< 4; channel
++) {
558 rcCommand
[channel
] = lastCommand
[channel
] - deltaRC
[channel
] * factor
/rcInterpolationFactor
;
565 void taskMainPidLoop(void)
567 cycleTime
= getTaskDeltaTime(TASK_SELF
);
568 dT
= (float)cycleTime
* 0.000001f
;
570 imuUpdateAccelerometer();
571 imuUpdateGyroAndAttitude();
575 if (masterConfig
.rxConfig
.rcSmoothing
) {
576 filterRc(isRXDataNew
);
581 updateWaypointsAndNavigationMode();
588 updatePositionEstimator();
589 applyWaypointNavigationAndAltitudeHold();
593 if (sensors(SENSOR_MAG
)) {
598 // If we're armed, at minimum throttle, and we do arming via the
599 // sticks, do not process yaw input from the rx. We do this so the
600 // motors do not spin up while we are trying to arm or disarm.
601 // Allow yaw control for tricopters if the user wants the servo to move even when unarmed.
602 if (isUsingSticksForArming() && rcData
[THROTTLE
] <= masterConfig
.rxConfig
.mincheck
603 #ifndef USE_QUAD_MIXER_ONLY
605 && !((masterConfig
.mixerMode
== MIXER_TRI
|| masterConfig
.mixerMode
== MIXER_CUSTOM_TRI
) && masterConfig
.mixerConfig
.tri_unarmed_servo
)
607 && masterConfig
.mixerMode
!= MIXER_AIRPLANE
608 && masterConfig
.mixerMode
!= MIXER_FLYING_WING
609 && masterConfig
.mixerMode
!= MIXER_CUSTOM_AIRPLANE
615 // Apply throttle tilt compensation
616 if (!STATE(FIXED_WING
)) {
617 int16_t thrTiltCompStrength
= 0;
619 if (navigationRequiresThrottleTiltCompensation()) {
620 thrTiltCompStrength
= 100;
622 else if (currentProfile
->throttle_tilt_compensation_strength
&& (FLIGHT_MODE(ANGLE_MODE
) || FLIGHT_MODE(HORIZON_MODE
))) {
623 thrTiltCompStrength
= currentProfile
->throttle_tilt_compensation_strength
;
626 if (thrTiltCompStrength
) {
627 rcCommand
[THROTTLE
] = constrain(masterConfig
.escAndServoConfig
.minthrottle
628 + (rcCommand
[THROTTLE
] - masterConfig
.escAndServoConfig
.minthrottle
) * calculateThrottleTiltCompensationFactor(thrTiltCompStrength
),
629 masterConfig
.escAndServoConfig
.minthrottle
,
630 masterConfig
.escAndServoConfig
.maxthrottle
);
634 pidController(¤tProfile
->pidProfile
, currentControlRateProfile
, &masterConfig
.rxConfig
);
638 hilUpdateControlState();
639 motorControlEnable
= false;
650 if (motorControlEnable
) {
655 if (!cliMode
&& feature(FEATURE_BLACKBOX
)) {
661 // Function for loop trigger
662 void taskMainPidLoopChecker(void) {
663 // getTaskDeltaTime() returns delta time freezed at the moment of entering the scheduler. currentTime is freezed at the very same point.
664 // To make busy-waiting timeout work we need to account for time spent within busy-waiting loop
665 uint32_t currentDeltaTime
= getTaskDeltaTime(TASK_SELF
);
667 if (masterConfig
.gyroSync
) {
669 if (gyroSyncCheckUpdate() || ((currentDeltaTime
+ (micros() - currentTime
)) >= (targetLooptime
+ GYRO_WATCHDOG_DELAY
))) {
678 void taskHandleSerial(void)
683 void taskUpdateBeeper(void)
685 beeperUpdate(); //call periodic beeper handler
688 void taskUpdateBattery(void)
690 static uint32_t vbatLastServiced
= 0;
691 static uint32_t ibatLastServiced
= 0;
693 if (feature(FEATURE_VBAT
)) {
694 if (cmp32(currentTime
, vbatLastServiced
) >= VBATINTERVAL
) {
695 uint32_t vbatTimeDelta
= currentTime
- vbatLastServiced
;
696 vbatLastServiced
= currentTime
;
697 updateBattery(vbatTimeDelta
);
701 if (feature(FEATURE_CURRENT_METER
)) {
702 int32_t ibatTimeSinceLastServiced
= cmp32(currentTime
, ibatLastServiced
);
704 if (ibatTimeSinceLastServiced
>= IBATINTERVAL
) {
705 ibatLastServiced
= currentTime
;
706 updateCurrentMeter(ibatTimeSinceLastServiced
, &masterConfig
.rxConfig
, masterConfig
.flight3DConfig
.deadband3d_throttle
);
711 bool taskUpdateRxCheck(uint32_t currentDeltaTime
)
713 UNUSED(currentDeltaTime
);
714 updateRx(currentTime
);
715 return shouldProcessRx(currentTime
);
718 void taskUpdateRxMain(void)
721 updatePIDCoefficients(¤tProfile
->pidProfile
, currentControlRateProfile
, &masterConfig
.rxConfig
);
726 void taskProcessGPS(void)
728 // if GPS feature is enabled, gpsThread() will be called at some intervals to check for stuck
729 // hardware, wrong baud rates, init GPS if needed, etc. Don't use SENSOR_GPS here as gpsThread() can and will
730 // change this based on available hardware
731 if (feature(FEATURE_GPS
)) {
735 if (sensors(SENSOR_GPS
)) {
736 updateGpsIndicator(currentTime
);
742 void taskUpdateCompass(void)
744 if (sensors(SENSOR_MAG
)) {
745 updateCompass(&masterConfig
.magZero
);
751 void taskUpdateBaro(void)
753 if (sensors(SENSOR_BARO
)) {
754 uint32_t newDeadline
= baroUpdate();
755 rescheduleTask(TASK_SELF
, newDeadline
);
758 //updatePositionEstimator_BaroTopic(currentTime);
763 void taskUpdateSonar(void)
765 if (sensors(SENSOR_SONAR
)) {
769 //updatePositionEstimator_SonarTopic(currentTime);
774 void taskUpdateDisplay(void)
776 if (feature(FEATURE_DISPLAY
)) {
783 void taskTelemetry(void)
785 telemetryCheckState();
787 if (!cliMode
&& feature(FEATURE_TELEMETRY
)) {
788 telemetryProcess(&masterConfig
.rxConfig
, masterConfig
.flight3DConfig
.deadband3d_throttle
);
794 void taskLedStrip(void)
796 if (feature(FEATURE_LED_STRIP
)) {