TF2 — The Transform Library
TF2 is the ROS coordinate frame transform library. It maintains a tree of coordinate transformations over time, allowing any part of the system to query the 3D pose of any frame relative to any other frame at any past timestamp.
Every physical component of the robot has a named frame: base_link (robot body), base_footprint (projection onto ground), camera_link, laser_link, odom, map, end_effector. The TF tree connects these with static or dynamic transforms.
Broadcasting transforms is done via tf2_ros.TransformBroadcaster (dynamic, e.g. wheel odometry updates odom→base_link) or tf2_ros.StaticTransformBroadcaster (static, e.g. camera mounting position). The robot_state_publisher node reads the URDF and publishes transforms for all joints automatically.
Querying transforms:
ros2 run tf2_ros tf2_echo base_link camera_link # print live transform
ros2 run tf2_tools view_frames # generate TF tree PDF
TF2 is critical for: fusing LIDAR scans (expressed in laser_link) with odometry (expressed in odom) — you transform both into map frame before combining. For manipulation, TF2 converts a detected object pose (camera frame) into the robot base frame for grasping. Without TF2, every node would need to maintain its own transform bookkeeping — a source of many bugs.
Launch Files — Composing ROS 2 Systems
Launch files in ROS 2 are Python scripts (not XML as in ROS 1) that programmatically describe an entire system configuration: which nodes to start, with what parameters, in what namespaces, with what remappings, and in what order.
Key building blocks:
LaunchDescription— the root container returned by thegenerate_launch_description()functionNode— declares a node to launch: package, executable, name, namespace, parameters, remappingsIncludeLaunchDescription— nests another launch file, enabling modular compositionDeclareLaunchArgument— declares a command-line argument (e.g.use_sim_time:=true)LaunchConfiguration— reads the value of a declared argument at runtimeGroupActionwithPushRosNamespace— applies a namespace to a group of nodes
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='my_robot_bringup',
executable='drive_controller',
name='drive_node',
parameters=[{'max_speed': 1.5, 'use_sim_time': False}],
remappings=[('/cmd_vel', '/robot/cmd_vel')]
),
])
Launch files replace shell scripts for starting robot systems, providing dependency ordering, conditional logic, and argument passing in a maintainable Python format.
ROS 2 Parameter System
| Concept | ROS 1 | ROS 2 | Notes |
|---|---|---|---|
| Parameter server | Global rosparam server (XMLRPC) | Per-node parameter server | Parameters are owned by individual nodes, not a global store |
| Node parameters | Set via rosparam YAML or rosparam set | Declared in node constructor, set via YAML or CLI | Each node declares parameters with types and defaults |
| Dynamic reconfigure | Separate dynamic_reconfigure package | Built-in: ros2 param set | Any parameter can be changed at runtime via the CLI or API |
| YAML config | rosparam load file.yaml | Node(parameters=[yaml_file]) in launch | YAML file maps node name to parameter key-value pairs |
| CLI tool | rosparam list/get/set/dump/load | ros2 param list/get/set/dump/load | Same concepts, new tool name; supports all parameter types |
ROS 2 Tooling Ecosystem
ROS 2 ships with a rich set of command-line and GUI tools for development, debugging, and data management:
Data logging and replay:
ros2 bag record -a records all active topics to an MCAP file. ros2 bag play replays them, allowing offline algorithm development without a physical robot. Bags can be filtered, merged, and converted with ros2 bag convert.
3D Visualisation:
RViz2 is the primary 3D visualiser. It displays robot models (URDF), sensor data (LIDAR scans, camera images, point clouds), transforms (TF tree), navigation costmaps, and planned paths in real time. Panels and displays are configurable and saveable as .rviz config files.
rqt Plugin Framework:
rqt provides a Qt-based plugin system with dozens of plugins: rqt_graph (computation graph), rqt_plot (live time-series plots of any numeric topic), rqt_console (log message viewer with severity filtering), rqt_image_view (camera feed viewer), rqt_reconfigure (live parameter editing).
Diagnostics:
ros2 doctor analyses the ROS 2 installation, environment variables, DDS settings, and running system for common configuration problems. ros2 interface show prints the full definition of any message, service, or action type.
5 Best Practices for ROS 2 Package Organisation
- 01
Separate interfaces from implementations: keep custom .msg/.srv/.action files in a dedicated *_interfaces package so they can be depended upon without pulling in node implementations — this prevents circular dependency issues
- 02
Use meaningful namespaces for multi-robot systems: launch all robot nodes under /robot_1/, /robot_2/ namespaces using PushRosNamespace so topic names do not collide and the same launch file can instantiate multiple robots
- 03
Parameterise everything that might change: use ros2 param with YAML config files instead of hardcoding values like topic names, speeds, or thresholds — this makes nodes reusable across different robot platforms
- 04
Prefer composition over standalone nodes for high-bandwidth pipelines: use component containers and intra-process communication to pass large messages (images, point clouds) as shared pointers with zero serialisation overhead
- 05
Always set use_sim_time consistently: when replaying bags or running in Gazebo, all nodes must use simulation time (/clock topic) — inconsistent use_sim_time settings cause TF extrapolation errors that are notoriously difficult to debug