EECE 5550 Mobile Robotics

Lecture 6

Sensors, Fusion, and Localization

Dr. Xian Li

Department of Electrical and Computer Engineering

Northeastern University

Back to the question

Ten minutes of driving. Which estimate would you trust?

0.00.20.40.60 min2 min4 min6 min8 min10 minposition error (m)/odom alonelidar against a map alonefused
/odomsmooth, but drifts without bound
Lidar + mapbounded, but noisy and sometimes ambiguous
Fusedsmooth and bounded; this is what Nav2 runs
2

Today

Every estimate is only as good as the models behind it.

  1. The Bayes filter, revisited. Belief, and the two models it needs.
  2. Choosing a filter. KF, EKF, UKF, and particles, step by step on small problems.
  3. The motion model. Odometry predicts the pose, as a distribution.
  4. Measurement models. What each TurtleBot 4 sensor reports, to correct the prediction: p(z | x).
  5. Localization. The EKF and Monte Carlo localization on the TurtleBot pose.
  6. Fusion and AMCL in practice. Count each sensor once; map → odom, in simulation and on the robot.
Reading
  • Thrun, Burgard, and Fox, Probabilistic Robotics, Ch. 3 to 6, and 8
  • Moore and Stouch, robot_localization, IAS 2014
  • Fox, KLD-sampling, IJRR 2003
  • Nav2 documentation: AMCL

Lecture 5 derived the Bayes and Kalman filters. Today: the filters that cope when models are nonlinear or non-Gaussian, the models the TurtleBot 4 needs, and AMCL, which puts them together.

3

The Bayes filter, revisited

From Lecture 5. Every filter today runs these two steps; they differ only in how they store the belief.

Predict
bel―(xt)=∫p(xt|ut,xt−1)bel(xt−1)dxt−1
Motion modelodometry, Part 3 of today
Correct
bel(xt)=ηp(zt|xt)bel―(xt)
Measurement modeleach sensor, Part 4 of today
bel― is the belief before the measurement; η normalizes the product so it integrates to one.
Histograma probability for each cellgrid filter: the next Try-it
Gaussian N(μ, Σ)a mean and a covarianceKF, EKF, UKF
Weighted samplesM particles, each with a weightparticle filter, AMCL
Three ways to store the same belief
4

Try it: a Bayes filter in a hallway

The robot has the map (three doors) but not its position. Alternate Sense and Move, and watch the belief.

5

KF, EKF, UKF, and PF: what each filter assumes

Same predict and correct steps. Choose by two questions: are the models linear, and is the noise Gaussian?

FilterLinear models?Gaussian noise?Belief stored asHow it handles nonlinearityOn the TurtleBot 4, ROS 2 Jazzy
Kalman filter (KF)requiredrequiredmean and covariancenot needed: exact, and optimal, for linear-Gaussian systemsNot in the default stack. Lecture 5's wall_kf.py; Lab 3's complementary filter is a fixed-gain KF.
Extended KF (EKF)not requiredrequiredmean and covariancefirst-order : Jacobians G and H at the meanNot launched by default. Available as robot_localization's ekf_node.
Unscented KF (UKF)not requiredrequiredmean and covariance2n + 1 through the exact model; no JacobiansNot launched by default. Available as robot_localization's ukf_node.
Particle filter (PF)not requirednot requiredM , any shapeevery sample goes through the exact model; cost grows with MYes: AMCL (nav2_amcl), from turtlebot4_navigation; it publishes map → odom.
Dotted terms with an i open a short explanation; underlined names with ↗ open the documentation.
The Create 3 fuses its wheel encoders, IMU, and optical floor sensor internally into /odom; iRobot does not document the algorithm. slam_toolbox (Lab 3) is not a filter: it optimizes a pose graph.
6

The KF, step by step: distance to a wall

Lecture 5's wall: the robot drives toward it and the lidar measures the distance d. Both models are linear.

