Skip to main content
Contents1 / 10 ▾
00
Chapter Zero · Read This First

Foundations: The Six Ideas Everything Else Is Built On

SLAM is a circular problem: the map needs your position, and your position needs the map. This chapter makes the circle, and the six ideas that break it, completely clear before any algorithm gets a name.

0.1The Problem, Stated Like a Human

Imagine you wake up in an unfamiliar building with a notepad. Your job: draw a floor plan of the building and mark, at every moment, exactly where you are standing on that floor plan.

Notice the trap. To draw the walls in the right place, you need to know where you are when you see them. But to know where you are, you need a map to locate yourself against. Each answer depends on the other. This chicken-and-egg is the whole problem, and it has a name.

SLAM = Simultaneous Localization And Mapping. Build the map and track your own position in it, at the same time, from the same noisy sensor data, while moving.

Why does a robot need this at all? Because GPS does not work indoors, under bridges, in warehouses, in tunnels, or precisely enough for a robot that must pass through a 90 cm doorway. A robot with no SLAM only knows "I told my wheels to spin." It has no idea what actually happened.

0.2Idea 1: Odometry, or Counting Your Steps

The simplest way to track yourself: start at a known point and add up your own motion. Wheels turned 10 times, times wheel circumference, means you moved 3.1 m forward. This is odometry (from the Greek hodos, "path"), also called dead reckoning.

Close your eyes and walk across a room, counting steps. Twenty steps forward, turn roughly 90°, ten steps more. You have an estimate of where you are, and it's not bad. But every step was slightly uneven, your turn wasn't exactly 90°, and those small errors added up. Open your eyes after five minutes of this and you'll be surprised how far off you are.

Odometry comes in four main flavors, and every SLAM system runs at least one of them:

  • Wheel odometry. Encoders count wheel revolutions; kinematics turns counts into motion. Nearly free, but it measures what the wheels did, not what the robot did. Slip on dust, carpet, or a threshold and the two diverge silently.
  • Inertial odometry. Integrate an IMU's gyroscope for orientation and accelerometer (twice) for position. Superb over a tenth of a second, hopeless alone over a minute: any accelerometer bias integrates into a position error that grows with time squared.
  • Visual odometry. Track features between camera frames and solve for the motion that explains their shift. A good implementation drifts around 0.5 to 1% of distance traveled. Dies in darkness, blur, and on blank walls.
  • Lidar odometry. Align each laser scan to the previous one (scan matching, Chapter 3). Centimeter-level in geometry-rich scenes, degenerate in a long straight corridor where every scan looks identical.

All four share the same disease. Position is the sum of every increment, so per-step errors accumulate instead of canceling. That accumulation is called drift, and it is the villain of this entire book. Pure translation noise grows roughly like a random walk, with the square root of distance. Heading error is far nastier: it grows linearly with everything you drive afterwards.

Here is the lever-arm intuition worth memorizing. A heading error of θ radians turns into θ·d meters of sideways error after driving d meters. One degree is about 0.017 radians, so a single 1° gyro hiccup costs 1.7 cm per meter, which is 1.7 m after a 100 m aisle. A 1.7 cm translation error after the same aisle would be a rounding error. This is why every serious odometry stack spends its best sensor (usually the gyro) on rotation, and why IMU gyro calibration gets a whole section in Chapter 2.

Odometry
Estimating your motion incrementally from your own sensors: wheel encoders, an IMU, camera frames, or lidar scans compared to the previous one.
IMU (Inertial Measurement Unit)
A chip with accelerometers and gyroscopes. Measures acceleration and rotation rate hundreds of times per second. Great for a fraction of a second; drifts badly if integrated alone, because errors get integrated twice on the way to position.
Drift
Accumulated error in an incremental estimate. Small per step, unbounded over time.
Pose
Position plus orientation. In 2D: (x, y, heading θ). In 3D: (x, y, z) plus three rotation angles, hence "6 degrees of freedom" (6-DOF).

Concrete stakes: 1% drift sounds great until you have driven 500 meters and you are 5 meters off, which is the difference between "docked at the charger" and "in the pond."

0.3Idea 2: Loop Closure, or Recognizing Where You Have Been

Here is the escape hatch from drift. Suppose, while blindfold-walking, you occasionally reach out and touch a landmark: "ah, this is the same doorframe I touched five minutes ago." The instant you recognize a previously visited place, you learn something powerful. However much your step-counting says you have wandered, you are actually back here. You can now go back and correct your whole path, smearing the accumulated error across every step you took in between.

