Skip to content

MC Braking BOOST accelerates instead of decelerating — possible jerk limiter interaction with boost #11422

@PCS-Hazak

Description

@PCS-Hazak

Current Behavior

Multicopter braking BOOST causes the drone to accelerate to 2-3x its pre-braking speed instead of decelerating. After digging into the blackbox data and source, we believe this may be caused by lastAccelTargetX/Y (used by the jerk limiter) being saved after boost amplification, which could create a feedback loop that prevents the acceleration from reversing direction.

This appears to be the same issue reported in:

Decoded blackbox data from the failure event (Y-axis, pitch):

 time | rcData[1] | rcCmd[1] | velP   velI  velD  velFF | velOut | vel_xy | pitch  | braking state
------+-----------+----------+-------------------------+--------+--------+--------+--------------
229.5 |   1933    |   +384   |  -509   +42   +37   -97 |   -490 |   17   |  +9.6  | (cruise)
229.7 |   2012    |   +500   |  -645   +36   +68  -139 |   -681 |   61   | +22.8  | (cruise, max stick)
229.9 |   2012    |   +398   |  -465   +29   +57  -140 |   -519 |  142   | +27.7  | (cruise, building speed)
230.1 |   2012    |   +301   |  -264   +24   +12  -139 |   -368 |  230   | +24.4  | (last frame before release)
------+-----------+----------+-------------------------+--------+--------+--------+--- STICK RELEASED ---
230.2 |   1432    |   +182   |  +416   +22   +85   -35 |   -223 |  271   | +21.7  | BOOST  <-- PID flips, output doesn't
230.3 |   1495    |   +354   |  +708   +13  +103    +4 |   -257 |  305   | +17.6  | BOOST  <-- PID sum=+828, out=-257
230.4 |   1495    |   +500   |  +811    -2   +89   +11 |   -980 |  333   | +22.4  | BOOST  <-- output SATURATED wrong way
230.5 |   1495    |   +500   |  +947    -1  +114   +18 |   -980 |  375   | +27.5  | BOOST
230.6 |   1495    |   +500   | +1098     0  +114   +27 |   -980 |  421   | +30.1  | BOOST
230.7 |   1495    |   +500   | +1260    -5  +110   +36 |   -980 |  469   | +31.5  | BOOST  <-- 31 deg pitch, stick centered
------+-----------+----------+-------------------------+--------+--------+--------+--- BOOST ENDS ---
230.8 |   1427    |   +500   | +1206    -2  +144    +7 |   -979 |  520   | +32.4  |
230.9 |    989    |   +500   | +1735    -2   +14   +85 |   -841 |  560   | +33.0  | <-- pilot FULL REVERSE, cmd still +500
231.0 |    989    |   +485   | +2129    -4   +12  +140 |   -668 |  597   | +33.4  | <-- jerk limiter slowly recovering
231.2 |    989    |   +260   | +2252    +3    +7  +140 |   -322 |  653   | +28.3  |
231.4 |    989    |    -14   | +2325    -1    +8  +139 |    +23 |  687   | +15.6  | <-- velOut FINALLY crosses zero
231.6 |    989    |   -278   | +2418     0    +5  +139 |   +369 |  732   |  -1.4  | <-- PEAK VELOCITY (2.7x pre-braking)
------+-----------+----------+-------------------------+--------+--------+--------+--- RECOVERY ---
231.9 |    989    |   -500   | +2254    +2    -9  +136 |   +887 |  667   | -24.9  |
232.3 |    989    |   -500   | +1585    +3   -19  +106 |   +962 |  450   | -32.1  | <-- finally decelerating hard

What we're seeing in the data:

  1. PID terms look correct. At t=230.3, all four velocity PID terms sum to +828 (braking direction), so the PID controller appears to be computing the right answer.

  2. Something clamps the output in the wrong direction. mcVelAxisOut[1] = -257 at t=230.3, then saturates at -980 by t=230.4 — opposite to what the PID is requesting. This looks like the jerk limiter window is still centered on the previous cycle's large negative value and can't slew fast enough to reverse.

  3. The gap between PID sum and output grows each cycle. This is what made us suspect a feedback loop — each iteration seems to push the jerk window further in the wrong direction rather than recovering.

  4. ~1.2 seconds of wrong-direction thrust. From t=230.2 to t=231.4, velOut is negative (forward acceleration) despite the stick being centered and then at full reverse. The drone accelerates from 271 to 687 cm/s during this window.

  5. Pilot input doesn't override. At t=230.9, the pilot commands full reverse stick (rcData=989) but rcCommand[1] remains +500 (forward). We assume this is because the nav controller output takes priority during braking, but we're not 100% sure of that path.

