Motion · Lesson 03
Damp it with D
This is the written walk-through of the lesson: the idea, stage by stage, plus the deeper asides. The interactive version, where you write real Python in the browser and drive a simulated robot, lives on the lesson page.
steer = Kp·error + Kd·Δerror. It’s a shock absorber: it eases off as the bot rushes back toward the line, killing the overshoot. With D off it wobbles; flip it on and it glides.A controller that remembers
Your snappy Kp from lesson 2b is still in charge, and you can see the result on the right: it reacts hard, overshoots, and rings back and forth across the line. Derivative control adds a second term that watches how fast the error is changing and pushes back against it: steer = Kp·error + Kd·Δerror. A shock absorber on the correction.
To know how fast the error is changing, the controller has to remember last tick’s error. A plain function forgets everything the moment it returns, so this lesson hands you a class.
Read the skeleton in the editor. class PIDController: is a blueprint. When you press Run, the sim builds one instance from it, and __init__ runs once to give that instance its starting state. self is the instance itself: the same object on every tick, so anything stored on it, like self.prev_error, is still there when step() is called again a sixtieth of a second later.
Compute the derivative
The derivative is just a difference: this tick’s error minus last tick’s, divided by dt. Two moves in a careful order: read the old self.prev_error first, then overwrite it with this tick’s error. And on the very first tick there is no history yet, so guard against None.
Damp the correction
The raw derivative is jittery: the sensor twitches, and dividing by a sixtieth of a second turns every twitch into a scream. Blend it through a low-pass first, then return the full correction, kp·error + kd·d. Press Run when it’s written and let the bot chase the line all the way to the end.
Go deeper: why D damps
P looks at where the error is; D looks at where it is going. The derivative of a swing peaks a quarter cycle before the swing itself, so the D term’s push arrives early: it leans against the bot while it is still rushing toward the line and eases off before the crossing. Control engineers call this phase lead.
That early arrival is exactly what the delayed sensor takes away from P. Corrections that land late pump energy into the swing, which is why your hot Kp rings; D’s preview puts the timing back. It is also why too much Kd turns twitchy: leading the error means amplifying its fastest wiggles, and calming those is the job of the low-pass you just wrote.
Feel the wobble fall
Now feel what D actually does. Watch the wobble meter under the sim: it climbs every time the bot swings across the line.
Your gains live in the code: the kd default in __init__ is the tuning surface, and the editor highlights it. With kd=0.0 (where the starter ships it) you have pure P, the same hot controller that rings. Press Run and watch the wobble meter climb.
Then edit the default (try kd=1.0) and press Run again. Each Run builds a fresh controller from your source, so the new value drives from the first tick. The ringing dies out, the wobble meter stays low, and the bot glides home. That glide finishes the lesson.
Ready to build it? The interactive lesson is where you write the code and watch the robot run.