That recognition event is called a loop closure, and the correction it triggers is what upgrades mere odometry into SLAM.

BEFORE LOOP CLOSURE start truth belief (drifted) AFTER LOOP CLOSURE "I've been here!" whole path corrected
Fig 0.1: odometry drifts (dashed red); one recognized place pulls the entire trajectory back into shape.

How does a robot recognize a place it cannot "see" the way you do? The universal recipe has two stages. First, place recognition: compress each sensor snapshot into a compact fingerprint and search a database of past fingerprints for near-matches. For images the classic fingerprint is a bag of visual words (DBoW2); for lidar, a polar signature of the scan such as Scan Context. Second, geometric verification: take the candidate match and try to actually align the two scans or images. If no sensible relative pose explains both views, the candidate is rejected. Fingerprints propose; geometry disposes.

A missed loop closure costs you a little accuracy. A false one can destroy the map, because the optimizer will happily bend the whole trajectory to satisfy a spring that connects two places that were never the same. The classic trigger is perceptual aliasing: identical warehouse aisles, hotel corridors, rows of solar panels. Field rule: tune loop detectors to be paranoid. Reject ten real loops before you accept one fake, and keep geometric verification on even when the fingerprint match looks perfect. Chapter 1 covers robust kernels and switchable constraints, the seatbelts for when a fake gets through anyway.
Place recognition
Answering "have I seen this place before?" from sensor data alone, usually by matching compact descriptors against a database of past views.
Perceptual aliasing
Two different places that look identical to the sensor. The main source of false loop closures.
Geometric verification
Confirming a candidate loop by actually aligning the two views and checking the alignment quality before adding the constraint.
Keyframe
A selected subset of sensor frames kept for matching and mapping, so the database grows with the environment rather than with time.
Odometry is local, smooth, and drifts forever. Loop closure is an occasional injection of global truth. SLAM is odometry plus loop closures plus an optimizer that reconciles them. Every system in this book, no matter how fancy, is this sentence.

Setup A: Simulate Drift and One Loop Closure in 30 Lines of NumPy

Goal: watch odometry drift away from a square ground-truth path, then fix the trajectory with a single endpoint loop closure. Prereqs: any OS with Python 3.10+, no ROS needed.

python3 -m venv slamlab && source slamlab/bin/activate
pip install numpy matplotlib

Save as drift_demo.py and run with python drift_demo.py:

import numpy as np
import matplotlib.pyplot as plt

rng = np.random.default_rng(7)

# Ground truth: a 10 m square, 40 steps per side, 0.25 m per step
steps_per_side, step = 40, 0.25
headings = np.repeat([0.0, np.pi/2, np.pi, 3*np.pi/2], steps_per_side)
truth = np.vstack([[0, 0], np.cumsum(
    np.c_[step*np.cos(headings), step*np.sin(headings)], axis=0)])

# Odometry: each step's length and heading increment are slightly wrong
sigma_step, sigma_yaw = 0.01, np.deg2rad(0.6)     # 1 cm, 0.6 deg per step
dyaw = np.diff(headings, prepend=headings[0])
yaw_meas = np.cumsum(dyaw + rng.normal(0, sigma_yaw, len(headings)))
step_meas = step + rng.normal(0, sigma_step, len(headings))
odom = np.vstack([[0, 0], np.cumsum(
    np.c_[step_meas*np.cos(yaw_meas), step_meas*np.sin(yaw_meas)], axis=0)])

# Loop closure: the robot is back at the start; its belief says otherwise
err = odom[-1] - truth[0]
print(f"endpoint error before correction: {np.linalg.norm(err):.2f} m")

# Distribute the error along the path (poor man's pose graph relaxation)
w = np.linspace(0, 1, len(odom))[:, None]
corrected = odom - w * err

fig, ax = plt.subplots(figsize=(6, 6))
ax.plot(*truth.T,     'k-',  lw=2,   label='ground truth')
ax.plot(*odom.T,      'r--', lw=1.5, label='odometry (drifted)')
ax.plot(*corrected.T, 'g-',  lw=1.5, label='after loop closure')
ax.scatter(0, 0, s=80, c='teal', zorder=5, label='start = end')
ax.set_aspect('equal'); ax.legend(); ax.set_title('drift, then one loop closure')
plt.savefig('loop_closure.png', dpi=150); plt.show()

