Click & WhirrAll lessons

Trust Issues · Lesson 13

The kidnapped robot

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.

Someone picked your robot up and put it down somewhere else, but its odometry was told the old starting spot. That’s the classic kidnapped robot problem: dead reckoning is exact here, so the belief stays wrong by the same 70 px forever. It can’t notice. What can? A landmark: the diamond on the map sits at a known spot and sends you a noisy range and bearing. Every tick, work out where that fix implies you are, and nudge your belief a fraction gain toward it. That nudge is the measurement update, the heart of every real localizer.

Dead reckoning that starts wrong

Someone picked your robot up and set it down somewhere else. Teach it to find itself again from a landmark.

Its Odometry from lesson 5 is still running the prediction, counting wheel moves and adding them up, and here the wheels do not slip, so that dead reckoning is exact. The trouble is where it started counting from. It was told the old spot, so its whole belief is shifted by that same offset, about 70 px, and it holds that offset forever. Exact arithmetic on a wrong anchor stays wrong. It cannot notice on its own, because nothing it reads ever mentions the anchor.

What can mention it is a landmark. The diamond on the map sits at a spot you know, and every tick it sends a noisy range and bearing: how far off it is, and at what angle from your heading. From those two numbers and the beacon’s known position you can work out where the fix implies you are, then nudge your belief a fraction of the way toward it. That nudge is the measurement update, the move at the heart of every real localizer, and it is the last thing this course has to teach.

Predict, then pull toward the fix

Read the skeleton in the editor. It imports your Odometry, builds it once from the believed start, and already runs it every tick: self.odo.update(v_left, v_right, dt) is the prediction. If the import banner is up, adopt the reference Odometry first, then this line drives the same guess you built in lesson 5. On its own it is pure drift from a wrong anchor: the belief sits at the full offset and never moves in.

Your one move is the correction. The beacon says you are beacon_range px away at beacon_bearing from your heading, and you know where the beacon is, so you can walk that range and bearing backward from the beacon to the position it implies. Nudge your x and y a fraction gain of the way toward that implied spot, then write the result back into self.odo. The write-back matters: without it the next prediction restarts from the uncorrected guess and your nudge evaporates. With both lines in, the belief peels off the wrong anchor and walks onto the truth.

Hold it without chasing noise

Now the trust. The gain default in __init__ is how hard you believe each fix, and the editor highlights it. The starter ships gain=0.4, near the top: the belief snaps in fast, but it also chases every twitch of the noisy beacon and jitters in place. It locks on, then will not sit still.

Lower the gain default (try about 0.08) and press Run again. Each Run builds a fresh Localizer from your source, so the new value drives from the first tick. A gentler gain leans less on any single fix and lets the many fixes average out, so the belief eases in and then stays put. That steady hold finishes the lesson.

Go too low and the pull-in crawls: the fixes barely move the belief and it takes too long to arrive. Somewhere between chasing the noise and crawling is the value that snaps on and holds. Run, edit, Run again until you find it.

And that is the robot you built: from two wheels and no idea where it was to a machine that can lose itself and find its way back.

Go deeper: the gain is a one-number Kalman gain

The nudge you wrote is a stripped-down Kalman filter. The real thing keeps track of how uncertain the prediction is and how noisy the fix is, and each tick it computes the exact blend that trusts the more reliable of the two: that blend weight is the Kalman gain. Here you set that weight by hand as a single constant. When your gain is small you are declaring the beacon noisy and the prediction steady, so you lean on the prediction and only sip from the fix. Push it toward 1 and you are declaring the fix gospel, so you jump to it and inherit all its jitter. The full filter earns that number from the noise; you are choosing it, which is exactly enough to feel what it does.

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