Transforms
Practical
Terminal window
Transforms are mathematical objects that describe the position and orientation of one coordinate frame relative to another. They are the foundation of robotics math, enabling robots to understand spatial relationships between the world, their body, sensors, and objects they interact with.
Prerequisites
Section titled “Prerequisites” Degrees of Freedom How many independent ways a body can move
Kinematics How robots move through space
Coordinate Frames
Section titled “Coordinate Frames”A coordinate frame is a reference point with three axes (x, y, z). Every robot component has its own frame:
z ↑ | | +----→ y / / ↙ x
ROS Convention (REP-103): x = forward y = left z = upStandard frames in a robot system (REP-105):
| Frame | Description |
|---|---|
map | Global world-fixed frame |
odom | Odometry frame (continuous but drifts) |
base_link | Robot body center |
sensor_frame | Individual sensor frames |
Homogeneous Transformation Matrices
Section titled “Homogeneous Transformation Matrices”Transforms are represented as 4x4 matrices combining rotation and translation:
T = | R p | R = 3x3 rotation matrix | 0 1 | p = 3x1 translation vector
| r₁₁ r₁₂ r₁₃ px |T = | r₂₁ r₂₂ r₂₃ py | | r₃₁ r₃₂ r₃₃ pz | | 0 0 0 1 |Key properties:
- Composable:
T_world_gripper = T_world_base @ T_base_gripper - Invertible:
T⁻¹gives the reverse transform - Non-commutative:
T₁ × T₂ ≠ T₂ × T₁
Rotation Representations
Section titled “Rotation Representations”| Representation | Size | Pros | Cons |
|---|---|---|---|
| Rotation Matrix | 9 values | Fast composition | Redundant, numerical drift |
| Euler Angles | 3 values | Human-readable | Gimbal lock, 24 conventions |
| Quaternion | 4 values | Compact, no gimbal lock | Less intuitive |
| Axis-Angle | 4 values | Intuitive single rotation | Composition harder |
Gimbal Lock
Section titled “Gimbal Lock”When two rotation axes align, you lose a degree of freedom:
Normal: Gimbal Lock (pitch = 90°): Roll ──┐ Roll ─────┐ │ │ (same axis!) Pitch ─┤ Pitch ────┘ │ Yaw ───┘ Yaw (lost!)Solution: Use quaternions internally, Euler angles only for display.
ROS 2 TF2 System
Section titled “ROS 2 TF2 System”TF2 maintains a tree of transforms between all frames:
map └── odom └── base_link ├── camera_link │ └── camera_optical ├── lidar_link └── arm_base └── gripperBroadcasting Transforms
Section titled “Broadcasting Transforms”import rclpyfrom rclpy.node import Nodefrom tf2_ros import TransformBroadcasterfrom geometry_msgs.msg import TransformStampedimport tf_transformations
class TFBroadcaster(Node): def __init__(self): super().__init__('tf_broadcaster') self.broadcaster = TransformBroadcaster(self) self.timer = self.create_timer(0.1, self.broadcast)
def broadcast(self): t = TransformStamped() t.header.stamp = self.get_clock().now().to_msg() t.header.frame_id = 'base_link' t.child_frame_id = 'camera_link'
# Translation: 10cm forward, 20cm up t.transform.translation.x = 0.1 t.transform.translation.y = 0.0 t.transform.translation.z = 0.2
# Rotation: quaternion (no rotation here) t.transform.rotation.w = 1.0
self.broadcaster.sendTransform(t)Listening for Transforms
Section titled “Listening for Transforms”from tf2_ros import Buffer, TransformListenerfrom rclpy.duration import Duration
class TFListener(Node): def __init__(self): super().__init__('tf_listener') self.tf_buffer = Buffer() self.tf_listener = TransformListener(self.tf_buffer, self)
def get_transform(self): try: transform = self.tf_buffer.lookup_transform( 'base_link', # target frame 'camera_link', # source frame rclpy.time.Time(), timeout=Duration(seconds=1.0) ) return transform except Exception as e: self.get_logger().error(f'Lookup failed: {e}')Python: SciPy Transforms
Section titled “Python: SciPy Transforms”import numpy as npfrom scipy.spatial.transform import Rotation
# Create rotation (90° about Z-axis)rot = Rotation.from_euler('z', 90, degrees=True)
# Apply to a pointpoint = np.array([1.0, 0.0, 0.0])rotated = rot.apply(point)# Result: [0, 1, 0]
# Convert between representationsquat = rot.as_quat() # [x, y, z, w]matrix = rot.as_matrix() # 3x3euler = rot.as_euler('xyz', degrees=True)C++: Eigen Transforms
Section titled “C++: Eigen Transforms”#include <Eigen/Geometry>
// Create rigid transformEigen::Isometry3d T = Eigen::Isometry3d::Identity();
// Set rotation (90° about Z)T.rotate(Eigen::AngleAxisd(M_PI_2, Eigen::Vector3d::UnitZ()));
// Set translationT.pretranslate(Eigen::Vector3d(1.0, 0.0, 0.5));
// Apply to pointEigen::Vector3d p(1.0, 0.0, 0.0);Eigen::Vector3d result = T * p;
// Compose and invertEigen::Isometry3d T_combined = T1 * T2;Eigen::Isometry3d T_inv = T.inverse();Debugging Tools
Section titled “Debugging Tools”# Visualize TF tree as PDFros2 run tf2_tools view_frames
# Print live transform between framesros2 run tf2_ros tf2_echo base_link camera_link
# Publish a static transformros2 run tf2_ros static_transform_publisher \ --x 0.1 --y 0 --z 0.2 \ --frame-id base_link --child-frame-id sensorRelated Terms
Section titled “Related Terms” Kinematics Motion through space using transforms
SLAM Localization via transform estimation
Learn More
Section titled “Learn More”- ROS 2 TF2 Tutorial — Official introduction to TF2
- Modern Robotics Ch. 3 — Homogeneous transformation theory
- Articulated Robotics TF Guide — Practical TF2 walkthrough
Sources
Section titled “Sources”- REP-103: Standard Units and Conventions — ROS coordinate frame conventions
- REP-105: Coordinate Frames for Mobile Platforms — Standard frame naming
- TF2 Concepts — ROS 2 Humble TF2 architecture
- SciPy Rotation API — Python rotation library
- Eigen Geometry Module — C++ transform library