What you should see: the printed endpoint error lands around 0.5 to 1.5 m (about 1 to 4% of the 40 m path), the red dashed path curls away from the black square, and the green corrected path hugs it, with the largest residual bow mid-path where the correction is weakest.

Sanity checks: (1) Set sigma_yaw = 0 and rerun: drift almost vanishes, even with the step noise untouched. Heading error dominates, exactly the lever-arm effect from 0.2. (2) Raise it to 2° per step and the square becomes a banana. (3) Honesty note: subtracting a linearly growing share of the error is a cheat that only translates points. A real pose graph also rotates the path segments, which is why the green corners still bow slightly. Chapter 1 does it properly.

0.4Idea 3: The Map, or What We Are Actually Drawing

"Map" can mean several very different data structures, and choosing one is a real engineering decision:

Map typeWhat it storesGood for
Landmark / feature mapA sparse cloud of distinctive points ("corner of the poster at x,y,z")Localization: cheap to match against
Occupancy gridThe world chopped into cells, each labeled occupied / free / unknownPlanning safe paths: "can I drive through this cell?"
Point cloudRaw 3D points from lidar or depth sensors, stitched togetherVisualization, registration, surveying
Distance field (TSDF/ESDF)Each cell stores how far to the nearest surfaceSmooth trajectory optimization (Ch. 3 and 8)
Mesh / neural / Gaussian mapSurfaces, or a learned function you can render fromReconstruction, simulation, semantics (Ch. 4 and 6)

Size intuition makes these concrete. A landmark map of a building is a few thousand to a few hundred thousand points with descriptors, tens of megabytes at most; this is what ORB-SLAM3 keeps and relocalizes against. An occupancy grid at 5 cm resolution covering 100×100 m is 2000×2000 cells, about 4 MB at a byte per cell; this is the product of slam_toolbox and the diet of every 2D planner, and OctoMap extends the idea to 3D with octree compression. A raw point cloud is the memory hog: a 16-beam lidar at 10 Hz produces roughly 300k points per second, so a ten-minute survey is nearly 200 million points and gigabytes on disk, which is why FAST-LIO2 style pipelines voxel-downsample aggressively. A TSDF stores dense voxels near surfaces; at 10 cm voxels a room is cheap, at 1 cm it is not, and systems like Voxblox exist to manage exactly that trade. Neural and Gaussian maps invert the trade-off: a NeRF-style network is only megabytes of weights but costs a GPU to query, while a Gaussian-splat map of a house runs to millions of primitives and hundreds of megabytes, in exchange for photorealistic rendering (Chapter 4).

Keep the word "unknown" in mind for occupancy grids. A good map distinguishes "I know this is empty" from "I have never looked there," and an exploring robot lives on that difference.

0.5Idea 4: Everything Is Uncertain, So Everything Is Probability

Every sensor lies a little. Wheels slip. Lidar ranges have noise. Cameras blur. So SLAM never says "I am at (3.20, 5.10)." It says "I believe I am near (3.20, 5.10), give or take this much": a probability distribution over poses. The math machinery of the field is about maintaining and updating that belief:

  • Predict: use your motion (odometry) to shift the belief forward, and widen it, because motion adds uncertainty.
  • Correct: use a sensor observation ("the wall is 2.1 m ahead") to narrow the belief, because observations remove uncertainty.

This predict/correct heartbeat is the Bayes filter, and its two famous children are the Kalman filter (belief is a single Gaussian blob: fast, but it can only believe in one place at a time) and the particle filter (belief is a swarm of thousands of guesses, which can believe in several places at once; that matters for the kidnapped-robot problem in Chapter 9). The bible for all of this is Probabilistic Robotics, Thrun, Burgard & Fox (MIT Press, 2005).

Kalman filter: one confident friend pointing at the map saying "we're here-ish." Particle filter: a crowd of 5,000 tourists each dropping a pin; the pins that match what you see out the window survive, the rest get deleted and respawned near the survivors.

That is all the probability this chapter needs. The full machinery (Bayes rule to Kalman to particle filters, and why they are all the same idea wearing different clothes) now lives in Chapter 1, which is the toolbox every later chapter reaches into.

0.6Idea 5: Modern SLAM Is an Optimization Problem

