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/>.
25 #include "common/maths.h"
26 #include "common/axis.h"
27 #include "common/color.h"
28 #include "common/utils.h"
29 #include "common/filter.h"
31 #include "drivers/sensor.h"
32 #include "drivers/accgyro.h"
33 #include "drivers/compass.h"
34 #include "drivers/light_led.h"
36 #include "drivers/gpio.h"
37 #include "drivers/system.h"
38 #include "drivers/serial.h"
39 #include "drivers/timer.h"
40 #include "drivers/pwm_rx.h"
42 #include "sensors/sensors.h"
43 #include "sensors/boardalignment.h"
44 #include "sensors/sonar.h"
45 #include "sensors/compass.h"
46 #include "sensors/acceleration.h"
47 #include "sensors/barometer.h"
48 #include "sensors/gyro.h"
49 #include "sensors/battery.h"
51 #include "io/beeper.h"
52 #include "io/display.h"
53 #include "io/escservo.h"
54 #include "io/rc_controls.h"
55 #include "io/rc_curves.h"
56 #include "io/gimbal.h"
58 #include "io/ledstrip.h"
59 #include "io/serial.h"
60 #include "io/serial_cli.h"
61 #include "io/serial_msp.h"
62 #include "io/statusindicator.h"
67 #include "telemetry/telemetry.h"
68 #include "blackbox/blackbox.h"
70 #include "flight/mixer.h"
71 #include "flight/pid.h"
72 #include "flight/imu.h"
73 #include "flight/altitudehold.h"
74 #include "flight/failsafe.h"
75 #include "flight/gtune.h"
76 #include "flight/navigation.h"
78 #include "config/runtime_config.h"
79 #include "config/config.h"
80 #include "config/config_profile.h"
81 #include "config/config_master.h"
83 ///////////////////////
84 #include "drivers/sound_beeper.h"
85 ///////////////////////
95 /* VBAT monitoring interval (in microseconds) - 1s*/
96 #define VBATINTERVAL (6 * 3500)
97 /* IBat monitoring interval (in microseconds) - 6 default looptimes */
98 #define IBATINTERVAL (6 * 3500)
100 uint32_t currentTime
= 0;
101 uint32_t previousTime
= 0;
102 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
106 int16_t headFreeModeHold
;
108 uint8_t motorControlEnable
= false;
110 //int16_t telemTemperature1; // gyro sensor temperature
111 static uint32_t disarmAt
; // Time of automatic disarm when "Don't spin the motors when armed" is enabled and auto_disarm_delay is nonzero
113 extern uint8_t dynP8
[3], dynI8
[3], dynD8
[3], PIDweight
[3];
115 static bool isRXDataNew
;
117 typedef void (*pidControllerFuncPtr
)(pidProfile_t
*pidProfile
, controlRateConfig_t
*controlRateConfig
,
118 uint16_t max_angle_inclination
, rollAndPitchTrims_t
*angleTrim
, rxConfig_t
*rxConfig
); // pid controller function prototype
120 extern pidControllerFuncPtr pid_controller
;
122 void applyAndSaveAccelerometerTrimsDelta(rollAndPitchTrims_t
*rollAndPitchTrimsDelta
)
124 currentProfile
->accelerometerTrims
.values
.roll
+= rollAndPitchTrimsDelta
->values
.roll
;
125 currentProfile
->accelerometerTrims
.values
.pitch
+= rollAndPitchTrimsDelta
->values
.pitch
;
127 saveConfigAndNotify();
132 void updateGtuneState(void)
134 static bool GTuneWasUsed
= false;
136 if (IS_RC_MODE_ACTIVE(BOXGTUNE
)) {
137 if (!FLIGHT_MODE(GTUNE_MODE
) && ARMING_FLAG(ARMED
)) {
138 ENABLE_FLIGHT_MODE(GTUNE_MODE
);
139 init_Gtune(¤tProfile
->pidProfile
);
142 if (!FLIGHT_MODE(GTUNE_MODE
) && !ARMING_FLAG(ARMED
) && GTuneWasUsed
) {
143 saveConfigAndNotify();
144 GTuneWasUsed
= false;
147 if (FLIGHT_MODE(GTUNE_MODE
) && ARMING_FLAG(ARMED
)) {
148 DISABLE_FLIGHT_MODE(GTUNE_MODE
);
157 if (sensors(SENSOR_BARO
) && !isBaroCalibrationComplete()) {
162 // Note: compass calibration is handled completely differently, outside of the main loop, see f.CALIBRATE_MAG
164 return (!isAccelerationCalibrationComplete() && sensors(SENSOR_ACC
)) || (!isGyroCalibrationComplete());
170 int32_t axis
, prop1
= 0, prop2
;
172 static uint32_t vbatLastServiced
= 0;
173 static uint32_t ibatLastServiced
= 0;
174 // PITCH & ROLL only dynamic PID adjustment, depending on throttle value
175 if (rcData
[THROTTLE
] < currentControlRateProfile
->tpa_breakpoint
) {
178 if (rcData
[THROTTLE
] < 2000) {
179 prop2
= 100 - (uint16_t)currentControlRateProfile
->dynThrPID
* (rcData
[THROTTLE
] - currentControlRateProfile
->tpa_breakpoint
) / (2000 - currentControlRateProfile
->tpa_breakpoint
);
181 prop2
= 100 - currentControlRateProfile
->dynThrPID
;
185 for (axis
= 0; axis
< 3; axis
++) {
186 tmp
= MIN(ABS(rcData
[axis
] - masterConfig
.rxConfig
.midrc
), 500);
187 if (axis
== ROLL
|| axis
== PITCH
) {
188 if (currentProfile
->rcControlsConfig
.deadband
) {
189 if (tmp
> currentProfile
->rcControlsConfig
.deadband
) {
190 tmp
-= currentProfile
->rcControlsConfig
.deadband
;
197 rcCommand
[axis
] = lookupPitchRollRC
[tmp2
] + (tmp
- tmp2
* 100) * (lookupPitchRollRC
[tmp2
+ 1] - lookupPitchRollRC
[tmp2
]) / 100;
198 prop1
= 100 - (uint16_t)currentControlRateProfile
->rates
[axis
] * tmp
/ 500;
199 prop1
= (uint16_t)prop1
* prop2
/ 100;
200 } else if (axis
== YAW
) {
201 if (currentProfile
->rcControlsConfig
.yaw_deadband
) {
202 if (tmp
> currentProfile
->rcControlsConfig
.yaw_deadband
) {
203 tmp
-= currentProfile
->rcControlsConfig
.yaw_deadband
;
209 rcCommand
[axis
] = (lookupYawRC
[tmp2
] + (tmp
- tmp2
* 100) * (lookupYawRC
[tmp2
+ 1] - lookupYawRC
[tmp2
]) / 100) * -masterConfig
.yaw_control_direction
;
210 prop1
= 100 - (uint16_t)currentControlRateProfile
->rates
[axis
] * ABS(tmp
) / 500;
212 // FIXME axis indexes into pids. use something like lookupPidIndex(rc_alias_e alias) to reduce coupling.
213 dynP8
[axis
] = (uint16_t)currentProfile
->pidProfile
.P8
[axis
] * prop1
/ 100;
214 dynI8
[axis
] = (uint16_t)currentProfile
->pidProfile
.I8
[axis
] * prop1
/ 100;
215 dynD8
[axis
] = (uint16_t)currentProfile
->pidProfile
.D8
[axis
] * prop1
/ 100;
217 // non coupled PID reduction scaler used in PID controller 1 and PID controller 2. YAW TPA disabled. 100 means 100% of the pids
219 PIDweight
[axis
] = 100;
222 PIDweight
[axis
] = prop2
;
225 if (rcData
[axis
] < masterConfig
.rxConfig
.midrc
)
226 rcCommand
[axis
] = -rcCommand
[axis
];
229 tmp
= constrain(rcData
[THROTTLE
], masterConfig
.rxConfig
.mincheck
, PWM_RANGE_MAX
);
230 tmp
= (uint32_t)(tmp
- masterConfig
.rxConfig
.mincheck
) * PWM_RANGE_MIN
/ (PWM_RANGE_MAX
- masterConfig
.rxConfig
.mincheck
); // [MINCHECK;2000] -> [0;1000]
232 rcCommand
[THROTTLE
] = lookupThrottleRC
[tmp2
] + (tmp
- tmp2
* 100) * (lookupThrottleRC
[tmp2
+ 1] - lookupThrottleRC
[tmp2
]) / 100; // [0;1000] -> expo -> [MINTHROTTLE;MAXTHROTTLE]
234 if (FLIGHT_MODE(HEADFREE_MODE
)) {
235 float radDiff
= degreesToRadians(heading
- headFreeModeHold
);
236 float cosDiff
= cos_approx(radDiff
);
237 float sinDiff
= sin_approx(radDiff
);
238 int16_t rcCommand_PITCH
= rcCommand
[PITCH
] * cosDiff
+ rcCommand
[ROLL
] * sinDiff
;
239 rcCommand
[ROLL
] = rcCommand
[ROLL
] * cosDiff
- rcCommand
[PITCH
] * sinDiff
;
240 rcCommand
[PITCH
] = rcCommand_PITCH
;
243 if (feature(FEATURE_VBAT
)) {
244 if (cmp32(currentTime
, vbatLastServiced
) >= VBATINTERVAL
) {
245 vbatLastServiced
= currentTime
;
250 if (feature(FEATURE_CURRENT_METER
)) {
251 int32_t ibatTimeSinceLastServiced
= cmp32(currentTime
, ibatLastServiced
);
253 if (ibatTimeSinceLastServiced
>= IBATINTERVAL
) {
254 ibatLastServiced
= currentTime
;
255 updateCurrentMeter(ibatTimeSinceLastServiced
, &masterConfig
.rxConfig
, masterConfig
.flight3DConfig
.deadband3d_throttle
);
259 beeperUpdate(); //call periodic beeper handler
261 if (ARMING_FLAG(ARMED
)) {
264 if (IS_RC_MODE_ACTIVE(BOXARM
) == 0) {
265 ENABLE_ARMING_FLAG(OK_TO_ARM
);
268 if (!STATE(SMALL_ANGLE
)) {
269 DISABLE_ARMING_FLAG(OK_TO_ARM
);
272 if (isCalibrating()) {
274 DISABLE_ARMING_FLAG(OK_TO_ARM
);
276 if (ARMING_FLAG(OK_TO_ARM
)) {
287 telemetryCheckState();
293 if (sensors(SENSOR_GPS
)) {
294 updateGpsIndicator(currentTime
);
298 // Read out gyro temperature. can use it for something somewhere. maybe get MCU temperature instead? lots of fun possibilities.
299 /*if (gyro.temperature)
300 gyro.temperature(&telemTemperature1);*/
305 if (ARMING_FLAG(ARMED
)) {
306 DISABLE_ARMING_FLAG(ARMED
);
309 if (feature(FEATURE_BLACKBOX)) {
314 beeper(BEEPER_DISARMING
); // emit disarm tone
318 #define TELEMETRY_FUNCTION_MASK (FUNCTION_TELEMETRY_FRSKY | FUNCTION_TELEMETRY_HOTT | FUNCTION_TELEMETRY_MSP | FUNCTION_TELEMETRY_SMARTPORT | FUNCTION_TELEMETRY_MFD)
320 void releaseSharedTelemetryPorts(void) {
321 serialPort_t
*sharedPort
= findSharedSerialPort(TELEMETRY_FUNCTION_MASK
, FUNCTION_MSP
);
323 mspReleasePortIfAllocated(sharedPort
);
324 sharedPort
= findNextSharedSerialPort(TELEMETRY_FUNCTION_MASK
, FUNCTION_MSP
);
330 if (ARMING_FLAG(OK_TO_ARM
)) {
331 if (ARMING_FLAG(ARMED
)) {
334 if (IS_RC_MODE_ACTIVE(BOXFAILSAFE
)) {
337 if (!ARMING_FLAG(PREVENT_ARMING
)) {
338 ENABLE_ARMING_FLAG(ARMED
);
339 headFreeModeHold
= heading
;
342 if (feature(FEATURE_BLACKBOX
)) {
343 serialPort_t
*sharedBlackboxAndMspPort
= findSharedSerialPort(FUNCTION_BLACKBOX
, FUNCTION_MSP
);
344 if (sharedBlackboxAndMspPort
) {
345 mspReleasePortIfAllocated(sharedBlackboxAndMspPort
);
350 disarmAt
= millis() + masterConfig
.auto_disarm_delay
* 1000; // start disarm timeout, will be extended when throttle is nonzero
352 //beep to indicate arming
354 if (feature(FEATURE_GPS
) && STATE(GPS_FIX
) && GPS_numSat
>= 5)
355 beeper(BEEPER_ARMING_GPS_FIX
);
357 beeper(BEEPER_ARMING
);
359 beeper(BEEPER_ARMING
);
366 if (!ARMING_FLAG(ARMED
)) {
367 beeperConfirmationBeeps(1);
371 // Automatic ACC Offset Calibration
372 bool AccInflightCalibrationArmed
= false;
373 bool AccInflightCalibrationMeasurementDone
= false;
374 bool AccInflightCalibrationSavetoEEProm
= false;
375 bool AccInflightCalibrationActive
= false;
376 uint16_t InflightcalibratingA
= 0;
378 void handleInflightCalibrationStickPosition(void)
380 if (AccInflightCalibrationMeasurementDone
) {
381 // trigger saving into eeprom after landing
382 AccInflightCalibrationMeasurementDone
= false;
383 AccInflightCalibrationSavetoEEProm
= true;
385 AccInflightCalibrationArmed
= !AccInflightCalibrationArmed
;
386 if (AccInflightCalibrationArmed
) {
387 beeper(BEEPER_ACC_CALIBRATION
);
389 beeper(BEEPER_ACC_CALIBRATION_FAIL
);
394 void updateInflightCalibrationState(void)
396 if (AccInflightCalibrationArmed
&& ARMING_FLAG(ARMED
) && rcData
[THROTTLE
] > masterConfig
.rxConfig
.mincheck
&& !IS_RC_MODE_ACTIVE(BOXARM
)) { // Copter is airborne and you are turning it off via boxarm : start measurement
397 InflightcalibratingA
= 50;
398 AccInflightCalibrationArmed
= false;
400 if (IS_RC_MODE_ACTIVE(BOXCALIB
)) { // Use the Calib Option to activate : Calib = TRUE Meausrement started, Land and Calib = 0 measurement stored
401 if (!AccInflightCalibrationActive
&& !AccInflightCalibrationMeasurementDone
)
402 InflightcalibratingA
= 50;
403 AccInflightCalibrationActive
= true;
404 } else if (AccInflightCalibrationMeasurementDone
&& !ARMING_FLAG(ARMED
)) {
405 AccInflightCalibrationMeasurementDone
= false;
406 AccInflightCalibrationSavetoEEProm
= true;
410 void updateMagHold(void)
412 if (ABS(rcCommand
[YAW
]) < 15 && FLIGHT_MODE(MAG_MODE
)) {
413 int16_t dif
= heading
- magHold
;
418 dif
*= -masterConfig
.yaw_control_direction
;
419 if (STATE(SMALL_ANGLE
))
420 rcCommand
[YAW
] -= dif
* currentProfile
->pidProfile
.P8
[PIDMAG
] / 30; // 18 deg
435 #if defined(BARO) || defined(SONAR)
436 CALCULATE_ALTITUDE_TASK
,
441 #define PERIODIC_TASK_COUNT (UPDATE_DISPLAY_TASK + 1)
444 void executePeriodicTasks(void)
446 static int periodicTaskIndex
= 0;
448 switch (periodicTaskIndex
++) {
450 case UPDATE_COMPASS_TASK
:
451 if (sensors(SENSOR_MAG
)) {
452 updateCompass(&masterConfig
.magZero
);
458 case UPDATE_BARO_TASK
:
459 if (sensors(SENSOR_BARO
)) {
460 baroUpdate(currentTime
);
465 #if defined(BARO) || defined(SONAR)
466 case CALCULATE_ALTITUDE_TASK
:
469 || (sensors(SENSOR_BARO
) && isBaroReady())
472 || sensors(SENSOR_SONAR
)
475 calculateEstimatedAltitude(currentTime
);
480 case UPDATE_SONAR_TASK
:
481 if (sensors(SENSOR_SONAR
)) {
487 case UPDATE_DISPLAY_TASK
:
488 if (feature(FEATURE_DISPLAY
)) {
495 if (periodicTaskIndex
>= PERIODIC_TASK_COUNT
) {
496 periodicTaskIndex
= 0;
502 static bool armedBeeperOn
= false;
504 calculateRxChannelsAndUpdateFailsafe(currentTime
);
506 // in 3D mode, we need to be able to disarm by switch at any time
507 if (feature(FEATURE_3D
)) {
508 if (!IS_RC_MODE_ACTIVE(BOXARM
))
512 updateRSSI(currentTime
);
514 if (feature(FEATURE_FAILSAFE
)) {
516 if (currentTime
> FAILSAFE_POWER_ON_DELAY_US
&& !failsafeIsMonitoring()) {
517 failsafeStartMonitoring();
520 failsafeUpdateState();
523 throttleStatus_e throttleStatus
= calculateThrottleStatus(&masterConfig
.rxConfig
, masterConfig
.flight3DConfig
.deadband3d_throttle
);
525 if (throttleStatus
== THROTTLE_LOW
) {
526 pidResetErrorAngle();
530 // When armed and motors aren't spinning, do beeps and then disarm
531 // board after delay so users without buzzer won't lose fingers.
532 // mixTable constrains motor commands, so checking throttleStatus is enough
533 if (ARMING_FLAG(ARMED
)
534 && feature(FEATURE_MOTOR_STOP
)
535 && !STATE(FIXED_WING
)
537 if (isUsingSticksForArming()) {
538 if (throttleStatus
== THROTTLE_LOW
) {
539 if (masterConfig
.auto_disarm_delay
!= 0
540 && (int32_t)(disarmAt
- millis()) < 0
542 // auto-disarm configured and delay is over
544 armedBeeperOn
= false;
546 // still armed; do warning beeps while armed
547 beeper(BEEPER_ARMED
);
548 armedBeeperOn
= true;
551 // throttle is not low
552 if (masterConfig
.auto_disarm_delay
!= 0) {
553 // extend disarm time
554 disarmAt
= millis() + masterConfig
.auto_disarm_delay
* 1000;
559 armedBeeperOn
= false;
563 // arming is via AUX switch; beep while throttle low
564 if (throttleStatus
== THROTTLE_LOW
) {
565 beeper(BEEPER_ARMED
);
566 armedBeeperOn
= true;
567 } else if (armedBeeperOn
) {
569 armedBeeperOn
= false;
574 processRcStickPositions(&masterConfig
.rxConfig
, throttleStatus
, masterConfig
.retarded_arm
, masterConfig
.disarm_kill_switch
);
576 if (feature(FEATURE_INFLIGHT_ACC_CAL
)) {
577 updateInflightCalibrationState();
580 updateActivatedModes(currentProfile
->modeActivationConditions
);
583 updateAdjustmentStates(currentProfile
->adjustmentRanges
);
584 processRcAdjustments(currentControlRateProfile
, &masterConfig
.rxConfig
);
587 bool canUseHorizonMode
= true;
589 if ((IS_RC_MODE_ACTIVE(BOXANGLE
) || (feature(FEATURE_FAILSAFE
) && failsafeIsActive())) && (sensors(SENSOR_ACC
))) {
590 // bumpless transfer to Level mode
591 canUseHorizonMode
= false;
593 if (!FLIGHT_MODE(ANGLE_MODE
)) {
594 pidResetErrorAngle();
595 ENABLE_FLIGHT_MODE(ANGLE_MODE
);
598 DISABLE_FLIGHT_MODE(ANGLE_MODE
); // failsafe support
601 if (IS_RC_MODE_ACTIVE(BOXHORIZON
) && canUseHorizonMode
) {
603 DISABLE_FLIGHT_MODE(ANGLE_MODE
);
605 if (!FLIGHT_MODE(HORIZON_MODE
)) {
606 pidResetErrorAngle();
607 ENABLE_FLIGHT_MODE(HORIZON_MODE
);
610 DISABLE_FLIGHT_MODE(HORIZON_MODE
);
613 if (FLIGHT_MODE(ANGLE_MODE
) || FLIGHT_MODE(HORIZON_MODE
)) {
620 if (sensors(SENSOR_ACC
) || sensors(SENSOR_MAG
)) {
621 if (IS_RC_MODE_ACTIVE(BOXMAG
)) {
622 if (!FLIGHT_MODE(MAG_MODE
)) {
623 ENABLE_FLIGHT_MODE(MAG_MODE
);
627 DISABLE_FLIGHT_MODE(MAG_MODE
);
629 if (IS_RC_MODE_ACTIVE(BOXHEADFREE
)) {
630 if (!FLIGHT_MODE(HEADFREE_MODE
)) {
631 ENABLE_FLIGHT_MODE(HEADFREE_MODE
);
634 DISABLE_FLIGHT_MODE(HEADFREE_MODE
);
636 if (IS_RC_MODE_ACTIVE(BOXHEADADJ
)) {
637 headFreeModeHold
= heading
; // acquire new heading
643 if (sensors(SENSOR_GPS
)) {
644 updateGpsWaypointsAndMode();
648 if (IS_RC_MODE_ACTIVE(BOXPASSTHRU
)) {
649 ENABLE_FLIGHT_MODE(PASSTHRU_MODE
);
651 DISABLE_FLIGHT_MODE(PASSTHRU_MODE
);
654 if (masterConfig
.mixerMode
== MIXER_FLYING_WING
|| masterConfig
.mixerMode
== MIXER_AIRPLANE
) {
655 DISABLE_FLIGHT_MODE(HEADFREE_MODE
);
659 if (feature(FEATURE_TELEMETRY
)) {
660 if ((!masterConfig
.telemetryConfig
.telemetry_switch
&& ARMING_FLAG(ARMED
)) ||
661 (masterConfig
.telemetryConfig
.telemetry_switch
&& IS_RC_MODE_ACTIVE(BOXTELEMETRY
))) {
663 releaseSharedTelemetryPorts();
665 // the telemetry state must be checked immediately so that shared serial ports are released.
666 telemetryCheckState();
667 mspAllocateSerialPorts(&masterConfig
.serialConfig
);
675 static int16_t lastCommand
[4] = { 0, 0, 0, 0 };
676 static int16_t deltaRC
[4] = { 0, 0, 0, 0 };
677 static int16_t factor
, rcInterpolationFactor
;
678 static filterStatePt1_t filteredCycleTimeState
;
679 uint16_t rxRefreshRate
, filteredCycleTime
;
681 // Set RC refresh rate for sampling and channels to filter
682 initRxRefreshRate(&rxRefreshRate
);
684 filteredCycleTime
= filterApplyPt1(cycleTime
, &filteredCycleTimeState
, 1, dT
);
685 rcInterpolationFactor
= rxRefreshRate
/ filteredCycleTime
+ 1;
688 for (int channel
=0; channel
< 4; channel
++) {
689 deltaRC
[channel
] = rcCommand
[channel
] - (lastCommand
[channel
] - deltaRC
[channel
] * factor
/ rcInterpolationFactor
);
690 lastCommand
[channel
] = rcCommand
[channel
];
694 factor
= rcInterpolationFactor
- 1;
699 // Interpolate steps of rcCommand
701 for (int channel
=0; channel
< 4; channel
++) {
702 rcCommand
[channel
] = lastCommand
[channel
] - deltaRC
[channel
] * factor
/rcInterpolationFactor
;
710 void filterGyro(void) {
712 static filterStatePt1_t gyroADCState
[XYZ_AXIS_COUNT
];
714 for (axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
715 if (masterConfig
.looptime
> 0) {
716 // Static dT calculation based on configured looptime
717 if (!gyroADCState
[axis
].constdT
) {
718 gyroADCState
[axis
].constdT
= (float)masterConfig
.looptime
* 0.000001f
;
721 gyroADC
[axis
] = filterApplyPt1(gyroADC
[axis
], &gyroADCState
[axis
], currentProfile
->pidProfile
.gyro_cut_hz
, gyroADCState
[axis
].constdT
);
725 gyroADC
[axis
] = filterApplyPt1(gyroADC
[axis
], &gyroADCState
[axis
], currentProfile
->pidProfile
.gyro_cut_hz
, dT
);
732 static uint32_t loopTime
;
733 /*#if defined(BARO) || defined(SONAR)
734 static bool haveProcessedAnnexCodeOnce = false;
737 updateRx(currentTime);
739 if (shouldProcessRx(currentTime)) {
744 // the 'annexCode' initialses rcCommand, updateAltHoldState depends on valid rcCommand data.
745 if (haveProcessedAnnexCodeOnce) {
746 if (sensors(SENSOR_BARO)) {
747 updateAltHoldState();
753 // the 'annexCode' initialses rcCommand, updateAltHoldState depends on valid rcCommand data.
754 if (haveProcessedAnnexCodeOnce) {
755 if (sensors(SENSOR_SONAR)) {
756 updateSonarAltHoldState();
762 // not processing rx this iteration
763 executePeriodicTasks();
765 // if GPS feature is enabled, gpsThread() will be called at some intervals to check for stuck
766 // hardware, wrong baud rates, init GPS if needed, etc. Don't use SENSOR_GPS here as gpsThread() can and will
767 // change this based on available hardware
769 if (feature(FEATURE_GPS)) {
775 currentTime
= micros();
776 if (masterConfig
.looptime
== 0 || (int32_t)(currentTime
- loopTime
) >= 0) {
777 loopTime
= currentTime
+ masterConfig
.looptime
;
779 //imuUpdate(¤tProfile->accelerometerTrims);
781 // Measure loop rate just after reading the sensors
782 currentTime
= micros();
783 cycleTime
= (int32_t)(currentTime
- previousTime
);
784 previousTime
= currentTime
;
786 dT
= (float)cycleTime
* 0.000001f
;
797 /*if (currentProfile->pidProfile.gyro_cut_hz) {
803 if (masterConfig.rxConfig.rcSmoothing) {
807 #if defined(BARO) || defined(SONAR)
808 haveProcessedAnnexCodeOnce = true;
812 if (sensors(SENSOR_MAG)) {
821 #if defined(BARO) || defined(SONAR)
822 if (sensors(SENSOR_BARO) || sensors(SENSOR_SONAR)) {
823 if (FLIGHT_MODE(BARO_MODE) || FLIGHT_MODE(SONAR_MODE)) {
824 applyAltHold(&masterConfig.airplaneConfig);
829 // If we're armed, at minimum throttle, and we do arming via the
830 // sticks, do not process yaw input from the rx. We do this so the
831 // motors do not spin up while we are trying to arm or disarm.
832 // Allow yaw control for tricopters if the user wants the servo to move even when unarmed.
833 if (isUsingSticksForArming() && rcData[THROTTLE] <= masterConfig.rxConfig.mincheck
834 #ifndef USE_QUAD_MIXER_ONLY
835 && !((masterConfig.mixerMode == MIXER_TRI || masterConfig.mixerMode == MIXER_CUSTOM_TRI) && masterConfig.mixerConfig.tri_unarmed_servo)
836 && masterConfig.mixerMode != MIXER_AIRPLANE
837 && masterConfig.mixerMode != MIXER_FLYING_WING
844 if (currentProfile->throttle_correction_value && (FLIGHT_MODE(ANGLE_MODE) || FLIGHT_MODE(HORIZON_MODE))) {
845 rcCommand[THROTTLE] += calculateThrottleAngleCorrection(currentProfile->throttle_correction_value);
849 if (sensors(SENSOR_GPS)) {
850 if ((FLIGHT_MODE(GPS_HOME_MODE) || FLIGHT_MODE(GPS_HOLD_MODE)) && STATE(GPS_FIX_HOME)) {
851 updateGpsStateForHomeAndHoldMode();
856 // PID - note this is function pointer set by setPIDController()
858 ¤tProfile->pidProfile,
859 currentControlRateProfile,
860 masterConfig.max_angle_inclination,
861 ¤tProfile->accelerometerTrims,
862 &masterConfig.rxConfig
872 if (motorControlEnable) {
877 if (!cliMode && feature(FEATURE_BLACKBOX)) {
884 if (!cliMode && feature(FEATURE_TELEMETRY)) {
885 telemetryProcess(&masterConfig.rxConfig, masterConfig.flight3DConfig.deadband3d_throttle);
890 if (feature(FEATURE_LED_STRIP)) {