hallway, top viewwallbelief over the distance to the wall, d0 m1 m2 m3 m4 mbelief at t − 1robot, true d = 1.90 mpredictedrange zposteriormeasurement model: the lidar reads d directly1 m2 m3 m4 mz = Cd, C = 1a straight line: nothing to linearizemeasured z = 1.88 minnovationC maps z back to d = 1.88;the gain blends that with μ̄
  1. Belief at t − 1. 𝒩(μ,σ2)=𝒩(3.00,0.302)
  2. Predict. A=1,B=−1,u=1.00u: odometry, 1 m toward the wallμ¯=Aμ+Bu=2.00,σ¯2=Aσ2A+R=0.362
  3. Measurement model. z=Cd+δ,C=1,Q=0.102Linear already: the EKF's Jacobian H is just C.
  4. Measure. z=1.88,Cμ¯=2.00innovation z − Cμ̄ = −0.12 m
  5. Gain. K=σ¯2CC2σ¯2+Q=0.93The lidar is the better source here, so K is near 1.
  6. Correct. μ=μ¯+K(z−Cμ¯)=1.89
    σ2=(1−KC)σ¯2,σ=0.096
  7. Check. Lecture 5's precision-weighted mean, 1/σ² = 1/σ̄² + 1/Q, gives the same σ = 0.096 m. Linear and Gaussian, so this is the exact posterior, not an approximation.
7

The EKF, step by step: range to a pillar

The same robot, now measuring its range to a pillar at (4, 1) m. The motion is still linear; the range is not.

hallway, top viewpillar at (4, 1) mbelief over the robot's position x0 m1 m2 m3 m4 m5 m6 mbelief at t − 1robot, true x = 2.25predictedrange zposteriorexact (grid)measurement model: range to the pillar1 m2 m3 m4 mh(x) = √((4 − x)² + 1²)dashed: tangent at μ̄, slope Hmeasured z = 1.99 minnovationthe tangent maps z back to x = 2.28;the gain blends that with μ̄
  1. Belief at t − 1. 𝒩(μ,σ2)=𝒩(1.00,0.302)
  2. Predict. g=x+u,G=1
    μ¯=μ+u=2.00,σ¯2=σ2+R=0.362
  3. Linearize h at μ̄. H=∂h∂x|μ¯=−(4−μ¯)h(μ¯)=−0.89
  4. Measure. z=1.99,h(μ¯)=2.24innovation z − h(μ̄) = −0.25 m
  5. Gain. K=σ¯2HH2σ¯2+Q=−1.02Q = 0.10². K < 0 because a larger x gives a shorter range.
  6. Correct. μ=μ¯+K(z−h(μ¯))=2.25
    σ2=(1−KH)σ¯2,σ=0.11
  7. Check. The exact posterior is 2.26 ± 0.11 m. Over ±σ̄ the tangent fits h well, so the EKF is accurate here.
8

The UKF: sigma points instead of a tangent

When the belief is wide, the tangent is a poor fit. The unscented transform pushes a few chosen points through h instead.

1234range y = h(x), mh ≥ 1 m always0 m1 m2 m3 m4 m5 m6 mbelief over x:N(3.2, 0.8²)p(y)near 1 m: clippedtrue p(y),10⁵ samplesEKF tangent1/62/31/6
  1. The question. A wide belief near the pillar: what is the distribution of the range y = h(x)?
  2. Ground truth. 10⁵ samples through h: skewed, never below 1 m. Mean 1.44, std 0.44 m.
  3. EKF. Tangent at μ: N(1.28, 0.50²). The mean is too low, and 29% lies below 1 m, an impossible range.
  4. Sigma points. χ0=μ,χ±=μ±(n+λ)σ2n = 1, λ = 2: 1.81, 3.20, 4.59 m; weights 1/6, 2/3, 1/6.
  5. Propagate. Through the exact h: Yi = 2.40, 1.28, 1.16 m.
  6. Recombine. y¯=∑wiYi=1.45,σy2=∑wi(Yi−y¯)2σy = 0.43 m: close to the truth, and no Jacobian.
  7. The trade. Cost like the EKF (2n + 1 evaluations), accurate to second order. Still one Gaussian: the 1 m floor and multiple peaks need particles.
9

The particle filter, step by step: the hallway again

Same hallway, same three doors. Fifty particles replace the histogram; each click runs one line of the algorithm.

0 m2 m4 m6 m8 m10 mp(z = door | x): 0.85 at a door, 0.05 at a wallp(z = door | x): 0.85 at a door, 0.05 at a wallparticlesN_eff = 18 of 50N_eff = 18 of 50
  1. Initialize xt[m]∼uniform over the map,w=1/M
  2. Predict xt[m]∼p(xt|ut,xt−1[m])
  3. Weight wt[m]=p(zt|xt[m])
  4. Resample draw M particles with probability ∝ wt[m]
