A cruise-control car, a drone holding its height, a 3D printer keeping its nozzle hot — all of them do the same trick: measure what they control, compare it with the target, and correct the difference, hundreds of times per second. That loop is called feedback control, and the most widely used controller in the world is the PID controller — by some estimates it sits inside over 90% of industrial control loops.
What PID stands for: the controller looks at the error e = target − actual from three angles at once. P (Proportional) reacts to the error right now — the bigger the miss, the harder it pushes. I (Integral) remembers the errors of the past — a small stubborn error adds up over time until the controller finally kills it (this is what fixes the P-only droop). D (Derivative) predicts the future from how fast the error is changing — it slakes the push when the speed is racing toward the target, which tames overshoot.
Why it needs tuning: too little P and the motor never gets there; too much I and the controller overshoots and oscillates; too much D and it overreacts to sensor noise. Tuning a PID is finding the sweet spot for this motor, this load. There is one more trap: the controller can only command the actuator between its limits (here 0–100%). If the target needs more than 100%, the loop saturates — and a naive integrator keeps accumulating error it can never spend, a sickness called integrator windup that causes a huge overshoot when the target finally becomes reachable again.
Where you see it in real engineering
Car cruise control (speed), quadcopter flight controllers (attitude), 3D printers (temperature), robot arm joints (position), coffee machines (temperature), even the sugar level in a pharmaceutical fermenter. Anywhere a machine must hold a number steady against disturbances, a PID is probably holding it.
🧮 The maths
dv/dt = (K·u − v) / τ v — motor speed (m/s) u — controller output, clamped to 0…1 (–) K — plant gain, 0.8 (m/s per unit u) τ — time constant, 0.5 (s)
dv/dt = (K·u − 0.3·ℓ − v) / τ (load on) ℓ — load flag: 1 when the disturbance is active, else 0 the −0.3 m/s droop is the "pushing a heavy cart" effect
e = setpoint − v · u = clamp( Kp·e + Ki·∫e dt + Kd·de/dt , 0, 1 ) e — error (m/s) Kp, Ki, Kd — the three tunable gains the integral is updated every step, then frozen (anti-windup) while u is saturated and e would push it further out
Integration runs at a fixed step dt = 0.01 s with the speed-multiplying select only replaying it faster or slower. With P-only (Ki = Kd = 0) the motor settles into a closed-form steady state you can check by hand:
Worked example 1 (P-only droop): at steady state v = K·u = K·Kp·e and e = setpoint − v. With Kp = 2, setpoint 1.0 m/s, no load: v = 0.8·2·(1 − v) → 2.6·v = 1.6 → v = 0.615 m/s, e = 0.385 m/s. The motor never reaches the target — P-only always droops. Worked example 2 (the P-term): Kp = 2, current error e = 0.1 m/s → P-term = 2 × 0.1 = 0.2; if the integral says 0.5 and the error is shrinking at 0.4 m/s per second, u = clamp(0.2 + 0.5 − 0.4·Kd, 0, 1).
Measured quality metrics: overshoot = (max v − setpoint)/setpoint × 100% after the first arrival; settling time = when v enters the ±2% band around the setpoint and stays; load recovery = time from the disturbance step back into that band; steady-state error = mean of e over the last 2 s.
Assumptions & limitations: the plant is a first-order linear motor (no inertia, no brush friction, no actuator lag or backlash), the disturbance is a constant −0.3 m/s droop while it is on, the controller output is clamped to 0–1 with instant action, and measurements are noise-free. Real motors are second-order at best and real sensors are noisy — that is why Kd exists but is used carefully. This simulation is an educational approximation of a real DC motor under PID speed control.
🕹 Simulation workspace
Controls
Watch out: with K = 0.8 and u capped at 100%, the motor can never exceed 0.8 m/s unloaded, or 0.5 m/s with the load on. A setpoint above the reachable ceiling saturates the controller — that is not a tuning failure, it is physics.
Live measurements
Error e (m/s)1.000
Control output u (%)—
Overshoot (%)—
Settling (s)—
Load recovery (s)—
Steady-state error (m/s)—
Ready — press ▶ Run.
Settling = time from run start into the ±2% band for good. Load recovery = time from the disturbance step back into that band. Steady-state error = mean of e over the last 2 s of simulated time.
setpointmotor speed verror econtrol output u (0–1)±2% band
🧪 Guided experiments
🏆 Engineering challenges
🌍 Real-world applications
🚗 Cruise controlA car's PID holds 100 km/h uphill and down: the P-term responds to the grade, the I-term kills the hill's steady droop, the D-term stops the surge when the road flattens.
🚁 Drone flight controllersBetaflight/PX4 stack three cascaded PID loops per axis (rate → attitude → position). Tuning them is exactly the Kp/Ki/Kd balancing you are doing here.
🖨 3D printer hot endThe heater PID fights a "disturbance" every time cold filament enters. A badly tuned one rings — you can see the temperature ripple on the printer's graph.
🦾 Robot arm jointsIndustrial servos run PID (plus gravity feed-forward) at 1–10 kHz. The anti-windup you can toggle here is a mandatory feature in every real drive.
Try it with hardwareAn Arduino UNO R4 (or ESP32) with a DC gear motor and a wheel encoder: read speed from encoder pulses every 20 ms, compute e = setpoint − speed, wire up u = Kp·e + Ki·∫e + Kd·Δe and drive the motor through a PWM pin. Pinch the wheel to apply a load disturbance by hand and watch your loop fight back. Our Torque & DC Motor simulation explains the motor physics behind this plant.
✅ Check your understanding
📌 What you discovered
P-only control always droops — with Kp = 2 the speed settles 0.385 m/s short, because the push shrinks as the error shrinks.
The I-term kills the droop by accumulating past error — and the bigger Ki is, the faster the error dies, at the price of overshoot when disturbances or limits are involved.
The D-term damps overshoot by reading the error's rate of change — the controller's "future error" sensor.
Actuators have limits: u can never leave 0–100%, so a setpoint above 0.8 m/s (0.5 under load) is unreachable — no gain combination fixes that.
Windup is a real disease: an unfrozen integrator stores error it cannot spend and dumps it as a 14% overshoot blast when the load clears; the freeze rule cuts that to ~2%.
➡ Engineering takeaway: feedback control is a bargain between now (P), memory (I) and foresight (D) — and every controller must respect its actuator's limits, because you cannot regulate what you cannot actuate.