You are driving gentle when the car enters a tunnel and the GPS goes quiet. Nothing tells you where you are any more. Two sensors still work: the wheels count how far the car rolls, and the steering sensor reports the wheels' angle. Every 0.05 s they say how the car moved since the last step: about 0.4 m forward, a hair to the left, a sliver of turn. If the car knows only how it moved since the last step, can it still know where it is?
Pretend the whole lap is the tunnel: 1777 steps, 88.85 s. By the end of this lesson you will write relative_pose, which turns two poses into the step between them, and dead_reckon, which chains the 1777 steps back into the lap. Then you will see what a tiny error in every step does to the answer.

That gap is m (Python prints 1.5e-12): the rebuilt lap is exact, and the gap is only the rounding in the computer's last digits. This lesson builds the tool that does it, one idea at a time.
A pose is a frame
In The view from the driver's seat you described the car by its pose, three numbers : where its front axle is in the world frame, and which way it points, its yaw. At step 400, 20.00 s into the lap, the simulator's record says . The car is on the first bend, pointing 0.704 rad, 40.33°, left of east. Here θ is the yaw. The heading , from Your first perception box, is the yaw minus the road's direction, wrapped into −π to π.
A pose also places a frame. Put the ego frame's origin at and turn its forward axis to θ, and you have the car's own frame at that moment.
A cone stands 10 m ahead of the car and 2 m to its left, in the ego frame. Where is it in the world? You know the recipe: ego_to_world rotates, then adds. To rotate, walk 10 m along the car's forward axis, , and 2 m along its left axis, :
Then add the car's position:

Rotate, then add: two operations for one frame change. This lesson chains frame changes, from the rear axle to the car, from the car to the world, from one step to the next. Written as rotate-then-add pairs, even two of them nest awkwardly: . One small trick turns each pair into a single multiplication.
Give the point a third entry, a 1: . Give the rotation matrix a third column holding the car's position, and a third row :
Now multiply by row by row, as in The view from the driver's seat. The first row gives : the rotate and the add, in one row. The 1 at the end of the point is what picks up the position. The third row gives , so the answer keeps its trailing 1, ready for the next matrix.
Guess first: what does each column of contribute to the answer?

Answer: a matrix times a vector is the matrix's columns, each scaled by one entry of the vector and added. The first two columns are the ego frame's forward and left axes, written in world coordinates, just as the columns of were. The third is where the ego frame's origin sits. So the matrix is the ego frame from the step-400 figure, written as nine numbers. The code gives (160.987, 27.8514), and it matches rotate-then-add exactly.
Look at the bottom row too. The axis columns end in 0, so the trailing 1 never adds a position to them: an axis is an arrow, which turns but has no place. The origin column ends in 1: it is a point. Send through both ways to see the difference. The camera's point of view leans on it.

This matrix takes a point in ego coordinates and returns it in world coordinates. It is written and read "T, world from ego": the point comes in on the right, in ego coordinates, and leaves on the left, in world coordinates. Writing a point with a trailing 1 is called using homogeneous coordinates, and is a homogeneous transform, or just a transform.
In the lab you write pose_to_matrix(pose), which builds , and matrix_to_pose(T), which reads the pose back: and from the third column, and as of T[1, 0] and T[0, 0], the first column's north and east parts. Round trips through the two are exact, with one trap. As Positions and headings showed, atan2 answers only between −π and π, while the simulator never wraps its yaw, which reaches 6.2264 rad by the end of the lap. Whenever the yaw is above π, the two differ by 6.2832 rad, a full turn. Wrap the difference before comparing, and they agree to 0.0.

Subscripts that cancel
The ego frame's origin is the front axle. The rear axle, 2.7 m behind it (the wheelbase , first used in Closing the loop), gets a frame of its own: the rear frame, with its origin at the rear axle and its axes pointing the same way as the ego frame's. Its pose in the ego frame is , so
read "T, ego from rear". It turns nothing and moves every point 2.7 m back.
Where is the rear axle in the world at step 400? In its own frame the rear axle is the origin, . First take it to the ego frame: times is its third column, . Then take that to the world with :
The rear axle is 2.7 m behind the front one, along the car's forward axis, as it should be.

