← All lessons
Feedback · error · P · I · D

Close the loop.

A thermostat, a cruise control, and a robot elevator all run the same three-beat trick: measure what's happening, compare it to what you wanted, push against the difference. That's feedback — and PID is the classic recipe for how hard to push.

setpoint (the goal) P (the present) I (the past) D (the future) the mechanism
Part 1 / One loop, one number

Everything runs on the error

Here is the machine this whole page lives inside. The setpoint is what you want. The sensor reports what you have. Subtract them and you get the error — a single number saying how wrong you are, and in which direction. The controller's entire job is to turn that number into motor voltage:

setpoint r + − error e Controller V = ??? — this page voltage V Plant (elevator + motor) height y Sensor (encoder) measured y
The feedback loop. If this picture reads like hieroglyphics, take ten minutes with the primer Boxes, Arrows, Circles first — this page assumes you can trace it. The one box we left blank is the controller. Filling it in well is the art.

The simplest possible filling is a reflex: bang-bang control — full power when you're below the target, nothing when you're above. No subtlety, just a light switch. Watch it fight a proportional controller (coming up next) for the job of parking an elevator carriage on a target line:

Widget 00 — The parking contestbang-bang vs proportional
Plots — height & voltage vs time

Top: bang-bang crosses the line and never stops crossing it — a permanent wobble. The proportional carriage glides in once and stays. Bottom: the voltages tell you why — bang-bang is a square wave slamming between 12 V and 0 V, while the proportional voltage tapers smoothly as the gap closes.

Bang-bang arrives fast, all right — so fast it slams clear into the top of the shaft, then bounces across the line and never stops crossing it, because "full power or nothing" has no way to say almost there. The proportional carriage eases off as it approaches and parks smoothly. But look closely at where it parks: slightly below the line. Remember that gap — it's the cliffhanger for Part 2.

Vocabulary check (all from the block-diagrams primer): the mechanism being controlled is the plant — here, a motor-driven elevator with real gravity and inertia. The goal is the setpoint r. The controller's output is motor voltage V, and error e = r − y where y is the measured height.
Part 2 / P — the present

Push proportional to the gap

The fix for bang-bang's chatter is embarrassingly simple: push harder when you're far away, gently when you're close. Multiply the error by a constant and call the result voltage. That constant is the gain, written kP, and the whole controller is one line:

P V = kP · e
V — motor voltagee — the error, setpoint − measured height (meters here)kP — the proportional gain, in volts per meter of error: how aggressively distance is converted into push.kP is a personality dial. Small kP: patient, gentle, slow. Big kP: eager, fast — and, past a point, so eager it flies through the target and has to come back. You are about to meet all three personalities.

Think of it as tying the carriage to the target with a rubber band: the farther it strays, the harder it's pulled back. Tune the band's stiffness yourself:

Widget 01 — The P playgroundone gain, three personalities
Plots — height & voltage vs time

Height settles into a flat line below the dashed setpoint — that vertical gap is the steady-state error, and it shrinks (but never dies) as kP grows. The voltage plot shows the elevator's dirty secret: holding still costs a constant 1.5 V against gravity, and with V = kP·e the only way to produce it is to keep some error alive.

Error
—
Voltage
—
Overshoot
—

Experiments: (1) kP = 4 — sluggish crawl, huge droop below the line. (2) kP = 10 — quicker, and the droop parks at almost exactly 15 cm. That's no accident: this elevator needs 1.5 V to hover, and 1.5 V ÷ 10 V/m = 0.15 m. Check it against the error readout. (3) kP = 35 — it flies through the target, rings back and forth, and still settles a few cm low. Speed and droop trade off; neither ever reaches zero.

So P alone has a flaw, and it's structural, not a tuning mistake. Gravity charges this elevator a standing bill of 1.5 V just to hold still. But V = kP·e can only produce voltage out of error — so to pay a permanent bill, it must hold a permanent error. The rubber band says it plainly: a spring holding up a weight must stay stretched.

