Skip to content

Commit 64c2e68

Browse files
sensei-hackerclaude
andcommitted
Improve APA safety: reduce I-term scaling and maximum gain
Changes to Airspeed-based PID Attenuation (APA) for fixed-wing aircraft: 1. Reduced I-term scaling aggressiveness - I-term now scales with (apa_pow - 1) instead of apa_pow - Example: apa_pow=120 → I uses 1.19 exponent vs 1.20 for P/D/FF - Prevents integral windup and overshoot - Follows industry best practice (Betaflight, ArduPilot) - Maintains trim stability across speed range 2. Reduced maximum gain increase from 200% to 150% - Changed upper constraint from 2.0 to 1.5 - Prevents excessive gain multiplication at low speeds - More conservative approach reduces control sensitivity spikes - Still provides adequate authority for slow-speed flight 3. Changed default apa_pow from 120 to 0 (disabled) - APA now opt-in for safety - Users must explicitly enable after validating pitot sensor - Updated description to reflect new behavior - Safer default for new users Control theory rationale: - P/D/FF scaling compensates for dynamic pressure (½ρV²) - I-term serves different purpose (steady-state trim) - Aggressive I scaling causes windup and oscillation - Conservative I scaling improves control stability Combined with pitot validation (previous commit), these changes provide comprehensive safety improvements for APA feature. Addresses GitHub issue #11208 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 490065a commit 64c2e68

File tree

2 files changed

+24
-5
lines changed

2 files changed

+24
-5
lines changed

src/main/fc/settings.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,10 +1380,10 @@ groups:
13801380
min: 0
13811381
max: 100
13821382
- name: apa_pow
1383-
description: "Use airspeed instead of throttle position for PID attenuation if airspeed is available on fixedwing. pid_multiplier = (referenceAirspeed/airspeed)**(apa_pow/100). Set to 0 will disable this feature and use throttle based PID attenuation;"
1383+
description: "Use airspeed instead of throttle position for PID attenuation if airspeed is available on fixedwing. Scales P/D/FF with airspeed (I-term scaled less aggressively). Gains range from 30% (high speed) to 150% (low speed). Set to 0 to disable and use throttle-based attenuation. Recommended: 120 for aircraft with validated pitot sensor."
13841384
type: uint16_t
13851385
field: throttle.apa_pow
1386-
default_value: 120
1386+
default_value: 0
13871387
min: 0
13881388
max: 200
13891389
- name: tpa_rate

src/main/flight/pid.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,10 +446,25 @@ static float calculateFixedWingAirspeedTPAFactor(void){
446446
const float airspeed = getAirspeedEstimate(); // in cm/s
447447
const float referenceAirspeed = pidProfile()->fixedWingReferenceAirspeed; // in cm/s
448448
float tpaFactor= powf(referenceAirspeed/(airspeed+0.01f), currentControlProfile->throttle.apa_pow/100.0f);
449-
tpaFactor= constrainf(tpaFactor, 0.3f, 2.0f);
449+
tpaFactor= constrainf(tpaFactor, 0.3f, 1.5f); // Reduced from 2.0 to 1.5 (max 50% gain increase)
450450
return tpaFactor;
451451
}
452452

453+
// Calculate I-term scaling factor (less aggressive than P/D/FF)
454+
static float calculateFixedWingAirspeedITermFactor(void){
455+
const float airspeed = getAirspeedEstimate(); // in cm/s
456+
const float referenceAirspeed = pidProfile()->fixedWingReferenceAirspeed; // in cm/s
457+
const float apa_pow = currentControlProfile->throttle.apa_pow;
458+
459+
if (apa_pow <= 100.0f) {
460+
return 1.0f;
461+
}
462+
463+
float iTermFactor = powf(referenceAirspeed/(airspeed+0.01f), (apa_pow/100.0f) - 1.0f);
464+
iTermFactor = constrainf(iTermFactor, 0.3f, 1.5f);
465+
return iTermFactor;
466+
}
467+
453468
static float calculateFixedWingTPAFactor(uint16_t throttle)
454469
{
455470
float tpaFactor;
@@ -535,14 +550,18 @@ void updatePIDCoefficients(void)
535550
}
536551

537552
float tpaFactor=1.0f;
553+
float iTermFactor=1.0f; // Separate factor for I-term scaling
538554
if(usedPidControllerType == PID_TYPE_PIFF){ // Fixed wing TPA calculation
539555
if(currentControlProfile->throttle.apa_pow>0 && pitotValidForAirspeed()){
540556
tpaFactor = calculateFixedWingAirspeedTPAFactor();
557+
iTermFactor = calculateFixedWingAirspeedITermFactor(); // Less aggressive I-term scaling
541558
}else{
542559
tpaFactor = calculateFixedWingTPAFactor(calculateTPAThtrottle());
560+
iTermFactor = tpaFactor; // Use same factor for throttle-based TPA
543561
}
544562
} else {
545563
tpaFactor = calculateMultirotorTPAFactor(calculateTPAThtrottle());
564+
iTermFactor = tpaFactor; // Multirotor uses same factor
546565
}
547566
if (tpaFactor != tpaFactorprev) {
548567
pidGainsUpdateRequired = true;
@@ -560,9 +579,9 @@ void updatePIDCoefficients(void)
560579
//TODO: Next step would be to update those only at THROTTLE or inflight adjustments change
561580
for (int axis = 0; axis < 3; axis++) {
562581
if (usedPidControllerType == PID_TYPE_PIFF) {
563-
// Airplanes - scale all PIDs according to TPA
582+
// Airplanes - scale PIDs according to TPA (I-term scaled less aggressively)
564583
pidState[axis].kP = pidBank()->pid[axis].P / FP_PID_RATE_P_MULTIPLIER * tpaFactor;
565-
pidState[axis].kI = pidBank()->pid[axis].I / FP_PID_RATE_I_MULTIPLIER * tpaFactor;
584+
pidState[axis].kI = pidBank()->pid[axis].I / FP_PID_RATE_I_MULTIPLIER * iTermFactor; // Less aggressive scaling
566585
pidState[axis].kD = pidBank()->pid[axis].D / FP_PID_RATE_D_MULTIPLIER * tpaFactor;
567586
pidState[axis].kFF = pidBank()->pid[axis].FF / FP_PID_RATE_FF_MULTIPLIER * tpaFactor;
568587
pidState[axis].kCD = 0.0f;

0 commit comments

Comments
 (0)