Filters update a belief step by step and throw the past away. Modern SLAM keeps the past and solves it all at once. Picture a graph:

  • Nodes are your pose at each moment ("where I was at t=1, t=2, ...").
  • Edges are measurements connecting poses: "odometry says node 5 is 1 m ahead of node 4," or "loop closure says node 200 is the same place as node 12."

Each edge is a soft constraint, a spring. Odometry springs chain the nodes together; a loop closure adds a long-range spring from late in the trajectory back to early. Then you relax the spring network: find the set of poses that stretches all springs the least. That "least total squared stretch" is least-squares optimization, the formulation is called pose graph optimization, and its general form is a factor graph. Libraries that solve it: GTSAM, Ceres Solver, g2o.

When a loop closure "snaps the map into place," what physically happened is: one new spring was added to the graph, and the solver re-relaxed the whole network. Remember the springs. You will reuse this picture in every chapter.
Front-end
The part that processes raw sensor data into constraints: feature matching, scan matching, loop closure detection. Deals with pixels and points.
Back-end
The optimizer that takes those constraints and solves for the best poses and map. Deals with math. "Front-end proposes, back-end disposes."
Bundle adjustment (BA)
The camera version of graph optimization: jointly refine camera poses and 3D point positions so that points re-project onto the images where they were actually seen. The gold standard of accuracy in visual SLAM.

How the springs become sparse linear algebra, why the problem is solvable at all for millions of variables, and what "optimizing on a manifold" means when rotations enter the picture: that is Chapter 1. Here, keep the physical picture.

0.7Idea 6: Coordinate Frames, the Robot's Family Tree

A robot juggles several coordinate systems at once, and confusing them causes the most embarrassing bugs in robotics. The convention the whole industry converged on (written down as REP 105, but honored far beyond its birthplace): frames form a tree, every frame has exactly one parent, and a typical mobile robot's tree looks like this:

map                               <- map->odom maintained by SLAM / localization
└── odom                          <- odom->base maintained by the odometry source
    └── base_footprint            (robot projected onto the floor plane)
        └── base_link             (robot body; x forward, y left, z up)
            ├── laser_link            (static: measured extrinsic)
            ├── imu_link              (static: measured extrinsic)
            └── camera_link           (static: measured extrinsic)
                ├── camera_color_optical_frame   (z forward, x right, y down)
                └── camera_depth_optical_frame
  • base_link: the robot's own body. "Forward" for the robot. Body-frame axes by convention: x forward, y left, z up.
  • odom: where odometry thinks the robot has moved since power-on. Smooth and continuous, but drifts.
  • map: the globally correct world frame. The SLAM system maintains the correction between map and odom, and that correction can jump when a loop closure fires.

Who owns what is a contract, and it is worth reciting. The wheel or VIO odometry code owns odom→base. The SLAM or localization code owns map→odom, computed so that the chain map→odom→base equals its best pose estimate. The static sensor transforms base_link→laser_link and friends are your measured extrinsics from Chapter 2, loaded from a config file at startup. Nobody writes map→base directly.

Why the odd split? Because the motor controller must never see the robot's position teleport 30 cm mid-motion. Smooth things (steering, velocity control) consume odom→base; correct things (global plans, "go to the charger") consume map→base through the full chain. Chapter 9 turns this contract into a superpower, and it remains one of the most senior-sounding things you can explain in an interview.

map→odom is a slowly evolving, occasionally jumping correction. odom→base is smooth and drifting. Their composition is the robot's best pose. Control reads the smooth one, planning reads the composed one, and no one gets teleported.
Frame bugs that bite real robots: (1) Two writers for one transform. Run a localizer while the mapper is still alive and both fight over map→odom; the pose flickers between two answers on every visualization. (2) Extrinsics with a sign flip. A lidar mounted 180° off makes the map build mirrored; the map looks fine until the first loop, then tears itself apart. (3) Forgetting the optical-frame convention. Camera data lives in z-forward optical frames; skip that rotation and your point cloud renders sideways or under the floor. (4) Controlling in the map frame. A loop closure fires, map→odom jumps 40 cm, and a controller fed map-frame pose slams the wheels to "correct" a teleport that never physically happened.

Setup B: The Frame Contract, Live, in 60 Lines of Python

Goal: watch map→odom jump while odom→base stays smooth, in raw numbers you generate yourself. Prereqs: Python 3.10+ with numpy. No robot, no simulator, no framework.

