Merge pull request #11195 from mathiasvr/pr-elrs-clean
[betaflight.git] / src / main / sensors / gyro.c
blob5ce7e3571571ad4c105b1f1698b01e85fadef6ea
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <string.h>
24 #include <math.h>
25 #include <stdlib.h>
27 #include "platform.h"
29 #include "build/debug.h"
31 #include "common/axis.h"
32 #include "common/maths.h"
33 #include "common/filter.h"
35 #include "config/feature.h"
36 #include "config/simplified_tuning.h"
38 #include "pg/pg.h"
39 #include "pg/pg_ids.h"
40 #include "pg/gyrodev.h"
42 #include "drivers/bus_spi.h"
43 #include "drivers/io.h"
45 #include "config/config.h"
46 #include "fc/runtime_config.h"
48 #ifdef USE_DYN_NOTCH_FILTER
49 #include "flight/dyn_notch_filter.h"
50 #endif
51 #include "flight/rpm_filter.h"
53 #include "io/beeper.h"
54 #include "io/statusindicator.h"
56 #include "scheduler/scheduler.h"
58 #include "sensors/boardalignment.h"
59 #include "sensors/gyro.h"
60 #include "sensors/gyro_init.h"
62 #if ((TARGET_FLASH_SIZE > 128) && (defined(USE_GYRO_SPI_ICM20601) || defined(USE_GYRO_SPI_ICM20689) || defined(USE_GYRO_SPI_MPU6500)))
63 #define USE_GYRO_SLEW_LIMITER
64 #endif
66 FAST_DATA_ZERO_INIT gyro_t gyro;
68 static FAST_DATA_ZERO_INIT bool overflowDetected;
69 #ifdef USE_GYRO_OVERFLOW_CHECK
70 static FAST_DATA_ZERO_INIT timeUs_t overflowTimeUs;
71 #endif
73 #ifdef USE_YAW_SPIN_RECOVERY
74 static FAST_DATA_ZERO_INIT bool yawSpinRecoveryEnabled;
75 static FAST_DATA_ZERO_INIT int yawSpinRecoveryThreshold;
76 static FAST_DATA_ZERO_INIT bool yawSpinDetected;
77 static FAST_DATA_ZERO_INIT timeUs_t yawSpinTimeUs;
78 #endif
80 static FAST_DATA_ZERO_INIT float gyroFilteredDownsampled[XYZ_AXIS_COUNT];
82 static FAST_DATA_ZERO_INIT int16_t gyroSensorTemperature;
84 FAST_DATA uint8_t activePidLoopDenom = 1;
86 static bool firstArmingCalibrationWasStarted = false;
88 #ifdef UNIT_TEST
89 STATIC_UNIT_TESTED gyroSensor_t * const gyroSensorPtr = &gyro.gyroSensor1;
90 STATIC_UNIT_TESTED gyroDev_t * const gyroDevPtr = &gyro.gyroSensor1.gyroDev;
91 #endif
94 #define DEBUG_GYRO_CALIBRATION 3
96 #define GYRO_OVERFLOW_TRIGGER_THRESHOLD 31980 // 97.5% full scale (1950dps for 2000dps gyro)
97 #define GYRO_OVERFLOW_RESET_THRESHOLD 30340 // 92.5% full scale (1850dps for 2000dps gyro)
99 PG_REGISTER_WITH_RESET_FN(gyroConfig_t, gyroConfig, PG_GYRO_CONFIG, 9);
101 #ifndef GYRO_CONFIG_USE_GYRO_DEFAULT
102 #define GYRO_CONFIG_USE_GYRO_DEFAULT GYRO_CONFIG_USE_GYRO_1
103 #endif
105 void pgResetFn_gyroConfig(gyroConfig_t *gyroConfig)
107 gyroConfig->gyroCalibrationDuration = 125; // 1.25 seconds
108 gyroConfig->gyroMovementCalibrationThreshold = 48;
109 gyroConfig->gyro_hardware_lpf = GYRO_HARDWARE_LPF_NORMAL;
110 gyroConfig->gyro_lpf1_type = FILTER_PT1;
111 gyroConfig->gyro_lpf1_static_hz = GYRO_LPF1_DYN_MIN_HZ_DEFAULT;
112 // NOTE: dynamic lpf is enabled by default so this setting is actually
113 // overridden and the static lowpass 1 is disabled. We can't set this
114 // value to 0 otherwise Configurator versions 10.4 and earlier will also
115 // reset the lowpass filter type to PT1 overriding the desired BIQUAD setting.
116 gyroConfig->gyro_lpf2_type = FILTER_PT1;
117 gyroConfig->gyro_lpf2_static_hz = GYRO_LPF2_HZ_DEFAULT;
118 gyroConfig->gyro_high_fsr = false;
119 gyroConfig->gyro_to_use = GYRO_CONFIG_USE_GYRO_DEFAULT;
120 gyroConfig->gyro_soft_notch_hz_1 = 0;
121 gyroConfig->gyro_soft_notch_cutoff_1 = 0;
122 gyroConfig->gyro_soft_notch_hz_2 = 0;
123 gyroConfig->gyro_soft_notch_cutoff_2 = 0;
124 gyroConfig->checkOverflow = GYRO_OVERFLOW_CHECK_ALL_AXES;
125 gyroConfig->gyro_offset_yaw = 0;
126 gyroConfig->yaw_spin_recovery = YAW_SPIN_RECOVERY_AUTO;
127 gyroConfig->yaw_spin_threshold = 1950;
128 gyroConfig->gyro_lpf1_dyn_min_hz = GYRO_LPF1_DYN_MIN_HZ_DEFAULT;
129 gyroConfig->gyro_lpf1_dyn_max_hz = GYRO_LPF1_DYN_MAX_HZ_DEFAULT;
130 gyroConfig->gyro_filter_debug_axis = FD_ROLL;
131 gyroConfig->gyro_lpf1_dyn_expo = 5;
132 gyroConfig->simplified_gyro_filter = true;
133 gyroConfig->simplified_gyro_filter_multiplier = SIMPLIFIED_TUNING_DEFAULT;
136 FAST_CODE bool isGyroSensorCalibrationComplete(const gyroSensor_t *gyroSensor)
138 return gyroSensor->calibration.cyclesRemaining == 0;
141 FAST_CODE bool gyroIsCalibrationComplete(void)
143 switch (gyro.gyroToUse) {
144 default:
145 case GYRO_CONFIG_USE_GYRO_1: {
146 return isGyroSensorCalibrationComplete(&gyro.gyroSensor1);
148 #ifdef USE_MULTI_GYRO
149 case GYRO_CONFIG_USE_GYRO_2: {
150 return isGyroSensorCalibrationComplete(&gyro.gyroSensor2);
152 case GYRO_CONFIG_USE_GYRO_BOTH: {
153 return isGyroSensorCalibrationComplete(&gyro.gyroSensor1) && isGyroSensorCalibrationComplete(&gyro.gyroSensor2);
155 #endif
159 static bool isOnFinalGyroCalibrationCycle(const gyroCalibration_t *gyroCalibration)
161 return gyroCalibration->cyclesRemaining == 1;
164 static int32_t gyroCalculateCalibratingCycles(void)
166 return (gyroConfig()->gyroCalibrationDuration * 10000) / gyro.sampleLooptime;
169 static bool isOnFirstGyroCalibrationCycle(const gyroCalibration_t *gyroCalibration)
171 return gyroCalibration->cyclesRemaining == gyroCalculateCalibratingCycles();
174 static void gyroSetCalibrationCycles(gyroSensor_t *gyroSensor)
176 #if defined(USE_FAKE_GYRO) && !defined(UNIT_TEST)
177 if (gyroSensor->gyroDev.gyroHardware == GYRO_FAKE) {
178 gyroSensor->calibration.cyclesRemaining = 0;
179 return;
181 #endif
182 gyroSensor->calibration.cyclesRemaining = gyroCalculateCalibratingCycles();
185 void gyroStartCalibration(bool isFirstArmingCalibration)
187 if (isFirstArmingCalibration && firstArmingCalibrationWasStarted) {
188 return;
191 gyroSetCalibrationCycles(&gyro.gyroSensor1);
192 #ifdef USE_MULTI_GYRO
193 gyroSetCalibrationCycles(&gyro.gyroSensor2);
194 #endif
196 if (isFirstArmingCalibration) {
197 firstArmingCalibrationWasStarted = true;
201 bool isFirstArmingGyroCalibrationRunning(void)
203 return firstArmingCalibrationWasStarted && !gyroIsCalibrationComplete();
206 STATIC_UNIT_TESTED void performGyroCalibration(gyroSensor_t *gyroSensor, uint8_t gyroMovementCalibrationThreshold)
208 for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
209 // Reset g[axis] at start of calibration
210 if (isOnFirstGyroCalibrationCycle(&gyroSensor->calibration)) {
211 gyroSensor->calibration.sum[axis] = 0.0f;
212 devClear(&gyroSensor->calibration.var[axis]);
213 // gyroZero is set to zero until calibration complete
214 gyroSensor->gyroDev.gyroZero[axis] = 0.0f;
217 // Sum up CALIBRATING_GYRO_TIME_US readings
218 gyroSensor->calibration.sum[axis] += gyroSensor->gyroDev.gyroADCRaw[axis];
219 devPush(&gyroSensor->calibration.var[axis], gyroSensor->gyroDev.gyroADCRaw[axis]);
221 if (isOnFinalGyroCalibrationCycle(&gyroSensor->calibration)) {
222 const float stddev = devStandardDeviation(&gyroSensor->calibration.var[axis]);
223 // DEBUG_GYRO_CALIBRATION records the standard deviation of roll
224 // into the spare field - debug[3], in DEBUG_GYRO_RAW
225 if (axis == X) {
226 DEBUG_SET(DEBUG_GYRO_RAW, DEBUG_GYRO_CALIBRATION, lrintf(stddev));
229 // check deviation and startover in case the model was moved
230 if (gyroMovementCalibrationThreshold && stddev > gyroMovementCalibrationThreshold) {
231 gyroSetCalibrationCycles(gyroSensor);
232 return;
235 // please take care with exotic boardalignment !!
236 gyroSensor->gyroDev.gyroZero[axis] = gyroSensor->calibration.sum[axis] / gyroCalculateCalibratingCycles();
237 if (axis == Z) {
238 gyroSensor->gyroDev.gyroZero[axis] -= ((float)gyroConfig()->gyro_offset_yaw / 100);
243 if (isOnFinalGyroCalibrationCycle(&gyroSensor->calibration)) {
244 schedulerResetTaskStatistics(TASK_SELF); // so calibration cycles do not pollute tasks statistics
245 if (!firstArmingCalibrationWasStarted || (getArmingDisableFlags() & ~ARMING_DISABLED_CALIBRATING) == 0) {
246 beeper(BEEPER_GYRO_CALIBRATED);
250 --gyroSensor->calibration.cyclesRemaining;
253 #if defined(USE_GYRO_SLEW_LIMITER)
254 FAST_CODE int32_t gyroSlewLimiter(gyroSensor_t *gyroSensor, int axis)
256 int32_t ret = (int32_t)gyroSensor->gyroDev.gyroADCRaw[axis];
257 if (gyroConfig()->checkOverflow || gyro.gyroHasOverflowProtection) {
258 // don't use the slew limiter if overflow checking is on or gyro is not subject to overflow bug
259 return ret;
261 if (abs(ret - gyroSensor->gyroDev.gyroADCRawPrevious[axis]) > (1<<14)) {
262 // there has been a large change in value, so assume overflow has occurred and return the previous value
263 ret = gyroSensor->gyroDev.gyroADCRawPrevious[axis];
264 } else {
265 gyroSensor->gyroDev.gyroADCRawPrevious[axis] = ret;
267 return ret;
269 #endif
271 #ifdef USE_GYRO_OVERFLOW_CHECK
272 static FAST_CODE_NOINLINE void handleOverflow(timeUs_t currentTimeUs)
274 // This will need to be revised if we ever allow different sensor types to be
275 // used simultaneously. In that case the scale might be different between sensors.
276 // It's complicated by the fact that we're using filtered gyro data here which is
277 // after both sensors are scaled and averaged.
278 const float gyroOverflowResetRate = GYRO_OVERFLOW_RESET_THRESHOLD * gyro.scale;
280 if ((fabsf(gyro.gyroADCf[X]) < gyroOverflowResetRate)
281 && (fabsf(gyro.gyroADCf[Y]) < gyroOverflowResetRate)
282 && (fabsf(gyro.gyroADCf[Z]) < gyroOverflowResetRate)) {
283 // if we have 50ms of consecutive OK gyro vales, then assume yaw readings are OK again and reset overflowDetected
284 // reset requires good OK values on all axes
285 if (cmpTimeUs(currentTimeUs, overflowTimeUs) > 50000) {
286 overflowDetected = false;
288 } else {
289 // not a consecutive OK value, so reset the overflow time
290 overflowTimeUs = currentTimeUs;
294 static FAST_CODE_NOINLINE void checkForOverflow(timeUs_t currentTimeUs)
296 // check for overflow to handle Yaw Spin To The Moon (YSTTM)
297 // ICM gyros are specified to +/- 2000 deg/sec, in a crash they can go out of spec.
298 // This can cause an overflow and sign reversal in the output.
299 // Overflow and sign reversal seems to result in a gyro value of +1996 or -1996.
300 if (overflowDetected) {
301 handleOverflow(currentTimeUs);
302 } else {
303 #ifndef SIMULATOR_BUILD
304 // check for overflow in the axes set in overflowAxisMask
305 gyroOverflow_e overflowCheck = GYRO_OVERFLOW_NONE;
307 // This will need to be revised if we ever allow different sensor types to be
308 // used simultaneously. In that case the scale might be different between sensors.
309 // It's complicated by the fact that we're using filtered gyro data here which is
310 // after both sensors are scaled and averaged.
311 const float gyroOverflowTriggerRate = GYRO_OVERFLOW_TRIGGER_THRESHOLD * gyro.scale;
313 if (fabsf(gyro.gyroADCf[X]) > gyroOverflowTriggerRate) {
314 overflowCheck |= GYRO_OVERFLOW_X;
316 if (fabsf(gyro.gyroADCf[Y]) > gyroOverflowTriggerRate) {
317 overflowCheck |= GYRO_OVERFLOW_Y;
319 if (fabsf(gyro.gyroADCf[Z]) > gyroOverflowTriggerRate) {
320 overflowCheck |= GYRO_OVERFLOW_Z;
322 if (overflowCheck & gyro.overflowAxisMask) {
323 overflowDetected = true;
324 overflowTimeUs = currentTimeUs;
325 #ifdef USE_YAW_SPIN_RECOVERY
326 yawSpinDetected = false;
327 #endif // USE_YAW_SPIN_RECOVERY
329 #endif // SIMULATOR_BUILD
332 #endif // USE_GYRO_OVERFLOW_CHECK
334 #ifdef USE_YAW_SPIN_RECOVERY
335 static FAST_CODE_NOINLINE void handleYawSpin(timeUs_t currentTimeUs)
337 const float yawSpinResetRate = yawSpinRecoveryThreshold - 100.0f;
338 if (fabsf(gyro.gyroADCf[Z]) < yawSpinResetRate) {
339 // testing whether 20ms of consecutive OK gyro yaw values is enough
340 if (cmpTimeUs(currentTimeUs, yawSpinTimeUs) > 20000) {
341 yawSpinDetected = false;
343 } else {
344 // reset the yaw spin time
345 yawSpinTimeUs = currentTimeUs;
349 static FAST_CODE_NOINLINE void checkForYawSpin(timeUs_t currentTimeUs)
351 // if not in overflow mode, handle yaw spins above threshold
352 #ifdef USE_GYRO_OVERFLOW_CHECK
353 if (overflowDetected) {
354 yawSpinDetected = false;
355 return;
357 #endif // USE_GYRO_OVERFLOW_CHECK
359 if (yawSpinDetected) {
360 handleYawSpin(currentTimeUs);
361 } else {
362 #ifndef SIMULATOR_BUILD
363 // check for spin on yaw axis only
364 if (abs((int)gyro.gyroADCf[Z]) > yawSpinRecoveryThreshold) {
365 yawSpinDetected = true;
366 yawSpinTimeUs = currentTimeUs;
368 #endif // SIMULATOR_BUILD
371 #endif // USE_YAW_SPIN_RECOVERY
373 static FAST_CODE void gyroUpdateSensor(gyroSensor_t *gyroSensor)
375 if (!gyroSensor->gyroDev.readFn(&gyroSensor->gyroDev)) {
376 return;
378 gyroSensor->gyroDev.dataReady = false;
380 if (isGyroSensorCalibrationComplete(gyroSensor)) {
381 // move 16-bit gyro data into 32-bit variables to avoid overflows in calculations
383 #if defined(USE_GYRO_SLEW_LIMITER)
384 gyroSensor->gyroDev.gyroADC[X] = gyroSlewLimiter(gyroSensor, X) - gyroSensor->gyroDev.gyroZero[X];
385 gyroSensor->gyroDev.gyroADC[Y] = gyroSlewLimiter(gyroSensor, Y) - gyroSensor->gyroDev.gyroZero[Y];
386 gyroSensor->gyroDev.gyroADC[Z] = gyroSlewLimiter(gyroSensor, Z) - gyroSensor->gyroDev.gyroZero[Z];
387 #else
388 gyroSensor->gyroDev.gyroADC[X] = gyroSensor->gyroDev.gyroADCRaw[X] - gyroSensor->gyroDev.gyroZero[X];
389 gyroSensor->gyroDev.gyroADC[Y] = gyroSensor->gyroDev.gyroADCRaw[Y] - gyroSensor->gyroDev.gyroZero[Y];
390 gyroSensor->gyroDev.gyroADC[Z] = gyroSensor->gyroDev.gyroADCRaw[Z] - gyroSensor->gyroDev.gyroZero[Z];
391 #endif
393 if (gyroSensor->gyroDev.gyroAlign == ALIGN_CUSTOM) {
394 alignSensorViaMatrix(gyroSensor->gyroDev.gyroADC, &gyroSensor->gyroDev.rotationMatrix);
395 } else {
396 alignSensorViaRotation(gyroSensor->gyroDev.gyroADC, gyroSensor->gyroDev.gyroAlign);
398 } else {
399 performGyroCalibration(gyroSensor, gyroConfig()->gyroMovementCalibrationThreshold);
403 FAST_CODE void gyroUpdate(void)
405 switch (gyro.gyroToUse) {
406 case GYRO_CONFIG_USE_GYRO_1:
407 gyroUpdateSensor(&gyro.gyroSensor1);
408 if (isGyroSensorCalibrationComplete(&gyro.gyroSensor1)) {
409 gyro.gyroADC[X] = gyro.gyroSensor1.gyroDev.gyroADC[X] * gyro.gyroSensor1.gyroDev.scale;
410 gyro.gyroADC[Y] = gyro.gyroSensor1.gyroDev.gyroADC[Y] * gyro.gyroSensor1.gyroDev.scale;
411 gyro.gyroADC[Z] = gyro.gyroSensor1.gyroDev.gyroADC[Z] * gyro.gyroSensor1.gyroDev.scale;
413 break;
414 #ifdef USE_MULTI_GYRO
415 case GYRO_CONFIG_USE_GYRO_2:
416 gyroUpdateSensor(&gyro.gyroSensor2);
417 if (isGyroSensorCalibrationComplete(&gyro.gyroSensor2)) {
418 gyro.gyroADC[X] = gyro.gyroSensor2.gyroDev.gyroADC[X] * gyro.gyroSensor2.gyroDev.scale;
419 gyro.gyroADC[Y] = gyro.gyroSensor2.gyroDev.gyroADC[Y] * gyro.gyroSensor2.gyroDev.scale;
420 gyro.gyroADC[Z] = gyro.gyroSensor2.gyroDev.gyroADC[Z] * gyro.gyroSensor2.gyroDev.scale;
422 break;
423 case GYRO_CONFIG_USE_GYRO_BOTH:
424 gyroUpdateSensor(&gyro.gyroSensor1);
425 gyroUpdateSensor(&gyro.gyroSensor2);
426 if (isGyroSensorCalibrationComplete(&gyro.gyroSensor1) && isGyroSensorCalibrationComplete(&gyro.gyroSensor2)) {
427 gyro.gyroADC[X] = ((gyro.gyroSensor1.gyroDev.gyroADC[X] * gyro.gyroSensor1.gyroDev.scale) + (gyro.gyroSensor2.gyroDev.gyroADC[X] * gyro.gyroSensor2.gyroDev.scale)) / 2.0f;
428 gyro.gyroADC[Y] = ((gyro.gyroSensor1.gyroDev.gyroADC[Y] * gyro.gyroSensor1.gyroDev.scale) + (gyro.gyroSensor2.gyroDev.gyroADC[Y] * gyro.gyroSensor2.gyroDev.scale)) / 2.0f;
429 gyro.gyroADC[Z] = ((gyro.gyroSensor1.gyroDev.gyroADC[Z] * gyro.gyroSensor1.gyroDev.scale) + (gyro.gyroSensor2.gyroDev.gyroADC[Z] * gyro.gyroSensor2.gyroDev.scale)) / 2.0f;
431 break;
432 #endif
435 if (gyro.downsampleFilterEnabled) {
436 // using gyro lowpass 2 filter for downsampling
437 gyro.sampleSum[X] = gyro.lowpass2FilterApplyFn((filter_t *)&gyro.lowpass2Filter[X], gyro.gyroADC[X]);
438 gyro.sampleSum[Y] = gyro.lowpass2FilterApplyFn((filter_t *)&gyro.lowpass2Filter[Y], gyro.gyroADC[Y]);
439 gyro.sampleSum[Z] = gyro.lowpass2FilterApplyFn((filter_t *)&gyro.lowpass2Filter[Z], gyro.gyroADC[Z]);
440 } else {
441 // using simple averaging for downsampling
442 gyro.sampleSum[X] += gyro.gyroADC[X];
443 gyro.sampleSum[Y] += gyro.gyroADC[Y];
444 gyro.sampleSum[Z] += gyro.gyroADC[Z];
445 gyro.sampleCount++;
449 #define GYRO_FILTER_FUNCTION_NAME filterGyro
450 #define GYRO_FILTER_DEBUG_SET(mode, index, value) do { UNUSED(mode); UNUSED(index); UNUSED(value); } while (0)
451 #define GYRO_FILTER_AXIS_DEBUG_SET(axis, mode, index, value) do { UNUSED(axis); UNUSED(mode); UNUSED(index); UNUSED(value); } while (0)
452 #include "gyro_filter_impl.c"
453 #undef GYRO_FILTER_FUNCTION_NAME
454 #undef GYRO_FILTER_DEBUG_SET
455 #undef GYRO_FILTER_AXIS_DEBUG_SET
457 #define GYRO_FILTER_FUNCTION_NAME filterGyroDebug
458 #define GYRO_FILTER_DEBUG_SET DEBUG_SET
459 #define GYRO_FILTER_AXIS_DEBUG_SET(axis, mode, index, value) if (axis == (int)gyro.gyroDebugAxis) DEBUG_SET(mode, index, value)
460 #include "gyro_filter_impl.c"
461 #undef GYRO_FILTER_FUNCTION_NAME
462 #undef GYRO_FILTER_DEBUG_SET
463 #undef GYRO_FILTER_AXIS_DEBUG_SET
465 FAST_CODE void gyroFiltering(timeUs_t currentTimeUs)
467 if (gyro.gyroDebugMode == DEBUG_NONE) {
468 filterGyro();
469 } else {
470 filterGyroDebug();
473 #ifdef USE_DYN_NOTCH_FILTER
474 if (isDynNotchActive()) {
475 dynNotchUpdate();
477 #endif
479 if (gyro.useDualGyroDebugging) {
480 switch (gyro.gyroToUse) {
481 case GYRO_CONFIG_USE_GYRO_1:
482 DEBUG_SET(DEBUG_DUAL_GYRO_RAW, 0, gyro.gyroSensor1.gyroDev.gyroADCRaw[X]);
483 DEBUG_SET(DEBUG_DUAL_GYRO_RAW, 1, gyro.gyroSensor1.gyroDev.gyroADCRaw[Y]);
484 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED, 0, lrintf(gyro.gyroSensor1.gyroDev.gyroADC[X] * gyro.gyroSensor1.gyroDev.scale));
485 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED, 1, lrintf(gyro.gyroSensor1.gyroDev.gyroADC[Y] * gyro.gyroSensor1.gyroDev.scale));
486 break;
488 #ifdef USE_MULTI_GYRO
489 case GYRO_CONFIG_USE_GYRO_2:
490 DEBUG_SET(DEBUG_DUAL_GYRO_RAW, 2, gyro.gyroSensor2.gyroDev.gyroADCRaw[X]);
491 DEBUG_SET(DEBUG_DUAL_GYRO_RAW, 3, gyro.gyroSensor2.gyroDev.gyroADCRaw[Y]);
492 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED, 2, lrintf(gyro.gyroSensor2.gyroDev.gyroADC[X] * gyro.gyroSensor2.gyroDev.scale));
493 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED, 3, lrintf(gyro.gyroSensor2.gyroDev.gyroADC[Y] * gyro.gyroSensor2.gyroDev.scale));
494 break;
496 case GYRO_CONFIG_USE_GYRO_BOTH:
497 DEBUG_SET(DEBUG_DUAL_GYRO_RAW, 0, gyro.gyroSensor1.gyroDev.gyroADCRaw[X]);
498 DEBUG_SET(DEBUG_DUAL_GYRO_RAW, 1, gyro.gyroSensor1.gyroDev.gyroADCRaw[Y]);
499 DEBUG_SET(DEBUG_DUAL_GYRO_RAW, 2, gyro.gyroSensor2.gyroDev.gyroADCRaw[X]);
500 DEBUG_SET(DEBUG_DUAL_GYRO_RAW, 3, gyro.gyroSensor2.gyroDev.gyroADCRaw[Y]);
501 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED, 0, lrintf(gyro.gyroSensor1.gyroDev.gyroADC[X] * gyro.gyroSensor1.gyroDev.scale));
502 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED, 1, lrintf(gyro.gyroSensor1.gyroDev.gyroADC[Y] * gyro.gyroSensor1.gyroDev.scale));
503 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED, 2, lrintf(gyro.gyroSensor2.gyroDev.gyroADC[X] * gyro.gyroSensor2.gyroDev.scale));
504 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED, 3, lrintf(gyro.gyroSensor2.gyroDev.gyroADC[Y] * gyro.gyroSensor2.gyroDev.scale));
505 DEBUG_SET(DEBUG_DUAL_GYRO_DIFF, 0, lrintf((gyro.gyroSensor1.gyroDev.gyroADC[X] * gyro.gyroSensor1.gyroDev.scale) - (gyro.gyroSensor2.gyroDev.gyroADC[X] * gyro.gyroSensor2.gyroDev.scale)));
506 DEBUG_SET(DEBUG_DUAL_GYRO_DIFF, 1, lrintf((gyro.gyroSensor1.gyroDev.gyroADC[Y] * gyro.gyroSensor1.gyroDev.scale) - (gyro.gyroSensor2.gyroDev.gyroADC[Y] * gyro.gyroSensor2.gyroDev.scale)));
507 DEBUG_SET(DEBUG_DUAL_GYRO_DIFF, 2, lrintf((gyro.gyroSensor1.gyroDev.gyroADC[Z] * gyro.gyroSensor1.gyroDev.scale) - (gyro.gyroSensor2.gyroDev.gyroADC[Z] * gyro.gyroSensor2.gyroDev.scale)));
508 break;
509 #endif
513 #ifdef USE_GYRO_OVERFLOW_CHECK
514 if (gyroConfig()->checkOverflow && !gyro.gyroHasOverflowProtection) {
515 checkForOverflow(currentTimeUs);
517 #endif
519 #ifdef USE_YAW_SPIN_RECOVERY
520 if (yawSpinRecoveryEnabled) {
521 checkForYawSpin(currentTimeUs);
523 #endif
525 if (!overflowDetected) {
526 for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
527 gyroFilteredDownsampled[axis] = pt1FilterApply(&gyro.imuGyroFilter[axis], gyro.gyroADCf[axis]);
531 #if !defined(USE_GYRO_OVERFLOW_CHECK) && !defined(USE_YAW_SPIN_RECOVERY)
532 UNUSED(currentTimeUs);
533 #endif
536 float gyroGetFilteredDownsampled(int axis)
538 return gyroFilteredDownsampled[axis];
541 int16_t gyroReadSensorTemperature(gyroSensor_t gyroSensor)
543 if (gyroSensor.gyroDev.temperatureFn) {
544 gyroSensor.gyroDev.temperatureFn(&gyroSensor.gyroDev, &gyroSensor.gyroDev.temperature);
546 return gyroSensor.gyroDev.temperature;
549 void gyroReadTemperature(void)
551 switch (gyro.gyroToUse) {
552 case GYRO_CONFIG_USE_GYRO_1:
553 gyroSensorTemperature = gyroReadSensorTemperature(gyro.gyroSensor1);
554 break;
556 #ifdef USE_MULTI_GYRO
557 case GYRO_CONFIG_USE_GYRO_2:
558 gyroSensorTemperature = gyroReadSensorTemperature(gyro.gyroSensor2);
559 break;
561 case GYRO_CONFIG_USE_GYRO_BOTH:
562 gyroSensorTemperature = MAX(gyroReadSensorTemperature(gyro.gyroSensor1), gyroReadSensorTemperature(gyro.gyroSensor2));
563 break;
564 #endif // USE_MULTI_GYRO
568 int16_t gyroGetTemperature(void)
570 return gyroSensorTemperature;
573 bool gyroOverflowDetected(void)
575 #ifdef USE_GYRO_OVERFLOW_CHECK
576 return overflowDetected;
577 #else
578 return false;
579 #endif // USE_GYRO_OVERFLOW_CHECK
582 #ifdef USE_YAW_SPIN_RECOVERY
583 bool gyroYawSpinDetected(void)
585 return yawSpinDetected;
587 #endif // USE_YAW_SPIN_RECOVERY
589 uint16_t gyroAbsRateDps(int axis)
591 return fabsf(gyro.gyroADCf[axis]);
594 #ifdef USE_DYN_LPF
596 float dynThrottle(float throttle)
598 return throttle * (1 - (throttle * throttle) / 3.0f) * 1.5f;
601 void dynLpfGyroUpdate(float throttle)
603 if (gyro.dynLpfFilter != DYN_LPF_NONE) {
604 float cutoffFreq;
605 if (gyro.dynLpfCurveExpo > 0) {
606 cutoffFreq = dynLpfCutoffFreq(throttle, gyro.dynLpfMin, gyro.dynLpfMax, gyro.dynLpfCurveExpo);
607 } else {
608 cutoffFreq = fmaxf(dynThrottle(throttle) * gyro.dynLpfMax, gyro.dynLpfMin);
610 DEBUG_SET(DEBUG_DYN_LPF, 2, lrintf(cutoffFreq));
611 const float gyroDt = gyro.targetLooptime * 1e-6f;
612 switch (gyro.dynLpfFilter) {
613 case DYN_LPF_PT1:
614 for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
615 pt1FilterUpdateCutoff(&gyro.lowpassFilter[axis].pt1FilterState, pt1FilterGain(cutoffFreq, gyroDt));
617 break;
618 case DYN_LPF_BIQUAD:
619 for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
620 biquadFilterUpdateLPF(&gyro.lowpassFilter[axis].biquadFilterState, cutoffFreq, gyro.targetLooptime);
622 break;
623 case DYN_LPF_PT2:
624 for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
625 pt2FilterUpdateCutoff(&gyro.lowpassFilter[axis].pt2FilterState, pt2FilterGain(cutoffFreq, gyroDt));
627 break;
628 case DYN_LPF_PT3:
629 for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
630 pt3FilterUpdateCutoff(&gyro.lowpassFilter[axis].pt3FilterState, pt3FilterGain(cutoffFreq, gyroDt));
632 break;
636 #endif
638 #ifdef USE_YAW_SPIN_RECOVERY
639 void initYawSpinRecovery(int maxYawRate)
641 bool enabledFlag;
642 int threshold;
644 switch (gyroConfig()->yaw_spin_recovery) {
645 case YAW_SPIN_RECOVERY_ON:
646 enabledFlag = true;
647 threshold = gyroConfig()->yaw_spin_threshold;
648 break;
649 case YAW_SPIN_RECOVERY_AUTO:
650 enabledFlag = true;
651 const int overshootAllowance = MAX(maxYawRate / 4, 200); // Allow a 25% or minimum 200dps overshoot tolerance
652 threshold = constrain(maxYawRate + overshootAllowance, YAW_SPIN_RECOVERY_THRESHOLD_MIN, YAW_SPIN_RECOVERY_THRESHOLD_MAX);
653 break;
654 case YAW_SPIN_RECOVERY_OFF:
655 default:
656 enabledFlag = false;
657 threshold = YAW_SPIN_RECOVERY_THRESHOLD_MAX;
658 break;
661 yawSpinRecoveryEnabled = enabledFlag;
662 yawSpinRecoveryThreshold = threshold;
664 #endif