Skip to content

Commit 3878e4d

Browse files
sensei-hackerclaude
andcommitted
Fix iNavFlight#9912: Add I-term stability check to servo autotrim
Prevent continuous servo autotrim from applying trim adjustments during maneuver transitions when I-term is changing rapidly due to transient error. Root Cause: The autotrim code verified all flight conditions (level attitude, centered sticks, low rotation rate) but failed to check that the I-term was in a steady state before transferring it to servo trim. During maneuver transitions (e.g., exiting a turn), I-term accumulates transient error. When the plane momentarily satisfies all level-flight conditions, this transient I-term is incorrectly transferred to servo midpoints, causing the aircraft to fly out-of-trim. Changes: - Added I-term rate-of-change tracking in processContinuousServoAutotrim() - Added stability threshold check before applying autotrim - Added configurable parameter: servo_autotrim_iterm_rate_limit (default: 2) - Only transfers I-term to trim when rate of change is below threshold The fix ensures trim updates only occur during true steady-level flight, not during transient conditions following maneuvers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 2c9854d commit 3878e4d

4 files changed

Lines changed: 26 additions & 1 deletion

File tree

docs/Settings.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6052,6 +6052,16 @@ When feature SERIALRX is enabled, this allows connection to several receivers wh
60526052

60536053
---
60546054

6055+
### servo_autotrim_iterm_rate_limit
6056+
6057+
Maximum I-term rate of change (units/sec) for autotrim to be applied. Prevents trim updates during maneuver transitions when I-term is changing rapidly. Only applies when using `feature FW_AUTOTRIM`.
6058+
6059+
| Default | Min | Max |
6060+
| --- | --- | --- |
6061+
| 2 | 0 | 50 |
6062+
6063+
---
6064+
60556065
### servo_autotrim_rotation_limit
60566066

60576067
Servo midpoints are only updated when total aircraft rotation is less than this threshold [deg/s]. Only applies when using `feature FW_AUTOTRIM`.

src/main/fc/settings.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,11 @@ groups:
13611361
default_value: 15
13621362
min: 1
13631363
max: 60
1364+
- name: servo_autotrim_iterm_rate_limit
1365+
description: "Maximum I-term rate of change (units/sec) for autotrim to be applied. Prevents trim updates during maneuver transitions when I-term is changing rapidly. Only applies when using `feature FW_AUTOTRIM`."
1366+
default_value: 2
1367+
min: 0
1368+
max: 50
13641369

13651370
- name: PG_CONTROL_PROFILES
13661371
type: controlConfig_t

src/main/flight/servos.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,7 @@ void processContinuousServoAutotrim(const float dT)
617617
static timeMs_t lastUpdateTimeMs;
618618
static servoAutotrimState_e trimState = AUTOTRIM_IDLE;
619619
static uint32_t servoMiddleUpdateCount;
620+
static float prevAxisIterm[2] = {0}; // Track previous I-term for rate-of-change calculation
620621

621622
const float rotRateMagnitudeFiltered = pt1FilterApply4(&rotRateFilter, fast_fsqrtf(vectorNormSquared(&imuMeasuredRotationBF)), SERVO_AUTOTRIM_FILTER_CUTOFF, dT);
622623
const float targetRateMagnitudeFiltered = pt1FilterApply4(&targetRateFilter, getTotalRateTarget(), SERVO_AUTOTRIM_FILTER_CUTOFF, dT);
@@ -641,7 +642,15 @@ void processContinuousServoAutotrim(const float dT)
641642
for (int axis = FD_ROLL; axis <= FD_PITCH; axis++) {
642643
// For each stabilized axis, add 5 units of I-term to all associated servo midpoints
643644
const float axisIterm = getAxisIterm(axis);
644-
if (fabsf(axisIterm) > SERVO_AUTOTRIM_UPDATE_SIZE) {
645+
646+
// Calculate I-term rate of change (per second) to detect stability
647+
const float itermRateOfChange = fabsf(axisIterm - prevAxisIterm[axis]) / 0.5f;
648+
prevAxisIterm[axis] = axisIterm;
649+
650+
// Only apply trim if I-term is stable (not changing rapidly due to recent maneuver)
651+
const bool itermIsStable = itermRateOfChange < servoConfig()->servo_autotrim_iterm_rate_limit;
652+
653+
if (fabsf(axisIterm) > SERVO_AUTOTRIM_UPDATE_SIZE && itermIsStable) {
645654
const int8_t ItermUpdate = axisIterm > 0.0f ? SERVO_AUTOTRIM_UPDATE_SIZE : -SERVO_AUTOTRIM_UPDATE_SIZE;
646655
for (int i = 0; i < servoRuleCount; i++) {
647656
#ifdef USE_PROGRAMMING_FRAMEWORK

src/main/flight/servos.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ typedef struct servoConfig_s {
170170
uint8_t servo_protocol; // See servoProtocolType_e
171171
uint8_t tri_unarmed_servo; // send tail servo correction pulses even when unarmed
172172
uint8_t servo_autotrim_rotation_limit; // Max rotation for servo midpoints to be updated
173+
uint8_t servo_autotrim_iterm_rate_limit; // Max I-term rate of change (units/sec) to apply autotrim
173174
uint8_t servo_autotrim_iterm_threshold; // How much of the Iterm is carried over to the servo midpoints on each update
174175
} servoConfig_t;
175176

0 commit comments

Comments
 (0)