Click & WhirrAll lessons

Motion · Lesson 04

Zero the drift

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.

Kp and Kd drive it smoothly toward the target heading, but a steady side wind (or a wheel running a touch weak) keeps nudging it off course. Proportional control only pushes back in proportion to the error, so once the correction balances the wind it just settles there: a small, permanent offset. Derivative control can’t fix it either: it only reacts to change, and a steady error isn’t changing. Integral control adds a third term that accumulates error over time: steer = Kp·error + Ki·∫error + Kd·Δerror. As long as any offset remains, the integral keeps growing and pushing harder, until it’s gone.

Why P and D settle short

A side wind keeps nudging your robot off course. Teach it to lean in and hold a heading dead on.

The wind is steady: about twenty degrees a second of induced yaw, a breeze on the chassis, or a wheel running a touch weak. Your Kp and Kd carry over from lesson 3 already tuned, and they steer smoothly toward the target heading. But proportional control only pushes back in proportion to the error. Once its correction exactly balances the wind, the two cancel and nothing is left to close the last gap. The gauge settles a few degrees short: a small, permanent offset.

Derivative control cannot fix it either. D reacts to how fast the error is changing, and a steady offset is not changing, so D reads zero and stays quiet. What is missing is a term that cares about error that persists. Integral control accumulates the error over time: steer = Kp·error + Ki·∫error + Kd·Δerror. As long as any offset remains, the integral keeps growing and pushing harder, until the offset is gone.

The good news: the PIDController you built in lesson 3 already has the integral machinery inside it. This lesson feeds it a Ki and puts that third term to work.

Wire the correction to the wheels

Read the skeleton in the editor. It imports your PIDController, converts the delayed radians error into degrees (the gain scales are tuned for degrees), and asks the controller for a steer correction every tick. Then it throws that correction away and returns a straight-ahead speed for both wheels, so the bot ignores the wind entirely.

Your one move is to wire the correction to the wheels. Split the base speed by steer: slow one wheel and speed the other so the bot turns to cancel the error. Once that line is written, the carried Kp and Kd start doing their job.

Ride it to the target zone

With the steer wired, press Run and watch the bot lean into the wind and drive for the target zone. The carried Kp and Kd are enough to reach it, so this beat just confirms the correction flows through to the wheels.

Keep an eye on the heading gauge as it arrives. It closes most of the gap, then stalls a few degrees off zero and holds there. That leftover offset is the droop, and closing it is the next beat.

Raise Ki until it lands dead-on

Now put the integral to work. Your gains live in the code: the ki default in __init__ is the tuning surface, and the editor highlights it. The starter ships ki=0, so the integral term is switched off and the gauge settles a few degrees short: that is the wind winning.

Raise the ki default (try about 6) and press Run again. Each Run builds a fresh controller from your source, so the new value drives from the first tick. Watch the integral wind the leftover error out and the gauge land dead on zero. That clean hold finishes the lesson.

Go too far and it hunts: a large Ki keeps piling on correction past the point where the error is gone, then swings back the other way. Somewhere between switched off and overdoing it is the value that lands square. Run, edit, Run again until you find it.

Go deeper: when the integral winds up

A big enough Ki keeps accumulating past the target and overshoots, and if the actuator were clamped at its top speed, a naive integral would get much worse: it keeps piling on correction the wheels cannot deliver, and all of it has to bleed back off before the bot responds. Taming that wind-up is a whole lesson of its own. For now, keeping Ki modest steps around it.

Ready to build it? The interactive lesson is where you write the code and watch the robot run.