Initialize. No idea where the robot is: 50 particles spread uniformly, with equal weights.
Weight. The robot sees a door. Each particle gets w = p(door | x): particles in front of any door gain weight.
Resample. Draw 50 new particles, each with probability proportional to its weight. Three clusters, one per door: three peaks.
Predict. The robot drives 1.5 m. Move every particle by u plus sampled noise: the clusters shift together and spread.
Weight. A door again. Only the cluster that is now in front of a door keeps its weight.
Resample. 70% of the particles now sit within 0.5 m of the robot at x = 3.25 m. One or two more readings remove the rest.
10

The odometry motion model

Thrun et al., Table 5.6, and nav2_amcl: each increment is a rotation, a translation, and a second rotation.

δrot1=atan2(y¯′−y¯,x¯′−x¯)−θ¯δtrans=(x¯′−x¯)2+(y¯′−y¯)2δrot2=θ¯′−θ¯−δrot1
1. Decompose the odometry increment
σrot12=α1δrot12+α2δtrans2σtrans2=α3δtrans2+α4(δrot12+δrot22)σrot22=α1δrot22+α2δtrans2
2. Its noise grows with each component
δˆj=δj−εj,εj∼𝒩(0,σj2)x′,y′=x+δˆtranscos(θ+δˆrot1),y+δˆtranssin(θ+δˆrot1)θ′=θ+δˆrot1+δˆrot2
3. Sample a new pose, once per particle
α1 rotation noise from rotationα2 rotation noise from translationα3 translation noise from translationα4 translation noise from rotation
Nav2 parameters alpha1 to alpha4, default 0.2 each.
nav2_amcl uses min(|δrot|, |π − δrot|) in these variances, so driving backward is not treated as a half turn.
11

Try it: where could the robot be?

Sample the motion model 800 times and compare the cloud with the EKF's linearized 95% ellipse.

· 800 sampled poses◯ EKF 95% ellipse▬ the reported pathgrid: 0.5 m

The odometry increment, repeated

Noise (Nav2 alpha1 to alpha4)

12

The TurtleBot 4 sensors and their models

Each sensor needs a model p(z | x): the reading it should give at pose x, and how real readings scatter around it.

IMUtop platesecond platebscan plane
RPLIDAR A1M8/scan: range per beam, one plane, 360°
zk=rk*(x,m)+ε,ε∼𝒩(0,σhit2)
glass, black surfaces, objects below the plane
OAK-D Prostereo depth from disparity d, baseline b
Z=fb/d,σZ≈Z2σd/(fb)
far, blank, or shiny surfaces
Wheel encodersticks Δn per wheel, inside /odom
Δs˜=(2πr/N)ΔnΔs˜=Δs+ε,ε∼𝒩(0,k|Δs|)
slip, wrong r or wheel base
Optical floor sensorfloor displacement Δp, inside /odom
Δp˜=sΔp+ε,ε∼𝒩(0,σ2I)
glossy or featureless floors: no reading
Gyro, in the Create 3/imu: angular rate ω about z
ω˜=ω+b+n,b˙=nb
bias b drifts with temperature
13

What the readings look like

Illustrative shapes of p(z | x): for a known true state, where the readings land and how likely each value is.

Gaussian is the default, not a law.Short readings, missing returns, slip, and dropouts are not Gaussian. A model that leaves them out makes the filter overconfident exactly when the sensor misleads it.
14

Try it: the beam model for one lidar beam

One beam, with the map predicting range z*. The reading comes from one of four causes; the weights sum to one.

p(z|z*)=zhitphit+zshortpshort+zmaxpmax+zrandprand
phit=𝒩(z;z*,σhit2),pshort=λe−λz1−e−λz*forz<z*
pmax:point mass atzmax,prand=1zmax,zhit+zshort+zmax+zrand=1

The world

The sensor

15

Try it: the likelihood field, as AMCL scores a scan

Given an occupancy grid (Lecture 7 builds one), AMCL precomputes each cell's distance d to the nearest wall and scores each beam endpoint by its d.

