Skip to content

Conversation

@sensei-hacker
Copy link
Member

@sensei-hacker sensei-hacker commented Jan 3, 2026

User description

Summary

Improves safety of Airspeed-based PID Attenuation (APA) feature with automatic pitot sensor validation and more conservative gain limits.

Changes

Pitot Sensor Validation:

  • Automatically detects blocked or failed pitot tubes by comparing against GPS+wind airspeed
  • Displays "PITOT FAIL" OSD warning when pitot reading is implausible
  • Automatically falls back to GPS-based airspeed when pitot fails
  • Prevents dangerous high gains from invalid pitot data

Safer Gain Limits:

  • Maximum gain reduced from 200% to 150% for more conservative operation
  • I-term scaling reduced to prevent integral windup at low speeds
  • Better control stability across the speed envelope

Safe Defaults:

  • APA now defaults to disabled (apa_pow = 0)
  • Pilots must explicitly enable after validating pitot sensor
  • Existing configurations unchanged

Testing

  • Hardware builds: ✅ Verified (MATEKF405SE, SITL)
  • Runtime testing: Requires flight testing with pitot sensor

Related Issues

Closes #11208

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Jan 3, 2026

PR Compliance Guide 🔍

All compliance sections have been disabled in the configurations.

@sensei-hacker sensei-hacker force-pushed the implement-pitot-sensor-validation branch 2 times, most recently from d38c246 to 9afef93 Compare January 3, 2026 06:16
Implements pitot sensor validation by comparing hardware pitot readings
against virtual airspeed (GPS + wind estimator). Detects blocked or
failed pitot tubes and automatically falls back to GPS-based airspeed.

Features:
- Compares pitot against virtual airspeed (wind-corrected, not raw GPS)
- Wide thresholds (30%-200%) catch gross failures while avoiding false positives
- Sustained failure detection (1 second) before declaring sensor failed
- Automatic fallback to GPS airspeed when pitot fails validation
- OSD warning displays "PITOT FAIL" when sensor invalid
- Automatic recovery after 0.5 seconds of good readings
- Conservative approach: only validates when GPS available and moving >7 m/s

Safety improvements:
- Detects blocked pitot tubes (forgotten cover, insects, ice)
- Prevents dangerous high gains with invalid pitot data
- Maintains aircraft controllability when pitot fails
- Clear pilot awareness via OSD warning

Addresses GitHub issue #11208
Changes to Airspeed-based PID Attenuation (APA) for fixed-wing aircraft:

1. Reduced I-term scaling aggressiveness
   - I-term now scales with (apa_pow/100 - 1) instead of apa_pow/100
   - Example: apa_pow=120 → I uses 0.20 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
Clamp airspeed to 100-20000 cm/s (3.6-720 km/h) before using in
power calculations to prevent:
- Division by zero or near-zero values
- NaN results from invalid airspeed readings
- Overflow from extreme values

The constrainf() output clamps are still in place as the final safeguard,
but this prevents bad intermediate calculations.
@sensei-hacker sensei-hacker added this to the 9.0 milestone Jan 3, 2026
@MrD-RC
Copy link
Member

MrD-RC commented Jan 3, 2026

I have a couple of questions:

  1. Does APA only work if GPS is enabled? In theory it shouldn't need to be. But the tests for the pitot blockage rely on the virtual airspeed sensor (wind + ground speed). So what happens if GPS is disabled?

  2. Likewise, what happens if the virtual airspeed sensor is deemed unreliable? For example, you have been flying in a straight line for 10 minutes. So the wind estimation is stale.

  3. Did any aircraft in the testing require gains between 150-200%? Or were some marginal at 150%? If so, the higher gains may still be necessary.

I agree with apa_pow defaulting to 0. To use this feature an airspeed sensor needs to be enabled. By default they are not. So long as there are sensible starting point examples in the documentation. I think this is all good.

@sensei-hacker
Copy link
Member Author

sensei-hacker commented Jan 3, 2026

Excellent questions, thank you!
I'm going to write out my thinking here so that hopefully you or someone can catch any mistakes I am making.

  1. Does APA only work if GPS is enabled? In theory it shouldn't need to be. But the tests for the pitot blockage rely on the virtual airspeed sensor (wind + ground speed). So what happens if GPS is disabled?

This is what I'm seeing; please tell me if you see anywhere I am mistaken:

getVirtualAirspeedEstimate() returns 0 if GPS is not available
That's less than minValidationSpeed (minimum speed for the GPS-based reading to be used), so isPitotReadingPlausible() returns true

So the pitot reading is treated as plausible and the failure counter in pitotValidForAirspeed() does not increase -- APA is used.

I am also attaching a PDF with flowcharts and a decision table. That document is of course not authoritative - the code is.
APA_TPA_Decision_Logic.pdf

  1. Likewise, what happens if the virtual airspeed sensor is deemed unreliable? For example, you have been flying in a straight line for 10 minutes. So the wind estimation is stale.

wind_estimator.c will virtually never deem the wind estimate unreliable while the aircraft is moving, so let's consider the case where the wind estimator calls itself reliable, but the data isn't great. Suppose the following actual speeds:

stale headwind estimate: 20 km/h
true current headwind  30 km/h
ground speed: 20 km/h

true airspeed (and pitot reading):: 50 km/h
estimated airspeed: 40 km/h

