Skip to content

Conversation

@shota3527
Copy link
Contributor

@shota3527 shota3527 commented Sep 27, 2025

User description

add a cli command to let fixed wing use airspeed based tpa.
It calculates the corresponding throttle value based on the airspeed. Ensure a seamless integration with the current throttle-based TPA. Turn it on with cli command and no more tunning is needed, fallback to old throttle based tpa if airspeed is not avaliable

tpa_breakpoint + (airspeed - fw_reference_airspeed)/fw_reference_airspeed * (tpa_breakpoint - ThrottleIdleValue(default:1150))
sim test ok

recommend to raise pitot_lpf_milli_hz on vitual pitot


PR Type

Enhancement


Description

This description is generated by an AI tool. It may have inaccuracies

  • Add airspeed-based TPA calculation for fixed-wing aircraft

  • New airspeed_tpa setting to enable airspeed TPA mode

  • Refactor TPA calculation to support both throttle and airspeed

  • Add airspeed validity check function for sensor health


Diagram Walkthrough

flowchart LR
  A["Throttle Input"] --> B["TPA Calculation"]
  C["Airspeed Sensor"] --> D["Airspeed Valid Check"]
  D --> E["Airspeed TPA Mode"]
  E --> B
  B --> F["PID Coefficients Update"]
Loading

File Walkthrough

Relevant files
Configuration changes
controlrate_profile.c
Initialize airspeed TPA setting                                                   

src/main/fc/controlrate_profile.c

  • Add airspeed_tpa field initialization to control rate profile reset
    function
+2/-1     
controlrate_profile_config_struct.h
Add airspeed TPA configuration field                                         

src/main/fc/controlrate_profile_config_struct.h

  • Add airspeed_tpa boolean field to throttle configuration structure
+1/-0     
settings.yaml
Configure airspeed TPA setting                                                     

src/main/fc/settings.yaml

  • Add airspeed_tpa setting configuration with description
  • Set default value to OFF
+5/-0     
Enhancement
pid.c
Implement airspeed-based TPA calculation                                 

src/main/flight/pid.c

  • Refactor TPA calculation to support airspeed-based mode
  • Add airspeed TPA calculation using reference airspeed
  • Modify calculateMultirotorTPAFactor to accept throttle parameter
  • Update PID coefficient calculation logic
+20/-17 
pitotmeter.c
Add airspeed sensor validity check                                             

src/main/sensors/pitotmeter.c

  • Add pitotValidForAirspeed function to check sensor validity
  • Include GPS fix requirement for virtual pitot sensors
+9/-0     
pitotmeter.h
Expose airspeed validity function                                               

src/main/sensors/pitotmeter.h

  • Add function declaration for pitotValidForAirspeed
+1/-0     
Documentation
Settings.md
Document airspeed TPA setting                                                       

docs/Settings.md

  • Add documentation for airspeed_tpa setting
  • Include formula and usage description
+10/-0   

@qodo-merge-pro
Copy link

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
⚡ Recommended focus areas for review

Possible Issue

The new multirotor TPA now takes a throttle parameter but updatePIDCoefficients passes prevThrottle, which may represent airspeed-derived or filtered values in fixed-wing mode. Ensure that for multirotor mode the raw throttle is used so attenuation matches actual RC throttle, and verify integer vs float math does not cause unintended clamping.

