From fd6d88e32714dddb65146e756f58b8333d039d32 Mon Sep 17 00:00:00 2001 From: Raphael Hunziker Date: Thu, 10 Sep 2026 19:59:55 +0200 Subject: [PATCH 1/2] gyro: scale zero calibration movement threshold with gyro sensitivity The movement threshold of the gyro zero calibration was a fixed number of raw sensor counts. A gyro configured for a higher sensitivity reports more counts for the same physical rotation, so its standard deviation exceeded the threshold while the board was perfectly still and the calibration restarted forever. Express the threshold as a rotation rate and convert it into sensor counts using the scale reported by the driver. At the default 16.4 LSB/dps the effective threshold stays at 32 counts. Fixes #10650 --- src/main/sensors/gyro.c | 6 +++++- src/main/sensors/sensors.h | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/sensors/gyro.c b/src/main/sensors/gyro.c index 38b56b22ae0..9e5f85cc230 100644 --- a/src/main/sensors/gyro.c +++ b/src/main/sensors/gyro.c @@ -377,7 +377,11 @@ void gyroStartCalibration(void) #endif gyroCalibrationComplete = false; - zeroCalibrationStartV(&gyroCalibration[0], CALIBRATING_GYRO_TIME_MS, CALIBRATING_GYRO_MORON_THRESHOLD, false); + // Zero calibration works on raw gyro readings, convert the movement threshold from dps into + // sensor LSB using the sensitivity of the detected gyro + const float movementThreshold = CALIBRATING_GYRO_MORON_THRESHOLD_DPS / gyroDev[0].scale; + + zeroCalibrationStartV(&gyroCalibration[0], CALIBRATING_GYRO_TIME_MS, movementThreshold, false); } bool gyroIsCalibrationComplete(void) diff --git a/src/main/sensors/sensors.h b/src/main/sensors/sensors.h index ac588581a7e..bcbbd426c52 100644 --- a/src/main/sensors/sensors.h +++ b/src/main/sensors/sensors.h @@ -43,7 +43,10 @@ typedef union flightDynamicsTrims_u { #define CALIBRATING_PITOT_TIME_MS 4000 #define CALIBRATING_GYRO_TIME_MS 2000 #define CALIBRATING_ACC_TIME_MS 500 -#define CALIBRATING_GYRO_MORON_THRESHOLD 32 +// Gyro zero calibration movement threshold, in dps. Expressed as a physical rotation rate so +// that it does not depend on the gyro sensitivity. Equals the legacy threshold of 32 LSB at +// the default scale of 16.4 LSB/dps +#define CALIBRATING_GYRO_MORON_THRESHOLD_DPS (32.0f / 16.4f) // These bits have to be aligned with sensorIndex_e typedef enum { From 668db00977ea4edd6e3506d1ce5721845a4b2fd2 Mon Sep 17 00:00:00 2001 From: Raphael Hunziker Date: Mon, 14 Sep 2026 07:01:59 +0200 Subject: [PATCH 2/2] Move the threshold conversion into a helper Asks each gyro for its own scale by index instead of hardcoding the primary. A dual-IMU board may pair two unrelated parts, so the primary's sensitivity is the wrong reference for a secondary sensor. Requested on #11933, which adds a second calibration call site in this function. --- src/main/sensors/gyro.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/sensors/gyro.c b/src/main/sensors/gyro.c index 9e5f85cc230..725f3e00f80 100644 --- a/src/main/sensors/gyro.c +++ b/src/main/sensors/gyro.c @@ -364,6 +364,15 @@ bool gyroInit(void) return true; } +/* Zero calibration works on raw gyro readings, so the movement threshold has to be + * expressed in that sensor's LSB. Each gyro is asked for its own scale: a dual-IMU + * board may pair two unrelated parts, and the primary's sensitivity would be the + * wrong reference for the secondary. */ +static float gyroMovementThreshold(uint8_t index) +{ + return CALIBRATING_GYRO_MORON_THRESHOLD_DPS / gyroDev[index].scale; +} + void gyroStartCalibration(void) { if (!gyro.initialized) { @@ -377,11 +386,7 @@ void gyroStartCalibration(void) #endif gyroCalibrationComplete = false; - // Zero calibration works on raw gyro readings, convert the movement threshold from dps into - // sensor LSB using the sensitivity of the detected gyro - const float movementThreshold = CALIBRATING_GYRO_MORON_THRESHOLD_DPS / gyroDev[0].scale; - - zeroCalibrationStartV(&gyroCalibration[0], CALIBRATING_GYRO_TIME_MS, movementThreshold, false); + zeroCalibrationStartV(&gyroCalibration[0], CALIBRATING_GYRO_TIME_MS, gyroMovementThreshold(0), false); } bool gyroIsCalibrationComplete(void)