p(z|x,m)=∏k[zhit𝒩(dk;0,σhit2)+zrandzmax]
● candidate pose○ true pose● endpoint within σhit of a wall● farthershading: N(d; 0, σ²hit)

The model

The candidate pose (one particle)

nav2_amcl sums pk³ over the beams instead of multiplying, a heuristic that keeps a few bad beams from eliminating a good particle.
16

The EKF on the TurtleBot pose

The same steps on the full pose (x, y, θ): predict with the odometry model, correct with the lidar.

Predict, with the odometry motion model
μ¯t=g(ut,μt−1),Σt=GtΣt−1GtT+VtMtVtT
Gt=[10−δtranssin(θ+δrot1)01δtranscos(θ+δrot1)001]
Mt=diag(σrot12,σtrans2,σrot22),Vt=∂g∂(δrot1,δtrans,δrot2)
Correct, with a lidar measurement
Kt=ΣtHtT(HtΣtHtT+Qt)−1
μt=μ¯t+Kt(zt−h(μ¯t)),Σt=(I−KtHt)Σt
Lecture 5's Kalman filter, with Aμ + Bu replaced by g(u, μ), and A and C by the Jacobians G and H, evaluated at each step. The red ellipse in the motion-model Try-it is exactly GΣGT + VMVT.
Notation follows Thrun et al. and the Lecture 5 summary: a bar marks the prediction, Rt = VtMtVtT is the motion noise, Qt the measurement noise. robot_localization and many texts swap the letters Q and R.
17

Monte Carlo localization: the same loop in 2D

Fox, Burgard, Dellaert, and Thrun, 1999. Each particle is a pose (x, y, θ); the scan is scored with the likelihood field.

Neff=1∑wi2
A common rule resamples only when Neff falls below M/2; nav2_amcl instead resamples every resample_interval updates (default 1). Cost grows as particles × beams.
18

Try it: a particle filter in a room

Press Global localization: the cloud splits between look-alike places until the room's asymmetry resolves it.

The filter

● the robot· particles○ weighted mean—  lidar beams
19

A complementary filter, for heading

High-pass the integrated gyro, low-pass an absolute heading; the two filters sum to one. You build one in Lab 3.

θˆk=α(θˆk−1+(ωk−bˆ)Δt)+(1−α)zk
τ=αΔt1−α,K=1−α
Δt is the interval between blends: the gyro step in Lab 3. The form matches heading_filter.py and Problem Set 2.
τ sets the crossoverHeading changes faster than τ come from the gyro, slower ones from the absolute heading. One parameter (α, K, or τ) trades bias drift, about b·τ, against passed noise, about σz√(K / (2 − K)).
A Kalman filter with a fixed gainK is the steady-state Kalman gain for the gyro and heading variances (Lab 3, TODO 2).
Angles wrapBlend wrap(z − θ̂), the atan2(sin, cos) of the difference, never raw angles.
20

Try it: blending a gyro with an absolute heading

Sixty seconds of turning. The gyro has a bias; the absolute heading is noisy. Find the gain that outperforms both.

The gyro

The absolute heading

The blend

▬ gyro integrated alone▬ absolute heading alone▬ complementary filter- - predicted offset b·τ
21

Count each sensor once

A Kalman filter assumes independent measurement errors. Fusing /imu on top of /odom counts the same gyro twice.

On the TurtleBot 4the Create 3 already fuses /odom, and AMCL adds map → odom. The default stack needs no additional EKF.
Before fusing a topicWhat is already inside it? Is its covariance realistic? Is its timestamp correct?
22

AMCL, as Nav2 runs it

Each parameter maps to a model or a Try-it from this lecture.

ParameterNav2 defaultControls
min_particles, max_particles500, 2000how many hypotheses (KLD adapts between them)
update_min_d, update_min_a0.25 m, 0.2 radhow far to move before updating
laser_model_type, max_beamslikelihood_field, 60the measurement model, and how many beams it scores
sigma_hit, z_hit, z_rand0.2 m, 0.5, 0.5the likelihood field's width and mixture weights
alpha1 to alpha40.2the odometry motion model's noise
resample_interval1how many updates between resampling steps
recovery_alpha_slow, _fast0.0, 0.0random particles injected when the fit drops: off
These are Nav2's defaults; turtlebot4_navigation's configuration can override them. Query what your robot runs: ros2 param get /amcl max_particles.
23

