Φferromotion · textbook · chapter 12 rust → wasm · on-device

Revising the past

A robot's dead-reckoned map of where it has been slowly drifts, and by the time it returns to the start the loop no longer closes. The fix is not a better guess about the present — it is the willingness to go back and correct the whole past at once. This page does it live, with the same Rust pose-graph smoother the native tools use.

01 — the problemSmall errors, compounded

Every step, the robot estimates how far it moved from its wheels or its legs — and every estimate is a little wrong. Those little errors compound: over a long loop the belief spirals away from the truth, so when the robot physically returns to where it began, its map says it is somewhere else entirely. A filter, which keeps only the present estimate and throws the past away, can never repair this — the drift is baked into history it no longer holds.

02 — the loop closure"I have been here before"

A smoother keeps the whole trajectory as a graph of poses tied by constraints, and re-optimizes all of it whenever a new constraint arrives. The powerful one is a loop closure: the robot recognizes a place it has already visited and adds a single edge — "this pose equals that one." That one late fact is inconsistent with the drifted chain, and resolving the inconsistency pushes a correction backward through every pose in the loop.

Below, the robot has driven a loop with drifting odometry. Close the loop and watch the entire path snap into alignment with the truth.

the loop
trajectory error
loop gap

the dashed line is the true path; the drifting estimate never returns to start — until the closure edge ties the ends together

03 — the correction flows backwardNot just the endpoint

Notice what moves when you close the loop: not only the final pose snapping onto the start, but every pose along the way shifting to share the correction. The smoother does not clamp the end and leave the rest; it finds the trajectory that best satisfies all the constraints at once — the odometry chain and the closure together — so the error is distributed smoothly around the whole loop. That backward flow of information is exactly what a filter gives up.

04 — the numberHow much it helps

On load, this page drove the drifting loop and measured the whole-trajectory error with and without the single closure edge:

trajectory RMS error — odometry only
trajectory RMS error — with one loop closure
error removed by one late factor
verdict

One constraint, added at the end, cuts the error across the entire history — because the estimate was never committed. Turn the drift up and the open loop yawns wider, yet the same single closure still pulls it shut.

05 — the pointKeep the past editable

A map is a hypothesis, not a record.

By holding the whole trajectory as a graph of constraints rather than a fixed log, a smoother can accept a fact learned late and let it rewrite everything that came before — which is how a robot builds a map that actually closes.

This is the backbone of modern SLAM: pose-graph back-ends that keep every keyframe live and re-solve on each loop closure. It is the sibling of the estimation chapter — the invariant filter keeps the present consistent moment to moment; the smoother keeps the past consistent in hindsight — and together they are how an embodied system knows where it is and where it has been. The same sparse least-squares solver drives both a legged robot's foothold history and a drone's flight around a building.

What you just drove: the LegSmoother from ferromotion-core — an SE(2) pose-graph fixed-lag smoother over a sparse factor graph (faer sparse Cholesky), compiled to WebAssembly, the same code the native tools link against. The estimate is re-solved from the constraints on every change; nothing is precomputed.

Verified in the library: it recovers a ground-truth trajectory from perfect factors to 1e-6; a late long-baseline factor retro-corrects interior poses (a smoother, not a filter); loop closure slashes the trajectory error >60% and shuts the loop; more drift opens a wider loop. Each is a test in cargo test, not a claim in prose. See also ch.6 — the estimator that stays honest · the full textbook.

Institute for Physical AI · the Rust library · crates.io