Steps to Reproduce

  1. Arm multicopter in POSHOLD with BRAKING mode enabled (user_control_mode = CRUISE)
  2. Push pitch stick to maximum, build speed above nav_mc_braking_boost_speed_threshold (default 150 cm/s)
  3. Release stick abruptly
  4. Drone accelerates instead of braking

Expected behavior

Drone decelerates and stops at a position near where stick was released.

Suggested solution(s)

We traced the issue to an interaction between the jerk limiter and braking boost in navigation_multicopter.c. We could be wrong on the details, but the blackbox data seems consistent with this theory.

The jerk limiter (lines ~593-596) constrains acceleration change per cycle:

const float accelLimitXMin = constrainf(lastAccelTargetX - maxAccelChange, -accelLimitX, +accelLimitX);
const float accelLimitXMax = constrainf(lastAccelTargetX + maxAccelChange, -accelLimitX, +accelLimitX);

The boost (lines ~670-671) amplifies the PID output:

newAccelX = newAccelX * (1.0f + boostFactor);
newAccelY = newAccelY * (1.0f + boostFactor);

The save (lines ~677-679) stores the post-boost value for the next cycle's jerk limiter:

lastAccelTargetX = newAccelX;
lastAccelTargetY = newAccelY;

If we're reading this correctly, this could create a feedback loop:

  1. During cruise flight, lastAccelTargetY is large in the flight direction (e.g., -500)
  2. Pilot releases stick, braking BOOST activates
  3. PID now wants acceleration in the opposite direction (+828)
  4. But jerk limiter window is centered on -500 with small maxAccelChange (even 2x during braking)
  5. PID output gets clamped to still-negative value (e.g., -257)
  6. Boost amplifies this wrong-direction value: -257 * 2.5 = -642
  7. -642 is saved as lastAccelTargetY for next cycle
  8. Next cycle: jerk window centers on -642, clamping gets worse
  9. The system converges to maximum wrong-direction acceleration instead of reversing

If this is right, the jerk limiter would effectively have (1 + boostFactor) times its intended inertia because it's tracking boosted output instead of raw PID output. With default nav_mc_braking_boost_factor = 100 (boostFactor = 1.0), that would be 2x the intended inertia.

Possible fix — moving the lastAccelTarget save to before the boost block:

+    lastAccelTargetX = newAccelX;
+    lastAccelTargetY = newAccelY;
+
     if (STATE(NAV_CRUISE_BRAKING_BOOST) && ...) {
         // ... boost factor calculation ...
         newAccelX = newAccelX * (1.0f + boostFactor);
         newAccelY = newAccelY * (1.0f + boostFactor);
         maxBankAngle = DEGREES_TO_DECIDEGREES(navConfig()->mc.braking_bank_angle);
     }

-    lastAccelTargetX = newAccelX;
-    lastAccelTargetY = newAccelY;

The idea is that the jerk limiter would then track the raw PID output instead of the boosted output, which should break the feedback loop while still preserving both the jerk limiter's smoothing function and the boost's amplification of braking force.

We haven't tested this fix yet, so there may be side effects we're not seeing. Happy to test if this direction looks right.

Additional context

  • Roll-axis braking events in the same flight worked correctly at lower speeds, which seems consistent with the feedback loop being speed/magnitude-dependent
  • The doubled jerk limit during braking (maxAccelChange * 2, line ~589) helps but doesn't appear to be enough to overcome the boost amplification
  • This looks like it may have been present since the original braking implementation and could be related to what others have reported in Mc-braking fail. Quad shoots forward instead of braking #4437 and Cruise mode + MC braking mode +Poshold quad flyaway #8110
  • Blackbox log attached — recorded at ~443 Hz with debug mode POS_EST (20) and all 9 BB include flags active. The critical braking failure event is at t=230.2s in the log.

Braking settings:

nav_mc_braking_speed_threshold = 100
nav_mc_braking_disengage_speed = 75
nav_mc_braking_boost_factor = 100
nav_mc_braking_boost_timeout = 750
nav_mc_braking_boost_speed_threshold = 150
nav_mc_braking_boost_disengage_speed = 100
nav_mc_braking_bank_angle = 40
user_control_mode = CRUISE

  • FC Board name and vendor: SpeedyBee F7V3
  • INAV version string: 9.0.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions