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)
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/>.
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"
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_GYRO_DATA_ANALYSE
49 #include "flight/gyroanalyse.h"
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
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
;
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
;
80 static FAST_DATA_ZERO_INIT
float accumulatedMeasurements
[XYZ_AXIS_COUNT
];
81 static FAST_DATA_ZERO_INIT
float gyroPrevious
[XYZ_AXIS_COUNT
];
82 static FAST_DATA_ZERO_INIT
int accumulatedMeasurementCount
;
84 static FAST_DATA_ZERO_INIT
int16_t gyroSensorTemperature
;
86 FAST_DATA
uint8_t activePidLoopDenom
= 1;
88 static bool firstArmingCalibrationWasStarted
= false;
91 STATIC_UNIT_TESTED gyroSensor_t
* const gyroSensorPtr
= &gyro
.gyroSensor1
;
92 STATIC_UNIT_TESTED gyroDev_t
* const gyroDevPtr
= &gyro
.gyroSensor1
.gyroDev
;
96 #define DEBUG_GYRO_CALIBRATION 3
98 #define GYRO_OVERFLOW_TRIGGER_THRESHOLD 31980 // 97.5% full scale (1950dps for 2000dps gyro)
99 #define GYRO_OVERFLOW_RESET_THRESHOLD 30340 // 92.5% full scale (1850dps for 2000dps gyro)
101 PG_REGISTER_WITH_RESET_FN(gyroConfig_t
, gyroConfig
, PG_GYRO_CONFIG
, 9);
103 #ifndef GYRO_CONFIG_USE_GYRO_DEFAULT
104 #define GYRO_CONFIG_USE_GYRO_DEFAULT GYRO_CONFIG_USE_GYRO_1
107 void pgResetFn_gyroConfig(gyroConfig_t
*gyroConfig
)
109 gyroConfig
->gyroCalibrationDuration
= 125; // 1.25 seconds
110 gyroConfig
->gyroMovementCalibrationThreshold
= 48;
111 gyroConfig
->gyro_hardware_lpf
= GYRO_HARDWARE_LPF_NORMAL
;
112 gyroConfig
->gyro_lowpass_type
= FILTER_PT1
;
113 gyroConfig
->gyro_lowpass_hz
= 200; // NOTE: dynamic lpf is enabled by default so this setting is actually
114 // overridden and the static lowpass 1 is disabled. We can't set this
115 // value to 0 otherwise Configurator versions 10.4 and earlier will also
116 // reset the lowpass filter type to PT1 overriding the desired BIQUAD setting.
117 gyroConfig
->gyro_lowpass2_type
= FILTER_PT1
;
118 gyroConfig
->gyro_lowpass2_hz
= GYRO_LOWPASS_2_HZ_DEFAULT
;
119 gyroConfig
->gyro_high_fsr
= false;
120 gyroConfig
->gyro_to_use
= GYRO_CONFIG_USE_GYRO_DEFAULT
;
121 gyroConfig
->gyro_soft_notch_hz_1
= 0;
122 gyroConfig
->gyro_soft_notch_cutoff_1
= 0;
123 gyroConfig
->gyro_soft_notch_hz_2
= 0;
124 gyroConfig
->gyro_soft_notch_cutoff_2
= 0;
125 gyroConfig
->checkOverflow
= GYRO_OVERFLOW_CHECK_ALL_AXES
;
126 gyroConfig
->gyro_offset_yaw
= 0;
127 gyroConfig
->yaw_spin_recovery
= YAW_SPIN_RECOVERY_AUTO
;
128 gyroConfig
->yaw_spin_threshold
= 1950;
129 gyroConfig
->dyn_lpf_gyro_min_hz
= DYN_LPF_GYRO_MIN_HZ_DEFAULT
;
130 gyroConfig
->dyn_lpf_gyro_max_hz
= DYN_LPF_GYRO_MAX_HZ_DEFAULT
;
131 gyroConfig
->dyn_notch_max_hz
= 600;
132 gyroConfig
->dyn_notch_count
= 3;
133 gyroConfig
->dyn_notch_q
= 300;
134 gyroConfig
->dyn_notch_min_hz
= 150;
135 gyroConfig
->gyro_filter_debug_axis
= FD_ROLL
;
136 gyroConfig
->dyn_lpf_curve_expo
= 5;
137 gyroConfig
->simplified_gyro_filter
= false;
138 gyroConfig
->simplified_gyro_filter_multiplier
= SIMPLIFIED_TUNING_DEFAULT
;
141 #ifdef USE_GYRO_DATA_ANALYSE
142 bool isDynamicFilterActive(void)
144 return featureIsEnabled(FEATURE_DYNAMIC_FILTER
);
148 FAST_CODE
bool isGyroSensorCalibrationComplete(const gyroSensor_t
*gyroSensor
)
150 return gyroSensor
->calibration
.cyclesRemaining
== 0;
153 FAST_CODE
bool gyroIsCalibrationComplete(void)
155 switch (gyro
.gyroToUse
) {
157 case GYRO_CONFIG_USE_GYRO_1
: {
158 return isGyroSensorCalibrationComplete(&gyro
.gyroSensor1
);
160 #ifdef USE_MULTI_GYRO
161 case GYRO_CONFIG_USE_GYRO_2
: {
162 return isGyroSensorCalibrationComplete(&gyro
.gyroSensor2
);
164 case GYRO_CONFIG_USE_GYRO_BOTH
: {
165 return isGyroSensorCalibrationComplete(&gyro
.gyroSensor1
) && isGyroSensorCalibrationComplete(&gyro
.gyroSensor2
);
171 static bool isOnFinalGyroCalibrationCycle(const gyroCalibration_t
*gyroCalibration
)
173 return gyroCalibration
->cyclesRemaining
== 1;
176 static int32_t gyroCalculateCalibratingCycles(void)
178 return (gyroConfig()->gyroCalibrationDuration
* 10000) / gyro
.sampleLooptime
;
181 static bool isOnFirstGyroCalibrationCycle(const gyroCalibration_t
*gyroCalibration
)
183 return gyroCalibration
->cyclesRemaining
== gyroCalculateCalibratingCycles();
186 static void gyroSetCalibrationCycles(gyroSensor_t
*gyroSensor
)
188 #if defined(USE_FAKE_GYRO) && !defined(UNIT_TEST)
189 if (gyroSensor
->gyroDev
.gyroHardware
== GYRO_FAKE
) {
190 gyroSensor
->calibration
.cyclesRemaining
= 0;
194 gyroSensor
->calibration
.cyclesRemaining
= gyroCalculateCalibratingCycles();
197 void gyroStartCalibration(bool isFirstArmingCalibration
)
199 if (isFirstArmingCalibration
&& firstArmingCalibrationWasStarted
) {
203 gyroSetCalibrationCycles(&gyro
.gyroSensor1
);
204 #ifdef USE_MULTI_GYRO
205 gyroSetCalibrationCycles(&gyro
.gyroSensor2
);
208 if (isFirstArmingCalibration
) {
209 firstArmingCalibrationWasStarted
= true;
213 bool isFirstArmingGyroCalibrationRunning(void)
215 return firstArmingCalibrationWasStarted
&& !gyroIsCalibrationComplete();
218 STATIC_UNIT_TESTED
void performGyroCalibration(gyroSensor_t
*gyroSensor
, uint8_t gyroMovementCalibrationThreshold
)
220 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
221 // Reset g[axis] at start of calibration
222 if (isOnFirstGyroCalibrationCycle(&gyroSensor
->calibration
)) {
223 gyroSensor
->calibration
.sum
[axis
] = 0.0f
;
224 devClear(&gyroSensor
->calibration
.var
[axis
]);
225 // gyroZero is set to zero until calibration complete
226 gyroSensor
->gyroDev
.gyroZero
[axis
] = 0.0f
;
229 // Sum up CALIBRATING_GYRO_TIME_US readings
230 gyroSensor
->calibration
.sum
[axis
] += gyroSensor
->gyroDev
.gyroADCRaw
[axis
];
231 devPush(&gyroSensor
->calibration
.var
[axis
], gyroSensor
->gyroDev
.gyroADCRaw
[axis
]);
233 if (isOnFinalGyroCalibrationCycle(&gyroSensor
->calibration
)) {
234 const float stddev
= devStandardDeviation(&gyroSensor
->calibration
.var
[axis
]);
235 // DEBUG_GYRO_CALIBRATION records the standard deviation of roll
236 // into the spare field - debug[3], in DEBUG_GYRO_RAW
238 DEBUG_SET(DEBUG_GYRO_RAW
, DEBUG_GYRO_CALIBRATION
, lrintf(stddev
));
241 // check deviation and startover in case the model was moved
242 if (gyroMovementCalibrationThreshold
&& stddev
> gyroMovementCalibrationThreshold
) {
243 gyroSetCalibrationCycles(gyroSensor
);
247 // please take care with exotic boardalignment !!
248 gyroSensor
->gyroDev
.gyroZero
[axis
] = gyroSensor
->calibration
.sum
[axis
] / gyroCalculateCalibratingCycles();
250 gyroSensor
->gyroDev
.gyroZero
[axis
] -= ((float)gyroConfig()->gyro_offset_yaw
/ 100);
255 if (isOnFinalGyroCalibrationCycle(&gyroSensor
->calibration
)) {
256 schedulerResetTaskStatistics(TASK_SELF
); // so calibration cycles do not pollute tasks statistics
257 if (!firstArmingCalibrationWasStarted
|| (getArmingDisableFlags() & ~ARMING_DISABLED_CALIBRATING
) == 0) {
258 beeper(BEEPER_GYRO_CALIBRATED
);
262 --gyroSensor
->calibration
.cyclesRemaining
;
265 #if defined(USE_GYRO_SLEW_LIMITER)
266 FAST_CODE
int32_t gyroSlewLimiter(gyroSensor_t
*gyroSensor
, int axis
)
268 int32_t ret
= (int32_t)gyroSensor
->gyroDev
.gyroADCRaw
[axis
];
269 if (gyroConfig()->checkOverflow
|| gyro
.gyroHasOverflowProtection
) {
270 // don't use the slew limiter if overflow checking is on or gyro is not subject to overflow bug
273 if (abs(ret
- gyroSensor
->gyroDev
.gyroADCRawPrevious
[axis
]) > (1<<14)) {
274 // there has been a large change in value, so assume overflow has occurred and return the previous value
275 ret
= gyroSensor
->gyroDev
.gyroADCRawPrevious
[axis
];
277 gyroSensor
->gyroDev
.gyroADCRawPrevious
[axis
] = ret
;
283 #ifdef USE_GYRO_OVERFLOW_CHECK
284 static FAST_CODE_NOINLINE
void handleOverflow(timeUs_t currentTimeUs
)
286 // This will need to be revised if we ever allow different sensor types to be
287 // used simultaneously. In that case the scale might be different between sensors.
288 // It's complicated by the fact that we're using filtered gyro data here which is
289 // after both sensors are scaled and averaged.
290 const float gyroOverflowResetRate
= GYRO_OVERFLOW_RESET_THRESHOLD
* gyro
.scale
;
292 if ((fabsf(gyro
.gyroADCf
[X
]) < gyroOverflowResetRate
)
293 && (fabsf(gyro
.gyroADCf
[Y
]) < gyroOverflowResetRate
)
294 && (fabsf(gyro
.gyroADCf
[Z
]) < gyroOverflowResetRate
)) {
295 // if we have 50ms of consecutive OK gyro vales, then assume yaw readings are OK again and reset overflowDetected
296 // reset requires good OK values on all axes
297 if (cmpTimeUs(currentTimeUs
, overflowTimeUs
) > 50000) {
298 overflowDetected
= false;
301 // not a consecutive OK value, so reset the overflow time
302 overflowTimeUs
= currentTimeUs
;
306 static FAST_CODE
void checkForOverflow(timeUs_t currentTimeUs
)
308 // check for overflow to handle Yaw Spin To The Moon (YSTTM)
309 // ICM gyros are specified to +/- 2000 deg/sec, in a crash they can go out of spec.
310 // This can cause an overflow and sign reversal in the output.
311 // Overflow and sign reversal seems to result in a gyro value of +1996 or -1996.
312 if (overflowDetected
) {
313 handleOverflow(currentTimeUs
);
315 #ifndef SIMULATOR_BUILD
316 // check for overflow in the axes set in overflowAxisMask
317 gyroOverflow_e overflowCheck
= GYRO_OVERFLOW_NONE
;
319 // This will need to be revised if we ever allow different sensor types to be
320 // used simultaneously. In that case the scale might be different between sensors.
321 // It's complicated by the fact that we're using filtered gyro data here which is
322 // after both sensors are scaled and averaged.
323 const float gyroOverflowTriggerRate
= GYRO_OVERFLOW_TRIGGER_THRESHOLD
* gyro
.scale
;
325 if (fabsf(gyro
.gyroADCf
[X
]) > gyroOverflowTriggerRate
) {
326 overflowCheck
|= GYRO_OVERFLOW_X
;
328 if (fabsf(gyro
.gyroADCf
[Y
]) > gyroOverflowTriggerRate
) {
329 overflowCheck
|= GYRO_OVERFLOW_Y
;
331 if (fabsf(gyro
.gyroADCf
[Z
]) > gyroOverflowTriggerRate
) {
332 overflowCheck
|= GYRO_OVERFLOW_Z
;
334 if (overflowCheck
& gyro
.overflowAxisMask
) {
335 overflowDetected
= true;
336 overflowTimeUs
= currentTimeUs
;
337 #ifdef USE_YAW_SPIN_RECOVERY
338 yawSpinDetected
= false;
339 #endif // USE_YAW_SPIN_RECOVERY
341 #endif // SIMULATOR_BUILD
344 #endif // USE_GYRO_OVERFLOW_CHECK
346 #ifdef USE_YAW_SPIN_RECOVERY
347 static FAST_CODE_NOINLINE
void handleYawSpin(timeUs_t currentTimeUs
)
349 const float yawSpinResetRate
= yawSpinRecoveryThreshold
- 100.0f
;
350 if (fabsf(gyro
.gyroADCf
[Z
]) < yawSpinResetRate
) {
351 // testing whether 20ms of consecutive OK gyro yaw values is enough
352 if (cmpTimeUs(currentTimeUs
, yawSpinTimeUs
) > 20000) {
353 yawSpinDetected
= false;
356 // reset the yaw spin time
357 yawSpinTimeUs
= currentTimeUs
;
361 static FAST_CODE
void checkForYawSpin(timeUs_t currentTimeUs
)
363 // if not in overflow mode, handle yaw spins above threshold
364 #ifdef USE_GYRO_OVERFLOW_CHECK
365 if (overflowDetected
) {
366 yawSpinDetected
= false;
369 #endif // USE_GYRO_OVERFLOW_CHECK
371 if (yawSpinDetected
) {
372 handleYawSpin(currentTimeUs
);
374 #ifndef SIMULATOR_BUILD
375 // check for spin on yaw axis only
376 if (abs((int)gyro
.gyroADCf
[Z
]) > yawSpinRecoveryThreshold
) {
377 yawSpinDetected
= true;
378 yawSpinTimeUs
= currentTimeUs
;
380 #endif // SIMULATOR_BUILD
383 #endif // USE_YAW_SPIN_RECOVERY
385 static FAST_CODE FAST_CODE_NOINLINE
void gyroUpdateSensor(gyroSensor_t
*gyroSensor
)
387 if (!gyroSensor
->gyroDev
.readFn(&gyroSensor
->gyroDev
)) {
390 gyroSensor
->gyroDev
.dataReady
= false;
392 if (isGyroSensorCalibrationComplete(gyroSensor
)) {
393 // move 16-bit gyro data into 32-bit variables to avoid overflows in calculations
395 #if defined(USE_GYRO_SLEW_LIMITER)
396 gyroSensor
->gyroDev
.gyroADC
[X
] = gyroSlewLimiter(gyroSensor
, X
) - gyroSensor
->gyroDev
.gyroZero
[X
];
397 gyroSensor
->gyroDev
.gyroADC
[Y
] = gyroSlewLimiter(gyroSensor
, Y
) - gyroSensor
->gyroDev
.gyroZero
[Y
];
398 gyroSensor
->gyroDev
.gyroADC
[Z
] = gyroSlewLimiter(gyroSensor
, Z
) - gyroSensor
->gyroDev
.gyroZero
[Z
];
400 gyroSensor
->gyroDev
.gyroADC
[X
] = gyroSensor
->gyroDev
.gyroADCRaw
[X
] - gyroSensor
->gyroDev
.gyroZero
[X
];
401 gyroSensor
->gyroDev
.gyroADC
[Y
] = gyroSensor
->gyroDev
.gyroADCRaw
[Y
] - gyroSensor
->gyroDev
.gyroZero
[Y
];
402 gyroSensor
->gyroDev
.gyroADC
[Z
] = gyroSensor
->gyroDev
.gyroADCRaw
[Z
] - gyroSensor
->gyroDev
.gyroZero
[Z
];
405 if (gyroSensor
->gyroDev
.gyroAlign
== ALIGN_CUSTOM
) {
406 alignSensorViaMatrix(gyroSensor
->gyroDev
.gyroADC
, &gyroSensor
->gyroDev
.rotationMatrix
);
408 alignSensorViaRotation(gyroSensor
->gyroDev
.gyroADC
, gyroSensor
->gyroDev
.gyroAlign
);
411 performGyroCalibration(gyroSensor
, gyroConfig()->gyroMovementCalibrationThreshold
);
415 FAST_CODE
void gyroUpdate(void)
417 switch (gyro
.gyroToUse
) {
418 case GYRO_CONFIG_USE_GYRO_1
:
419 gyroUpdateSensor(&gyro
.gyroSensor1
);
420 if (isGyroSensorCalibrationComplete(&gyro
.gyroSensor1
)) {
421 gyro
.gyroADC
[X
] = gyro
.gyroSensor1
.gyroDev
.gyroADC
[X
] * gyro
.gyroSensor1
.gyroDev
.scale
;
422 gyro
.gyroADC
[Y
] = gyro
.gyroSensor1
.gyroDev
.gyroADC
[Y
] * gyro
.gyroSensor1
.gyroDev
.scale
;
423 gyro
.gyroADC
[Z
] = gyro
.gyroSensor1
.gyroDev
.gyroADC
[Z
] * gyro
.gyroSensor1
.gyroDev
.scale
;
426 #ifdef USE_MULTI_GYRO
427 case GYRO_CONFIG_USE_GYRO_2
:
428 gyroUpdateSensor(&gyro
.gyroSensor2
);
429 if (isGyroSensorCalibrationComplete(&gyro
.gyroSensor2
)) {
430 gyro
.gyroADC
[X
] = gyro
.gyroSensor2
.gyroDev
.gyroADC
[X
] * gyro
.gyroSensor2
.gyroDev
.scale
;
431 gyro
.gyroADC
[Y
] = gyro
.gyroSensor2
.gyroDev
.gyroADC
[Y
] * gyro
.gyroSensor2
.gyroDev
.scale
;
432 gyro
.gyroADC
[Z
] = gyro
.gyroSensor2
.gyroDev
.gyroADC
[Z
] * gyro
.gyroSensor2
.gyroDev
.scale
;
435 case GYRO_CONFIG_USE_GYRO_BOTH
:
436 gyroUpdateSensor(&gyro
.gyroSensor1
);
437 gyroUpdateSensor(&gyro
.gyroSensor2
);
438 if (isGyroSensorCalibrationComplete(&gyro
.gyroSensor1
) && isGyroSensorCalibrationComplete(&gyro
.gyroSensor2
)) {
439 gyro
.gyroADC
[X
] = ((gyro
.gyroSensor1
.gyroDev
.gyroADC
[X
] * gyro
.gyroSensor1
.gyroDev
.scale
) + (gyro
.gyroSensor2
.gyroDev
.gyroADC
[X
] * gyro
.gyroSensor2
.gyroDev
.scale
)) / 2.0f
;
440 gyro
.gyroADC
[Y
] = ((gyro
.gyroSensor1
.gyroDev
.gyroADC
[Y
] * gyro
.gyroSensor1
.gyroDev
.scale
) + (gyro
.gyroSensor2
.gyroDev
.gyroADC
[Y
] * gyro
.gyroSensor2
.gyroDev
.scale
)) / 2.0f
;
441 gyro
.gyroADC
[Z
] = ((gyro
.gyroSensor1
.gyroDev
.gyroADC
[Z
] * gyro
.gyroSensor1
.gyroDev
.scale
) + (gyro
.gyroSensor2
.gyroDev
.gyroADC
[Z
] * gyro
.gyroSensor2
.gyroDev
.scale
)) / 2.0f
;
447 if (gyro
.downsampleFilterEnabled
) {
448 // using gyro lowpass 2 filter for downsampling
449 gyro
.sampleSum
[X
] = gyro
.lowpass2FilterApplyFn((filter_t
*)&gyro
.lowpass2Filter
[X
], gyro
.gyroADC
[X
]);
450 gyro
.sampleSum
[Y
] = gyro
.lowpass2FilterApplyFn((filter_t
*)&gyro
.lowpass2Filter
[Y
], gyro
.gyroADC
[Y
]);
451 gyro
.sampleSum
[Z
] = gyro
.lowpass2FilterApplyFn((filter_t
*)&gyro
.lowpass2Filter
[Z
], gyro
.gyroADC
[Z
]);
453 // using simple averaging for downsampling
454 gyro
.sampleSum
[X
] += gyro
.gyroADC
[X
];
455 gyro
.sampleSum
[Y
] += gyro
.gyroADC
[Y
];
456 gyro
.sampleSum
[Z
] += gyro
.gyroADC
[Z
];
461 #define GYRO_FILTER_FUNCTION_NAME filterGyro
462 #define GYRO_FILTER_DEBUG_SET(mode, index, value) do { UNUSED(mode); UNUSED(index); UNUSED(value); } while (0)
463 #define GYRO_FILTER_AXIS_DEBUG_SET(axis, mode, index, value) do { UNUSED(axis); UNUSED(mode); UNUSED(index); UNUSED(value); } while (0)
464 #include "gyro_filter_impl.c"
465 #undef GYRO_FILTER_FUNCTION_NAME
466 #undef GYRO_FILTER_DEBUG_SET
467 #undef GYRO_FILTER_AXIS_DEBUG_SET
469 #define GYRO_FILTER_FUNCTION_NAME filterGyroDebug
470 #define GYRO_FILTER_DEBUG_SET DEBUG_SET
471 #define GYRO_FILTER_AXIS_DEBUG_SET(axis, mode, index, value) if (axis == (int)gyro.gyroDebugAxis) DEBUG_SET(mode, index, value)
472 #include "gyro_filter_impl.c"
473 #undef GYRO_FILTER_FUNCTION_NAME
474 #undef GYRO_FILTER_DEBUG_SET
475 #undef GYRO_FILTER_AXIS_DEBUG_SET
477 FAST_CODE
void gyroFiltering(timeUs_t currentTimeUs
)
479 if (gyro
.gyroDebugMode
== DEBUG_NONE
) {
485 #ifdef USE_GYRO_DATA_ANALYSE
486 if (isDynamicFilterActive()) {
487 gyroDataAnalyse(&gyro
.gyroAnalyseState
);
491 if (gyro
.useDualGyroDebugging
) {
492 switch (gyro
.gyroToUse
) {
493 case GYRO_CONFIG_USE_GYRO_1
:
494 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 0, gyro
.gyroSensor1
.gyroDev
.gyroADCRaw
[X
]);
495 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 1, gyro
.gyroSensor1
.gyroDev
.gyroADCRaw
[Y
]);
496 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED
, 0, lrintf(gyro
.gyroSensor1
.gyroDev
.gyroADC
[X
] * gyro
.gyroSensor1
.gyroDev
.scale
));
497 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED
, 1, lrintf(gyro
.gyroSensor1
.gyroDev
.gyroADC
[Y
] * gyro
.gyroSensor1
.gyroDev
.scale
));
500 #ifdef USE_MULTI_GYRO
501 case GYRO_CONFIG_USE_GYRO_2
:
502 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 2, gyro
.gyroSensor2
.gyroDev
.gyroADCRaw
[X
]);
503 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 3, gyro
.gyroSensor2
.gyroDev
.gyroADCRaw
[Y
]);
504 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED
, 2, lrintf(gyro
.gyroSensor2
.gyroDev
.gyroADC
[X
] * gyro
.gyroSensor2
.gyroDev
.scale
));
505 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED
, 3, lrintf(gyro
.gyroSensor2
.gyroDev
.gyroADC
[Y
] * gyro
.gyroSensor2
.gyroDev
.scale
));
508 case GYRO_CONFIG_USE_GYRO_BOTH
:
509 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 0, gyro
.gyroSensor1
.gyroDev
.gyroADCRaw
[X
]);
510 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 1, gyro
.gyroSensor1
.gyroDev
.gyroADCRaw
[Y
]);
511 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 2, gyro
.gyroSensor2
.gyroDev
.gyroADCRaw
[X
]);
512 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 3, gyro
.gyroSensor2
.gyroDev
.gyroADCRaw
[Y
]);
513 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED
, 0, lrintf(gyro
.gyroSensor1
.gyroDev
.gyroADC
[X
] * gyro
.gyroSensor1
.gyroDev
.scale
));
514 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED
, 1, lrintf(gyro
.gyroSensor1
.gyroDev
.gyroADC
[Y
] * gyro
.gyroSensor1
.gyroDev
.scale
));
515 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED
, 2, lrintf(gyro
.gyroSensor2
.gyroDev
.gyroADC
[X
] * gyro
.gyroSensor2
.gyroDev
.scale
));
516 DEBUG_SET(DEBUG_DUAL_GYRO_SCALED
, 3, lrintf(gyro
.gyroSensor2
.gyroDev
.gyroADC
[Y
] * gyro
.gyroSensor2
.gyroDev
.scale
));
517 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
)));
518 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
)));
519 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
)));
525 #ifdef USE_GYRO_OVERFLOW_CHECK
526 if (gyroConfig()->checkOverflow
&& !gyro
.gyroHasOverflowProtection
) {
527 checkForOverflow(currentTimeUs
);
531 #ifdef USE_YAW_SPIN_RECOVERY
532 if (yawSpinRecoveryEnabled
) {
533 checkForYawSpin(currentTimeUs
);
537 if (!overflowDetected
) {
538 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
539 // integrate using trapezium rule to avoid bias
540 accumulatedMeasurements
[axis
] += 0.5f
* (gyroPrevious
[axis
] + gyro
.gyroADCf
[axis
]) * gyro
.targetLooptime
;
541 gyroPrevious
[axis
] = gyro
.gyroADCf
[axis
];
543 accumulatedMeasurementCount
++;
546 #if !defined(USE_GYRO_OVERFLOW_CHECK) && !defined(USE_YAW_SPIN_RECOVERY)
547 UNUSED(currentTimeUs
);
551 bool gyroGetAccumulationAverage(float *accumulationAverage
)
553 if (accumulatedMeasurementCount
) {
554 // If we have gyro data accumulated, calculate average rate that will yield the same rotation
555 const timeUs_t accumulatedMeasurementTimeUs
= accumulatedMeasurementCount
* gyro
.targetLooptime
;
556 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
557 accumulationAverage
[axis
] = accumulatedMeasurements
[axis
] / accumulatedMeasurementTimeUs
;
558 accumulatedMeasurements
[axis
] = 0.0f
;
560 accumulatedMeasurementCount
= 0;
563 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
564 accumulationAverage
[axis
] = 0.0f
;
570 int16_t gyroReadSensorTemperature(gyroSensor_t gyroSensor
)
572 if (gyroSensor
.gyroDev
.temperatureFn
) {
573 gyroSensor
.gyroDev
.temperatureFn(&gyroSensor
.gyroDev
, &gyroSensor
.gyroDev
.temperature
);
575 return gyroSensor
.gyroDev
.temperature
;
578 void gyroReadTemperature(void)
580 switch (gyro
.gyroToUse
) {
581 case GYRO_CONFIG_USE_GYRO_1
:
582 gyroSensorTemperature
= gyroReadSensorTemperature(gyro
.gyroSensor1
);
585 #ifdef USE_MULTI_GYRO
586 case GYRO_CONFIG_USE_GYRO_2
:
587 gyroSensorTemperature
= gyroReadSensorTemperature(gyro
.gyroSensor2
);
590 case GYRO_CONFIG_USE_GYRO_BOTH
:
591 gyroSensorTemperature
= MAX(gyroReadSensorTemperature(gyro
.gyroSensor1
), gyroReadSensorTemperature(gyro
.gyroSensor2
));
593 #endif // USE_MULTI_GYRO
597 int16_t gyroGetTemperature(void)
599 return gyroSensorTemperature
;
602 bool gyroOverflowDetected(void)
604 #ifdef USE_GYRO_OVERFLOW_CHECK
605 return overflowDetected
;
608 #endif // USE_GYRO_OVERFLOW_CHECK
611 #ifdef USE_YAW_SPIN_RECOVERY
612 bool gyroYawSpinDetected(void)
614 return yawSpinDetected
;
616 #endif // USE_YAW_SPIN_RECOVERY
618 uint16_t gyroAbsRateDps(int axis
)
620 return fabsf(gyro
.gyroADCf
[axis
]);
625 float dynThrottle(float throttle
) {
626 return throttle
* (1 - (throttle
* throttle
) / 3.0f
) * 1.5f
;
629 void dynLpfGyroUpdate(float throttle
)
631 if (gyro
.dynLpfFilter
!= DYN_LPF_NONE
) {
632 unsigned int cutoffFreq
;
633 if (gyro
.dynLpfCurveExpo
> 0) {
634 cutoffFreq
= dynLpfCutoffFreq(throttle
, gyro
.dynLpfMin
, gyro
.dynLpfMax
, gyro
.dynLpfCurveExpo
);
636 cutoffFreq
= fmax(dynThrottle(throttle
) * gyro
.dynLpfMax
, gyro
.dynLpfMin
);
638 DEBUG_SET(DEBUG_DYN_LPF
, 2, cutoffFreq
);
639 const float gyroDt
= gyro
.targetLooptime
* 1e-6f
;
640 switch (gyro
.dynLpfFilter
) {
642 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
643 pt1FilterUpdateCutoff(&gyro
.lowpassFilter
[axis
].pt1FilterState
, pt1FilterGain(cutoffFreq
, gyroDt
));
647 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
648 biquadFilterUpdateLPF(&gyro
.lowpassFilter
[axis
].biquadFilterState
, cutoffFreq
, gyro
.targetLooptime
);
652 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
653 pt2FilterUpdateCutoff(&gyro
.lowpassFilter
[axis
].pt2FilterState
, pt2FilterGain(cutoffFreq
, gyroDt
));
657 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
658 pt3FilterUpdateCutoff(&gyro
.lowpassFilter
[axis
].pt3FilterState
, pt3FilterGain(cutoffFreq
, gyroDt
));
666 #ifdef USE_YAW_SPIN_RECOVERY
667 void initYawSpinRecovery(int maxYawRate
)
672 switch (gyroConfig()->yaw_spin_recovery
) {
673 case YAW_SPIN_RECOVERY_ON
:
675 threshold
= gyroConfig()->yaw_spin_threshold
;
677 case YAW_SPIN_RECOVERY_AUTO
:
679 const int overshootAllowance
= MAX(maxYawRate
/ 4, 200); // Allow a 25% or minimum 200dps overshoot tolerance
680 threshold
= constrain(maxYawRate
+ overshootAllowance
, YAW_SPIN_RECOVERY_THRESHOLD_MIN
, YAW_SPIN_RECOVERY_THRESHOLD_MAX
);
682 case YAW_SPIN_RECOVERY_OFF
:
685 threshold
= YAW_SPIN_RECOVERY_THRESHOLD_MAX
;
689 yawSpinRecoveryEnabled
= enabledFlag
;
690 yawSpinRecoveryThreshold
= threshold
;