You can also multiply the two matrices first, to get one matrix that goes straight from the rear frame to the world. A matrix times a matrix works column by column: each column of the product is the left matrix times that column of the right one.
- The first two columns of are and . Their trailing 0s skip the position, so they come out as the first two columns of : the car's own axes.
- Its third column, , is the point you just moved. It comes out as .
Its pose is : the same yaw as the car, with the origin 2.7 m further back. In NumPy the product is T_world_ego @ T_EGO_REAR, where @ is the matrix product, and it agrees with the two-step route to 0.0 m.
Now look at the names:
The two inner names, ego and ego, meet and cancel, leaving the outer two. That is the whole rule for chaining frames: write the transforms so that neighbouring names match, and the product is named by the first and the last.

If the inner names do not match, as in , the product means nothing. It would feed world coordinates into a matrix that expects rear-frame ones. NumPy will multiply the numbers anyway, so the names are your only check.
Order matters
Numbers can be multiplied in either order: . Transforms hide a trap here. Take two moves, each written as a pose:
- : drive 1 m forward, and end a quarter turn to the left;
- : drive 1 m forward.
With names, is : is measured from wherever left the car. So means "do , then ", and means "do , then ".
Guess first: does the order of the two moves matter? The quick answer adds their parts: , whichever order you add them in.

Answer: yes. Do then : drive 1 m east, turn to face north, drive 1 m north, and you end at . Do then : drive 2 m east, then turn, and you end at . The two ends are m apart. Adding the parts gave , the -then- answer, and it can never give the other one, because addition ignores order.
The matrices agree with the figure. With and :
The third column of is times 's third column, . Row by row: , then , then 1. That is the point . The third column of is times : , then 0, then 1, the point .
Both products have the same first two columns, and , so both end facing north. Turns on their own add up in any order. What the order changes is where the driving happens.
Two operations commute when their order does not matter, as and do. Transforms do not commute in general, which is why the names matter: they tell you which order is right.
Undoing a pose
Now go the other way, from a point's world coordinates to the car's. World coordinates go in and ego coordinates come out, so the transform is . Undo the two operations in reverse order: first take away the car's position, then undo the turn.

You wrote exactly that in The view from the driver's seat: world_to_ego computes , where is the car's position and the transpose undoes the turn . Multiplied out, that is : a turn, then a fixed shift, which fits the same 3×3 pattern:
The top left is a 2×2 block: the turn, undone. The top right is a column of two numbers: the car's position, turned into the car's own axes and negated. The bottom row stays . This transform undoes , so it is also written , read "the inverse of T, world from ego". Inverting swaps the two names.
How we got the inverse's third column
The ego coordinates of a world point are . Multiplying the bracket out gives two terms. The first, , depends on the point: it is the turn, and it fills the top-left block. The second, , is the same for every point: it is the shift, and it fills the third column, where the point's trailing 1 picks it up. So the inverse is a turn by followed by a shift of .
Try it on , the frame 1 m east of the start, facing north. Its turn is , so . Its position is , so and :

Its pose is . Stand at facing north: the start lies 1 m to your left, to the west, and its forward axis, east, points to your right.
Check it by multiplying. times 's third column, , gives . The first two columns come back as and . So is the identity matrix , with 1s down its diagonal and 0s elsewhere, which leaves every point where it is.
Guess first: at step 400 the car is on the first bend, pointing 40° left of east. Where is the world origin, the start of the road's centre line, as seen from the car: in front or behind, to the left or to the right?