The pitot will be treated as plausible if reading is between 30-200% of the estimate.
That is, between (estimate * 0.3) and - (estimate * 2.0)
Here it is estimate * 1.25, WELL within the range of plausibility!

Let's try another:

stale headwind estimate: 40 km/h
true current headwind  20 km/h
ground speed: 40 km/h

true airspeed (and pitot reading): 60 km/h
estimated airspeed: 80 km/h

Still not even close to being treated as implausible.

What if we fly really slow, only 10 km/h actual airspeed, with a strong tailwind? (With the wind being stronger than our airspeed, which will mess up other things)

stale tailwind estimate: 40 km/h
true current tailwind  20 km/h
ground speed:  30 km/h

true airspeed (and pitot reading): 10  km/h
estimated airspeed: -10 km/h

NOW it wouldn't be trusted and would revert to the existing TPA behavior, if the stale wind estimate is four times higher than our airspeed.
So lesson learned - if the wind is much faster than your airspeed, you may get TPA. (also, your plane just got blown to the next town over since it's airspeed is much less than the wind speed).

  1. Did any aircraft in the testing require gains between 150-200%? Or were some marginal at 150%? If so, the higher gains may still be necessary.

What gains (and therefore effective P-term and D-term) are "required" is of course a bit subjective and hard to measure - the PID loop will make things work with a range of PID/FF values. So this is an area it would be good to get feedback from testers - preferably with very clear observations of behavior, and blackbox logs would be wonderful. The earlier testing (RC4) improperly scaled the I-term changes, probably overdriving I and making the low-speed tests no longer applicable.

150 (50% increase) is conservative, IMHO. But 0% flew just fine for years before we had TPA.

@MrD-RC
Copy link
Member

MrD-RC commented Jan 3, 2026

  1. Does APA only work if GPS is enabled? In theory it shouldn't need to be. But the tests for the pitot blockage rely on the virtual airspeed sensor (wind + ground speed). So what happens if GPS is disabled?

This is what I'm seeing; please tell me if you see anywhere I am mistaken:

getVirtualAirspeedEstimate() returns 0 if GPS is not available That's less than minValidationSpeed (minimum speed for the GPS-based reading to be used), so isPitotReadingPlausible() returns true

Shouldn't this instead be false; as there is no way to validate the airspeed sensor? So we don't know if it's reading is plausible or not. Erring on the side of caution, but it is a safety feature. It does tie having an airspeed sensor to needing a GPS. But we could always make an explicit parameter, with a warning, to bypass that safety check if no GPS is found. Then it's the pilot's responsibility if they disable the safety feature and things go wrong.

  1. Likewise, what happens if the virtual airspeed sensor is deemed unreliable? For example, you have been flying in a straight line for 10 minutes. So the wind estimation is stale.

wind_estimator.c will virtually never deem the wind estimate unreliable while the aircraft is moving.

I seem to recall that the wind estimate is marked as stale (unreliable) after 10 minutes of flying in the same direction. It will show an X in the OSD to warn that the wind speed reading is stale.

so let's consider the case where the wind estimator calls itself reliable, but the data isn't great. Suppose the following actual speeds:

stale headwind estimate: 40 km/h
true current headwind  20 km/h
ground speed: 40 km/h

true airspeed (and pitot reading): 60 km/h
estimated airspeed: 80 km/h

Still not even close to being treated as implausible.

Honestly, I'd have expected that to start being close to implausible. 200% seems like a big difference. If I'm seeing 20km/h difference at those sorts of speeds. I start not trusting the airspeed sensor. Usually calibration could be out. But not that the tube is blocked (unless it's reading wildly under). I'm visually looking at +/- ~30% difference at most for my known flying speed. Usually it is much closer, easily within 5-10%. Perhaps this could issue a calibration warning on the OSD. Then not fully trust the airspeed at higher values?

  1. Did any aircraft in the testing require gains between 150-200%? Or were some marginal at 150%? If so, the higher gains may still be necessary.

What gains (and therefore effective P-term and D-term) are "required" is of course a bit subjective and hard to measure - the PID loop will make things work with a range of PID/FF values. So this is an area it would be good to get feedback from testers - preferably with very clear observations of behavior, and blackbox logs would be wonderful. The earlier testing (RC4) improperly scaled the I-term changes, probably overdriving I and making the low-speed tests no longer applicable.

150 (50% increase) is conservative, IMHO. But 0% flew just fine for years before we had TPA.
True. But I think I recall one of the testers requesting a higher value at one stage. Because the values at the time weren't enough for their aircraft. If this new feature calls for a slightly higher range. It would be nice if it's there from the get-go.

I'll trust the opinions of the @Jetrell and the guys who were testing this extensively with regard to this. I just wouldn't want to make this feature inapplicable in some applications. Especially when it's the result of one guy, who likely had his PIDs tuned too tightly.

@sensei-hacker
Copy link
Member Author

sensei-hacker commented Jan 3, 2026

I seem to recall that the wind estimate is marked as stale (unreliable) after 10 minutes of flying in the same direction. It will show an X in the OSD to warn that the wind speed reading is stale.

I'm showing 15 minutes without a combined change in pitch and yaw, 11.5 degrees. A bit higher than I was thinking.
There is a quite a bit of math involved to compute the threshold of 11.5 degrees.

#define WINDESTIMATOR_TIMEOUT 60*15 // 15min with out altitude change

Shouldn't this instead be false; as there is no way to validate the airspeed sensor? S

Let's consider what we do with other sensors. If the gyro is giving reasonable readings, maybe 30 degrees per second, and we have no other sensor to cross-validate, do we throw out the gyro reading, mark it as untrusted?

If the GPS is giving reasonable location and speed readings, and we have no other location sensor to cross-validate, do we throw out the GPS reading, mark it as untrusted?

Heck, if the RC commands from the receiver are reasonable values 1000us-2000us and we have no other source to cross-validate ...

If every source of input required two independent sources -- well we'd be Ardupilot. 😀
( Kidding, Ardupilot doesn't do that. Boeing doesn't. Airbus might.)

If I'm seeing 20km/h difference at those sorts of speeds.

Would you rather trust that the ground speed is the same as the airspeed? (Which will never be true for an airplane in flight). So long as the airspeed sensor isn't giving clearly questionable readings (-1, or INT16_MAX), I would treat it as the most reliable source of airspeed data, barring clear reason not to. Full scale pilots are trained that if your pitot says one thing and your eyes say another, trust your instruments more than your eyes. Given reasonable readings, I would certainly trust it more than the alternatives, which are guaranteed to be wrong.

I'll trust the opinions of the @Jetrell and the guys who were testing this extensively with regard to this.

Jetrell is amazing. And cross-validation is always good when can get it, so I'd also love to hear from anyone else who has some data. Especially with blackbox data. "Data is king."

@MrD-RC
Copy link
Member

MrD-RC commented Jan 3, 2026

To be honest, with ground speed + wind speed available. I would use that as a pretty good indicator within reason. Certainly enough for a sanity check. If it's more than +/-50% off. Something is wrong.

I completely agree with not trusting your eyes. Anyone who's flown lowish over water knows how deceiving that is. But, I would also say there are big differences between full size pitots and the size most people are using. The hole is tiny on the hobby tubes. I've seen a couple of occurrences of them getting foreign matter in there. It doesn't always completely block the tube too. So you still get readings. They're just off. We actually moved to a larger pitot tube to get away from this issue. But people in the hobby wouldn't. Mainly because of thse size.

So would I 100% trust a pitot tube over everything else at the hobby scale? No.

@sensei-hacker
Copy link
Member Author

sensei-hacker commented Jan 3, 2026

I've seen a couple of occurrences of them getting foreign matter in there. It doesn't always completely block the tube too. So you still get readings.

I would love to see those blackbox logs and see if higher-frequency components of the reading fluctuate a lot more than a clear tube, or any other signs we could pay attention to. I suppose a sudden drop in reported airspeed that doesn't correlate with either accelerometer or GPS could be a clue. If the airspeed drops from 60 km/h to 20 km/h in just 20 milliseconds, something is wrong. That would be a deceleration of 30G.

I'm more comfortable looking at things like that. A bug strike or similar would be a sudden event, a sudden big change in reported speed. We pretty much know the aircraft didn't decelerate at 30G and remain in one piece, so that gives us a solid reason to say something is wrong with that pitot data.

@Jetrell
Copy link

Jetrell commented Jan 3, 2026

After again reviewing the changes @sensei-hacker made in these commits. It seems like it now accounts for far more failure conditions.

Especially when it's the result of one guy, who likely had his PIDs tuned too tightly.

@MrD-RC I think that tuning the PID's too tight could always be a point of concern. Because it leaves little room for sensor deviation. I made a few notes about that in the Wiki.
When I was testing the RC4 logic using virtual airspeed. I travel a long distance in a straight line in Cruise to see what would happen if that data become untrusted.
I did notice some virtual airspeed fluctuations. However it didn't see it become untrusted.. The only time I seen this occur in flight, was once at launch. When the wind estimator was slow to provide data.. In this case, with the RC 4 logic. The roll axis started to oscillate for a quick second until the date became trusted.

Edit : @sensei-hacker we are heading off soon. But I'll have a quick look and see if I can find that log to DM it to you.

@Jetrell
Copy link

Jetrell commented Jan 5, 2026

I started to write a draft for these changes to update the wiki once this is tested and merged.
But as I was writing I noticed that the default settings aren't really that adequate.
Even setting apa_pow = 0 as default to disable it isn't ideal. Because the default TPA + pitch angle settings aren't good. I mentioned this in the wiki. But most users will likely ignore it, while not grasping the fullness of how much pitch actually influences raw throttle in the adjustment of the gains when that function is in operation.

You may say. Isn't it the same attenuation/boost scaling as before. And the answer is yes. But now the base gains are tuned much tighter than they ever were with the old TPA/B method. And the dynamic gain control over TPA is much smoother and more incremental than before. With it always making adjustments as the planes pitch attitude changes.

I'll explain. The defaults for TPA + Pitch angle are as followed -

  • tpa_breakpoint = 1500
    With no wind, this throttle value should provide an equal amount of thrust to what is required to hold fw_reference_airspeed for the APA function. This is so the base PID tune response is roughly the same, when switching between APA and TPA + Pitch angle.
    Remembering this is a shared setting between Planes and Multicopters.
    The default of 1500 isn't too bad for either. But being that both platforms are getting more powerful. This could be lowered to something like 1400 to 1450 for both.

  • fw_tpa_time_constant = 1500 (0 to 5 seconds)
    The default of 1.5secs to delay the none instantaneous response of airspeed to a change in throttle. Its a little low to smooth gain transition for the average airframe. Increasing it to 2000 would be more useful for most models.

  • tpa_rate = 0
    The main issue here is this setting is also shared between Planes and Multicopters.
    Multicopter = 0 - 100
    Fixedwing = 0 - 200
    The default value of Zero is ideal for the way multicopter tpa_rate works. But it's not good for the operation of Fixedwing TPA + Pitch angle.
    e.g. If the plane has the base gains tuned firmly at the tpa_breakpoint. And the user raises the throttle. No attenuation will be applied to those gains as the airspeed starts to increase, leading to control surface oscillations.
    Being that this setting ranges from 0 to 200. A conservative value of 60 at least provides some higher speed attenuation.
    For optimal user support. It would require being broken into two separate settings. One for each platform. i.e. mc_tpa_rate and fw_tpa_rate.. Or at the least. Providing different defaults settings to be loaded by the configurator, when a platform is selected in setup.

  • tpa_pitch_compensation = 8 (0 to 20 - default is okay)

And when it comes to the APA side of things. I consider the default of fw_refernce_airspeed to also be a little low.
Holding a speed as low as 1500 or 54km/h on most airframes while tuning isn't that easy. They often exceed that speed easily.
That is why I set it as 70km/h in the graph. Because new users generally have little idea of what's a good value. So I figure a safer more marginal speed is better. While more advanced users can lower it to 50km/h if their goal is power management for long range.

@sensei-hacker
Copy link
Member Author

sensei-hacker commented Jan 5, 2026

Thanks, Jetrell. That all makes sense about the default TPA + Pitch angle settings.

Some of this comes back to a fundamental oversight in how TPA is currently implemented.

The fundamental problem is that it currently treats a commanded change of setpoint from pilot input the same as a uncommanded change of attitude from a wind gust or from pitch-roll coupling. Treats trying to change the attitude the same as resisting a change of attitude.

The proper response is different between those two. Between a command to change the setpoint vs an uncommanded disturbance to attitude. Trying to treat them as the same is what makes the tuning and settings necessary - trying to balance two things that shouldn't be mixed together at all. It's same thing that was discussed with the exponent for pow_apa. I'll have a PR for that in a future version.

The exponent should actually be 1, 2, or 0, depending on what you're trying to accomplish (the term). Are you trying to change course (commanding a change to the setpoint, feed-forward FF), or are you trying to resist the force of the camera gimbal acting as a rudder (uncommanded disturbance, the P-term)? The setting exists only because the current *PA code mixes these different things together, requiring a compromise between the correct value of 1 and the correct value of 2, for the different things. Trying to find a value you can live with for both when the correct value is 1 for the first thing and 2 for the second thing.
(Tuning to try to find Pi again 😃 )

Separating them will especially help for tailless planes ("flying wings"). If you command pitch, TPA should be applied at ^2 to the pitch commmand. But you will also get uncommanded roll and yaw because elevons. That correction should either not be TPAed at all, or arguably linearly. Treating them the same as why you have to do the testing and tuning to try to find a balance you can live with. So the to account for the fact that the pilot is WANTING the attitude to change.

But that's for future work. For now, we can adjust the default settings to work best with the TPA code we have.

@quadlawnmowerman-coder
Copy link

Gave this branch a try, quick first flight locally to test compile and flashing, had no issues and gave it the beans on 6s. Went out to a spot with some more room to test failures and first test with pitot sock left on failed. The code did not detect the poor data and did not display a OSD warning and I felt the impact of the increased gains almost immediately, could not test for long however as I had an ESC failure about 20sec into the flight so not much log data. Had to land some distance away from me that took a while to retrieve, so most of the log is just me fiddling the sticks on my walk to collect the airframe.

Worth noting I set the TPA rate to 0 and breakpoint to 2000 so it would not come into play during the simulated airspeed sensor data failure.

INAV_9.0.0_cli_20260106_160015.txt
LOG00002.TXT

@trailx
Copy link
Contributor

trailx commented Jan 8, 2026

I'd like to voice my disagreement of the change of the max scaling to 1.5 instead of 2.0.

tpaFactor= constrainf(tpaFactor, 0.3f, 1.5f);

I understand this feels like risk mitigation, but its a bandaid that doesn't really solve anything and neuters some of the benefits of the *PA system. I fly a penguin that has a flight envelope from 100mph to as little as 10 mph when you're flying at a high AOA. The APA system at 2x scaling is perfect for stabilizing these high AOA flights. It holds attitude beautifully even at these super low speeds due to the high gains. Its like an F35 matching speed beside a Cessna 172 - the F35 control surfaces are fluttering all over the place, but the plane is rock-steady. If we are trying to satisfy all users here, maybe this needs to be a user-set variable. Someone like me can set it to 2.0, and someone like @quadlawnmowerman-coder can set it to 0 if he wants. Though - I think IF the airspeed detection could be adequate, this change isn't necessary at all.

As a possible contributing factor, in my experience, some portion of the pitot initialization is not working right. Every time I plug in my plane (pitot sock installed), I have a residual pressure that is indicating something in the range of 7-12 mph airspeed when still sitting on the ground. At the recommendation from someone on discord, I have started restarting the FC via OSD after GNSS is satisfied, and the airspeeds appear much more accurate, and the residual pressure drops to ~0-4 mph - and returns there once landed. Not sure what your experience @quadlawnmowerman-coder is with the airspeed accuracy, but if you've got 11 mph at 0 dynamic pressure, at low speeds you could still be outside of the check that @sensei-hacker outlined:

The pitot will be treated as plausible if reading is between 30-200% of the estimate.

@sensei-hacker, why are you checking the 200% case anyway? I think the only real concern here is if the pitot reports low, and indicating a clogged tip. For the use of any *PA system, the only real concern is over-gain, because over-attenuation will not crash the plane (at least - not due to oscillations).

Is the only way to test this literally to take off with a pitot sock installed? A proper pitot sock really should be impossible to forget to remove. So we're really talking about solving either improper maintenance of the pitot tube, or the 1:1,000,000 chance of the perfect bug strike?

@quadlawnmowerman-coder do you have an OSD video of the last test you can share?

@b14ckyy
Copy link
Collaborator

b14ckyy commented Jan 9, 2026

@trailx thats great feedback!
Another question from my end: Do we ACTUALLY have a flight recorded in blackbox or even better DVR, with RC4, that shows a real problem with the 2.0 factor? Maybe I missed it but if it actually caused an issue, I would really like to check the logs.

And with the other planned validity checks in place, a blocked pitot tube should not be an issue anyway with the 2.0 factor.

@sensei-hacker
Copy link
Member Author

sensei-hacker commented Jan 9, 2026

Another question from my end: Do we ACTUALLY have a flight recorded in blackbox or even better DVR, with RC4, that shows a real problem with the 2.0 factor?

We do not. That change was simply an "abundance of caution" thing. Not based on any log, any actual experience, or any aerodynamic formula. It was purely a "it seems like maybe a good idea" thing.

Personally, I think 2.0 or higher makes more sense. If TrailX and b14ckyy agree, we'll do that.

The flight experience and log we have is from BEFORE other things were fixed.

The most recent log and report from quadlawnmowerman-coder revealed another issue. I am pushing a commit to address that right now.

When hardware pitot fails validation, getAirspeedEstimate() now returns
GPS-based virtual airspeed instead of the corrupted pitot value. This
ensures APA (Airspeed-based PID Attenuation) continues working correctly
with valid airspeed data.

Changes:
- getAirspeedEstimate() falls back to virtual airspeed when pitotHardwareFailed
- Faster failure detection: 0.2s (20 samples) vs 1s (100 samples)
- Slower recovery: 2s of consecutive good readings required
- Separate recovery counter prevents underflow with asymmetric thresholds

Fixes issue where blocked pitot caused APA to use invalid airspeed,
resulting in incorrect PID gain scaling.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@sensei-hacker
Copy link
Member Author

It looks like we have fresh builds for testing.
Screenshot_20260108-200913

@sensei-hacker
Copy link
Member Author

sensei-hacker commented Jan 9, 2026

Thanks so much for the log and report, @quadlawnmowerman-coder !

I ran that log through SITL, reproducing the flight in an instrumented environment. From that, I was able to identify two issues, which should be fixed in the latest commits here. Note I am not able to fly right now, so I have only tested my fixes by a limited simulation.

Actually I may do more simulator testing on it tomorrow, to double-check that the OSD message ACTUALLY appears.

@b14ckyy
Copy link
Collaborator

b14ckyy commented Jan 9, 2026

Yeah I would in this case also agree to leave the max gain at 2.0 at low speed. It makes sense mathematically and as long as we can exclude false low speed readings from the sensor, i see no reason for that extra caution that might reduce flight performance for the majority.

@sensei-hacker
Copy link
Member Author

sensei-hacker commented Jan 10, 2026

Thanks for your comments, @trailx

The consensus both here and on the Discord seem to be stick with 2.0 for maximum tpaFactor as originally written.
I am told testing was done when TPA was originally introduced and it was found it needed to be increased to 2.0.

Trailx wrote:

As a possible contributing factor, in my experience, some portion of the pitot initialization is not working right. Every time I plug in my plane (pitot sock installed), I have a residual pressure that is indicating something in the range of 7-12 mph airspeed when still sitting on the ground. At the recommendation from someone on discord, I have started restarting the FC via OSD after GNSS is satisfied, and the airspeeds appear much more accurate

That sounds like an Issue that should be recorded separately so it doesn't get lost and we can address that. It may be we should delay pitot calibration by a few seconds --- if it ends up mattering anyway, though I suspect it won't because of one thing:

10 MPH is about 12 Pascals, so that would be 12 Pa of error.
Because dynamic pressure is proportional to the SQUARE of airspeed, at standard temperature and pressure it will be:
12.24 Pa at 10 MPH
306.01 Pa at 50 MPH
318.38 Pa at 51 MPH
440.66 Pa at 60 MPH

So 12 Pa of error reads as less than 1 MPH difference at flight speed.
A separate issue could compare pitot airspeed vs GPS-estimated speed in a large circle to negate wind effects, and and without a restart.

You asked:

sensei-hacker, why are you checking the 200% case anyway?

My thinking is that if the GPS shows 40 MPH and the pitot is reading 2,300 MPH, maybe something is wrong with the pitot. :) In particular, one common sensor type maxes out at 223.694 MPH. If it reports infinity 223.694) while the GPS says 50 MPH, the pitot is broken. Different sesnors have different infinity / maxed out values. There's nothing special about the exact value of 200%, just trying to catch readings that look quite suspect.

