Chapter 1.3: Launch Files and Configuration
Module: 1 - The Robotic Nervous System Week: 3 Estimated Reading Time: 30 minutes
Learning Objectives
By the end of this chapter, you will be able to:
- Write Python launch files to start complex multi-node systems
- Configure node parameters using YAML files
- Use namespaces and remapping for multi-robot systems
- Implement node composition for improved performance
- Debug launch file issues
Prerequisites
- Completed Chapters 1.1 and 1.2
- Understanding of ROS 2 nodes, topics, services, and actions
- Basic Python programming
Introduction
As your robotics projects grow in complexity, manually starting each node becomes impractical. Imagine a mobile robot with:
- A camera node
- A LIDAR node
- A localization node
- A path planning node
- A motor controller node
Starting these individually, configuring parameters, and managing dependencies would be tedious and error-prone. This is where launch files come in.
Launch files allow you to:
- Start multiple nodes with a single command
- Configure parameters programmatically
- Set up namespaces for multi-robot systems
- Manage node lifecycle and dependencies
- Create reusable robot configurations
Key Terms
- Launch File: Python script that automates starting multiple nodes with configuration
- Parameter: Runtime configuration value for nodes (e.g., topic names, sensor IDs)
- Namespace: Hierarchical grouping of nodes and topics (e.g.,
/robot1/camera) - Node Composition: Running multiple nodes in a single process for efficiency
- Launch Description: Python object representing the launch configuration
Core Concepts
1. Python Launch Files
ROS 2 uses Python launch files (not XML like ROS 1) for flexibility and programmability.
Basic Launch File Structure
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='demo_nodes_cpp',
executable='talker',
name='talker'
),
Node(
package='demo_nodes_cpp',
executable='listener',
name='listener'
),
])
Key Components:
LaunchDescription: Container for all launch actionsNode: Action to start a ROS 2 nodegenerate_launch_description(): Function that returns the launch configuration
Running a Launch File
# Run launch file
ros2 launch <package_name> <launch_file_name>
# Example
ros2 launch my_robot_bringup robot.launch.py
2. Node Configuration with Parameters
Inline Parameters
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='my_robot',
executable='camera_node',
name='camera',
parameters=[{
'frame_rate': 30,
'resolution': '1920x1080',
'camera_id': 0
}]
),
])
YAML Parameter Files
parameters.yaml:
camera_node:
ros__parameters:
frame_rate: 30
resolution: "1920x1080"
camera_id: 0
auto_exposure: true
Launch file using YAML:
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
# Get path to parameters file
config = os.path.join(
get_package_share_directory('my_robot'),
'config',
'parameters.yaml'
)
return LaunchDescription([
Node(
package='my_robot',
executable='camera_node',
name='camera',
parameters=[config]
),
])
3. Namespaces and Remapping
Namespaces for Multi-Robot Systems
def generate_launch_description():
return LaunchDescription([
# Robot 1
Node(
package='my_robot',
executable='controller',
name='controller',
namespace='robot1' # Topics become /robot1/cmd_vel, /robot1/odom, etc.
),
# Robot 2
Node(
package='my_robot',
executable='controller',
name='controller',
namespace='robot2' # Topics become /robot2/cmd_vel, /robot2/odom, etc.
),
])
Topic Remapping
Node(
package='my_robot',
executable='camera_node',
name='camera',
remappings=[
('image_raw', 'camera/image'), # Remap /image_raw → /camera/image
('camera_info', 'camera/info')
]
)
4. Node Composition
Node composition allows multiple nodes to run in a single process, reducing overhead.
Component Node
from launch_ros.actions import ComposableNodeContainer
from launch_ros.descriptions import ComposableNode
def generate_launch_description():
container = ComposableNodeContainer(
name='my_container',
namespace='',
package='rclcpp_components',
executable='component_container',
composable_node_descriptions=[
ComposableNode(
package='my_robot',
plugin='my_robot::CameraComponent',
name='camera'
),
ComposableNode(
package='my_robot',
plugin='my_robot::ProcessorComponent',
name='processor'
),
],
output='screen',
)
return LaunchDescription([container])
Benefits:
- Reduced inter-process communication overhead
- Lower memory footprint
- Better performance for high-frequency data pipelines
5. Launch File Arguments
Make launch files configurable with command-line arguments:
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
# Declare arguments
use_sim_time_arg = DeclareLaunchArgument(
'use_sim_time',
default_value='false',
description='Use simulation time'
)
camera_id_arg = DeclareLaunchArgument(
'camera_id',
default_value='0',
description='Camera device ID'
)
return LaunchDescription([
use_sim_time_arg,
camera_id_arg,
Node(
package='my_robot',
executable='camera_node',
name='camera',
parameters=[{
'use_sim_time': LaunchConfiguration('use_sim_time'),
'camera_id': LaunchConfiguration('camera_id')
}]
),
])
Usage:
# Use defaults
ros2 launch my_robot camera.launch.py
# Override arguments
ros2 launch my_robot camera.launch.py use_sim_time:=true camera_id:=1
6. Conditional Launch Logic
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription, DeclareLaunchArgument
from launch.conditions import IfCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
use_rviz_arg = DeclareLaunchArgument(
'use_rviz',
default_value='true',
description='Launch RViz for visualization'
)
return LaunchDescription([
use_rviz_arg,
# Always launch robot nodes
Node(
package='my_robot',
executable='controller',
name='controller'
),
# Conditionally launch RViz
Node(
condition=IfCondition(LaunchConfiguration('use_rviz')),
package='rviz2',
executable='rviz2',
name='rviz2',
arguments=['-d', '/path/to/config.rviz']
),
])
Practical Examples
Example 1: Simple Robot Bringup
robot_bringup.launch.py:
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
# Motor controller
Node(
package='my_robot',
executable='motor_controller',
name='motor_controller',
parameters=[{'wheel_radius': 0.05, 'wheel_base': 0.3}],
output='screen'
),
# Sensor fusion
Node(
package='my_robot',
executable='sensor_fusion',
name='sensor_fusion',
remappings=[
('imu_raw', 'sensors/imu'),
('odom_raw', 'sensors/wheel_odom')
],
output='screen'
),
# State publisher
Node(
package='robot_state_publisher',
executable='robot_state_publisher',
name='robot_state_publisher',
output='screen'
),
])
Example 2: Multi-Robot Simulation
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
robots = []
# Launch 3 robots with different namespaces
for i in range(3):
robot_namespace = f'robot_{i}'
robots.append(
Node(
package='turtlebot3_gazebo',
executable='turtlebot3_drive',
name='turtlebot3_drive',
namespace=robot_namespace,
parameters=[{
'initial_x': float(i * 2),
'initial_y': 0.0
}]
)
)
return LaunchDescription(robots)
Example 3: Including Other Launch Files
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
def generate_launch_description():
# Path to another launch file
gazebo_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource([
os.path.join(
get_package_share_directory('gazebo_ros'),
'launch',
'gazebo.launch.py'
)
]),
launch_arguments={'world': 'my_world.world'}.items()
)
return LaunchDescription([
gazebo_launch,
# Add your nodes here
])
Debugging Launch Files
Common Issues and Solutions
-
Node not starting:
# Check if package/executable exists
ros2 pkg list | grep my_robot
ros2 pkg executables my_robot -
Parameter not loading:
# Check parameter file path
ros2 param list
ros2 param get /node_name parameter_name -
Topic remapping not working:
# Verify remapped topics
ros2 topic list
ros2 node info /node_name
Launch File Debugging Flags
# Verbose output
ros2 launch --debug my_robot robot.launch.py
# Show launch file structure
ros2 launch --show-dependencies my_robot robot.launch.py
Best Practices
-
Use Descriptive Names: Name nodes and parameters clearly
name='front_camera' # Good
name='node1' # Bad -
Parameterize Everything: Use arguments for flexibility
DeclareLaunchArgument('robot_model', default_value='turtlebot3_burger') -
Organize Config Files: Keep YAML parameters in
/configdirectory -
Use Namespaces: Avoid topic/service name collisions in multi-robot systems
-
Add Comments: Document complex launch logic
# Launch SLAM only if mapping mode is enabled -
Handle Errors Gracefully: Use try/except for file operations
try:
config = os.path.join(get_package_share_directory('my_robot'), 'config', 'params.yaml')
except Exception as e:
print(f'Error loading config: {e}')
Summary
In this chapter, you learned:
- ✅ Python launch files automate multi-node startup
- ✅ Parameters can be configured inline or via YAML files
- ✅ Namespaces enable multi-robot coordination
- ✅ Node composition improves performance
- ✅ Launch arguments make configurations reusable
- ✅ Conditional logic adapts launches to different scenarios
Key Takeaway: Launch files are the orchestration layer of ROS 2, enabling you to manage complex robotic systems efficiently.
End-of-Chapter Exercises
Exercise 1: Write a Multi-Node Launch File (Difficulty: Medium)
Create a launch file that starts:
- A
talkernode publishing to/chatter - A
listenernode subscribing to/chatter - A
rqt_graphnode for visualization
Bonus: Add a launch argument to control the talker's publish rate.
Exercise 2: Multi-Robot System (Difficulty: Hard)
Write a launch file that starts two robots (robot_a and robot_b) with:
- Separate namespaces
- Different starting positions
- Shared map topic (
/map)
Hint: Use topic remapping for the shared map.
Exercise 3: Parameter Configuration (Difficulty: Easy)
Create a YAML parameter file for a camera node with:
- Frame rate: 30 FPS
- Resolution: 1920x1080
- Auto-exposure: enabled
Write a launch file that loads these parameters.
Further Reading
Required
Optional
Next Chapter
Continue to Chapter 1.4: Building ROS 2 Packages to learn how to organize your code into reusable ROS 2 packages.
Pro Tip: Start simple with basic launch files, then gradually add parameters, namespaces, and composition as your project grows in complexity.