import numpy as np
rng = np.random.default_rng(7)

def T(x, y, th):                       # SE(2) as a 3x3 homogeneous matrix
    c, s = np.cos(th), np.sin(th)
    return np.array([[c, -s, x], [s, c, y], [0, 0, 1]])

def params(M):                         # back to (x, y, theta)
    return M[0, 2], M[1, 2], np.arctan2(M[1, 0], M[0, 0])

# ground truth: drive a 10 m square, 1 m steps, left turn at corners
truth, odom = [T(0, 0, 0)], [T(0, 0, 0)]
for leg in range(4):
    for step in range(10):
        step_true = T(1.0, 0, np.pi/2 if step == 9 else 0)
        noise     = T(rng.normal(0, .02), rng.normal(0, .02), rng.normal(0, .01))
        truth.append(truth[-1] @ step_true)
        odom.append(odom[-1] @ step_true @ noise)   # odometry integrates noise

T_map_odom = T(0, 0, 0)                # the SLAM correction, identity at start
for k, (Tt, To) in enumerate(zip(truth, odom)):
    if k == len(truth) - 1:            # back at start: loop closure fires!
        T_map_odom = Tt @ np.linalg.inv(To)
    x, y, th   = params(T_map_odom)          # map->odom: the correction
    ox, oy, ot = params(To)                  # odom->base: smooth, drifting
    mx, my, mt = params(T_map_odom @ To)     # map->base: the composed truth-estimate
    print(f'{k:3d}  map->odom [{x:+.3f} {y:+.3f} {th:+.3f}]   '
          f'odom->base [{ox:+.3f} {oy:+.3f}]   map->base [{mx:+.3f} {my:+.3f}]')

What you should see: for forty steps map→odom prints a constant [+0.000 +0.000 +0.000] while odom→base drifts quietly away from the true square. On the last line the loop closure fires: map→odom jumps to something like [+0.31 -0.18 +0.04] in a single step, and the composed map→base lands back on the origin. Odom→base never jumped; the correction absorbed the whole error. That pair of columns is the frame contract, live.

Things to try: (1) Raise the noise sigmas 5× and watch the final jump grow; the contract does not care how big the correction is, control stays smooth. (2) Fire the correction every 10 steps instead of once; map→odom now jumps at every partial loop, the way a real system behaves in a small room. (3) Feed a controller the map→base column and imagine the wheel command at the jump; that thought experiment is warfield bug 4 above.

0.8The Sensors, in One Honest Table

SensorGives youLovesHates
Wheel encodersLocal motion, cheapHard floorsSlippage, sand, carpets, stairs
IMURotation + acceleration at 200–1000 HzShort timescales, gravity directionLong-term integration (drifts in seconds)
Camera (mono/stereo/RGB-D)Rich texture, semantics, cheapWell-lit, textured scenesDarkness, blank walls, motion blur; mono can't measure scale
LiDAR (2D/3D)Precise range, works in the darkGeometry-rich scenesLong featureless corridors, rain and dust, price
GPS/GNSSAbsolute position outdoorsOpen skyIndoors, urban canyons, meters of noise

No sensor is sufficient alone, which is why the word fusion appears in every system name (LIO is Lidar-Inertial Odometry, VIO is Visual-Inertial Odometry). Sensors are chosen so that one's weakness is another's strength. The IMU carries you through the 0.1 s the camera is blurred; the camera cancels the IMU's drift. The physics behind each row, the noise models that describe them, and the calibration that makes fusion possible at all are Chapter 2.

0.9A Short History of SLAM

Knowing the eras is not trivia. Each one exists because the previous one broke somewhere specific, and interviewers love asking why.

1986, the problem gets its shape. Randall Smith and Peter Cheeseman publish "On the Estimation and Representation of Spatial Uncertainty," and with Matthew Self extend it to the stochastic map: robot pose and all landmark positions stacked into one Gaussian state with a full covariance matrix. The insight that matters is the off-diagonal terms. Landmark estimates are correlated through the robot that observed them, so seeing one landmark improves your estimate of all the others. What it fixed: SLAM became a well-posed estimation problem instead of a heuristic. What it broke: nothing yet, because computers of the era could not run it beyond toy sizes.

The 1990s, EKF-SLAM meets real robots. Leonard, Durrant-Whyte, and others put the stochastic map on sonar- and laser-equipped robots, and the acronym SLAM itself is coined mid-decade. Convergence proofs follow (Dissanayake et al., 2001). What it fixed: the first genuinely online systems that both mapped and localized. What it broke: the covariance update is O(n²) in the number of landmarks, capping honest maps at a few hundred features; linearizing around a wrong heading makes the filter quietly overconfident; and one bad data association is baked into the state forever, since a filter cannot revise the past.

2002, FastSLAM and the particle trick. Montemerlo, Thrun, Koller, and Wegbreit factor the problem: sample whole trajectories with a particle filter, and note that given a trajectory, landmarks become independent, so each particle carries N tiny per-landmark EKFs instead of one giant coupled one. Cost drops to O(M log N). What it fixed: tens of thousands of landmarks, plus per-particle data association, so a wrong match can die with its particle instead of poisoning everything. What it broke: long loops. Resampling collapses particle diversity, and the one particle that remembered the correct early trajectory is often gone by the time the loop closes.

The 2010s, the graph era. The idea dates to Lu and Milios in 1997, but sparse linear algebra made it practical: square-root SAM (Dellaert and Kaess, 2006), iSAM2, g2o (Kümmerle et al., ICRA 2011), GTSAM, and Ceres. The SLAM information matrix is naturally sparse, so re-optimizing an entire trajectory takes milliseconds, and loop closures can rewrite history. This is the substrate under ORB-SLAM, Cartographer, and the LOAM lineage. What it fixed: scale, accuracy, and retroactive correction. What it left open: the optimizer believes its front-end, so a single false loop closure still wrecks the map, which spawned robust kernels, switchable constraints, and a small industry of outlier-hardened solvers (Chapter 1).

The 2020s, the learning era. Neural networks replace the hand-tuned pieces one at a time: learned features (SuperPoint), learned matching (SuperGlue), learned dense bundle adjustment (DROID-SLAM, 2021), then maps themselves go neural with NeRF-style and Gaussian-splat representations, and feed-forward models like DUSt3R skip the pipeline entirely. What it fixed: robustness exactly where hand-crafted features die, in blur, low texture, and bad light. What it broke: compute budgets, predictability outside the training distribution, and the comfortable assumption that you can explain a failure by reading the code. Chapters 4 and 6 keep score honestly.

Past, Present, and Future of SLAM: Toward the Robust-Perception AgeCadena, Carlone, Carrillo, Latif, Scaramuzza, Neira, Reid, Leonard · IEEE T-RO 2016 · arXiv:1606.05830The field's own state-of-the-union; the best single survey to cite in an interview. Simultaneous Localization and Mapping: Part IDurrant-Whyte & Bailey · IEEE Robotics & Automation Magazine 2006The classic two-part tutorial that fixed the field's vocabulary and told its origin story. FastSLAM: a Factored Solution to the SLAM ProblemMontemerlo, Thrun, Koller, Wegbreit · AAAI 2002The Rao-Blackwellized particle filter that briefly beat the EKF at its own game. Factor Graphs for Robot PerceptionDellaert & Kaess · Foundations and Trends in Robotics 2017The graph era, explained by the people who built GTSAM; the long-form companion to Chapter 1.

0.10Anatomy of a Modern SLAM System

Strip the branding off any modern system, LiDAR or visual, classical or learned, and the same four organs appear. The front-end eats raw sensor data and produces odometry, features, and keyframes at sensor rate. The back-end holds the factor graph and re-optimizes it when new constraints arrive. The loop detector watches the keyframe stream, searches the past, and injects the occasional long-range constraint. The map manager owns the growing map: it culls redundant keyframes, maintains the landmark database the loop detector searches, and serves whatever map product the rest of the robot consumes.

SENSORS imu 200 Hz camera 30 Hz lidar 10 Hz wheels 50 Hz FRONT-END tracking / odometry feature extraction keyframe selection runs at sensor rate BACK-END factor graph sparse least squares re-optimizes on every new edge MAP MANAGER keyframe culling landmark database serves /map and map->odom LOOP DETECTOR place recognition + geometric verification odom edges poses keyframes loop edges search past track against existing map
Fig 0.2: the four organs of a modern SLAM system; solid arrows carry data forward, dashed arrows are the feedback that makes it SLAM rather than odometry.

The names change per community but the org chart survives. In ORB-SLAM3 the organs are called tracking, local mapping, loop closing, and the atlas. In a LiDAR stack like FAST-LIO2 plus a pose-graph layer, the front-end is the tight IMU-lidar filter and the back-end lives in a separate node. RTAB-Map (Chapter 5) ships all four in one process with a memory manager deciding which keyframes stay eligible for loop search. When you read any system paper, your first job is to find the four organs; whatever is left over is the paper's contribution.

Front-end at sensor rate, back-end at keyframe rate, loop detector on the keyframe stream, map manager owning what persists. Learn to see these four in any architecture diagram, then ask where each one fails.

0.11Your Map of the Book

Ten chapters, each stated in a line:

Reading order: 0, 1, 2 in sequence, then 3 or 4 depending on whether your robot carries a laser or a camera, then wherever your project points. Chapter 8 pays off whenever you touch it.

0.12Check Yourself: Interview Warm-Ups

Explain SLAM to a non-engineer in three sentences.

A robot in a new building must draw the floor plan while also tracking its own position on that plan, but drawing needs your position and finding your position needs the plan, so both must be estimated together. The robot counts its own motion, which slowly drifts, and corrects itself whenever it recognizes a place it has seen before. Software fuses all of these noisy clues into the single most consistent map plus trajectory.

Why does odometry drift, and why can't better sensors fully fix it?

Each incremental motion estimate carries a small error, and position is the sum of all increments, so errors accumulate rather than cancel. Better sensors shrink the per-step error, but the sum is still unbounded over time. Only absolute information can bound it: recognizing a known place (loop closure), matching a prior map, or GPS. Those constrain where you are rather than how you moved, which is the difference that matters.

What's the difference between a filter-based and a graph-based SLAM back-end?

A filter (Kalman or particle) maintains only the current belief and marginalizes the past: cheap and online, but a mistake baked in stays in. A graph keeps a subset of all past poses as variables and re-optimizes them whenever new constraints arrive, so a loop closure can retroactively fix the whole trajectory. Modern systems are graph-based, usually with a filter or fixed-lag smoother running the fast odometry front-end.

Why do robots separate the map frame from the odom frame?

Odometry is smooth but drifting; SLAM corrections are accurate but arrive as discrete jumps. Controllers steering the wheels must see a smooth pose (odom→base_link), while planners need the globally correct one (map→base_link through the chain). Publishing the correction as a separate map→odom transform lets a loop-closure jump update the plans without teleporting the robot under its controller. The full story is in Chapter 9.

What breaks first when you double the robot's speed?

The front-end, almost always. Camera frames blur and overlap less, so feature tracking loses lock; lidar scans smear more per sweep, so deskew errors grow; and the IMU must bridge larger motions between corrections, so its integrated error per interval grows too. The back-end math barely notices, since a factor graph does not care how fast the edges were collected. The honest senior answer names motion blur and inter-frame overlap first, then timestamp accuracy, because at higher speed a fixed few-millisecond sync error turns into centimeters of error (Chapter 2).

Grid map or landmark map for a warehouse robot?

Both, for different jobs. The planner needs an occupancy grid, because "which cells can I drive through" is exactly what a grid stores and a landmark cloud cannot answer. Localization in a warehouse is the harder call: identical racks cause perceptual aliasing for scan matching, so distinctive visual landmarks or fiducials can localize more reliably than geometry alone. Real deployments typically localize against one representation and plan on the grid, and the grid must keep its unknown state so the robot never confuses "empty" with "never seen."

Why is a small heading error worse than a small position error?

A position error stays the size it is, but a heading error is a lever arm: θ radians of heading becomes θ·d meters of lateral error after driving d meters. One degree costs about 1.7 cm per meter, so 1.7 m after a 100 m run, and it also corrupts the direction in which every subsequent motion increment is integrated. That is why gyros get the calibration attention, why rotation noise dominates drift budgets, and why the toy in Setup A collapses to near-perfect odometry the moment you zero the yaw noise.

Your finished map shows the same corridor twice, slightly offset. What happened?

A loop closure that should have fired did not. The robot revisited the corridor, but accumulated drift pushed its pose estimate outside the loop detector's search radius, or the place recognizer scored the revisit below threshold, so the corridor was mapped a second time in the wrong spot. Fixes in order: check drift over the loop length (better odometry buys the detector room), widen the loop search radius or lower the acceptance threshold with geometric verification kept strict, and confirm the two passes actually shared a viewpoint, since a corridor traversed in opposite directions can be unrecognizable to a camera-based detector.