HomeArticlesAutonomous Systems

SLAM: Simultaneous Localization and Mapping

A particle filter finds the robot, a log-odds occupancy grid builds the map — and each one needs the other's output to work.

mysimulator teamUpdated June 2026≈ 9 min read▶ Open the simulation

The chicken-and-egg problem

A robot dropped into an unknown space with only a noisy lidar and noisy wheel odometry faces a circular dependency: to know where it is, it needs an accurate map; to build an accurate map, it needs to know exactly where it was standing when it took each scan. Simultaneous Localization and Mapping solves both at once by treating them as one joint estimation problem rather than two sequential ones — this simulation runs a real particle filter for the localization half and a Bayesian occupancy grid for the mapping half, updating each other every step.

live demo · a particle swarm converging on the robot's true pose● LIVE

Localization: the particle filter

A particle filter (or Monte Carlo Localization) represents the robot's belief about its own pose — not as one number, but as a cloud of thousands of weighted hypotheses, each a candidate (x, y, theta). Every step runs three phases:

1. predict:  move every particle by the odometry reading + noise
2. update:   score each particle by how well its predicted lidar
             scan (cast against the current map estimate) matches
             the robot's actual lidar reading
3. resample: draw a new particle set, probability proportional to
             score - high-scoring particles get duplicated,
             low-scoring ones vanish

Because odometry drifts (wheel slip, integration error compounding over time) the predict step alone would let the cloud spread out and drift away from the truth. The update step is what pulls it back: a particle whose hypothesised position would have produced a very different lidar scan than what the sensor actually saw gets a low weight and is culled at resampling. After enough steps the surviving cloud collapses tightly around the true pose — that collapse, visible in the demo as the particle spread shrinking, is localization converging.

Mapping: the log-odds occupancy grid

In parallel, the environment is represented as a grid of cells, each holding the probability that cell is occupied. A single noisy lidar return is weak evidence — it might be a false positive, a reflection, or sensor noise — so instead of storing raw probabilities (which saturate awkwardly at 0 and 1) the standard trick stores the log-odds of occupancy, which turns Bayesian updates into simple addition:

l(cell) = log( p(occ) / (1 - p(occ)) )

// each lidar ray:
l(cell) += l_hit   if the ray terminated in this cell   (evidence: occupied)
l(cell) += l_miss  if the ray passed through this cell  (evidence: free, l_miss < 0)

p(occ) = 1 / (1 + e^(-l(cell)))   // convert back to a probability for display

Every additional scan through a cell nudges its log-odds further toward certainty in one direction; a handful of consistent detections is enough to be confident a wall exists, while a single stray return barely moves the estimate. This is exactly why the occupancy grid sharpens from grey uncertainty into confident black walls and white free space over the first several dozen scans of the demo.

Why they need each other

The particle filter's observation step needs a map to score lidar predictions against, and the occupancy grid's update needs a pose to know which cells a ray passed through — each is the other's input. In FastSLAM, the classical algorithm this style of simulation follows, that circularity is resolved by giving each particle its own occupancy grid: pose hypothesis and map hypothesis travel together, and resampling culls bad pose-map pairs as a unit rather than trying to disentangle a bad pose from a bad map after the fact. This is also why particle count is a real computational cost in SLAM, not just localization — every particle carries a whole grid.

The unresolved failure mode of any local method is loop closure: after a long traverse, accumulated drift can make the map self-inconsistent, so returning to a previously-visited room may show two overlapping copies of the same hallway offset by the drift. Detecting that the robot has returned somewhere and snapping the map back together (via pose-graph optimization) is a separate, harder problem that this local scan-matching demo does not attempt — it is what turns SLAM into modern SLAM systems like graph-based and factor-graph SLAM.

Frequently asked questions

Why does SLAM need a probabilistic filter instead of just trusting the sensors?

Because every sensor is wrong some of the time: wheel odometry drifts from slip, and lidar returns are noisy or occasionally spurious. A particle filter keeps a whole distribution of hypotheses alive and lets consistent evidence across many steps win out over any single bad reading, which is far more robust than trusting the latest measurement outright.

What does the log-odds representation buy you over storing raw probabilities?

Raw probabilities saturate near 0 and 1, which makes repeated Bayesian updates numerically awkward and asymmetric. In log-odds space, a Bayesian update is just addition — accumulate l_hit for occupied evidence and l_miss for free evidence — and the value can grow without bound in either direction, which keeps the arithmetic simple and stable over thousands of scans.

What is loop closure and why isn't it shown here?

Loop closure is recognising that the robot has returned to a place it already mapped, so the two independently-drifted map estimates of that place can be merged and the accumulated error corrected. It requires comparing the current scan against the entire map history, not just the local filter step, and is normally solved separately with pose-graph optimization — a different algorithm layered on top of the local SLAM loop shown here.

Try it live

Everything above runs in your browser — open SLAM and change the parameters while it is running. Nothing is installed, nothing is uploaded, the whole model lives in one tab.

▶ Open SLAM simulation

What did you find?

Add reproduction steps (optional)