A proper pitot sock really should be impossible to forget to remove.

True. And an improper one is just a piece of heat shrink with no tag, often forgotten.
About once per year a pilot of a full-size plane reports to NASA ASRS that they did that, even with a proper sock - it happens. (and I bet most cases aren't reported).

- Increase fw_tpa_time_constant default from 1500 to 2000ms
- Raise airspeed TPA factor upper limit from 1.5 to 2.0
…alidation

Adjust TPA parameters for fixed-wing aircraft
Updated fw_tpa_time_constant default value from 1500 to 2000 in Settings.md
to match the authoritative value in settings.yaml. The discrepancy was caused
by the documentation being out of sync with the YAML source.

Regenerated using: python3 src/utils/update_cli_docs.py
@sensei-hacker
Copy link
Member Author

sensei-hacker commented Jan 10, 2026

@Jetrell wrote:

I started to write a draft for these changes to update the wiki once this is tested and merged

Thanks so much for doing that. If you want to chuckle at the different places a bot thought could be updated:

Documentation Updates for PR #11222

Pitot Sensor Validation & APA Safety Improvements


Summary of Changes

PR #11222 implements:

  • Pitot sensor validation - Detects blocked/failed pitot tubes using GPS+wind cross-validation
  • Automatic fallback - Uses GPS-based virtual airspeed when pitot fails
  • OSD warning - "PITOT FAIL" message when sensor unreliable
  • Safer defaults - apa_pow now defaults to 0 (disabled) instead of 120 (Until at least INAV 9.1)
  • Improved I-term scaling - Less aggressive scaling

✅ Already Updated in PR

  • inav/docs/Settings.md - Parameter descriptions and defaults
  • inav/src/main/fc/settings.yaml - Settings definitions

🔴 Most important updates

inavwiki/PID-Attenuation-and-scaling.md

File: https://github.com/iNavFlight/inav/wiki/PID-Attenuation-and-scaling

Line 52: Update default value

  • Current: "Increasing its value from the default of 120..."
  • Add note: - in INAV 9.0, APA defaults to disabled (0). If you want to try this feature, 120 is the recommended value

Line 67-68: Update pitot reliability warning

  • Current: "Neither airspeed source is perfect. A Pitot tube can become partially blocked..."
  • Add after existing text:
**When INAV automatically detects pitot failures:**
- Compares pitot readings against GPS+wind virtual airspeed
- Automatically falls back to virtual airspeed if pitot reading is implausible
- Displays "PITOT FAIL" OSD warning when fallback is active
- Aircraft remains controllable with correct APA gains during fallback

Line 57: Update fallback behavior note

  • Current: "If either GNSS data or the Pitot sensor data becomes untrusted..."
  • Clarify: Add that pitot validation failures trigger automatic fallback with "PITOT FAIL" warning

🟢 MEDIUM PRIORITY - Nice to Have

inavwiki/Sensor-auto-detect-and-hardware-failure-detection.md

File: https://github.com/iNavFlight/inav/wiki/Sensor-auto-detect-and-hardware-failure-detection

  • After line 28: Add section on runtime pitot validation (INAV 9.1+)
  • Explain: Hardware detection at startup vs runtime validation during flight
  • Note: Pitot failures during flight don't prevent arming (automatic fallback instead)

inavwiki/Fixed-Wing-Guide.md

Mention pitot and/or APA?

inavwiki/Tune-INAV-PID‐FF-controller-for-fixedwing.md ?

@quadlawnmowerman-coder
Copy link

Actually I may do more simulator testing on it tomorrow, to double-check that the OSD message ACTUALLY appears.

I am away for work for the next few days unfortunately @sensei-hacker so I won't get a chance to test until my return.

The consensus both here and on the Discord seem to be stick with 2.0 for maximum tpaFactor as originally written.
I am told testing was done when TPA was originally introduced and it was found it needed to be increased to 2.0.

I don't see an issue increasing it once the data sanity check is confirmed working, but I think the apa-pow settings should also be split at the same time to enable control of the below and above fw_reference_airspeed rates changes independently so as to provide the ability to directly influence/tune above and below gain changes separately.

@Jetrell
Copy link

Jetrell commented Jan 11, 2026

Thanks so much for doing that. If you want to chuckle at the different places a bot thought could be updated:

@sensei-hacker
No problems mate. I'll load the updated info after this is merged... I didn't do it now in case others are still using RC4, and require the current documentation to tune with.
I'm also still away without planes for another couple of weeks. So I'll have to leave testing to the other guys if I don't get back before then.

@sensei-hacker sensei-hacker merged commit a06dd93 into maintenance-9.x Jan 11, 2026
23 checks passed
@trailx
Copy link
Contributor

trailx commented Jan 14, 2026

I think the apa-pow settings should also be split at the same time to enable control of the below and above fw_reference_airspeed rates changes independently so as to provide the ability to directly influence/tune above and below gain changes separately.

@quadlawnmowerman-coder , I don't think I follow the reason behind this. Its not like we're entering different realms of aerodynamics with different fluid compressibility, which could be an argument for changing the pow above and below the breakpoint or ref airspeed. Based on the physics, a continuous gain tune makes sense here.

One challenge is that to my knowledge the Airspeed POW has not been added to the adjustments tab yet - which would allow in-flight tuning. I've dialed in all my planes this way, but APA is not currently accessible in flight. So fine-tuning with guess-and-check of this parameter is difficult. (There's certainly a chance this has been done since my last test)