static float calculateMultirotorTPAFactor(uint16_t throttle)
{
    float tpaFactor;

    // TPA should be updated only when TPA is actually set
    if (currentControlRateProfile->throttle.dynPID == 0 || throttle < currentControlRateProfile->throttle.pa_breakpoint) {
        tpaFactor = 1.0f;
    } else if (throttle < getMaxThrottle()) {
        tpaFactor = (100 - (uint16_t)currentControlRateProfile->throttle.dynPID * (throttle - currentControlRateProfile->throttle.pa_breakpoint) / (float)(getMaxThrottle() - currentControlRateProfile->throttle.pa_breakpoint)) / 100.0f;
    } else {
        tpaFactor = (100 - currentControlRateProfile->throttle.dynPID) / 100.0f;
    }
Edge Conditions

The airspeed-to-throttle mapping can produce values below idle or above max; while comments say limits are applied in fixed-wing TPA, validate calculateFixedWingTPAFactor safely handles tpaThrottle outside [idle, max] to avoid negative or >1 factors.

if (usedPidControllerType == PID_TYPE_PIFF && pitotValidForAirspeed() && currentControlRateProfile->throttle.airspeed_tpa) {
    // Use airspeed instead of throttle for TPA calculation
    const float airspeed = getAirspeedEstimate(); // in cm/s
    const float referenceAirspeed = pidProfile()->fixedWingReferenceAirspeed; // in cm/s
    tpaThrottle = currentControlRateProfile->throttle.pa_breakpoint + (uint16_t)((airspeed - referenceAirspeed) / referenceAirspeed * (currentControlRateProfile->throttle.pa_breakpoint - getThrottleIdleValue()));
    //upper and lower limits will be applied in calculateFixedWingTPAFactor()
}
else if (usedPidControllerType == PID_TYPE_PIFF && (currentControlRateProfile->throttle.fixedWingTauMs > 0)) {
    tpaThrottle = pt1FilterApply(&fixedWingTpaFilter, rcCommand[THROTTLE]);
Maintainability

prevThrottle now serves as a generic TPA driver (raw, filtered, or airspeed-derived). Consider renaming to a neutral term and documenting its semantics to prevent future misuse across flight modes.

void updatePIDCoefficients(void)
{
    STATIC_FASTRAM uint16_t prevThrottle = 0;
    STATIC_FASTRAM uint16_t tpaThrottle = 0;

    if (usedPidControllerType == PID_TYPE_PIFF && pitotValidForAirspeed() && currentControlRateProfile->throttle.airspeed_tpa) {
        // Use airspeed instead of throttle for TPA calculation
        const float airspeed = getAirspeedEstimate(); // in cm/s
        const float referenceAirspeed = pidProfile()->fixedWingReferenceAirspeed; // in cm/s
        tpaThrottle = currentControlRateProfile->throttle.pa_breakpoint + (uint16_t)((airspeed - referenceAirspeed) / referenceAirspeed * (currentControlRateProfile->throttle.pa_breakpoint - getThrottleIdleValue()));
        //upper and lower limits will be applied in calculateFixedWingTPAFactor()
    }
    else if (usedPidControllerType == PID_TYPE_PIFF && (currentControlRateProfile->throttle.fixedWingTauMs > 0)) {
        tpaThrottle = pt1FilterApply(&fixedWingTpaFilter, rcCommand[THROTTLE]);
    }
    else {
        tpaThrottle = rcCommand[THROTTLE];
    }
    if (tpaThrottle != prevThrottle) {
        prevThrottle = tpaThrottle;
        pidGainsUpdateRequired = true;
    }

@qodo-merge-pro
Copy link

qodo-merge-pro bot commented Sep 27, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
The TPA implementation is overly complex

The current TPA implementation is overly complex, creating a "virtual throttle"
from airspeed. It should be replaced with a more direct approach that scales PID
gains inversely with dynamic pressure (airspeed^2).

Examples:

src/main/flight/pid.c [498-503]
    if (usedPidControllerType == PID_TYPE_PIFF && pitotValidForAirspeed() && currentControlRateProfile->throttle.airspeed_tpa) {
        // Use airspeed instead of throttle for TPA calculation
        const float airspeed = getAirspeedEstimate(); // in cm/s
        const float referenceAirspeed = pidProfile()->fixedWingReferenceAirspeed; // in cm/s
        tpaThrottle = currentControlRateProfile->throttle.pa_breakpoint + (uint16_t)((airspeed - referenceAirspeed) / referenceAirspeed * (currentControlRateProfile->throttle.pa_breakpoint - getThrottleIdleValue()));
        //upper and lower limits will be applied in calculateFixedWingTPAFactor()

Solution Walkthrough:

Before:

function updatePIDCoefficients() {
  // ...
  tpaThrottle = 0;
  if (airspeed_tpa_enabled && airspeed_is_valid) {
    // Convert airspeed to a "virtual throttle" value
    airspeed = getAirspeedEstimate();
    referenceAirspeed = pidProfile()->fixedWingReferenceAirspeed;
    tpaThrottle = breakpoint + (airspeed - referenceAirspeed) / referenceAirspeed * (breakpoint - idle_throttle);
  } else {
    tpaThrottle = rcCommand[THROTTLE];
  }

  // Feed virtual throttle into the old TPA formula
  tpaFactor = calculateFixedWingTPAFactor(tpaThrottle);

  // Scale PIDs
  pidState.kP = baseP * tpaFactor;
  // ...
}

After:

function updatePIDCoefficients() {
  // ...
  tpaFactor = 1.0;
  if (airspeed_tpa_enabled && airspeed_is_valid) {
    // Directly calculate scaling factor based on dynamic pressure (airspeed^2)
    airspeed = getAirspeedEstimate();
    referenceAirspeed = pidProfile()->fixedWingReferenceAirspeed;
    if (airspeed > 0) {
      tpaFactor = (referenceAirspeed * referenceAirspeed) / (airspeed * airspeed);
    }
    // Apply user-configured TPA amount and limits
    tpaFactor = 1.0 + (tpaFactor - 1.0) * (tpa_rate / 100.0);
    tpaFactor = constrain(tpaFactor, 0.5, 2.0);
  } else {
    tpaFactor = calculateFixedWingTPAFactor(rcCommand[THROTTLE]);
  }
  // Scale PIDs
  pidState.kP = baseP * tpaFactor;
  // ...
}
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a convoluted design choice and proposes a more direct, physically-grounded, and standard industry approach, significantly improving the feature's clarity and tunability.

High
Possible issue
Prevent division-by-zero in TPA calculation

Add a check to prevent division-by-zero when referenceAirspeed is zero in the
tpaThrottle calculation, falling back to the standard throttle value if
necessary.

src/main/flight/pid.c [501-502]

 const float referenceAirspeed = pidProfile()->fixedWingReferenceAirspeed; // in cm/s
-tpaThrottle = currentControlRateProfile->throttle.pa_breakpoint + (uint16_t)((airspeed - referenceAirspeed) / referenceAirspeed * (currentControlRateProfile->throttle.pa_breakpoint - getThrottleIdleValue()));
+if (referenceAirspeed > 0) {
+    tpaThrottle = currentControlRateProfile->throttle.pa_breakpoint + (uint16_t)((airspeed - referenceAirspeed) / referenceAirspeed * (currentControlRateProfile->throttle.pa_breakpoint - getThrottleIdleValue()));
+} else {
+    // Fallback to regular throttle if reference airspeed is not configured
+    tpaThrottle = rcCommand[THROTTLE];
+}
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a critical division-by-zero risk in the new TPA calculation, which could cause a flight controller crash or loss of control.

High
Ensure a pitot sensor is detected

Add a check in pitotValidForAirspeed to ensure a pitot sensor is detected
(PITOT_NONE) before proceeding with other validity checks.

src/main/sensors/pitotmeter.c [308-316]

 bool pitotValidForAirspeed(void)
 {
-    bool ret = false;
-    ret = pitotIsHealthy() && pitotIsCalibrationComplete();
+    if (detectedSensors[SENSOR_INDEX_PITOT] == PITOT_NONE) {
+        return false;
+    }
+
+    bool ret = pitotIsHealthy() && pitotIsCalibrationComplete();
     if (detectedSensors[SENSOR_INDEX_PITOT] == PITOT_VIRTUAL) {
         ret = ret && STATE(GPS_FIX);
     }
     return ret;
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a potential edge case where the system might incorrectly use airspeed TPA if no pitot sensor is configured, improving the robustness of the check.

Medium
  • Update

@shota3527
Copy link
Contributor Author

throttle position vs tpa factor
image

@sensei-hacker
Copy link
Collaborator

sensei-hacker commented Oct 15, 2025

This does look kinda over-complicated for historical reasons. But I'm not volunteering to refactor it, so I'm not really complaining.

We originally saw we need to reduce the PID when airspeed increases. Because the force/lift from the control surface is proportional to ( 0.5 * airspeed) ².

What we really wanted originally when TPA was introduced was the airspeed. But we often don't have the airspeed. So we used the throttle value to make a rough estimate of what the airspeed might be, in order to reduce the PID appropriately.

Now when we DO have the airspeed (the value we wanted in the first place), we're using the airspeed to simulate a throttle value, in order to estimate how much the throttle value might affect the airspeed and therefore the PID.

Kinda like:
We want to know how much Mike weighs.
The scale says he weighs 140 pounds.
Therefore we can estimate he's about six feet tall.
On average, people who are six feet tall weigh 155 pounds.
Therefore Mike probably weighs 155 pounds (an estimate originally based on the fact that he weighs 140 pounds).

Given we already know the airspeed, there's no need to mess around with estimating a "virtual throttle", then estimating how much that will affect the velocity and therefore the force.
The number we need is simply ( 0.5 * airspeed ) ² , from the lift equation.

@shota3527
Copy link
Contributor Author

shota3527 commented Oct 16, 2025

We originally saw we need to reduce the PID when airspeed increases. Because the force/lift from the control surface is proportional to ( 0.5 * airspeed) ².

I think this only explain the first half of the theory and it is not proportial but inverse propotional, The following are my thoughts, in short the angular velocity of the plane is propotional to the control surface multiplied by airspeed. If the old TPA assumes throttle is propotional to airspeed. then it is on same page with the following. And airspeed gain reduction(TPA) will need some internal variable to calculate, then why dont we use the virtual throttle value as the internal variable to maintain the compability, reducing the workload of users to shift from throttle based to airspeed based.

Relationship Between Airspeed, Control Surface Deflection, and Angular Velocity in Model Aircraft

1. Fundamental Dynamic Equation

For a single rotational axis (roll, pitch, or yaw):

dot(ω) + A·V·ω = B·V²·δ

  • ω: angular velocity (rad/s)
  • dot(ω): angular acceleration (rad/s²)
  • V: airspeed (m/s)
  • δ: control surface deflection angle (rad)
  • A, B: lumped constants (geometry, aero derivatives, inertia, air density)

Interpretation:
Angular acceleration + rate damping = airspeed² × control surface deflection


2. Steady-State Condition

In our small plane, the plane enters Steady-State quily, that is why the plane is mainly driven by FF gain
When angular acceleration is negligible:

0 + A·V·ω = B·V²·δ

Therefore:

ω = (B/A)·V·δ


3. Key Proportional Relationships

  • At fixed δ: angular velocity increases linearly with airspeed.
  • At fixed ω: required control deflection decreases as 1/V.

4. Quick Reference

  1. Constant angular rate control law
    δ ≈ K·(ω_cmd / V), where K = A / B

  2. Two-speed comparison
    For the same target angular rate ω:
    δ₂ / δ₁ = V₁ / V₂


Summary

Condition Relationship
General dynamics dot(ω) + A·V·ω = B·V²·δ
Steady state ω = (B/A)·V·δ
Constant rate control δ ∝ 1/V
Two-speed comparison δ₂ / δ₁ = V₁ / V₂

High-speed flight requires smaller control deflections to achieve the same rotation rate due to aerodynamic damping and increased control effectiveness.

@sensei-hacker
Copy link
Collaborator

sensei-hacker commented Oct 16, 2025

I think this only explain the first half of the theory and it is not proportial but inverse propotional,
...
High-speed flight requires smaller control deflections to achieve the same rotation rate due to aerodynamic damping and increased control effectiveness.

Agreed.
The lift force from the control surface (the dynamic pressure) at a given AoA is proportional to (0.5 * V)² .
(Assuming barometric pressure etc doesn't change)

Therefore the deflection needed to generate the force is ~ inversely proportional. (Given assumptions).

So no need to bring a simulated throttle into it.

THAT said, you actually wrote the dang code. And it works, presumably. I didn't write it and probably wouldn't, so whichever way you want to write it is fine by me. I'm somewhat regretting having said anything because you do great work and my comment wasn't pointing out a real problem that needed to be fixed. It just felt awkward to do a "virtual throttle".

Ps I had mentioned inversely proportional to (0.5 * V)², I see why you said inversely proportional to V itself. I see V is probably more correct for correcting for external disturbances, whereas V² would be for initiating maneuver, for starting a a turn. (If I understand correctly).

On an unrelated topic - I wanted to let you know I'm hoping to cut an INAV 9.0RC1 in the next couple of weeks. Hopefully with airspeed PID attenuation included. I sent a build with this plus some other PRs over to James Downing for testing.

@shota3527
Copy link
Contributor Author

shota3527 commented Oct 16, 2025

I see V is probably more correct for correcting for external disturbances, whereas V² would be for initiating a maneuver, for starting a turn. (If I understand correctly).

I think V is more important for continuous control stick input , and V² is more important for everything else including disturbances and starting a turn.

I am changing my mind. considering only V, then the TPA formula can be much simplier
δ = δref * Vref / V

but have some promlems.

  1. no uperlimit, hard code or config will introduce complexity
  2. the real situation might be some where between V² and V, and the formula could not mimic that
  3. there might be deflect in the control link

While the virtual throttle method has some extra parameters to toggle, or add a new parameter/modify δ = δref * Vref / V

curiousto know how others think

@sensei-hacker
Copy link
Collaborator

sensei-hacker commented Oct 16, 2025

I love that I have someone to discuss this with who understands it better than I do. :)

the real situation might be some where between V² and V, and the formula could not mimic that

It occurs to me that V^1.3 or V^1.4 will always be in between. I think V^1.3 would probably be a good compromise between the two.

Of course, if you didn't want to do a decimal exponent, something like (0.5 * V) ^ 2 would also give a compromise value in between V and V² 😜
(Assuming the velocity is faster than a snail).

no uperlimit, hard code or config will introduce complexity

The baseline is not having any airspeed-based attenuation at all, so IMHO capping the attenuation at 4 * vref or so would be pretty good. It's not like it explodes at the cap. It just doesn't attenuate any further. I don't think the exact cap is critical. Of course one could smooth out the saturation by multiplying by (10 - Vfactor) / (Vfactor + 8) or whatever. (Where Vfactor = current airspeed / Vref).

@sensei-hacker
Copy link
Collaborator

sensei-hacker commented Oct 16, 2025

there might be deflect in the control link

Yeah I expect the deflection will be approximately linear to the force (0.5V)^2 given the material is reasonably sized for the application.

In the end, I suspect that's about the difference between V^1.3 and V^1.35.

@trailx
Copy link
Contributor

trailx commented Oct 16, 2025

I got to do a preliminary test flight of this today. I am particularly interested in this because I've wanted it for a couple years. Currently I fly the three PID profiles based on custom programming logic that auto changes control profile based on airspeed. I have tuned these breakpoints as shown below (ignore the best-fit curves). These profiles are tuned fairly high to provide the best performance and stabilization without inducing oscillations. I've put many hours of flight on these settings without issues, and these PIDs are well established. Also I am using the Matek digital airspeed sensor.

Airspeed TPA Program

To test this PR, I applied airspeed TPA to profile 2, and added a switch that would force that profile over the airspeed-based changes. Profile 2 was tuned for use between 45 and 55 mph with no TPA in effect. So I applied the reference airspeed at 55mph, and the TPA throttle reference (BP) at 1500, which is roughly the throttle that achieves 55mph.

I'll talk through my flight today. I set up the TPA % at 35 to start.
Airspeed TPA Initial Setup
Above is the view as I started flight. I increased throttle to understand how the current setting operated, and I ran into roll oscillations around 66 mph airspeed. In flight, I adjusted the TPA number to try to push the oscillation point to a higher airspeed. I increased it up to its maximum, 100, and it didn't seem to have much affect on the airspeed in which I encountered oscillations. Oscillations always seemed to occur around 66-70 mph.

I expected increasing TPA to progressively attenuate PIDs and delay oscillation onset to higher speeds. However, changing it from 35% to 100% didn’t significantly affect the oscillation airspeed, suggesting the attenuation scaling or mapping may not be strong enough.

I also tried moving the BP or TPA throttle reference up and down, from 1380 to 1605 and it always seemed to oscillate around the same airspeed, 69 mph-ish. I was hesitant to change this a whole lot because I didn't really understand what effects it would have on flight performance.

I never ran into any oscillations or issues at lower airspeeds, only higher airspeeds. It was hard to tell, but it seemed like it may have a little more stability when in my profile 1, than when I locked in profile 2.

Because TPA is largely an invisible adjustment behind the scenes, its difficult to fully understand and visualize what's going on inside it while flying, and because airspeed is mapped on top of throttle, it makes it difficult to understand the attenuation curve when looking at the current graphs.

If you've got any advice for how I should adjust the "TPA levers", I can do another test flight tomorrow to test anything different. My takeaway is that 100% TPA doesn't seen to be enough. I'd love to get a better idea of what the formula is that I applied, and what that looks like on top of the stepped profile program that I use today.

BTW, I am James Downing FPV on discord.

@trailx
Copy link
Contributor

trailx commented Oct 20, 2025

I did some further digging on this, and I attempted to visualize the airspeed TPA math directly to my stepped curve. I think I uncovered something.

First, I realized I had something wrong in my earlier graph. In my second step profile, my Roll-P (which is what was likely causing my roll oscillation) is actually higher than I have depicted. I have it set at 46. So I marked that on the graph below with the green dot. That's at the reference airspeed, 55 mph.

I then graphed in red and orange the two curves I flew. Starting with 35% TPA factor, and then again at 100% TPA factor. I encountered an oscillation at roughly 65mph and 70 mph. Those two points are shown purple and annotated. A rough "local max" slope line can be inferred by these two points. It shows that the ideal curve needs to be steeper than what is provided.

I found what look to be two potential solutions, both graphed below.

The preferred solution I believe is to remove the reference to idle throttle (or more accurately pull that down to 0). This is shown in the blue line. Unless I did something wrong in my math, its not doing what we want it to. Its really the cause of the slope limitation. When I set that to 0, I get a curve that looks much more like what is intended, and its very close to the "local max" slope in that airspeed range.

An alternative approach could be to increase the TPA %. I increased it to 300% and was able to create the grey dashed line. I don't think this is as ideal, but it would be preferred to at least have greater control on the effective slope.

There's also a non-zero potential I got my math wrong and translated this incorrectly, but this matches my experience. Hope this helps shed some light on what I saw.

Airspeed TPA Curve Graph

@trailx
Copy link
Contributor

trailx commented Oct 21, 2025

I need to apologize, the graph I originally produced didn’t sit right with me. The curves didn’t match the logic I expected and saw from the code and other reference material, they were far too linear looking. After re-checking the math carefully, I found some errors. The overall takeaway about why oscillation occurs was still correct, but my earlier recommendation was not.

Below is the corrected airspeed-TPA graph based on the exact formulas pulled from the code (double checked this time). The red and orange lines and purple points still represent the same things in my prior post, but they show the correct overall shape. 100% TPA attenuates more than I showed before, but not significantly more. This increased the slope of the "local max" roll-P term calculated based on the oscillation points I encountered. The low-speed is boosted much more than I calculated last time, and I show the 2x cap on the graph rather than leaving it unbounded.

image

My conclusion has changed. We simply need a higher dynamic TPA range in order to better match the curve of the dynamic pressure effects. Planes with looser tuning may not reveal these effects when testing. However on my tightly tuned Penguin, the mismatch is noticeable. If I had to make an educated guess at the best dynamic pressure curve based on the data I have available, I think it would be in the range of 200-250% TPA.

I recommend opening the bounds for the dynamic TPA factor. Instead of limiting it to 0-100%, it needs to be 0-300% at minimum, but it may make sense to open this up further to accommodate and anticipate future needs. I also recommend the removal of the lower bound of 1/2 attenuation factor. If I had a lower bound of 1/2 TPA factor, there's a chance I'd still run into an oscillation at or above 100 mph. Difficult to extrapolate this, but I'd recommend lowering the lower scaler bound to 1/4 TPA. I think the upper bound of 2X can remain.

Thanks for your time on this. I think with these small tweaks it will be ideal.

Recommendations:

  • Increase allowable TPA dynamic factor from 0-100% to 0-300%, or even as much as 500%.
  • Remove the lower attenuation limit of 1/2, replace with 1/4.
  • Keep current upper bound of 2x.

@trailx
Copy link
Contributor

trailx commented Oct 22, 2025

In speaking with Jetrell, I realized some minor clarification would be helpful.

In my last post, I referred to the "TPA dynamic factor", for lack of the correct term. The correct term is tpa_rate. So to clarify my recommendation is to raise the upper limit of tpa_rate from 100 to at least 300, with 500 giving more headroom as needed to accommodate different unforeseen setups.

Second, I recommended moving the lower attenuation limit from 1/2 to 1/4. This is a hard coded sanity limit. I added an annotation on the graph with the dotted blue lines, showing where my "theoretically ideal" 225% tpa_rate line would be otherwise truncated at 1/2 with today's limit. This could potentially create oscillations at very high speeds, 100mph+ because it didn't allow enough attenuation.

The recommendation is to adjust the following line in pid.c from:
tpaFactor = constrainf(tpaFactor, 0.5f, 2.0f);
to:
tpaFactor = constrainf(tpaFactor, 0.25f, 2.0f);

image

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.

3 participants