What AMCL publishes: map → odom

The answer to Lecture 2's question.

Tmap,odom=Tmap,baseTodom,base−1
Controllers run in odomthe pose never jumps
Planners run in mapthe pose never drifts
Also published/amcl_pose and /particle_cloud
TF allows one parent per frame, and odom is already base_link's parent. AMCL therefore publishes the correction map → odom, not map → base_link.
24

Verify in simulation

Exercise 1: watch AMCL converge, then kidnap it

Run this on your Ubuntu PC: no robot needed

terminal 1
$ros2 launch turtlebot4_gz_bringup turtlebot4_gz.launch.py \$ nav2:=true slam:=false localization:=true rviz:=true

Press Play in Gazebo. In RViz, use 2D Pose Estimate to drop the robot roughly where it is, and watch the particle cloud. Then give it a deliberately wrong pose, about a meter off, and drive.

terminal 2
$ros2 topic echo /amcl_pose --once$ros2 run tf2_ros tf2_echo map odom$ros2 param get /amcl max_particles
Predict firstHow many particles after convergence? Does map → odom change while the robot sits still?
Then break itMove the robot in Gazebo while AMCL runs. Does it recover? Why not, with the defaults?
MeasureThe covariance in /amcl_pose before and after a turn near a wall.
25

Verify on your TurtleBot

Exercise 2: characterize your sensors before you trust a filter with them

Run this on your Ubuntu PC, with the robot on the network

terminal
$ros2 topic hz /scan$ros2 topic hz /imu$ros2 topic hz /odom
terminal
$ros2 topic echo /scan --once | head -n 12$ros2 interface show sensor_msgs/msg/LaserScan

If /imu is missing, it may only exist in the hidden namespace, as /wheel_ticks did in Lecture 4: ros2 topic list --include-hidden-topics | grep imu.

QuantityPredictMeasured
/scan rateHz
/imu rateHz
/odom rateHz
range_min, range_maxm
beams per scan
gyro bias at rest°/s
For the gyro bias: leave the robot still for 60 s, record ros2 bag record /imu, and average angular_velocity.z.
26

Verify on your TurtleBot

Exercise 3: localize on your own map

Run these on your Ubuntu PC, with the map from Lab 3

terminal 1
$ros2 launch turtlebot4_navigation localization.launch.py \$ map:=$HOME/maps/room122.yaml
terminal 2
$ros2 launch turtlebot4_viz view_navigation.launch.py
terminal 3
$ros2 run teleop_twist_keyboard teleop_twist_keyboard \$ --ros-args -p stamped:=true

Set the initial pose in RViz, then drive one lap of the room. Keep a fourth terminal on ros2 run tf2_ros tf2_echo map odom.

Watchmap → odom changes in small steps as AMCL corrects odometry's drift. Plot the steps: they are Lecture 4's error, measured.
CompareDrive the same lap with the room's cardboard walls moved. Where does the cloud spread?
Name the placeFind the spot in the room where AMCL is least certain. Why there?
27

When localization fails

Review these before Lab 4: every Nav2 plan depends on the pose AMCL reports.

Symmetrytwo poses produce the same scan
Glass and mirrorsthe wrong range, or no return
One scan planeobstacles below it are invisible
Dynamic obstaclespeople and objects absent from the map
Poor initial posewith recovery off, AMCL tracks but does not search
Overconfidencea tight cloud at the wrong pose
Each failure is a mismatch between a model and the world. Fix the model, the map, or the environment before retuning the filter.
28

What to take away

The one habitBefore you trust a filter, write down its models: how each sensor fails, and what is already inside each topic.
1The Bayes filter

Predict with the motion model, correct with the measurement model.

2Match the filter to the models

KF if linear-Gaussian; EKF or UKF if nonlinear but single-peaked; particles for many peaks.

3Ellipse or banana

Odometry noise is Gaussian in (δrot1, δtrans, δrot2), not in x and y.

4Sensors are distributions

Beam model or likelihood field for the lidar, σZ ∝ Z² for stereo, bias plus noise for the gyro.

5Fuse with care

Complementary filter: τ sets the crossover. Count each sensor once.

6map → odom

AMCL publishes the correction. Check its parameters on your robot.

29