droop ess = Vhold / kP
ess — the steady-state error: the error left over once everything stops movingVhold — the constant voltage the load demands (gravity's 1.5 V here)kP — the proportional gain.Bigger kP shrinks the droop but never erases it — and cranking kP for that reason buys you the ringing from experiment 3. Erasing it takes a new idea, and the new idea is memory.
Part 3 / I — the past

The term that holds a grudge

P only sees this instant. The integral term reads the history: it adds up the error over time — every second spent below the line grows the total — and pushes in proportion to that running sum. Persistently a little low? The sum quietly climbs, and the push climbs with it, until the error is actually zero. It is patience that turns into pressure:

I VI = kI · ∫ e dt
VI — the integral term's share of the voltage∫ e dt — the integral of error: the running total of error × time, in meter-seconds; think of it as the area under the error curvekI — the integral gain, volts per meter-second of accumulated error.The key property: this sum only stops changing when e = 0. Any leftover droop keeps feeding it, so the push keeps growing until the droop is gone. It cannot rest until you're exactly on target.

Watch it erase the droop. The memory tank next to the elevator shows the integral filling up — and notice what it holds once everything settles:

Widget 02 — The memory tankP + I
Plots — height & voltage split vs time

Bottom plot is the handoff, drawn live: as the carriage closes the gap, V_P fades toward zero while V_I ramps up and levels off at exactly 1.5 V — the gravity bill, now paid entirely from memory instead of from error.

V_P = kP·e
—
V_I = kI·∫e
—
Error
—

Experiments: (1) kI = 0 — the familiar droop, parked forever. (2) kI = 3 — watch the tank fill while the droop drains away to zero. Once settled, V_P ≈ 0 and V_I ≈ 1.5 V: the integral has memorized the gravity bill. (3) kI = 12 — the memory now builds faster than the elevator can respond, so it overfills, overshoots, and sloshes back and forth before calming down. Too much memory is a hothead.

Why "integral"? In calculus, the integral is the area under a curve. This term literally accumulates the area under the error curve — a small error held for a long time and a big error held briefly weigh the same. That's also its danger: during a long climb the tank fills with error that's already being handled, then has to slosh back out. Gentle kI values are the norm on real robots.
Part 4 / D — the future

The term that hits the brakes

Now for the opposite problem. Crank kP and the carriage doesn't just approach the target — it arrives at speed, blows through, and rings. P can't help: at the moment of crossing, the error is zero, so its push is zero, even though you're moving fast in the wrong direction. What's missing is a term that looks at how fast the error is changing — one that sees the line rushing toward you and starts braking early:

D VD = kD · de/dt
VD — the derivative term's share of the voltagede/dt — the derivative of error: its rate of change, in meters per second; negative while you're closing in on the targetkD — the derivative gain, volts per (meter per second).Closing fast on the setpoint makes de/dt negative, so V_D pushes against the motion — a braking force that grows with approach speed. It behaves exactly like a shock absorber, which is why engineers call its effect damping.

It's how you catch an egg: your hand gives way based on the egg's speed, not its position. Here's a deliberately over-eager P controller, plus the damper that civilizes it:

Widget 03 — The shock absorberP + D
Plots — height & voltage split vs time

V_D is the mirror image of the motion: zero whenever the carriage coasts, spiking against it whenever it moves fast. Watch it fight V_P during the approach — P says "go, you're not there", D says "slow down, you're arriving too hot".

Overshoot
—
V_D now
—
Settled in
—

Experiments (press Step the setpoint after each change): (1) kP = 30, kD = 0 — big overshoot, several rings. (2) kD = 1.5 — the ringing dies; one clean swoop into the target. (3) kD = 6 — now it's over-damped: no overshoot ever, but the last few centimeters take forever, like driving with the parking brake on. Damping is a dial, and both ends are wrong.

Part 5 / P + I + D

Three views of one error

Stack the three terms and you have the full controller. It's worth saying out loud how neat this is: each term reads the same error signal on a different axis of time. P reads the present — how wrong am I now? I reads the past — how long have I been wrong? D reads the future — which way is the error heading? Their votes simply add:

PID V = kP · e + kI · ∫ e dt + kD · de/dt
V — total motor voltagee — the error, r − ykP, kI, kD — the three gains: the entire tuning of the controller lives in these three numbers.Any gain set to zero simply switches that term off — a "PD controller" or "PI controller" is just PID with a zero in it. Most FRC mechanisms run P or PD; I joins when a stubborn load refuses to let the error die.
setpoint r + − error e Proportional V_P = kP · e Integral V_I = kI · ∫e dt Derivative V_D = kD · de/dt + + + voltage V Plant (elevator) height y measured y (sensor)
PID in boxes and arrows. One error, three parallel readings of it, one summed voltage. Every industrial controller, drone autopilot, and FRC mechanism you'll meet is some subset of this picture.

Now earn it. The tuning bay below is the exercise this whole page was building to: a full PID controller, a spec to hit, and a disturbance to survive. Tuners in the real world usually work in this order — P for muscle, D for calm, I for the last centimeter:

Widget 04 — The tuning baymeet the spec

Spec to hit, with the heavy load on: overshoot under 10%, settled (within ±2 cm and staying there) in under 2.0 s, and steady error under 1 cm. Metrics grade the most recent step — press Step the setpoint to be judged.

Plots — height & the three terms vs time

The bottom plot is the controller's inner monologue: V_P surges on each step and fades, V_D spikes against motion and returns to zero, and V_I drifts slowly to whatever constant the load demands and stays there. A well-tuned run has exactly that shape.

Overshoot (< 10%)
—
Settled (< 2.0 s)
—
Steady err (< 1 cm)
—

The recipe, as exercises: (1) kI = kD = 0. Raise kP until the carriage moves with authority and overshoots a little (try ~25). (2) Add kD until the ringing just disappears (~1.5–2). (3) The droop is still there — and toggling the heavy load on makes it worse — so add kI (~4–5) to erase it. Step again and check for three green marks. (4) For fun, break it: kP = 2 with kI = 15 never calms down — memory with no muscle is a disaster. (5) Found gains that pass? Flip the load mid-hold and watch V_I quietly re-learn the new bill.

In WPILib this controller is one object, and its gains have exactly the names you've been tuning:

pid = new PIDController(kP, kI, kD);
V = pid.calculate(measuredHeight, setpoint);
PIDController — WPILib's implementation of everything on this page, run once per robot loop (every 20 ms)calculate(measurement, setpoint) — computes the error internally and returns the summed P + I + D outputkP, kI, kD — the same three gains, in volts per unit of your sensor.Concepts and the math live in Introduction to PID; the class itself in PID Control in WPILib.
Part 6 / Recap

Five ideas to walk away with

1. Feedback is measure, compare, correct. Everything the controller does is powered by one number — the error — recomputed every loop.

2. P is a rubber band. Push proportional to the gap: simple and strong. But a spring holding a load must stay stretched — a constant demand like gravity leaves a permanent steady-state error.

3. I is memory. It accumulates unpaid error and ramps its push until the error is truly zero — then keeps holding the bill from memory. Overdo it and the memory sloshes.

4. D is a shock absorber. It reads the error's speed and brakes the approach, killing overshoot. Overdo it and everything turns to molasses.

5. Tuning has an order: P, then D, then I. Muscle first, then calm, then the last centimeter. Three numbers, tuned in the tuning bay the same way you'd tune them on a real robot.

One thing should still bother you: even perfectly tuned, this controller always reacts. It cannot lift a finger until the error already exists. The next lesson is about escaping exactly that — predicting the push instead of waiting to discover it. (And PID itself has real-world sharp edges — noisy sensors, motors that max out — which get their own lesson later.)

feedback — control powered by measuring the error
error e — setpoint − measurement, recomputed every loop
bang-bang — full power or nothing; arrives fast, chatters forever
kP — push per unit of error (the present)
kI — push per unit of accumulated error (the past)
kD — push against the error's rate of change (the future)
steady-state error — the droop P alone can never erase
overshoot — how far past the target you fly, as % of the step
settling time — time until you're inside the target band for good
Pocket glossary — the whole page, one line each. Further reading: Introduction to PID and PID Control in WPILib.