That said, I think if you follow the following steps:

  • Tune at ref airspeed, find P oscillation point, back-off by x0.85.
  • Fly slower, if you meet an oscillation, lower the APA-Pow until you no longer see an oscillation
  • Fly faster than ref, if you meet an oscillation, raise the APA-Pow until you no longer see an oscillation
  • If you see an oscillation when flying both faster and slower and cannot find the right middle ground APA-pow, then P is too high and needs to be reduced (though I think this is unlikely)

Then you should be able to get it really well dialed in without having to mess around with a high speed APApow and a low speed APApow.

Is there a scenario I'm missing that you think requires this?

I am contending with winter weather and haven't been able to fly lately, and a maiden flight of a new plane may take priority during the next decent day.

@Jetrell
Copy link

Jetrell commented Jan 15, 2026

  • Fly faster than ref, if you meet an oscillation, raise the APA-Pow until you no longer see an oscillation

The effect apa_pow has over high and low speed flight either side of fw_reference_airspeed is the same.
Meaning that if you experience oscillations towards the top end of the scaling range, you lower apa_pow. And if you experience oscillations at the bottom end of the scaling range, you also lower it.

All apa_pow effectively does is reduces or increase the scaling responsiveness. And reducing it, by way of the math will also broaden the whole boost/attenuation speed range at which the scaling takes place over. As can be seen in the plot.

