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 "build/build_config.h"
26 #include "build/debug.h"
28 #include "common/axis.h"
29 #include "common/calibration.h"
30 #include "common/filter.h"
31 #include "common/log.h"
32 #include "common/maths.h"
33 #include "common/utils.h"
35 #include "config/parameter_group.h"
36 #include "config/parameter_group_ids.h"
37 #include "config/feature.h"
39 #include "drivers/accgyro/accgyro.h"
40 #include "drivers/accgyro/accgyro_mpu.h"
41 #include "drivers/accgyro/accgyro_mpu6000.h"
42 #include "drivers/accgyro/accgyro_mpu6500.h"
43 #include "drivers/accgyro/accgyro_mpu9250.h"
45 #include "drivers/accgyro/accgyro_bmi088.h"
46 #include "drivers/accgyro/accgyro_bmi160.h"
47 #include "drivers/accgyro/accgyro_bmi270.h"
48 #include "drivers/accgyro/accgyro_icm20689.h"
49 #include "drivers/accgyro/accgyro_icm42605.h"
50 #include "drivers/accgyro/accgyro_lsm6dxx.h"
51 #include "drivers/accgyro/accgyro_fake.h"
52 #include "drivers/io.h"
54 #include "fc/config.h"
55 #include "fc/runtime_config.h"
56 #include "fc/rc_controls.h"
57 #include "fc/settings.h"
59 #include "io/beeper.h"
60 #include "io/statusindicator.h"
62 #include "scheduler/scheduler.h"
64 #include "sensors/boardalignment.h"
65 #include "sensors/gyro.h"
66 #include "sensors/sensors.h"
68 #include "flight/gyroanalyse.h"
69 #include "flight/rpm_filter.h"
70 #include "flight/kalman.h"
71 #include "flight/adaptive_filter.h"
73 #ifdef USE_HARDWARE_REVISION_DETECTION
74 #include "hardware_revision.h"
77 FASTRAM gyro_t gyro
; // gyro sensor object
79 #define MAX_GYRO_COUNT 1
81 STATIC_UNIT_TESTED gyroDev_t gyroDev
[MAX_GYRO_COUNT
]; // Not in FASTRAM since it may hold DMA buffers
82 STATIC_FASTRAM
int16_t gyroTemperature
[MAX_GYRO_COUNT
];
83 STATIC_FASTRAM_UNIT_TESTED zeroCalibrationVector_t gyroCalibration
[MAX_GYRO_COUNT
];
85 STATIC_FASTRAM filterApplyFnPtr gyroLpfApplyFn
;
86 STATIC_FASTRAM filter_t gyroLpfState
[XYZ_AXIS_COUNT
];
88 STATIC_FASTRAM filterApplyFnPtr gyroLpf2ApplyFn
;
89 STATIC_FASTRAM filter_t gyroLpf2State
[XYZ_AXIS_COUNT
];
91 STATIC_FASTRAM filterApplyFnPtr gyroLuluApplyFn
;
92 STATIC_FASTRAM filter_t gyroLuluState
[XYZ_AXIS_COUNT
];
94 #ifdef USE_DYNAMIC_FILTERS
96 EXTENDED_FASTRAM gyroAnalyseState_t gyroAnalyseState
;
97 EXTENDED_FASTRAM dynamicGyroNotchState_t dynamicGyroNotchState
;
98 EXTENDED_FASTRAM secondaryDynamicGyroNotchState_t secondaryDynamicGyroNotchState
;
102 PG_REGISTER_WITH_RESET_TEMPLATE(gyroConfig_t
, gyroConfig
, PG_GYRO_CONFIG
, 12);
104 PG_RESET_TEMPLATE(gyroConfig_t
, gyroConfig
,
105 .gyro_anti_aliasing_lpf_hz
= SETTING_GYRO_ANTI_ALIASING_LPF_HZ_DEFAULT
,
106 .looptime
= SETTING_LOOPTIME_DEFAULT
,
108 .gyro_to_use
= SETTING_GYRO_TO_USE_DEFAULT
,
110 .gyro_main_lpf_hz
= SETTING_GYRO_MAIN_LPF_HZ_DEFAULT
,
111 .gyroDynamicLpfMinHz
= SETTING_GYRO_DYN_LPF_MIN_HZ_DEFAULT
,
112 .gyroDynamicLpfMaxHz
= SETTING_GYRO_DYN_LPF_MAX_HZ_DEFAULT
,
113 .gyroDynamicLpfCurveExpo
= SETTING_GYRO_DYN_LPF_CURVE_EXPO_DEFAULT
,
114 #ifdef USE_DYNAMIC_FILTERS
115 .dynamicGyroNotchQ
= SETTING_DYNAMIC_GYRO_NOTCH_Q_DEFAULT
,
116 .dynamicGyroNotchMinHz
= SETTING_DYNAMIC_GYRO_NOTCH_MIN_HZ_DEFAULT
,
117 .dynamicGyroNotchEnabled
= SETTING_DYNAMIC_GYRO_NOTCH_ENABLED_DEFAULT
,
118 .dynamicGyroNotchMode
= SETTING_DYNAMIC_GYRO_NOTCH_MODE_DEFAULT
,
119 .dynamicGyroNotch3dQ
= SETTING_DYNAMIC_GYRO_NOTCH_3D_Q_DEFAULT
,
121 #ifdef USE_GYRO_KALMAN
122 .kalman_q
= SETTING_SETPOINT_KALMAN_Q_DEFAULT
,
123 .kalmanEnabled
= SETTING_SETPOINT_KALMAN_ENABLED_DEFAULT
,
125 .init_gyro_cal_enabled
= SETTING_INIT_GYRO_CAL_DEFAULT
,
126 .gyro_zero_cal
= {SETTING_GYRO_ZERO_X_DEFAULT
, SETTING_GYRO_ZERO_Y_DEFAULT
, SETTING_GYRO_ZERO_Z_DEFAULT
},
127 .gravity_cmss_cal
= SETTING_INS_GRAVITY_CMSS_DEFAULT
,
128 #ifdef USE_ADAPTIVE_FILTER
129 .adaptiveFilterTarget
= SETTING_GYRO_ADAPTIVE_FILTER_TARGET_DEFAULT
,
130 .adaptiveFilterMinHz
= SETTING_GYRO_ADAPTIVE_FILTER_MIN_HZ_DEFAULT
,
131 .adaptiveFilterMaxHz
= SETTING_GYRO_ADAPTIVE_FILTER_MAX_HZ_DEFAULT
,
132 .adaptiveFilterStdLpfHz
= SETTING_GYRO_ADAPTIVE_FILTER_STD_LPF_HZ_DEFAULT
,
133 .adaptiveFilterHpfHz
= SETTING_GYRO_ADAPTIVE_FILTER_HPF_HZ_DEFAULT
,
134 .adaptiveFilterIntegratorThresholdHigh
= SETTING_GYRO_ADAPTIVE_FILTER_INTEGRATOR_THRESHOLD_HIGH_DEFAULT
,
135 .adaptiveFilterIntegratorThresholdLow
= SETTING_GYRO_ADAPTIVE_FILTER_INTEGRATOR_THRESHOLD_LOW_DEFAULT
,
137 .gyroFilterMode
= SETTING_GYRO_FILTER_MODE_DEFAULT
,
138 .gyroLuluSampleCount
= SETTING_GYRO_LULU_SAMPLE_COUNT_DEFAULT
,
139 .gyroLuluEnabled
= SETTING_GYRO_LULU_ENABLED_DEFAULT
142 STATIC_UNIT_TESTED gyroSensor_e
gyroDetect(gyroDev_t
*dev
, gyroSensor_e gyroHardware
)
144 dev
->gyroAlign
= ALIGN_DEFAULT
;
146 switch (gyroHardware
) {
147 case GYRO_AUTODETECT
:
150 #ifdef USE_IMU_MPU6000
152 if (mpu6000GyroDetect(dev
)) {
153 gyroHardware
= GYRO_MPU6000
;
159 #if defined(USE_IMU_MPU6500)
161 if (mpu6500GyroDetect(dev
)) {
162 gyroHardware
= GYRO_MPU6500
;
168 #ifdef USE_IMU_MPU9250
170 if (mpu9250GyroDetect(dev
)) {
171 gyroHardware
= GYRO_MPU9250
;
177 #ifdef USE_IMU_BMI160
179 if (bmi160GyroDetect(dev
)) {
180 gyroHardware
= GYRO_BMI160
;
186 #ifdef USE_IMU_BMI088
188 if (bmi088GyroDetect(dev
)) {
189 gyroHardware
= GYRO_BMI088
;
195 #ifdef USE_IMU_ICM20689
197 if (icm20689GyroDetect(dev
)) {
198 gyroHardware
= GYRO_ICM20689
;
204 #ifdef USE_IMU_ICM42605
206 if (icm42605GyroDetect(dev
)) {
207 gyroHardware
= GYRO_ICM42605
;
213 #ifdef USE_IMU_BMI270
215 if (bmi270GyroDetect(dev
)) {
216 gyroHardware
= GYRO_BMI270
;
222 #ifdef USE_IMU_LSM6DXX
224 if (lsm6dGyroDetect(dev
)) {
225 gyroHardware
= GYRO_LSM6DXX
;
233 if (fakeGyroDetect(dev
)) {
234 gyroHardware
= GYRO_FAKE
;
242 gyroHardware
= GYRO_NONE
;
248 static void initGyroFilter(filterApplyFnPtr
*applyFn
, filter_t state
[], uint16_t cutoff
, uint32_t looptime
)
250 *applyFn
= nullFilterApply
;
252 *applyFn
= (filterApplyFnPtr
)pt1FilterApply
;
253 for (int axis
= 0; axis
< 3; axis
++) {
254 pt1FilterInit(&state
[axis
].pt1
, cutoff
, US2S(looptime
));
259 static void gyroInitFilters(void)
261 //First gyro LPF running at full gyro frequency 8kHz
262 initGyroFilter(&gyroLpfApplyFn
, gyroLpfState
, gyroConfig()->gyro_anti_aliasing_lpf_hz
, getGyroLooptime());
264 if (gyroConfig()->gyroLuluEnabled
&& gyroConfig()->gyroLuluSampleCount
> 0) {
265 gyroLuluApplyFn
= (filterApplyFnPtr
)luluFilterApply
;
267 for (int axis
= 0; axis
< 3; axis
++) {
268 luluFilterInit(&gyroLuluState
[axis
].lulu
, gyroConfig()->gyroLuluSampleCount
);
271 gyroLuluApplyFn
= nullFilterApply
;
274 if (gyroConfig()->gyroFilterMode
!= GYRO_FILTER_MODE_OFF
) {
275 initGyroFilter(&gyroLpf2ApplyFn
, gyroLpf2State
, gyroConfig()->gyro_main_lpf_hz
, getLooptime());
277 gyroLpf2ApplyFn
= nullFilterApply
;
280 #ifdef USE_ADAPTIVE_FILTER
281 if (gyroConfig()->gyroFilterMode
== GYRO_FILTER_MODE_ADAPTIVE
) {
282 adaptiveFilterSetDefaultFrequency(gyroConfig()->gyro_main_lpf_hz
, gyroConfig()->adaptiveFilterMinHz
, gyroConfig()->adaptiveFilterMaxHz
);
286 #ifdef USE_GYRO_KALMAN
287 if (gyroConfig()->kalmanEnabled
) {
288 gyroKalmanInitialize(gyroConfig()->kalman_q
);
295 memset(&gyro
, 0, sizeof(gyro
));
297 // Set inertial sensor tag (for dual-gyro selection)
299 gyroDev
[0].imuSensorToUse
= gyroConfig()->gyro_to_use
;
301 gyroDev
[0].imuSensorToUse
= 0;
305 gyroSensor_e gyroHardware
= gyroDetect(&gyroDev
[0], GYRO_AUTODETECT
);
306 if (gyroHardware
== GYRO_NONE
) {
307 gyro
.initialized
= false;
308 detectedSensors
[SENSOR_INDEX_GYRO
] = GYRO_NONE
;
312 // Gyro is initialized
313 gyro
.initialized
= true;
314 detectedSensors
[SENSOR_INDEX_GYRO
] = gyroHardware
;
315 sensorsSet(SENSOR_GYRO
);
317 // Driver initialisation
318 gyroDev
[0].lpf
= GYRO_LPF_256HZ
;
319 gyroDev
[0].requestedSampleIntervalUs
= TASK_GYRO_LOOPTIME
;
320 gyroDev
[0].sampleRateIntervalUs
= TASK_GYRO_LOOPTIME
;
321 gyroDev
[0].initFn(&gyroDev
[0]);
323 // initFn will initialize sampleRateIntervalUs to actual gyro sampling rate (if driver supports it). Calculate target looptime using that value
324 gyro
.targetLooptime
= gyroDev
[0].sampleRateIntervalUs
;
328 #ifdef USE_DYNAMIC_FILTERS
329 // Dynamic notch running at PID frequency
330 dynamicGyroNotchFiltersInit(&dynamicGyroNotchState
);
332 secondaryDynamicGyroNotchFiltersInit(&secondaryDynamicGyroNotchState
);
334 gyroDataAnalyseStateInit(
336 gyroConfig()->dynamicGyroNotchMinHz
,
343 void gyroStartCalibration(void)
345 if (!gyro
.initialized
) {
349 #ifndef USE_IMU_FAKE // fixes Test Unit compilation error
350 if (!gyroConfig()->init_gyro_cal_enabled
) {
355 zeroCalibrationStartV(&gyroCalibration
[0], CALIBRATING_GYRO_TIME_MS
, CALIBRATING_GYRO_MORON_THRESHOLD
, false);
358 bool gyroIsCalibrationComplete(void)
360 if (!gyro
.initialized
) {
364 #ifndef USE_IMU_FAKE // fixes Test Unit compilation error
365 if (!gyroConfig()->init_gyro_cal_enabled
) {
370 return zeroCalibrationIsCompleteV(&gyroCalibration
[0]) && zeroCalibrationIsSuccessfulV(&gyroCalibration
[0]);
373 STATIC_UNIT_TESTED
void performGyroCalibration(gyroDev_t
*dev
, zeroCalibrationVector_t
*gyroCalibration
)
377 // Consume gyro reading
378 v
.v
[X
] = dev
->gyroADCRaw
[X
];
379 v
.v
[Y
] = dev
->gyroADCRaw
[Y
];
380 v
.v
[Z
] = dev
->gyroADCRaw
[Z
];
382 zeroCalibrationAddValueV(gyroCalibration
, &v
);
384 // Check if calibration is complete after this cycle
385 if (zeroCalibrationIsCompleteV(gyroCalibration
)) {
386 zeroCalibrationGetZeroV(gyroCalibration
, &v
);
387 dev
->gyroZero
[X
] = v
.v
[X
];
388 dev
->gyroZero
[Y
] = v
.v
[Y
];
389 dev
->gyroZero
[Z
] = v
.v
[Z
];
391 #ifndef USE_IMU_FAKE // fixes Test Unit compilation error
392 setGyroCalibration(dev
->gyroZero
);
395 LOG_DEBUG(GYRO
, "Gyro calibration complete (%d, %d, %d)", (int16_t) dev
->gyroZero
[X
], (int16_t) dev
->gyroZero
[Y
], (int16_t) dev
->gyroZero
[Z
]);
396 schedulerResetTaskStatistics(TASK_SELF
); // so calibration cycles do not pollute tasks statistics
398 dev
->gyroZero
[X
] = 0;
399 dev
->gyroZero
[Y
] = 0;
400 dev
->gyroZero
[Z
] = 0;
405 * Calculate rotation rate in rad/s in body frame
407 void gyroGetMeasuredRotationRate(fpVector3_t
*measuredRotationRate
)
409 for (int axis
= 0; axis
< 3; axis
++) {
410 measuredRotationRate
->v
[axis
] = DEGREES_TO_RADIANS(gyro
.gyroADCf
[axis
]);
414 static bool FAST_CODE NOINLINE
gyroUpdateAndCalibrate(gyroDev_t
* gyroDev
, zeroCalibrationVector_t
* gyroCal
, float * gyroADCf
)
417 // range: +/- 8192; +/- 2000 deg/sec
418 if (gyroDev
->readFn(gyroDev
)) {
420 #ifndef USE_IMU_FAKE // fixes Test Unit compilation error
421 if (!gyroConfig()->init_gyro_cal_enabled
) {
422 // marks that the gyro calibration has ended
423 gyroCalibration
[0].params
.state
= ZERO_CALIBRATION_DONE
;
424 // pass the calibration values
425 gyroDev
->gyroZero
[X
] = gyroConfig()->gyro_zero_cal
[X
];
426 gyroDev
->gyroZero
[Y
] = gyroConfig()->gyro_zero_cal
[Y
];
427 gyroDev
->gyroZero
[Z
] = gyroConfig()->gyro_zero_cal
[Z
];
431 if (zeroCalibrationIsCompleteV(gyroCal
)) {
432 float gyroADCtmp
[XYZ_AXIS_COUNT
];
434 //Apply zero calibration with CMSIS DSP
435 arm_sub_f32(gyroDev
->gyroADCRaw
, gyroDev
->gyroZero
, gyroADCtmp
, 3);
437 // Apply sensor alignment
438 applySensorAlignment(gyroADCtmp
, gyroADCtmp
, gyroDev
->gyroAlign
);
439 applyBoardAlignment(gyroADCtmp
);
441 // Convert to deg/s and store in unified data
442 arm_scale_f32(gyroADCtmp
, gyroDev
->scale
, gyroADCf
, 3);
446 performGyroCalibration(gyroDev
, gyroCal
);
448 // Reset gyro values to zero to prevent other code from using uncalibrated data
456 // no gyro reading to process
461 void FAST_CODE NOINLINE
gyroFilter(void)
463 if (!gyro
.initialized
) {
467 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
468 float gyroADCf
= gyro
.gyroADCf
[axis
];
470 #ifdef USE_RPM_FILTER
471 gyroADCf
= rpmFilterGyroApply(axis
, gyroADCf
);
475 DEBUG_SET(DEBUG_LULU
, axis
, gyroADCf
); //Pre LULU debug
476 float preLulu
= gyroADCf
;
477 gyroADCf
= gyroLuluApplyFn((filter_t
*) &gyroLuluState
[axis
], gyroADCf
);
478 DEBUG_SET(DEBUG_LULU
, axis
+ 3, gyroADCf
); //Post LULU debug
481 DEBUG_SET(DEBUG_LULU
, 6, gyroADCf
- preLulu
); //LULU delta debug
485 gyroADCf
= gyroLpf2ApplyFn((filter_t
*) &gyroLpf2State
[axis
], gyroADCf
);
487 #ifdef USE_ADAPTIVE_FILTER
488 adaptiveFilterPush(axis
, gyroADCf
);
491 #ifdef USE_DYNAMIC_FILTERS
492 if (dynamicGyroNotchState
.enabled
) {
493 gyroDataAnalysePush(&gyroAnalyseState
, axis
, gyroADCf
);
494 gyroADCf
= dynamicGyroNotchFiltersApply(&dynamicGyroNotchState
, axis
, gyroADCf
);
498 * Secondary dynamic notch filter.
499 * In some cases, noise amplitude is high enough not to be filtered by the primary filter.
500 * This happens on the first frequency with the biggest aplitude
502 gyroADCf
= secondaryDynamicGyroNotchFiltersApply(&secondaryDynamicGyroNotchState
, axis
, gyroADCf
);
506 #ifdef USE_GYRO_KALMAN
507 if (gyroConfig()->kalmanEnabled
) {
508 gyroADCf
= gyroKalmanUpdate(axis
, gyroADCf
);
512 gyro
.gyroADCf
[axis
] = gyroADCf
;
515 #ifdef USE_DYNAMIC_FILTERS
516 if (dynamicGyroNotchState
.enabled
) {
517 gyroDataAnalyse(&gyroAnalyseState
);
519 if (gyroAnalyseState
.filterUpdateExecute
) {
520 dynamicGyroNotchFiltersUpdate(
521 &dynamicGyroNotchState
,
522 gyroAnalyseState
.filterUpdateAxis
,
523 gyroAnalyseState
.centerFrequency
[gyroAnalyseState
.filterUpdateAxis
]
526 secondaryDynamicGyroNotchFiltersUpdate(
527 &secondaryDynamicGyroNotchState
,
528 gyroAnalyseState
.filterUpdateAxis
,
529 gyroAnalyseState
.centerFrequency
[gyroAnalyseState
.filterUpdateAxis
]
538 void FAST_CODE NOINLINE
gyroUpdate(void)
541 if (ARMING_FLAG(SIMULATOR_MODE_HITL
)) {
542 //output: gyro.gyroADCf[axis]
543 //unused: dev->gyroADCRaw[], dev->gyroZero[];
547 if (!gyro
.initialized
) {
551 if (!gyroUpdateAndCalibrate(&gyroDev
[0], &gyroCalibration
[0], gyro
.gyroADCf
)) {
555 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
556 // At this point gyro.gyroADCf contains unfiltered gyro value [deg/s]
557 float gyroADCf
= gyro
.gyroADCf
[axis
];
559 // Set raw gyro for blackbox purposes
560 gyro
.gyroRaw
[axis
] = gyroADCf
;
563 * First gyro LPF is the only filter applied with the full gyro sampling speed
565 gyroADCf
= gyroLpfApplyFn((filter_t
*) &gyroLpfState
[axis
], gyroADCf
);
567 gyro
.gyroADCf
[axis
] = gyroADCf
;
571 bool gyroReadTemperature(void)
573 if (!gyro
.initialized
) {
577 // Read gyro sensor temperature. temperatureFn returns temperature in [degC * 10]
578 if (gyroDev
[0].temperatureFn
) {
579 return gyroDev
[0].temperatureFn(&gyroDev
[0], &gyroTemperature
[0]);
585 int16_t gyroGetTemperature(void)
587 if (!gyro
.initialized
) {
591 return gyroTemperature
[0];
594 int16_t gyroRateDps(int axis
)
596 if (!gyro
.initialized
) {
600 return lrintf(gyro
.gyroADCf
[axis
]);
603 void gyroUpdateDynamicLpf(float cutoffFreq
) {
604 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
605 pt1FilterUpdateCutoff(&gyroLpf2State
[axis
].pt1
, cutoffFreq
);
609 float averageAbsGyroRates(void)
611 return (fabsf(gyro
.gyroADCf
[ROLL
]) + fabsf(gyro
.gyroADCf
[PITCH
]) + fabsf(gyro
.gyroADCf
[YAW
])) / 3.0f
;