Tutorial · Intermediate · 25 min
Cross-Track Error: Measuring How Well You Follow
The number that says whether a path follower works, how to measure it honestly, and why Stanley swings wide of corners where pure pursuit cuts inside them.
One number, signed
Cross-track error is the perpendicular distance from the robot to the path, with a sign. Positive to the left of travel, negative to the right. That is the whole definition, and it is the only honest scoreboard a path follower has.
The sign matters more than it looks. An unsigned distance tells you the robot is 20 cm off; a signed one tells you which side, which is what any controller needs and what makes a plot of the error readable — a bias shows as an offset, an oscillation shows as a sine, a corner shows as a spike in a known direction.
Measuring it without fooling yourself
Three traps, in the order people fall into them.
Do not measure against the estimate. If the robot thinks it is on the path, its own reported error is zero by construction. Cross-track error must be scored against ground truth — a tape measure, a total station, a motion-capture rig, or in simulation the true pose the model integrates. In the path following simulator the controller sees a possibly-noisy fix and the error is always computed from the truth, which is the only reason the GPS penalty shows up as a number.
Take the sign from the path frame, not a cross product test. The natural implementation is to test which side of the current segment the robot is on. That sign flips discontinuously as the projection crosses a waypoint, and with any actuator lag the command chatters full-scale while the wheels barely move — which looks exactly like a broken controller. Project onto the path and take the lateral component in the path’s own frame instead:
float h = pathHeadingAt(s); // tangent direction there
float e = -(x - px) * sinf(h) + (y - py) * cosf(h); // + is left of travel
Search near where you were, not everywhere. A global nearest-point search on a path that doubles back will happily match a segment you drove a minute ago. Keep the last arc length and search a window around it — a couple of metres back, enough forward to cover the lookahead.
There is a fourth trap that is subtler and cost me a working controller: at a corner, both adjacent segments project to the same vertex at the same distance. Keep the incoming one and the heading error and lateral offset are both about zero, so a controller that steers on those two quantities sails straight off the path in complete confidence. Resolve the tie to the outgoing segment.
RMS, worst case, and where the error lives
Report three numbers, because each hides something the others show.
- RMS error is the honest average. It is what you tune against.
- Worst case is what decides whether the robot fits down the corridor. A 0.12 m RMS with a 0.50 m peak is a different machine from 0.12 m RMS with a 0.15 m peak.
- Error against distance along the path shows where. This is the plot that tells you whether you have a tuning problem or a geometry problem.
That third one is why the simulator draws it. A short lookahead produces jitter along the whole path; a long one is clean on the straights and spikes only at corners. The RMS can be identical.
Two controllers, two failure shapes
Pure pursuit aims at a point ahead and drives the arc. Stanley — the controller that won the 2005 DARPA Grand Challenge — references the front axle and steers on two terms added together:
δ = θ_e + atan(k · e / v)
The first term aligns the robot with the path’s direction. The second turns cross-track error into a steering angle, and dividing by speed is what makes the same gain behave at 1 m/s and at 10.
Measured over the same course at 2 m/s:
| RMS | Worst | Path length driven | Steering effort | |
|---|---|---|---|---|
| Pure pursuit | 0.12 m | 0.50 m | 0.8% short | 4.3 rad |
| Stanley | 0.17 m | 0.87 m | 2.2% long | 18.5 rad |
The sign of that third column is the whole story. Pure pursuit takes the inside line and finishes early; Stanley refuses to leave the path, overshoots the corner, and comes back — travelling further than the path it was given.
Steering effort is the number people forget. Four times the actuator movement is four times the wear on a servo, four times the current, and on a differential drive four times the wheel scrub. Stanley is not free.
Choosing
Pure pursuit when the path is a suggestion. Coverage sweeps, waypoint missions, anything outdoors where a corner cut of half a metre is nobody’s problem. It has one geometric knob, it degrades gracefully, and it is about twelve lines.
Stanley when the path is a constraint. A lane, a row of crops, a corridor with walls. It holds the line and it will not cut, at the cost of steering effort and a gain that genuinely needs tuning — the lookahead is geometry and transfers between robots; k is a control gain and does not.
Neither, alone, at low speed. Both divide by or scale with velocity. Below roughly 0.3 m/s a differential-drive robot is better served by turning in place to the bearing and then driving, which neither controller expresses.
When it goes wrong
| Symptom | Usually |
|---|---|
| Reported error is always near zero | Measuring against the estimate instead of ground truth |
| The command chatters at every waypoint | Sign taken from a cross-product test that flips at the vertex |
| Drives confidently off the path after a corner | Vertex tie resolved to the incoming segment — the silent one |
| Error jumps to a huge value and recovers | Global nearest-point search matched a distant segment |
| RMS looks fine, the robot clips a wall | Report the worst case too; RMS hides single spikes |
| Stanley oscillates on straights | k too high for the speed and lag; it is a gain, not a geometry |
| Both controllers wander together | The problem is upstream — the position estimate, not the steering |
Run both over the same course in the path following simulator, then follow the path following roadmap from odometry through to a robot that drives a mission on its own.
Explore the graph
Part of these builds
Projects and learning paths that include this tutorial.
Further reading