So if you experience oscillation before minimum touch down speed on a fast airplane that has fw_reference_airspeed set higher. You can either -

  • Lower apa_pow significantly. Maybe 90 down to 70. Which also means the gains won't be attenuated as strongly at the actual top speed of the airplane. Unless it can reach in excess of 250 to 350km/h.

  • Lower the base gain tune at fw_reference_airspeed. Which by nature will also reduce the overall gain scaling response at the top and bottom end of the curve,

  • Move fw_reference_airspeed down to a lower speed setpoint. This setting is a reference for the APA feature. Its actual setpoint is not excessively critical.. In fact that setting is more critical for use of dead reckoning, than for this feature.
    e.g. If you tune your base gains very tight at 100km/h, for a fast airplane. Then you lower the setpoint of fw_reference_airspeed from 100km/h down to 75km/h. This means the base gains will now be less attenuated with reference to the actual flight speed air density at the lowered fw_reference_airspeed. So full scaled boost won't occur until below touch down speed.
    With the only drawback being, full scaled attenuation will be reached at a slightly lower top speed... So you then adjust apa_pow accordingly.

This may all sound like workarounds. But that's the whole point of adjustable settings. So they can be tuned to suit the 5% of non typical airframes. That the defaults don't work as well with.

@sensei-hacker
Copy link
Member Author

