Merge pull request #194 from iNavFlight/sbas-none
[betaflight.git] / src / main / mw.c
blobd2e0528e312750195a3e59f5f3e2cb4ad046b78b
1 /*
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/>.
18 #include <stdbool.h>
19 #include <stdlib.h>
20 #include <stdint.h>
21 #include <math.h>
23 #include "platform.h"
24 #include "debug.h"
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"
61 #include "io/gps.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"
68 #include "rx/rx.h"
69 #include "rx/msp.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"
86 // June 2013 V2.2-dev
88 enum {
89 ALIGN_GYRO = 0,
90 ALIGN_ACCEL = 1,
91 ALIGN_MAG = 2
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
102 float dT;
104 int16_t magHold;
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;
116 bool isCalibrating()
118 #ifdef BARO
119 if (sensors(SENSOR_BARO) && !isBaroCalibrationComplete()) {
120 return true;
122 #endif
124 // Note: compass calibration is handled completely differently, outside of the main loop, see f.CALIBRATE_MAG
126 return (!isAccelerationCalibrationComplete() && sensors(SENSOR_ACC)) || (!isGyroCalibrationComplete());
129 void annexCode(void)
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;
139 } else {
140 tmp = 0;
144 tmp2 = tmp / 100;
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;
150 } else {
151 tmp = 0;
154 tmp2 = tmp / 100;
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]
164 tmp2 = tmp / 100;
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)) {
177 LED0_ON;
178 } else {
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()) {
188 warningLedFlash();
189 DISABLE_ARMING_FLAG(OK_TO_ARM);
192 #if defined(NAV)
193 if (naivationBlockArming()) {
194 DISABLE_ARMING_FLAG(OK_TO_ARM);
196 #endif
198 if (ARMING_FLAG(OK_TO_ARM)) {
199 warningLedDisable();
200 } else {
201 warningLedFlash();
204 warningLedUpdate();
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);
212 void mwDisarm(void)
214 if (ARMING_FLAG(ARMED)) {
215 DISABLE_ARMING_FLAG(ARMED);
217 #ifdef BLACKBOX
218 if (feature(FEATURE_BLACKBOX)) {
219 finishBlackbox();
221 #endif
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);
231 while (sharedPort) {
232 mspReleasePortIfAllocated(sharedPort);
233 sharedPort = findNextSharedSerialPort(TELEMETRY_FUNCTION_MASK, FUNCTION_MSP);
237 void mwArm(void)
239 if (ARMING_FLAG(OK_TO_ARM)) {
240 if (ARMING_FLAG(ARMED)) {
241 return;
243 if (IS_RC_MODE_ACTIVE(BOXFAILSAFE)) {
244 return;
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);
251 #ifdef BLACKBOX
252 if (feature(FEATURE_BLACKBOX)) {
253 serialPort_t *sharedBlackboxAndMspPort = findSharedSerialPort(FUNCTION_BLACKBOX, FUNCTION_MSP);
254 if (sharedBlackboxAndMspPort) {
255 mspReleasePortIfAllocated(sharedBlackboxAndMspPort);
257 startBlackbox();
259 #endif
260 disarmAt = millis() + masterConfig.auto_disarm_delay * 1000; // start disarm timeout, will be extended when throttle is nonzero
262 //beep to indicate arming
263 #ifdef NAV
264 if (navigationPositionEstimateIsHealthy())
265 beeper(BEEPER_ARMING_GPS_FIX);
266 else
267 beeper(BEEPER_ARMING);
268 #else
269 beeper(BEEPER_ARMING);
270 #endif
272 return;
276 if (!ARMING_FLAG(ARMED)) {
277 beeperConfirmationBeeps(1);
281 void applyMagHold(void)
283 int16_t dif = DECIDEGREES_TO_DEGREES(attitude.values.yaw) - magHold;
285 if (dif <= -180) {
286 dif += 360;
289 if (dif >= +180) {
290 dif -= 360;
293 dif *= masterConfig.yaw_control_direction;
295 if (STATE(SMALL_ANGLE)) {
296 rcCommand[YAW] = dif * currentProfile->pidProfile.P8[PIDMAG] / 30;
300 void updateMagHold(void)
302 #if defined(NAV)
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) {
308 applyMagHold();
311 else
312 #endif
313 if (ABS(rcCommand[YAW]) < 15 && FLIGHT_MODE(MAG_MODE)) {
314 applyMagHold();
316 else {
317 magHold = DECIDEGREES_TO_DEGREES(attitude.values.yaw);
321 void processRx(void)
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))
330 mwDisarm();
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
359 mwDisarm();
360 armedBeeperOn = false;
361 } else {
362 // still armed; do warning beeps while armed
363 beeper(BEEPER_ARMED);
364 armedBeeperOn = true;
366 } else {
367 // throttle is not low
368 if (masterConfig.auto_disarm_delay != 0) {
369 // extend disarm time
370 disarmAt = millis() + masterConfig.auto_disarm_delay * 1000;
373 if (armedBeeperOn) {
374 beeperSilence();
375 armedBeeperOn = false;
378 } else {
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) {
384 beeperSilence();
385 armedBeeperOn = false;
390 processRcStickPositions(&masterConfig.rxConfig, throttleStatus, masterConfig.disarm_kill_switch);
392 updateActivatedModes(currentProfile->modeActivationConditions);
394 if (!cliMode) {
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);
408 } else {
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);
419 } else {
420 DISABLE_FLIGHT_MODE(HORIZON_MODE);
423 if (FLIGHT_MODE(ANGLE_MODE) || FLIGHT_MODE(HORIZON_MODE)) {
424 LED1_ON;
425 } else {
426 LED1_OFF;
429 /* Heading lock mode */
430 if (IS_RC_MODE_ACTIVE(BOXHEADINGLOCK)) {
431 if (!FLIGHT_MODE(HEADING_LOCK)) {
432 ENABLE_FLIGHT_MODE(HEADING_LOCK);
434 } else {
435 DISABLE_FLIGHT_MODE(HEADING_LOCK);
438 #if defined(MAG)
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);
445 } else {
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);
452 } else {
453 DISABLE_FLIGHT_MODE(HEADFREE_MODE);
455 if (IS_RC_MODE_ACTIVE(BOXHEADADJ)) {
456 headFreeModeHold = DECIDEGREES_TO_DEGREES(attitude.values.yaw); // acquire new heading
459 #endif
461 // Navigation may override PASSTHRU_MODE
462 if (IS_RC_MODE_ACTIVE(BOXPASSTHRU) && !naivationRequiresAngleMode()) {
463 ENABLE_FLIGHT_MODE(PASSTHRU_MODE);
464 } else {
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();
476 else {
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);
485 else {
486 DISABLE_STATE(ANTI_WINDUP);
489 else {
490 pidResetErrorAccumulators();
493 ENABLE_STATE(PID_ATTENUATE);
495 else {
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);
505 #ifdef TELEMETRY
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();
511 } else {
512 // the telemetry state must be checked immediately so that shared serial ports are released.
513 telemetryCheckState();
514 mspAllocateSerialPorts();
517 #endif
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;
544 if (isRXDataNew) {
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;
551 } else {
552 factor--;
555 // Interpolate steps of rcCommand
556 if (factor > 0) {
557 for (int channel=0; channel < 4; channel++) {
558 rcCommand[channel] = lastCommand[channel] - deltaRC[channel] * factor/rcInterpolationFactor;
560 } else {
561 factor = 0;
565 void taskMainPidLoop(void)
567 cycleTime = getTaskDeltaTime(TASK_SELF);
568 dT = (float)cycleTime * 0.000001f;
570 imuUpdateAccelerometer();
571 imuUpdateGyroAndAttitude();
573 annexCode();
575 if (masterConfig.rxConfig.rcSmoothing) {
576 filterRc(isRXDataNew);
579 #if defined(NAV)
580 if (isRXDataNew) {
581 updateWaypointsAndNavigationMode();
583 #endif
585 isRXDataNew = false;
587 #if defined(NAV)
588 updatePositionEstimator();
589 applyWaypointNavigationAndAltitudeHold();
590 #endif
592 #ifdef MAG
593 if (sensors(SENSOR_MAG)) {
594 updateMagHold();
596 #endif
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
604 #ifdef USE_SERVOS
605 && !((masterConfig.mixerMode == MIXER_TRI || masterConfig.mixerMode == MIXER_CUSTOM_TRI) && masterConfig.mixerConfig.tri_unarmed_servo)
606 #endif
607 && masterConfig.mixerMode != MIXER_AIRPLANE
608 && masterConfig.mixerMode != MIXER_FLYING_WING
609 && masterConfig.mixerMode != MIXER_CUSTOM_AIRPLANE
610 #endif
612 rcCommand[YAW] = 0;
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(&currentProfile->pidProfile, currentControlRateProfile, &masterConfig.rxConfig);
636 #ifdef HIL
637 if (hilActive) {
638 hilUpdateControlState();
639 motorControlEnable = false;
641 #endif
643 mixTable();
645 #ifdef USE_SERVOS
646 filterServos();
647 writeServos();
648 #endif
650 if (motorControlEnable) {
651 writeMotors();
654 #ifdef BLACKBOX
655 if (!cliMode && feature(FEATURE_BLACKBOX)) {
656 handleBlackbox();
658 #endif
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) {
668 while (1) {
669 if (gyroSyncCheckUpdate() || ((currentDeltaTime + (micros() - currentTime)) >= (targetLooptime + GYRO_WATCHDOG_DELAY))) {
670 break;
675 taskMainPidLoop();
678 void taskHandleSerial(void)
680 handleSerial();
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)
720 processRx();
721 updatePIDCoefficients(&currentProfile->pidProfile, currentControlRateProfile, &masterConfig.rxConfig);
722 isRXDataNew = true;
725 #ifdef GPS
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)) {
732 gpsThread();
735 if (sensors(SENSOR_GPS)) {
736 updateGpsIndicator(currentTime);
739 #endif
741 #ifdef MAG
742 void taskUpdateCompass(void)
744 if (sensors(SENSOR_MAG)) {
745 updateCompass(&masterConfig.magZero);
748 #endif
750 #ifdef BARO
751 void taskUpdateBaro(void)
753 if (sensors(SENSOR_BARO)) {
754 uint32_t newDeadline = baroUpdate();
755 rescheduleTask(TASK_SELF, newDeadline);
758 //updatePositionEstimator_BaroTopic(currentTime);
760 #endif
762 #ifdef SONAR
763 void taskUpdateSonar(void)
765 if (sensors(SENSOR_SONAR)) {
766 sonarUpdate();
769 //updatePositionEstimator_SonarTopic(currentTime);
771 #endif
773 #ifdef DISPLAY
774 void taskUpdateDisplay(void)
776 if (feature(FEATURE_DISPLAY)) {
777 updateDisplay();
780 #endif
782 #ifdef TELEMETRY
783 void taskTelemetry(void)
785 telemetryCheckState();
787 if (!cliMode && feature(FEATURE_TELEMETRY)) {
788 telemetryProcess(&masterConfig.rxConfig, masterConfig.flight3DConfig.deadband3d_throttle);
791 #endif
793 #ifdef LED_STRIP
794 void taskLedStrip(void)
796 if (feature(FEATURE_LED_STRIP)) {
797 updateLedStrip();
800 #endif