Probability for Robotics · Theory · M5
M5-T2 — Odometry and Velocity Motion Models
A robot never goes exactly where its odometry says. The motion model gives the distribution of where it went, and its shape is a curved band, not a circle.
The motion model is the first of the two distributions every filter needs: given the old pose and a control, where might the robot be now? This lesson builds the two standard answers, the odometry model (used when the wheel encoders tell you how far the robot turned and travelled) and the velocity model (used when you only know the commanded speeds). It shows how to sample them, how to propagate their covariance with Jacobians, and why a small heading error turns into a large sideways error with distance.
Learning objectives
After this lesson, you should be able to:
- Write the odometry motion model (rotate, translate, rotate) with its four noise parameters, and sample from it.
- Write the velocity motion model as a circular arc, including its straight-line limit.
- Derive the Jacobians of the odometry model and propagate a pose covariance through a step.
- Explain why the sideways error grows like d^1.5, and when the first-order covariance underestimates the along-track error.
The intuition
A differential-drive robot knows how far each wheel has turned. Between two moments, its pose changes from to . Any such change can be described as three simple movements: turn to face the new position (), drive straight to it (), and turn to the new heading (). Those three numbers are the odometry reading, and the odometry motion model takes them as the control.
Each of the three has an error, and the errors have simple physical origins.
- A turn is wrong by a small angle, because the wheels slip and the wheel base is not known exactly. The bigger the turn, and the farther the robot has travelled, the larger the angle error.
- A distance is wrong by a few percent, because the wheel diameter is not exact and the floor is not perfectly grippy. The error is proportional to the distance.
Four parameters say how much of each (the table below), and they are the only things to tune.
The picture is the most important thing to take from this lesson. A tiny heading error, a degree or so, is harmless at the start of a drive and ruinous at the end: the robot points slightly the wrong way and keeps driving, so the sideways error is roughly distance times heading error. And the heading error itself accumulates, as a random walk. The two effects multiply: the sideways error grows not like the distance, nor like its square root, but like . After 20 m with each metre carrying 1° of heading noise, the robot is 1.46 m off to the side but only about 0.1 m off along the path. This is why the cloud of possible poses is a curved band, often called the banana, not a circle, and why a filter that describes the pose by independent x and y variances is badly wrong.
| Parameter | Controls | Typical cause |
|---|---|---|
| Rotation noise caused by rotation | Wheel slip while turning, a wheel base that is not exact | |
| Rotation noise caused by translation | A small heading drift per metre driven (unequal wheel diameters): the one that makes the banana | |
| Translation noise caused by translation | Wheel diameter error, slip on the floor, the 1–3% distance error | |
| Translation noise caused by rotation | Slip during turning that also moves the robot along the floor |
The odometry model has a rotate-drive-rotate structure with noise that grows with the size of each movement. Heading noise turns into sideways error, which grows faster than the distance.
Definitions
- Odometry
- The reported motion between two poses as turn, drive and turn. It is computed from the encoder readings of the two moments.
- Noise parameters
- Non-negative numbers (units: radians² per radian², radians² per m², m² per m², m² per radian²) that set the variance of each movement.
- Velocity control
- A commanded forward speed and turn rate, applied for a time . Used when no odometry is available.
- Jacobians
- is the derivative of the new pose with respect to the old pose, with respect to the control, both at the nominal values.
Derivation: the Jacobians and the d^1.5 law
The Jacobians
Write for the direction of travel. The motion function is .
Differentiate each row with respect to (note ). The third column says that an error in the heading of the old pose moves the new position sideways by the distance travelled.
Differentiate with respect to the three control components. The first column is the same sideways push (the first turn changes the direction of travel), the second is the direction of travel itself, the third shows that the last turn changes only the heading.
Apply the first-order propagation of the last module, with independent control noise .
Why sideways error grows like d^1.5
Let the robot drive steps of length straight ahead, . In each step the two turns contribute heading noise of variance (using for each of the two turns).
The heading error after steps is a random walk: independent increments of variance add up in variance (the variance lesson).
The sideways position is the sum of the sideways components of each step, , and for small angles . Exchanging the order of the double sum shows that heading noise from step is felt by all the later steps.
The variances of independent terms add; the sum of squares formula for gives for large .
Substitute and . With , m and m: m.
Doubling the distance multiplies the sideways standard deviation by , and the along-path error, which comes from distance noise alone, by only .
What the first-order propagation misses
The Jacobians treat the heading error as small. But a heading error also shortens the forward progress by the factor , a second-order effect that the Jacobians ignore (the last module showed the same effect for ). At 20 m the heading standard deviation is 7° and this adds along-path variance that the first-order calculation does not see.
Because heading error is integrated over distance, the pose covariance of dead reckoning is a long, curved, strongly correlated band. Its sideways spread grows like d^1.5, and a diagonal covariance would hide the correlation between position and heading.
A worked example
A robot drives 20 steps of 1 m straight ahead, with . Each step has a distance noise of cm and a noise of 0.02 rad (1.15°) in each of the two turns. The program propagates the covariance with the Jacobians and compares it with 4000 Monte Carlo runs.
- One step. At the start, , so (with ) and . The control noise is .
- After 5, 10 and 20 m. Standard deviations (along, sideways, heading): Monte Carlo (0.045 m, 0.182 m, 3.6°), (0.067, 0.51, 5.1°), (0.127, 1.44, 7.2°); Jacobians (0.045, 0.184, 3.6°), (0.063, 0.518, 5.1°), (0.089, 1.462, 7.3°).
- The d^1.5 law. Sideways: 0.18, 0.51, 1.44 m at 5, 10, 20 m. From 5 m to 10 m it grows by 2.8, from 10 to 20 m by 2.8 again: the factor . The formula gives 1.461 m at 20 m.
- Where first order fails. The sideways and heading entries agree with Monte Carlo to 2%. The along-path standard deviation at 20 m does not: 0.127 m against 0.089 m. The first-order calculation sees only the distance noise, and misses the loss of forward progress caused by the 7° heading spread (the mean final x is 19.92 m, not 20).
- The velocity model. A command of m/s and rad/s for 1 s moves the robot along an arc to , , heading 0.5 rad: shorter than the 1 m of arc length because the path curves.
import math
from robotprob import (Rng, sample_motion_odometry, motion_odometry, cov_matrix, mean_vector,
matmul, transpose, madd, symmetrize, zeros, sample_motion_velocity)
alphas = (0.0004, 0.0004, 0.0004, 0.0004) # a1: rot from rot, a2: rot from trans, a3: trans from trans, a4: trans from rot
def jacobians(pose, odom): # F: d pose' / d pose, G: d pose' / d control
rot1, trans, rot2 = odom
th = pose[2] + rot1
F = [[1.0, 0.0, -trans * math.sin(th)], [0.0, 1.0, trans * math.cos(th)], [0.0, 0.0, 1.0]]
G = [[-trans * math.sin(th), math.cos(th), 0.0], [trans * math.cos(th), math.sin(th), 0.0], [1.0, 0.0, 1.0]]
return F, G
def control_cov(odom, a): # the variances of the three movements
rot1, trans, rot2 = odom
a1, a2, a3, a4 = a
return [[a1 * rot1 ** 2 + a2 * trans ** 2, 0.0, 0.0],
[0.0, a3 * trans ** 2 + a4 * (rot1 ** 2 + rot2 ** 2), 0.0],
[0.0, 0.0, a1 * rot2 ** 2 + a2 * trans ** 2]]
step = (0.0, 1.0, 0.0) # drive 1 m straight, repeated 20 times
pose, P = [0.0, 0.0, 0.0], zeros(3, 3)
cov_track = {}
for k in range(1, 21): # propagate the covariance with the Jacobians
F, G = jacobians(pose, step)
P = symmetrize(madd(matmul(matmul(F, P), transpose(F)), matmul(matmul(G, control_cov(step, alphas)), transpose(G))))
pose = motion_odometry(pose, step)
cov_track[k] = [row[:] for row in P]
rng = Rng(9) # the reference: sample the model many times
runs = 4000
finals = {5: [], 10: [], 20: []}
for _ in range(runs):
p = [0.0, 0.0, 0.0]
for k in range(1, 21):
p = sample_motion_odometry(rng, p, step, alphas)
if k in finals:
finals[k].append(p)
print('after n metres of straight driving (std in m, m, degrees):')
for k in (5, 10, 20):
mc = cov_matrix(finals[k])
lin = cov_track[k]
print(k, 'm Monte Carlo', [round(math.sqrt(mc[0][0]), 3), round(math.sqrt(mc[1][1]), 3), round(math.degrees(math.sqrt(mc[2][2])), 2)],
' Jacobians', [round(math.sqrt(lin[0][0]), 3), round(math.sqrt(lin[1][1]), 3), round(math.degrees(math.sqrt(lin[2][2])), 2)])
print('mean final position after 20 m: x', round(mean_vector(finals[20])[0], 3), ' y', round(mean_vector(finals[20])[1], 3))
print('lateral std at 20 m from the formula sqrt(2 a2 d^3 / 3) =', round(math.sqrt(2 * 0.0004 * 20 ** 3 / 3), 3))
x, y, th = sample_motion_velocity(Rng(1), [0.0, 0.0, 0.0], 1.0, 0.5, 1.0, 0.0, 0.0) # the velocity model without noise
print('arc with v = 1 m/s, w = 0.5 rad/s for 1 s: x', round(x, 4), ' y', round(y, 4), ' theta', round(th, 4))after n metres of straight driving (std in m, m, degrees): 5 m Monte Carlo [0.045, 0.182, 3.56] Jacobians [0.045, 0.184, 3.62] 10 m Monte Carlo [0.067, 0.51, 5.14] Jacobians [0.063, 0.518, 5.12] 20 m Monte Carlo [0.127, 1.437, 7.18] Jacobians [0.089, 1.462, 7.25] mean final position after 20 m: x 19.92 y 0.011 lateral std at 20 m from the formula sqrt(2 a2 d^3 / 3) = 1.461 arc with v = 1 m/s, w = 0.5 rad/s for 1 s: x 0.9589 y 0.2448 theta 0.5
In robotics
Localizers use this model every step
A particle filter draws one sample of the model per particle and per step (sample_motion_odometry): the cloud of particles after a move is the banana of the figure. An extended Kalman filter instead propagates the covariance with the Jacobians above (module 8). Navigation stacks expose the four parameters under the names alpha1 to alpha4, with a fifth for omnidirectional bases, in their particle-filter localizer configuration. Wrongly small values make the filter overconfident after a long featureless corridor; wrongly large ones make it jumpy.
Tuning intuition
The parameters can be read off the behaviour. A robot that arrives too far to the side after long straight drives needs a larger . One that overshoots or undershoots in distance needs a larger . One whose heading is poorly known after turning in place needs a larger . M5-T4: Identifying Noise Parameters from Data shows how to estimate them from logged runs.
Systematic errors need calibration, not noise
The model treats odometry errors as random. The largest real errors are often systematic: wheels of slightly different diameters make a straight command curve to one side, a wrong wheel base makes every 90° turn 88°. These errors do not average out and do not look like noise: they look like drift in one direction. Calibration procedures such as driving a square clockwise and counter-clockwise separate the two main systematic errors (Borenstein and Feng's UMBmark); only the remainder is noise for .
The velocity model for planning
When no wheel odometry exists, as for a legged robot or in a planner that predicts motion before it happens, the velocity model describes the arc a commanded produces. Dynamic window and pure-pursuit planners use these arcs (see the Navigation course). The SLAM course covers the same models for localization in Odometry and Motion Models.
Other robots
For drones the motion model is the IMU integration of the next module and the UAV course; for manipulators it is the joint-space dynamics. The structure is always the same: a deterministic update plus noise whose size depends on what the robot did, and Jacobians for the covariance.
Common misconceptions
“Odometry noise is a small random number added to x and y.”
It is noise on the turns and the distance, which then appears in x and y through the heading. That is why the error is correlated and curved: a heading error shifts position more and more as the robot continues. Adding independent noise to x and y misses this and is the cause of overconfident filters.
“Doubling the distance doubles the error.”
The sideways error grows like d^1.5 (a factor 2.8 per doubling), the along-path error like √d (1.4), and a systematic bias like d (2). Which dominates depends on the distance; a robot that is accurate over 5 m can be unusable over 50.
“The covariance from the Jacobians is exact.”
It is a first-order approximation. In the example the sideways and heading entries are accurate to 2%, but the along-path standard deviation at 20 m is 30% too small, because heading errors cost forward progress at second order.
“More precise wheel encoders remove the need for a noise model.”
Encoders measure wheel rotation, not floor contact. Slip, unequal wheels and an uncertain wheel base remain, and they dominate the error of an encoder with hundreds of counts per degree.
Key takeaways
- The odometry model describes a movement as turn, drive, turn, each with Gaussian noise whose variance grows with the square of the size of the movement (α₁ to α₄).
- The velocity model moves the robot along a circular arc for a commanded (v, ω), with a straight-line limit as ω → 0; noise is added to v and ω.
- The Jacobians F (with respect to the old pose) and G (with respect to the control) give the covariance after a step: Σ′ = FΣFᵀ + GMGᵀ.
- A random heading error integrates into sideways position error: the sideways standard deviation grows like d^1.5, the along-path like √d. The cloud of poses is a curved band.
- First-order propagation is accurate for the sideways and heading spread but misses second-order loss of forward progress. Systematic errors are calibrated, not modelled as noise.
References and further reading
Each source is marked free or paid. Free to read does not mean free to reuse: the course resources page lists every source with its licence.
- S. Thrun, W. Burgard and D. Fox, Probabilistic Robotics, MIT Press, 2005, sections 5.3 (velocity motion model) and 5.4 (odometry motion model, with table 5.6). Paid book.
- N. Chebrolu and C. Stachniss, “Motion Models” (video lecture) , the odometry and velocity models. Free to watch.
- J. Borenstein and L. Feng, “Measurement and correction of systematic odometry errors in mobile robots”, IEEE Transactions on Robotics and Automation 12 (6), 1996. The UMBmark calibration. Paid journal article.
- T. D. Barfoot, State Estimation for Robotics, 2nd edition, Cambridge University Press, 2024 , chapter “Pose Estimation Problems” (motion models for poses). Free to read as the author’s PDF; the book is copyrighted.
Knowledge check
Three questions. Write an answer, then reveal the explanation. Your answers stay in your browser.
Question 1
With the parameters of the example (α₂ = 0.0004 and steps of 1 m), compute the sideways standard deviation of dead reckoning after 10 m and after 40 m. By what factor does it grow, and by what factor would it grow if it followed the √d law?
Explanation
σy = √(2 α₂ ℓ d³ / 3), which for ℓ = 1 m is √(2 × 0.0004 × d³ / 3). At 10 m: √(2 × 0.0004 × 1000 / 3) = √0.2667 = 0.516 m. At 40 m: √(2 × 0.0004 × 64000 / 3) = √17.07 = 4.13 m. The ratio is 8 = 4^1.5. A √d law would give only a factor of 2. The robot that was within half a metre sideways after 10 m is four metres off after 40 m: dead reckoning over long distances is dominated by heading drift.
Question 2
A robot turns 90° on the spot (δrot1 = π/2, δtrans = 0, δrot2 = 0) with α₁ = 0.01. What is the standard deviation of the turn, in degrees, and what would it be for a 180° turn? Which parameter would you change if turns are accurate but the robot also creeps forward while turning?
Explanation
σrot1 = √(α₁ δrot1²) = √(0.01 × 2.467) = 0.157 rad = 9.0° for 90°, and 18° for 180° (the standard deviation is proportional to the angle, so a half-turn is twice as noisy). Creeping forward during a turn shows up as translation noise caused by rotation, controlled by α₄ (σ²_trans = α₃ δtrans² + α₄ (δrot1² + δrot2²)); raise it, leaving α₁ alone.
Question 3
In the example the Jacobian propagation gives an along-path standard deviation of 0.089 m after 20 m, while Monte Carlo gives 0.127 m. Explain the difference, and say whether it matters for a robot that is limited by its sideways error.
Explanation
The first-order propagation sees only the distance noise (σ ≈ 0.02 m per metre, so 0.02 × √20 = 0.089 m). It misses the fact that a heading error θ shortens the forward progress by about θ²/2 per step; with a heading spread of about 7° (0.126 rad) the accumulated effect is of the order of 0.1 m in standard deviation and a mean shortening of 8 cm (the mean final x is 19.92 m). The added variance is 0.127² − 0.089² = 0.0082 m². It does not matter much here: the sideways error is 1.4 m, eleven times larger, so the along-path term has little effect on the shape. It matters when the robot is constrained along the path (a docking station), and then sampling or a second-order treatment is better.
What’s next
The motion model says where the robot may be after moving. The next lesson builds the other half: given where the robot is, what will its sensors read?
Related content
Nothing below is required to finish this lesson.
- BeforeM5-T1: State, Controls, Measurements and the Markov Assumption
Draw the dynamic Bayes network of a robot, state the Markov assumption, and say what must be in the state for it to hold.
- LabM5-L1: Probabilistic Odometry
Dead reckoning puts Rover on the far side of a wall after two corners. Implement the odometry motion model, grow the uncertainty with distance, and identify the wheel noise from logged runs.
Other courses on this site treat neighbouring topics from their own angle:
Get notified when the next lesson and new labs are released.
One email per new lesson or lab.