sensei-hacker commented Jan 15, 2026

You may not want to tune apa_pow that much based on oscillation - that may be more the base PIFF and rates. If you have oscillation at apa_pow 100, your PIFF are simply too high. (Probably mostly P). Putting in negative expo by lowering apa to less than unity would be a bodge, not a proper fix.

Really, for apa_pow, if you do NOT want strong stabilization against turbulence etc, set it close to 100 (which is really 1, a straight line). 100 does "the right thing" aerodynamically if you assume the control surfaces are used only for performing maneuvers, based on stick input or position commands. 100 means the ailerons and elevator follow the sticks, they don't do much stabilization against turbulence etc.

If you want more stabilization against turbulence etc, the aerodynamic effect of moving your camera gimbal, etc increase it. Closer to 200 (really 2) is the right fluid dynamics for a plane flying straight and level, only being stabilized against outside disturbances. So for cruise mode or long, straight missions. 200 would be "I don't plan to use the sticks at all, just keep it flying straight and level".

Around 120-130 is a compromise, saying "mostly the control surfaces respond to my sticks, but also I want some stabilization".

apa_pow below 100 will make the control response too flat in all conditions. Too much deflection at higher speeds and too little at lower speeds. apa_pow below 100 would be like having negative expo on your sticks. In fact, it actually WOULD be requesting negative expo on the I-term, saying that the surfaces should deflect FURTHER at higher speeds.

