TF Pipeline Overview
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
URDF (/robot_description) ───────────────────────────────────┐
│ │
↓ ↓
[joint_state_publisher / gui] [hardware driver] robot_state_publisher
↓ ↓ ↑
└───── /joint_states ────────────────────┘
↓
TF: base_link → child links
[static_transform_publisher]
↓
TF: world/map → base_link (fixed)
[odometry]
↓
TF: odom → base_link
[SLAM / AMCL]
↓
TF: map → odom
All transforms are broadcast into the shared TF tree. Standard ROS navigation frame chain:
map → odom → base_link → <sensor/limb links>
robot_state_publisher
Publishes base_link → <rest of robot> by:
- Reading the URDF/xacro (robot description).
- Subscribing to
/joint_states. - Computing and broadcasting TF transforms for every link — both fixed joints (directly from URDF) and moving joints (from
/joint_states).
Example for an arm:
1
base_link → shoulder → elbow → wrist
joint_state_publisher
Publishes /joint_states — one JointState message per joint. Sources:
| Source | Description |
|---|---|
joint_state_publisher node |
Reads URDF; publishes default (zero) values for all joints. Useful for visualization/testing. |
joint_state_publisher_gui |
Same, but with a GUI slider for manual control. |
| Your hardware driver node | Reads real encoder/sensor values and publishes to /joint_states. |
static_transform_publisher
Broadcasts fixed transforms that never change, e.g. world → base_link or base_link → lidar_link. These are published once (latched) rather than at a recurring rate.
TF at Different Publishing Frequencies
Different publishers emit transforms at different rates (e.g., odometry at 50 Hz, robot_state_publisher at 10 Hz, static transforms once). tf2 handles this transparently via a time-stamped transform buffer:
- Each transform is stored with a timestamp in the
tf2buffer (default 10-second history). - When a node queries
lookupTransform,tf2interpolates between the two nearest timestamped transforms in the buffer.