Localization & SLAM · Theory · M7
M7-T2 — TF Frames and Coordinate Consistency
The transform tree is a contract. Break it and the SLAM node cannot say where anything is.
Module 2 introduced transforms as maths: Tab takes points from frame b to frame a. In ROS 2 those transforms live in a shared, time-stamped tree called TF, and a whole set of conventions (REP 105) says what the frames mean and who is allowed to publish each connection. Most “SLAM is broken” reports in practice are violations of those conventions. This lesson states the rules, derives the key transform, and lists the typical errors.
Learning objectives
After this lesson, you should be able to:
- State the REP 105 frames map, odom and base_link and the properties of each.
- Compute the map → odom transform that a SLAM node publishes from two poses.
- Explain why every frame must have exactly one parent and who publishes each link.
- Recognise the common errors: duplicate parents, wrong frame names, missing static transforms and leading slashes.
The problem and the intuition
A robot needs two different answers to “where am I?”. One is smooth: a pose that never jumps, because a controller using it must not see sudden steps. The other is globally correct: a pose that does not drift, because a planner needs to know where the robot is on the map. No single estimate can have both: to remove drift the estimator must sometimes correct the position, and a correction is a jump.
REP 105 solves this by using two frames. The odom frame is the world in which the robot’s pose evolves smoothly from odometry; it drifts slowly. The map frame is the globally consistent world. The SLAM or localisation node publishes the offset between them, map → odom. When it learns the robot is 0.4 m from where it thought, it changes this offset (a jump in the map frame), but odom → base_link stays smooth. A controller uses the smooth chain; a planner uses the corrected one.
map → odom absorbs the corrections; odom → base_link stays smooth. Each frame has exactly one parent, and each link has exactly one publisher.
The rules and the key transform
Problem. Keep a consistent, single-rooted tree of coordinate frames in which every sensor measurement can be expressed in the map frame at its measurement time.
Assumptions. The sensors are rigidly mounted (fixed transforms); odometry is continuous but drifts; the SLAM or localisation node provides a globally consistent pose of the robot at a lower rate and sometimes with jumps; clocks are consistent (M7-T3).
The REP 105 frames
| Frame | Meaning | Property | Published by |
|---|---|---|---|
map | Global, fixed frame; the map’s coordinates | Globally consistent, but its transform to odom can jump | SLAM or localisation (SLAM Toolbox, AMCL) |
odom | World-fixed frame of the odometry | Continuous, no jumps, drifts over time | Odometry / EKF (as the parent of base_link) |
base_link | Rigidly attached to the robot body | The robot’s pose in odom | Odometry (odom → base_link) |
sensor frames (laser, camera_link, imu_link) | Where each sensor sits | Rigid, fixed relative to base_link | robot_state_publisher from the URDF or static_transform_publisher |
Some platforms (TurtleBot 3, many ground robots) add base_footprint, the projection of the base onto the ground, as the parent of base_link. Whichever frame is the robot base must be named identically in the odometry, in the URDF and in the SLAM parameter base_frame.
The map → odom transform
The SLAM node estimates the robot pose in the map frame, Tmap,base, by scan matching. The odometry provides Todom,base (from TF). The node does not publish map → base_link, because base_link already has a parent. It publishes the transform that closes the loop:
so that the chain map → odom → base_link reproduces the SLAM estimate. When the SLAM estimate improves (a loop closure), Tmap,odom changes and Todom,base does not.
Rules that the tree enforces
- One parent per frame. TF is a tree, not a graph. Two nodes publishing different parents for the same child gives an inconsistent tree: lookups flicker or fail.
- One publisher per link. If both the odometry node and a Gazebo plugin publish
odom → base_link, the two fight. - No leading slash in frame ids in tf2 (
base_link, not/base_link); and names are case-sensitive and spelled identically everywhere. - Static transforms go to
/tf_staticand are published once with transient-local durability; dynamic transforms to/tfat a regular rate. - Time travel. TF stores a buffer (10 s by default) of timestamped transforms and interpolates between them. A lookup at a time later than the newest transform needs extrapolation and fails; a lookup earlier than the buffer fails too.
- Tab
- transform expressing frame b in frame a (maps points from b to a), as in Module 2.
- REP 105
- ROS Enhancement Proposal defining the mobile-robot frames map, odom, base_link.
- static transform
- a fixed link, published once on
/tf_static. - extrapolation error
- a lookup for a time outside the range covered by the buffered transforms.
Common errors
| Error | Symptom | Fix |
|---|---|---|
Base frame name mismatch (base_link vs base_footprint) | Two separate trees; SLAM cannot find the robot | Use one name in URDF, odometry and SLAM parameters, or add the missing link |
Two publishers of odom → base_link | The robot jitters in RViz; transform jumps back and forth | Disable one (for example the EKF or the simulator’s plugin) |
Missing static transform (base_link → laser) | “Could not transform” for scans; empty map | Add it to the URDF or a static_transform_publisher |
| Wrong static transform (sensor mounted 90° off) | Map rotated, smeared walls, laser points in the wrong place in RViz | Fix the URDF; check by displaying the scan in base_link |
| Leading slash in a frame id | Frames exist but do not connect | Remove the slash everywhere |
| Sensor stamps in the future | Extrapolation errors | Fix the driver or the clock (M7-T3) |
A worked example: computing map → odom and reading a broken tree
- The numbers. The odometry says the robot is at Todom,base = (5.0, 0.0, 0°): it drove 5 m straight. Scan matching against the map says Tmap,base = (5.4, 0.3, 0.05 rad ≈ 2.9°): the robot is a little to the left and slightly rotated relative to the odometry’s opinion.
- The correction. Tmap,odom = Tmap,base · Todom,base⁻¹. The inverse of the odometry pose is (−5.0, 0, 0) with no rotation. Applying the SLAM rotation of 0.05 rad to it: translation = (5.4, 0.3) + R(0.05)(−5.0, 0) = (5.4 − 5 cos 0.05, 0.3 − 5 sin 0.05) = (5.4 − 4.994, 0.3 − 0.250) = (0.406, 0.050). So map → odom is (0.406, 0.050, 0.05 rad). Check: composing it with the odometry pose reproduces the SLAM pose.
- What a loop closure does. Next the robot returns to a known place and the SLAM estimate shifts by 0.3 m. The odometry pose changes smoothly by its normal increments; only map → odom changes by about 0.3 m, in one step. A controller that follows the pose in
odomsees no jump; the planner, usingmap, sees the correction. - Reading a broken tree.
view_framesshows:map → odom → base_footprint, and, as a separate tree,base_link → laser. The lidar frame is not connected to the map. SLAM Toolbox looks up the transform from the scan’slaserframe to itsbase_frameparameter. Withbase_frame: base_linkit finds the laser but cannot connectbase_linktoodom: “Failed to compute odom pose”. Either setbase_frame: base_footprintand publishbase_footprint → base_link → laser, or add the missing static link. Exactly this is the lab M7-L2. - Duplicate parents. Gazebo’s diff-drive plugin publishes
odom → base_footprintand a robot_localization EKF also publishesodom → base_footprintat 30 Hz.tf2_echo odom base_footprintalternates between two slightly different values. The visible effect: the robot’s pose in RViz vibrates, and scan matching sees a noisy initial guess. Disable the plugin’s transform publication or the EKF’s (publish_tf).
Engineering implications and limitations
Engineering implications
- Write the frame tree down for the robot, with the publisher of every link, before writing launch files.
- Visualise the tree with
ros2 run tf2_tools view_framesorros2 run tf2_ros tf2_echo map base_link; check every sensor’s data in RViz with the fixed frame set tobase_link, thenodom, thenmap. - Validate extrinsics physically. Drive toward a wall and confirm the laser points in
base_linkare in front; rotate and confirm the scan rotates the right way. - Let only one node own each transform. Decide whether the simulator, an EKF or the driver publishes
odom → base_link, and disable the others. - Use the same time source and publish transforms at a steady rate (30–50 Hz for odometry) so that lookups can interpolate.
- Handle jumps downstream. Anything that integrates a map-frame pose over time (a controller, an obstacle tracker) should use the
odomframe and transform only the goal.
Limits
REP 105 describes ground robots with a planar assumption and single-robot operation. Multi-robot systems need namespaced or prefixed frames; aerial and legged robots use other conventions (REP 103 defines the axis conventions). The tree also cannot represent uncertainty: a transform is a single value, so a poor map → odom estimate looks exactly like a good one.
Common misconceptions
“The SLAM node publishes the robot’s pose in the map frame as map → base_link.”
It publishes map → odom, so that base_link keeps its single parent (odom).
“odom is a global frame.”
It is continuous but drifts; its origin is wherever the robot started.
“Frame names are just labels and can differ between nodes.”
They are the keys of the tree; a one-character difference creates a disconnected tree.
“Static transforms can be published by any node at any time.”
They should have one publisher, usually robot_state_publisher; duplicates with different values conflict.
Engineering takeaways
- REP 105: map (global, may jump), odom (smooth, drifts), base_link (the robot); sensors are fixed children of base_link.
- The SLAM node publishes Tmap,odom = Tmap,base · Todom,base⁻¹, not map → base_link.
- Every frame has exactly one parent and every link exactly one publisher.
- Name mismatches, duplicate publishers, missing static transforms and leading slashes are the usual faults.
- Visualise the tree with view_frames and verify each sensor by looking at its data in base_link.
References and further reading
Primary papers and authoritative documentation.
- REP 105: Coordinate Frames for Mobile Platforms. ROS Enhancement Proposals (ros.org/reps/rep-0105.html).
- Foote, T. (2013). tf: The transform library. IEEE International Conference on Technologies for Practical Robot Applications (TePRA).
- Open Robotics. ROS 2 documentation: Tf2 tutorials and Introducing tf2. docs.ros.org.
- Macenski, S. and Jambrecic, I. (2021). SLAM Toolbox: SLAM for the dynamic world. Journal of Open Source Software 6(61), 2783.
- REP 103: Standard Units of Measure and Coordinate Conventions. ROS Enhancement Proposals (ros.org/reps/rep-0103.html).
Knowledge check
Three conceptual questions. Write an answer, then reveal the explanation. Your answers stay in your browser.
Question 1
The odometry says the robot is at (2, 0, 0) and the SLAM estimate in the map is (2.3, 0.1, 0). What is map → odom?
Explanation
With no rotation the correction is the difference of translations: Tmap,odom = (2.3 − 2.0, 0.1 − 0.0, 0) = (0.3, 0.1, 0). Composing it with the odometry pose gives (2.3, 0.1, 0), the SLAM estimate.
Question 2
Why does SLAM publish map → odom instead of map → base_link?
Explanation
In the tree every frame has exactly one parent, and base_link already has odom as its parent from the odometry. Publishing map → base_link would give it two parents. The correction is placed on map → odom so that the odometry stays smooth and the SLAM estimate is still reproduced.
Question 3
The robot icon in RViz vibrates between two positions. What tf fault is likely, and how do you confirm it?
Explanation
Two publishers are writing the same transform (for example odom → base_link from both the simulator plugin and an EKF) with slightly different values. Confirm with ros2 topic echo /tf or tf2_echo odom base_link, which alternate between two values, and disable one publisher.
What’s next
Even with a correct tree, a lookup can fail if the timestamps are wrong. The next lesson covers message stamps, quality-of-service profiles and the timing errors that make SLAM drop scans.
Related content
Nothing below is required to finish this lesson.
- BeforeM7-T1: SLAM System Architecture in ROS 2
Map the nodes, topics, frames and parameters of a ROS 2 SLAM system.
- LabM7-L2: Fix a TF Configuration Error
Repair a broken TF tree (duplicate parents, wrong frame names, missing static transform).
Get notified when the next lesson and new labs are released.
One email per new lesson or lab.