I have a check in the code to prevent it from actually going negative for I (below a setting of 100) because that's obviously wrong. If you set less than 100, it'll just act like you set 100, for the I-term. apa_pow below 100 is a bit like if someone set a cruise speed of -25 km/h. Clearly wrong. Really, logically valid values are 100-200, or 0 to turn it off and fly like you don't have FC, using your fingers to reduce movement at higher speeds.

If you're setting apa_pow below 100 to offset an issue at a certain velocity, that's likely a band-aid for having wrong PIFF settings to start with. Lower the P or FF.

I don't see much to test and tune with this parameter unless you can repeatedly fly through the same turbulence. (Maybe at a cliff edge?) That's really what the setting does - higher for more rejection of turbulence. Lower to follow the sticks more closely.

Use the P term, not the airspeed expo, to control how much the surfaces move when you move the sticks.

apa_pow below 100 is almost like saying "do the opposite of what my sticks are commanding". If you find you need to SUBTRACT motion by having negative apa_pow, the P or FF is too dang high. (Below 100 is essentially negative expo).

Maybe we should name the setting "turbulence_rejection" or similar to make it clear.

@trailx
Copy link
Contributor

trailx commented Jan 15, 2026

@sensei-hacker , double check the way you're thinking about apa_pow. I think you're forgetting its an inverse power. pid_multiplier = referenceAirspeed / (airspeed ^ (apa_pow/100) ) So it only goes to a line when apa_pow = 0.

