Skip to main content

How PID Works

A PID controller repeatedly adjusts a mechanism until it reaches a target. On a robot, that target might be an elevator height, an arm angle, a turning angle, or a wheel speed.

We will use a drone to explain PID:

Imagine that a drone starts at 0 metres and must hover at 50 metres.

The controller repeats this process many times per second:

  1. Measure the drone's current height.
  2. Find the difference between the target and the measurement.
  3. Calculate a motor output.
  4. Apply that output and measure again.

The difference is called the error:

error = setpoint - measurement

The simulator graphs the drone's height, not its error. The dashed line is the setpoint at 50, and the coloured line is the simulated response. Every graph is interactive, so move the sliders and observe what changes.

P: Moving the Drone Toward the Target​

Right now, the drone is sitting at 0 metres. We want it at 50 metres, but nothing is telling the propeller motors to spin.

Let's start with a simple idea:

The farther the drone is from 50, the harder the motors should push.

That is what P does:

P output = Kp * error

Suppose Kp is 0.5:

  • At 0 m, the error is 50, so the output is 25.
  • At 25 m, the error is 25, so the output is 12.5.
  • At 45 m, the error is 5, so the output is only 2.5.

The drone gets a big push when it is far away and a smaller push as it gets closer. Try changing Kp in the demo. A larger value makes the drone react more strongly.

02550750s3s6s9s12s15sSet pointResponseSet point
Target: 50 m

It looks like P should be enough—but if you watch the graph and animation carefully, you might find a problem.

The drone has to fight gravity (and maybe air resistance). As it gets closer to 50, P gives it less and less power. Eventually, the motor output may become just strong enough to fight gravity, but not strong enough to climb any higher. The drone gets stuck below the target.

This error is called steady-state error. P made the drone go up, but we need something to eliminate the constant error.

I: Eliminating the Remaining Error​

Imagine the drone has been stuck at 47 metres for several seconds. The error is only 3 metres, so P is not giving it much help.

What if the controller could say:

"We have been below the target for a while. Keep adding a little more power until we finally reach it."

That is what the I term does. It remembers the error from previous loops and adds it up:

accumulatedError += error * dt
I output = Ki * accumulatedError

A tiny error may not matter for one moment. But if that same error stays there, I keeps collecting it. The longer the drone remains below the target, the more extra output I adds.

This demo starts with P and I. Set Ki to 0 and watch where the drone stops. Then slowly increase Ki and see whether it reaches 50.

02550750s3s6s9s12s15sSet pointResponseSet point
Target: 50 m

Great—we fixed the leftover error. But we created another problem.

While the drone was climbing, I kept storing error and adding power. That stored push does not disappear instantly when the drone reaches 50, so the drone can fly past the target. This is called overshoot.

Now we need a way to slow the drone down before it shoots past 50.

D: Reducing Overshoot​

Imagine riding in a fast car. Even if the driver stops pressing the gas at the finish line, the car will not stop instantly because of inertia, so the driver must brake before reaching the line.

The drone has the same problem. P and I can push it toward 50, but something needs to notice that it is approaching too quickly.

That is what D does. It checks how quickly the error is changing:

errorRate = (error - previousError) / dt
D output = Kd * errorRate

When the drone rushes toward 50, its error drops very quickly. D notices that fast change and reduces the output. You can think of D as a brake: the faster the drone approaches the target, the harder D tries to slow it down.

In this demo, set Kd to 0 first and watch the drone overshoot. Then slowly increase Kd and compare the new curve.

02550750s3s6s9s12s15sSet pointResponseSet point
Target: 50 m

D helps with overshoot, but it cannot fix a drone that stays below the target. That is why we still need I. Each term solves a problem left by the previous one.

note

A real sensor is never perfectly smooth. Because D reacts to quick changes, too much D can also make a real motor shake or jitter.

Combining the Three Terms​

A PID controller adds all three results:

output = Kp * error
+ Ki * accumulatedError
+ Kd * errorRate
  • P responds to where the mechanism is now.
  • I remembers error that has persisted.
  • D responds to how quickly the mechanism is approaching or leaving the target.

Here is the standard mathematical formula:

u(t)=Kpe(t)+Ki∫0te(τ) dτ+Kdde(t)dtu(t) = K_p e(t) + K_i \int_0^t e(\tau)\,d\tau + K_d \frac{de(t)}{dt}

A balanced response​

This combination reaches the setpoint with very little overshoot. To see what each term contributes, set one gain to 0 at a time and compare the curve.

02550750s3s6s9s12s15sSet pointResponseSet point
Target: 50 m

There is no universally perfect set of gains. The values above only fit this simulated mechanism; a real arm, elevator, drivetrain, or shooter will behave differently.

The graph above shows the response as data. This separate animation shows the same tuned response as a moving drone.