PID overshoots after a long error: integral windup and how to limit it

Clamp the integral term. Without a limit it grows while the output is saturated and then drives a large overshoot.

What the message means

The integral adds up error over time. If the motor is already at full power, it keeps growing, and has to unwind later with the opposite error.

Fix it in this order

  1. Limit the integral to a sensible range.
  2. Reset the integral when the setpoint changes a lot or the controller starts.
  3. Stop adding to the integral while the output is at its limit.
  4. Try a P or PD controller first, and add I only if a steady error stays.
  5. Use a fixed time step in the calculation.
  6. Tune one term at a time.

Why it happens

If the output is already at its limit, the integral term keeps growing while the error is large. When the error finally drops, the stored integral keeps pushing the output the wrong way and the system overshoots. This is called integral windup.

Limit the integral term to a sensible range, stop adding to it while the output is saturated, and reset it when the setpoint changes a lot.

integral += error * dt;
integral = constrain(integral, -I_MAX, I_MAX);   // anti-windup clamp
float out = Kp * error + Ki * integral + Kd * dError;
out = constrain(out, -255, 255);

Example sketch: change pins and values for your own wiring. It has not been bench-tested on your hardware.

If you see this, do this

You seeDo this
Overshoots after being heldIntegral windup.
Steady error staysA little integral may help.

PID tuning, line follower oscillates.

Last reviewed: November 2026. These are the usual causes and the order that finds them fastest. Test on your own board; clones and cables differ.

Why this happens

The integral term adds up error over time: integral = integral + error x dt. While the actuator is saturated, say a motor already at full PWM, the error does not shrink fast, so the integral keeps growing even though more output cannot be delivered. When the process variable finally reaches the setpoint, the error becomes zero but the stored integral is still large, and it keeps pushing the output until enough opposite error unwinds it.

A number makes it clear. With Ki = 0.5 and an error of 100 held for 2 seconds, the integral reaches 100 x 2 = 200, which demands 0.5 x 200 = 100 output units. The motor is already at its limit, so none of that was useful, and all of it has to be undone later by overshoot. A hold on integration while saturated, or a clamp on the integral, stops this.

How to confirm the cause

  • Log the three terms and the output on the serial port, once per control step. Windup shows as the integral term growing large while the output stays at its limit.
  • Set Ki to zero and run the same move. If the overshoot disappears, the integral is the cause.
  • Print dt as well. A time step that varies between loops changes the integral without any change in error.
  • Watch how long the overshoot lasts. Windup recovery is slow, many times the time constant, while a P-gain that is too high shows a fast, repeating oscillation.
  • Check the output limit used in the code against the real limit of the motor driver.

Worked example

Conditional integration: only accumulate the error when the output is not pushed further into its limit. Variable names are examples.

float u = Kp * e + Ki * integral + Kd * dError;
float uSat = constrain(u, -255, 255);
// accumulate only if not saturated, or if e works against the saturation
if (u == uSat || e * u < 0) {
  integral += e * dt;
}
integral = constrain(integral, -I_MAX, I_MAX);
setMotor(uSat);

Common mistakes

  • Limiting the output but leaving the integral free to grow.
  • Setting the integral limit so high that it never acts.
  • Setting Ki high to remove a small steady error, when friction or a deadband is the real cause.
  • Taking the derivative of the setpoint, which causes a kick when the target changes.
  • Not resetting the integral when the controller is disabled and enabled again.

If this did not fix it

  • Check for a motor deadband. A motor that does not move at low PWM leaves a steady error that the integral keeps growing against.
  • Check the sample time. A control loop that is too slow adds delay, which also causes overshoot.
  • Check the sign of the feedback. Reversed feedback gives runaway, not simple overshoot.