A while back I had worked up this graph outlining a few examples of how the attenuation curve moves based on ref_airspeed and apa_pow:

image

apa_pow can absolutely be tuned based on the presence of oscillation, because that is exactly its job (at least at high speeds). Attenuation - because if you don't have it, the PIDs become too strong at high speeds, creating oscillations. This is how I knew the first draft of APA wasn't strong enough - because it generated oscillations at high speed.

If it generates oscillations at a high speed above ref_airspeed, then there is not enough attenuation, so apa_pow needs to be raised (which may sound counter intuitive).

If it generates oscillations at low speed, then the apa_pow line is too steep, and apa_pow needs to be reduced to flatten the gain/attenuation curve a little.

@Jetrell you're right, you can also move the ref_airspeed down which effectively scales the whole curve in the airspeed axis, effectively very similar to just raising and lowering the PIDs.

@Jetrell
Copy link

Jetrell commented Jan 15, 2026

@sensei-hacker

I don't see much to test and tune with this parameter unless you can repeatedly fly through the same turbulence.

I played around with the tuning of it a couple of months back when testing its operation. I adjusted it from between 80 on a very quick airplane. Upto 200 on a park-flyer.
I could see its benefit on slower planes when it was increased, while flying in windy conditions.
And I also noticed it had some benefit by lowering it. So to not reduce the base gains too much. And not cause oscillations at the extremes of the scaling range on fast airplanes. But that was before changes have been made. Which I haven't had the time to test whether they make workarounds better or worse.

But as you said. I really doubt that setting needs much inflight tuning. In general, just roughly working out what you should require in theory from the plot is good enough.

If you find you need to SUBTRACT motion by having negative apa_pow, the P or FF is too dang high.

Pretty much. I agree. The math scaling does get a bit sloppy the lower you take it. From memory it was around 25000km/h at the low end of apa_pow.

However it can still act as a workaround to provide some boardening of the scaling to suit airplanes that have a very high top-end speed. As mentioned earlier. Remembering, this is an edge case.
Lowering the gains at the fw_reference_airspeed is certainly a better way to go about it. But that isn't always desirable if the user also doesn't want their airplane feeling too loose at fw_reference_airspeed.
I guess tuning is always a balancing act on some models. Because its hard for opensource software to account for every variation of hardware it will be applied too.

Maybe the math could have been done better. But we have what we have. And it's still much better than what we had for 95% of users :-)

@sensei-hacker
Copy link
Member Author

sensei-hacker commented Jan 15, 2026

Rmemeber what Jetrell played around with a couple months ago was a different implementation, with different characteristics. Do not confuse the older implementation with the current one, and which removes the additional use of apa_pow against the time integral.

The workaround to deal with the incorrect initial implementation does not apply now that it has been corrected.

referenceAirspeed / (airspeed ^ (apa_pow/100) ) So it only goes to a line when apa_pow = 0.

With apa_pow = 100 (which really means 1):
y = x ^ 1
x ^ 1 = x

so y = x

"y = x" is a straight line, isn't it?

Specifically, isn't it a very particular straight line - the straight line that corresponds with having the deflection (rather than the force) scale linearly with airspeed?

And with apa_pow set to 0.5, what happens? (x is apa_pow) and the I-term multiple is of course:

y ^ (x - 1)
So:
y ^ ( 0.5 - 1)
==
y ^ -0.5

Now you have a curve going the wrong direction! More deflection at higher speeds, less deflection at lower speeds.

@sensei-hacker
Copy link
Member Author

sensei-hacker commented Jan 16, 2026

To maybe clarify:

Initial testers found they needed to reduce apa_pow BECAUSE it was improperly increasing (or decreasing) the time integral term. It was 100 too high on the I-term.

Final release fixes that bug. We're no longer blowing out the I term. So you shouldn't need to cut apa_pow anymore.

@sensei-hacker
Copy link
Member Author

sensei-hacker commented Jan 16, 2026

For even more detail on the fix for the bug that was overdriving it and creating the need to reduce apa_pow by 25% to 75, look closely at this code:

 pidState->errorGyroIf += rateError * pidState->kI * dT * pidState->attenuation.aI;

Vs:

newPTerm = pTermProcess(pidState, rateError, dT) * pidState->attenuation.aP;

Note the operator is for the time integral term is "+=". The I-term is increased or decreased each loop. The I-term is the time integral. Essentially a duration counter. Measuring the length of time that the error has persisted.

You'll notice the P, D, and FF are just "=", not "+=". They are measure of the current state, not measurements of time.

It was multiplying a time interval by a power of airspeed.

Then we have:

axisPID[pidState->axis] = constrainf(newPTerm + newFFTerm + pidState->errorGyroIf + newDTerm

So when testing, the total that testers saw in the earlier version was:

axisPID[pidState->axis] = constrainf(newPTerm + newFFTerm + WRONG-I-TERM!!!! + newDTerm

It would make sense you needed to reduce apa_pow by 25% in order to subtract out the incorrect scaling of the time integral.
That's the bug that was fixed. There should be no need to manually subtract that out by reducing apa_pow by 25% anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants