Skip to the content
FixTheRobot Explore Robotics / UAV / Module 4 / M4-T6

UAV Systems Engineering · Module 4

M4-T6: LiDAR SLAM

LiDAR SLAM turns scans into a metric map; the design choices are what to register (features or raw points), what to store (voxels or points) and how to close loops.

  • Lesson 6 of 15
  • SLAM and Autonomous Localization
  • Research-level
  • About 5 minutes to read

LiDAR gives direct 3-D geometry, so LiDAR SLAM systems tend to be metrically accurate and robust to lighting. The families differ in how they register scans and how they store the map, and those choices set their speed, robustness and failure modes.

Learning objectives

After this lesson, you should be able to:

  • Compare feature-based (LOAM family) and direct (FAST-LIO family) registration.
  • Describe map representations and the role of voxel downsampling.
  • Explain loop closure with global scan descriptors.
  • Choose a LiDAR SLAM approach for a UAV and state its limits.

Conceptual explanation

Feature-based methods (LOAM, A-LOAM, LeGO-LOAM) extract edge and planar points by local curvature and register them to a feature map (lesson M4-T7). Direct methods (FAST-LIO, FAST-LIO2, KISS-ICP) register downsampled raw points to a point or voxel map, without feature extraction (lesson M4-T8). Both fuse an IMU for deskewing and prediction. Back-ends add loop closure and pose-graph optimisation (LIO-SAM, LeGO-LOAM with SC).

LiDAR SLAM design choicesScans are deskewed and downsampled, then registered either by extracted features or by raw points to a local map stored as voxels or an incremental tree. A place-recognition descriptor proposes loop closures, which a pose graph then optimises.Deskew + filterIMU, voxel gridRegisterfeatures or pointsLocal mapvoxels / ikd-TreeLoop detectscan descriptorPose graphglobal mapchoose by sensor, scene and compute budget
Choices in a LiDAR SLAM system.
Animation of two-dimensional LiDAR mapping. A vehicle drives a loop inside a room with two obstacles and a partition wall. Each scan is transformed with the current pose and its points are added to a growing map, coloured by time, so the walls and obstacles appear as dense lines. A counter shows the number of scans and map points.
LiDAR SLAM builds a map by registering each scan against the map and appending it. Scans are range measurements taken from the estimated poses; consistent registration makes walls thin, drift makes them thick. Ray-cast scans (181 rays, 12 m range) with the true poses, to show the map-building mechanism. (Looping, about 6 seconds; drawn and computed for this course with illustrative values.)

Engineering intuition

A raw LiDAR frame holds tens of thousands of points; registering them all is unnecessary and expensive. A voxel filter keeps one representative per cell, giving even density and bounded cost. Feature extraction is a second kind of filtering that keeps only informative points (edges and planes), but needs tuning for each LiDAR’s scan pattern; direct methods skip it and accept more points. For loop closure, a global descriptor of a scan (for example a polar height map, as in Scan Context) lets a place be recognised from a different heading without any prior pose.

Mathematical formulation

Voxel downsampling: points pp with voxel size vv fall in cell ⌊p/v⌋\lfloor p/v\rfloor ; replace each occupied cell by the centroid (or the point closest to it). The number of retained points is bounded by the occupied volume divided by v3v^{3}, independent of the raw point count. Registration cost is then proportional to the retained points times the neighbour-search cost (lesson M2-T14).

Voxel grid filter
c(p)=⌊pv⌋∈Z3c(\mathbf p) = \left\lfloor\frac{\mathbf p}{v}\right\rfloor \in \mathbb Z^{3}
retained=∣{c(p)}∣,pˉc=1nc∑p∈cp\text{retained} = \left\lvert\{c(\mathbf p)\}\right\rvert, \qquad \bar{\mathbf p}_c = \frac{1}{n_c}\sum_{\mathbf p\in c}\mathbf p

Scan Context-style loop closure: encode the scan as a matrix of maximum heights over (ring, sector) bins; compare two descriptors by the column-shifted distance (to be yaw-invariant), then verify with ICP. Pose-graph optimisation (lesson M4-T12) distributes the loop correction. Map size must be bounded (sliding local map, keyframe submaps) for constant compute.

vv
voxel edge length (m): 0.1–0.5 m is typical in published systems for indoor to outdoor scenes (a tuning choice).
ncn_{c}
number of points in voxel cc.

Architecture and data flow

Hardware: LiDAR (rotating or solid-state), IMU, calibrated extrinsics, shared clock. Software: LIO node → odometry and local map; back-end → global map and pose graph; output frames: odom (smooth) and map (corrected). Choose the algorithm using the LiDAR’s field of view (solid-state LiDARs with a narrow field favour direct methods), the scene geometry (corridors need degeneracy handling, lesson M2-T13) and the compute budget (lesson M7-T12).

Real-world UAV applications

  • GNSS-denied mapping and localisation (Capstone 2).
  • Building prior maps for map-based localisation (lesson M4-T13).
  • Obstacle maps for planning.
  • Inspection with repeatable localisation.

Implementation example

This runs as shown: a voxel-grid filter on a dense synthetic cloud: the point count falls by an order of magnitude while the shape (centroid and extent) is preserved, and the retained count tracks the occupied volume, not the raw density.

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

def voxel_filter(P, v):
    cells = np.floor(P / v).astype(np.int64)
    _, inv, counts = np.unique(cells, axis=0, return_inverse=True, return_counts=True)
    sums = np.zeros((counts.size, 3)); np.add.at(sums, inv.ravel(), P)
    return sums / counts[:, None]

# a dense cloud on three walls of a 10 x 8 x 3 m room (about 90 000 points)
def wall(n, axis, value, ext):
    P = np.stack([rng.uniform(0, ext[0], n), rng.uniform(0, ext[1], n), rng.uniform(0, ext[2], n)], axis=1); P[:, axis] = value; return P
P = np.vstack([wall(40000, 0, 0.0, (0, 8, 3)), wall(40000, 1, 0.0, (10, 0, 3)), wall(10000, 2, 0.0, (10, 8, 0))]) + 0.005 * rng.standard_normal((90000, 3))
for v in (0.1, 0.25, 0.5):
    Q = voxel_filter(P, v); print(f"voxel {v} m: {len(P)} -> {len(Q)} points ({100 * len(Q) / len(P):.1f}%)")
Q = voxel_filter(P, 0.25)
assert len(Q) < len(P) / 10 and np.allclose(Q.min(0), P.min(0), atol=0.3) and np.allclose(Q.max(0), P.max(0), atol=0.3)
assert len(voxel_filter(np.vstack([P, P + 0.001]), 0.25)) <= len(Q) + 100          # doubling the density barely changes the retained count: bounded cost
Voxel filtering bounds the point count independent of raw density.

Common engineering mistakes

No downsampling

Registration cost explodes and gives no accuracy benefit.

Voxel size not matched to the scene

Too large loses structure, too small keeps cost; tune per environment.

Unbounded global map in the odometry loop

Use a local sliding map for registration.

No loop closure verification

Aliasing in repeated structure causes false loops.

Treating the corrected map-frame pose as continuous

Use odom for control.

Failure modes

Failure modes, symptoms and causes
Failure modeHow it shows upLikely cause
Corridor driftAlong-axis driftDegenerate geometry (lesson M2-T13)
Map smearDouble wallsTiming, extrinsics
Dynamic objectsGhost objects in the mapNo dynamic filtering
Compute overrunLatency growthMap or point count unbounded

Debugging approach

  1. Look at the map for double surfaces and scale drift.
  2. Plot the points per scan after filtering and the registration time.
  3. Evaluate drift with evo against ground truth.
  4. Check loop-closure accept/reject statistics.

Practical exercises

  1. Estimate the retained points for a 100 m2100\,\mathrm{m}^{2} floor at 0.25 m voxels.
  2. Compare feature-based and direct registration in terms of tuning parameters.
  3. Choose a LiDAR SLAM method for a solid-state LiDAR with a 70∘70^{\circ} field of view and justify it.
  4. Describe how Scan Context achieves yaw invariance.

Interview questions

Write an answer in your own words, then reveal the model answer. Nothing is sent anywhere.

Question 1

What is the difference between LOAM and FAST-LIO style registration?

Model answer

LOAM extracts edge and planar features and registers them; FAST-LIO registers downsampled raw points directly to a map, avoiding feature extraction.

Question 2

Why voxel-filter the scan?

Model answer

It bounds the point count and gives uniform density so the registration cost is predictable and accuracy is unharmed.

Question 3

How does a global scan descriptor help loop closure?

Model answer

It encodes the scan in a way that is comparable across viewpoints and headings, proposing candidates that are then verified geometrically.

References and further reading

Primary papers, official documentation and standards. Each claim above that is specific to a tool or version points here.

What’s next

Mark this lesson

Saved in this browser and synced to your account when you are signed in.

Practice this lesson

M4-L3: Build a 3D point-cloud map

Accumulate registered scans into a map.

Practice this lesson

M4-L4: Compare visual and LiDAR localization

Evaluate both against ground truth with evo.

Next lesson

M4-T7: LOAM and A-LOAM

Describe edge and planar feature extraction in LOAM and the scan-to-scan and scan-to-map registration it performs.