Answer: behind and to the left. invert_pose(T), the closed form you write in the lab, puts in the third column: the world origin is 130.74 m behind the car and 84.97 m to its left. Over every pose of the lap, invert_pose(T) @ T equals to within . Taking world points into the car's frame with it matches world_to_ego to m. NumPy's general inverse, np.linalg.inv, agrees to , but the lab asks for the closed form: it says what undoing a pose means.
What the car felt between two steps
Back in the tunnel. The car no longer knows its pose at step , . Its wheels and steering measure something else: where the car is now, in the frame it had one step ago. That is a transform too, , read "T, k from k plus 1". The names say how to get it:
Multiply both sides on the left by , the inverse of . On the left side the two cancel to , which leaves
In code that is relative_pose(T_world_a, T_world_b), which returns invert_pose(T_world_a) @ T_world_b. You write it in the lab.
Step 100, 5.00 s in, is on the first straight. The record gives the pose at step 100 and at step 101. In the world the car moved 0.39999 m east and 0.00082 m north. Seen from the car, relative_pose reports 0.4000 m forward, 0.00079 m left and a turn of 0.00027 rad (from the unrounded yaws).
Guess first: why is the left part, 0.00079 m, smaller than the northward shift, 0.00082 m?

Answer: the car already points 0.00008 rad left of east, so its forward axis leans slightly north. A small angle in radians times a distance is a sideways distance (Your first perception box), so m of the northward shift is really forward motion. The rest, m, is to the car's left.
Why does a car that points almost straight ahead move left at all? Because moving is not pointing (Positions and headings). The front axle rolls the way its wheels point, and during step 100 they point 0.00184 rad of steering, plus about half the step's turn, 0.00014 rad, left of the car's forward axis. So the left part is m.
Working out how a vehicle moved from its own wheels and steering is called odometry, and each is one odometry step. Over the lap the steps average 0.3998 m forward and 0.00350 rad of turn. Each step's left part never exceeds 0.01639 m.
Guess first: add up the turns of all 1777 steps. What do you get?

Answer: 6.2264 rad, the car's yaw at the end of the lap, 0.0568 rad short of a full turn, 6.2832 rad. Adding up the turns gives the yaw, because turns add in any order. The forward parts add up to 710.49 m. They do not give the position, though: each forward step points a different way.
Approximation. These steps come from the simulator's record, so they are exact: they match its motion rule to m. A real car's wheels slip and its sensors read off, so the Drift section below adds an error. Placeholder. You write the motion rule itself, from speed and steering to a step, in Longitudinal control and vehicle motion.
Dead reckoning
Now run the steps forwards. At the tunnel mouth the car knows its pose, , as the matrix . Then it feels step 0. The names say how to combine them:
Then , and so on. Each new step goes on the right, because each is measured in the frame the car had just before it.
dead_reckon(T_world_start, steps) does this. It returns all 1778 poses as one array of shape (1778, 3, 3): the start, then each running product. The first figure of this lesson was its answer. No pose is more than m or rad from the truth. Rebuilding where you are by chaining your own steps from a known start is called dead reckoning.
Guess first: skip the matrices and add each step's forward, left and turn straight onto , and . What does the rebuilt lap look like?

Answer: a straight line. Adding the forward part to assumes that forward is always east. The rebuilt car ends at : the 710.49 m the car drove, all laid out eastwards, 710.66 m from where the car really is. The sum is right only while the car points east. At the end of the first straight, step 250, it is 0.060 m off.
Guess first: now multiply in the other order, , so each step goes on the left. The inner names, and world, do not match. How far from the truth does the rebuilt car end the lap?

Answer: 1.11 m. That looks nearly right, and it is badly wrong. A step on the left is applied in the world's frame, so each step turns the car's position about the world origin, not about the car. By step 866, 43.30 s in, the car has turned 2.9984 rad, almost half a turn (π is 3.1416). The rebuilt car is at while the true one is at : 204.88 m apart. By the end the turns add up to almost a full turn, the spin nearly undoes itself, and the rebuilt car comes back close to the truth (challenge 4 shows why). Its yaw is right all lap, to rad, because turns add in any order.

