Trust Issues · Lesson 12
Two liars, one truth
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.
Two bad signals, one truth
Two of your robot’s signals lie, in opposite ways. Teach it to split the difference.
The heading you get by integrating the wheels is smooth: no jitter, tick to tick it barely moves. But it drifts. An unseen bias turns the robot a little more than the wheels report, and the error quietly piles up, the same way your L5 odometry peeled away from the truth. The absolute reading (think of a compass) has the opposite problem: it is honest, right on average, but it is noisy, twitching a few degrees every single tick. Neither one is trustworthy on its own.
The driving is not your job this time. Press Run and the sim steers a slow, fixed turn on its own, the same turn every run, so both lies stay visible. Your job is the ComplementaryFilter class in the editor: it takes both signals every tick and returns one number, its belief about the true heading. The fix is the classic complementary filter: mostly trust your smooth prediction, and let a small fraction of the honest absolute leak in so the drift can never accumulate. One blend knob, alpha, sets how much you trust yourself.
Predict from wheels, blend in the absolute
The filter is two moves, in order. Predict first: short-term truth comes from the wheel difference. The gap between the two commanded speeds, scaled by 1.6 / 55 (the speed scale over the wheelbase), is this tick’s turn rate, and one tick of it carries your last heading forward. This is the same integration your L5 odometry did, and it drifts for the same reason.
Then blend: mostly keep that smooth prediction, and pull a small fraction of the way toward the noisy absolute: alpha of the prediction plus (1 - alpha) of the absolute. Store the result back on self so next tick’s prediction starts from it. A filter with no memory is just the noise again. Write both moves and press Run: your belief should beat the raw reading, which latches the first gate.
Go deeper: the argument between two liars
The blend is a quiet argument. Alpha near one says: trust myself, my integration is smooth and steady tick to tick. That is true over a second or two, and it is exactly why you weight the prediction so heavily. But over the whole run the integration is the liar that never stops lying: every drift error it makes it keeps, because next tick starts from the wrong place. Left alone, it walks off and never comes back.
The (1 - alpha) leak is the other liar getting a vote. Any single absolute reading is noisy garbage, off by a few degrees at random, so you take only a sliver of it. But its errors do not accumulate: they average to zero over time, so a steady drip of the absolute pins the belief to the truth the drift keeps trying to leave. High alpha equals smooth but slowly drifting; low alpha equals honest on average but jittery. The value that beats both parents is the one where the slow drift and the fast noise cancel, and that is the whole lesson.
Hold steady, beat both
Now feel what the blend does. Your alpha lives in the code: the default in __init__ is the tuning surface, and the editor highlights it. At alpha=0.999 (where the starter ships it) you barely listen to the absolute at all, so the drift wins and the belief slides away from the truth. Press Run and watch it peel.
Then lower the default (try alpha=0.95) and press Run again. Each Run builds a fresh filter from your source, so the new value drives from the first tick. More of the absolute leaks in, the drift can no longer accumulate, and the belief locks onto the truth and stays there. Go too low and you let too much noise back in and it jitters. The value that holds steady near the end finishes the lesson.
Ready to build it? The interactive lesson is where you write the code and watch the robot run.