This is why the lab checks every step, to within m and rad, and not just the end. The wrong order is more than 100 m off for 562 of the 1778 poses. An end-only check is easy to fool: a "dead reckoning" that never moves the car at all ends just 0.401 m from the truth, because a lap ends near where it starts. Its worst pose is 210.47 m off.
Drift
So far the steps were exact. A real car's are not: its wheels slip a little, and its steering sensor reads a little off. Model that with the simplest error there is: each step's turn is off by a random amount. Each amount is drawn from the bell-shaped normal distribution of Images are arrays, with standard deviation ("sigma", the typical size of a nudge) of 0.0001 rad, or 0.0057°. That is about 3% of an average step's turn, and every step's error is drawn fresh, on its own.
Each run starts its random draws from a seed (Your first perception box), so the same seed replays the same draws. Each seed here is one possible trip through the tunnel, with its own 1777 errors. The measurements use 500 seeds, numbered 0 to 499.
Guess first: with 0.0001 rad of error per step, how far off is the rebuilt car at the end of the lap: millimetres, centimetres or metres?

Answer: most of a metre. Seed 0 ends 0.688 m from the truth. Over 500 seeds the RMS end error, the root mean square of Meet your car, is 0.608 m. Half the seeds end within 0.493 m, and the worst ends 2.098 m away. Ten times the error per step, rad, gives about ten times the drift: an RMS end error of 6.078 m, 9.994 times as much.
How does the error build up over the lap?

It grows for most of the lap. A yaw error does not stay put: a car whose yaw is 0.0001 rad off drives every later step slightly sideways, and each later step adds a yaw error of its own. The yaw errors themselves add up. After the lap their spread is 0.00424 rad, and the challenge problems at the end show why that is , 0.00422 rad. Near the end of the lap the position error eases a little, as the car comes back toward its start. The challenge problems explain why.
Guess first: keep driving round the tunnel. Does the error settle after a few laps?

Answer: no. The RMS end error is 0.608 m after one lap, 1.236 m after four and 2.454 m after sixteen. Four times the laps gives twice the error (2.03 and 1.98 times), with no sign of stopping.
An error that keeps growing because each estimate is built on the one before is called drift. ROS, the software framework many robots run on, says this plainly of its odometry frame: a robot's pose in it "can drift over time, without any bounds" (REP 105). The same document calls that frame "an accurate, short-term local reference". Dead reckoning is good over a few steps and never over a long tunnel.
Placeholder. The fix is to correct the estimate with something that does not drift: a GPS fix when the tunnel ends, or the lane lines in the camera. Combining a drifting estimate with such corrections is the subject of State estimation.
The rear axle is a frame too
The rear frame from earlier in this lesson does not belong to any one step. It is fixed to the car's body and moves with it, so the same works at every step. Such a frame is called body-fixed. One product gives the rear axle's pose at all 1778 steps at once:
T_world_rear = T_world_ego @ T_EGO_REAR
Here T_world_ego holds the lap's 1778 poses, with shape (1778, 3, 3), and @ multiplies each of them by T_EGO_REAR. The result agrees with doing them one at a time to 0.0 m.
Guess first: on gentle's bends the front axle rides about half a metre left of the lane centre, toward the inside of the bend (Closing the loop). Where does the rear axle ride: on the same line, nearer the lane centre, or further inside?

Answer: further inside. Measured the same way as , at the rear axle instead of the front, the rear axle's mean lateral error in the middle of the first bend is 0.5746 m, against 0.5298 m for the front. The rear rides 0.045 m further in.
Closing the loop drew the triangle a bend makes: the turning point, the rear axle and the front axle, with a right angle at the rear axle and the front axle's radius as the longest side. The side from the turning point to the rear axle is then the rear axle's radius, and by Pythagoras it is , shorter than . In the middle of the first bend the front axle rides 0.5298 m inside the 81.8 m lane centre, so m:
That is the measured gap.
Guess first: where on the lap are the two axles furthest apart?

Answer: just after the first bend ends, as the car straightens out: at step 893, 44.65 s in, the rear axle is 0.123 m further left than the front. On the straights the two agree to 0.0004 m on average. Over the lap, the rear axle's mean is 0.406 m and its largest 0.576 m, against 0.376 m and 0.533 m at the front. Both Longitudinal control and vehicle motion and Lateral control build on T_EGO_REAR.
Recap
- A pose is a 3×3 transform that works on points with a trailing 1. Neighbouring names cancel, the order matters, and the closed-form inverse swaps the names.
- Odometry measures . Dead reckoning multiplies the steps on the right and rebuilds
gentleto m. The wrong order ends 1.11 m off but is 204.88 m off mid-lap, so check every step. - A turn error of 0.0001 rad per step drifts 0.608 m RMS in one lap and keeps growing: 2.454 m after 16 laps.

Every frame in this lesson lay flat on the road, and a 3×3 matrix with a trailing 1 moved points between them. The camera's frame does not lie flat. It sits 1.4 m up and is tipped 5° down, so getting from what the camera sees to a place on the road takes one more transform: a 4×4 matrix, built with the same trailing 1. Given how the camera is mounted, where on the road is the thing a pixel sees?
That is the next lesson, The camera's point of view.
Challenge problems
Use one fact without proof: when you add errors that are random and drawn independently, their squared spreads add. Two errors of spread σ add up to an error of spread .
- Yaw drift. Each step's turn error has spread σ, drawn independently. Show that after steps the yaw error has spread . Check it against the measured 0.00424 rad at the end of the
gentlelap, with rad. - The straight-road law. On
straightevery step is m forward (, read "ell", for a step's length). Show that after steps the sideways error has spread about , using the sum of the first squares, . Predict it for the 501 steps ofstraightand for the 1777 steps ofgentle.

- The loop beats the law. Your prediction for
gentleis far bigger than the measured 0.608 m. Explain why. Hint: a yaw error at step turns the whole rest of the path about the car's position at step . - Why the wrong order comes home. In the wrong order, show that the position follows , where is the step's (forward, left) and its turn. Use it to explain the 204.88 m in mid-lap and the 1.11 m at the end.
Answers
After steps the yaw error is the sum of independent errors, each of spread σ. Their squared spreads add to , so the spread is . For the lap, rad, against 0.00424 rad measured over 500 seeds. On
straightit is 0.002238 rad against 0.002239 rad.After step the yaw is off by , the sum of the first turn errors. The next step of length then moves the car sideways, a small angle times a distance. So after steps the sideways error is . The error of step is inside every from on, so it is counted times. Its share has spread , and the squared spreads add to times the sum of the first squares, . For large , is about , so the spread is about . For 501 steps it predicts 0.25897 m. The exact sum gives 0.25859 m, and the measured RMS over 500 seeds is 0.26579 m, 2.6% above the law. On axes where each equal step multiplies the value by the same factor, a log scale, a law like is a straight line whose slope is the power, 3/2. The measured spread rises with slope 1.525 from on. For
gentle's 1777 steps the law predicts 1.729 m.

A yaw error at step turns everything the car does afterwards about the place it was then, . Turning by a small angle about moves the end point by times its distance from , , its lever. Adding the squared spreads, the end error's spread is . That gives 0.618 m for
gentle, against the measured 0.608 m. On a straight the lever is , which gives problem 2 back. On the loop the car comes back near its start, so no lever is longer than the loop is wide. Their RMS is 146.62 m, against 410.03 m on a straight of the same 1777 steps. The same sum, taken at every step, follows the measured drift curve to within 5.9% after step 50. It peaks at 0.716 m at step 1490, where the measured RMS peaks at 0.712 m at step 1485, and it eases off as the car comes home.The wrong order computes , where is the step's matrix. Its third column is times : the step's turn applied to the old position, plus the step's (forward, left) added straight onto world and . That is , and its yaw, , is right. Now turn each position back by the yaw so far, . Then : a path driven with every turn reversed, almost the true lap's mirror image. (The left parts are not mirrored, which moves its end by 0.307 m.) So the wrong-order car is that mirror lap, spun about the world origin by the yaw so far, ; the measured positions match this to m. At step 866 the yaw is 2.9984 rad, almost half a turn, so the mirror lap is spun almost to the other side of the origin, 204.88 m from the truth. At the end the yaw is 6.2264 rad, almost a full turn, so the spin nearly vanishes. The mirror lap, like the true one, ends near its start, and the car lands 1.11 m from the truth.