Chapter 1.8: Launch Files and Parameters
Learning Objectives
By the end of this chapter, you will be able to:
- Create and configure launch files for complex multi-node systems
- Manage parameters using YAML files and command-line arguments
- Understand and implement different parameter loading strategies
- Configure complex systems with multiple nodes and dependencies
- Use conditional launch logic for flexible system configuration
- Implement parameter validation and error handling
- Design reusable launch file components using composable nodes
- Configure logging and diagnostics for multi-node systems
Introduction
In physical AI and humanoid systems, launching complex robot software is far more intricate than starting a single program. A humanoid robot might need dozens of nodes running simultaneously: perception nodes for cameras and LiDAR, control nodes for different subsystems, AI processing nodes for navigation and manipulation planning, and communication nodes for cloud connectivity. Managing this complexity manually would be error-prone and inefficient.
Launch files provide a structured way to start, configure, and manage complex robotic systems. They handle node dependencies, parameter configuration, and orderly shutdown. In a Physical AI system, a launch file might start:
- Multiple sensor processing nodes (camera, LiDAR, IMU)
- Perception pipelines (object detection, SLAM)
- Control systems (walking, manipulation)
- AI services (chatbot, personalization)
- Communication interfaces (cloud connectivity)
Parameters complement launch files by controlling node behavior without code changes. For example, a humanoid's walking gait parameters can be tuned for different terrains through parameters without modifying the control algorithm code.
In this chapter, we'll explore how to design launch files that make complex Physical AI systems manageable, configurable, and reliable. You'll learn to create flexible system configurations that can adapt to different robot hardware, environments, and operational requirements.
1. Launch Files Fundamentals (800 words)
What are Launch Files? (300 words)
Launch files in ROS 2 are configuration files that define how to start, configure, and manage groups of nodes. They eliminate the need to manually start dozens of nodes with complex command-line arguments, making system deployment more reliable and reproducible.
In Physical AI systems, launch files are essential because:
- They ensure all necessary nodes start in the correct order
- They configure parameters for each node appropriately
- They handle namespace organization for multi-robot systems
- They manage dependencies between nodes
- They provide a single entry point for complex systems
Launch File Approaches: ROS 2 supports two approaches for launch files:
- Python-based launch files (preferred): More flexible and powerful
- XML-based launch files (legacy): Less flexible but still supported
- YAML-based compositions (for composable nodes): Lightweight for simple cases
Python Launch Files (500 words)
Python-based launch files offer maximum flexibility and are the recommended approach for complex systems.
Basic Launch File Structure:
# launch/simple_robot.launch.py
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration, TextSubstitution
from launch_ros.actions import Node
from launch.substitutions import PathJoinSubstitution
from launch_ros.substitutions import FindPackageShare
def generate_launch_description():
"""Generate launch description for simple robot system."""
# Define launch arguments that can be passed at runtime
namespace_launch_arg = DeclareLaunchArgument(
'namespace',
default_value='physical_ai_robot',
description='Namespace for the robot nodes'
)
use_sim_time_launch_arg = DeclareLaunchArgument(
'use_sim_time',
default_value='false',
description='Use simulation time'
)
# Get launch configuration values
namespace = LaunchConfiguration('namespace')
use_sim_time = LaunchConfiguration('use_sim_time')
# Define nodes
camera_driver_node = Node(
package='camera_ros',
executable='camera_driver',
name='camera_driver',
namespace=namespace,
parameters=[
{'camera_name': 'front_camera'},
{'frame_rate': 30.0},
{'image_width': 640},
{'image_height': 480},
{'use_sim_time': use_sim_time}
],
remappings=[
('/camera/image_raw', '/front_cam/image_raw'),
('/camera/camera_info', '/front_cam/camera_info'),
]
)
imu_driver_node = Node(
package='imu_ros',
executable='imu_driver',
name='imu_driver',
namespace=namespace,
parameters=[
{'imu_name': 'main_imu'},
{'rate': 200.0}, # Hz
{'frame_id': 'base_link'},
{'use_sim_time': use_sim_time}
]
)
perception_node = Node(
package='physical_ai_perception',
executable='object_detector',
name='object_detector',
namespace=namespace,
parameters=[
{'model_path': 'yolo_v5_weights.pt'},
{'confidence_threshold': 0.5},
{'use_gpu': True},
{'input_topics': ['/front_cam/image_raw']},
{'use_sim_time': use_sim_time}
]
)
# Return the complete launch description
return LaunchDescription([
namespace_launch_arg,
use_sim_time_launch_arg,
camera_driver_node,
imu_driver_node,
perception_node,
])
Key Launch Concepts:
Launch Actions: These are commands that can be executed during launch:
DeclareLaunchArgument: Defines arguments that can be passed at runtimeLogInfo: Outputs information to the consoleTimerAction: Delays execution of other actionsRegisterEventHandler: Responds to system eventsSetEnvironmentVariable: Sets environment variables
Substitutions: Values that can be computed at launch time:
LaunchConfiguration: Gets values from launch argumentsPathJoinSubstitution: Joins paths safelyFindPackageShare: Locates package-specific directoriesTextSubstitution: Literal text values
Nodes: Each ROS 2 node to be launched with its configuration:
- Package: The ROS package containing the executable
- Executable: The name of the executable to run
- Name: The name for this node instance
- Namespace: The namespace to add to all topics/services
- Parameters: Configuration values passed to the node
- Remappings: Change topic/service names
- Conditions: Control when a node launches
Conditional Launch (200 words)
Conditional launching allows nodes to start based on runtime conditions:
# Example of conditional node launching
from launch.conditions import IfCondition
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
# Declare argument to enable GUI
gui_enabled_arg = DeclareLaunchArgument(
'enable_gui',
default_value='false',
description='Enable GUI components'
)
# Conditional node launch
rviz_node = Node(
package='rviz2',
executable='rviz2',
name='rviz',
condition=IfCondition(LaunchConfiguration('enable_gui'))
)
Use conditional launching to create flexible configurations that can be adapted for different scenarios (development, testing, production) without duplicating launch files.
2. Parameter Management (1000 words)
Parameter Sources (300 words)
ROS 2 provides multiple ways to configure node parameters:
1. Command Line Arguments:
ros2 run package_name node_name --ros-args --param topic_rate:=10.0 --param enable_logging:=true
2. YAML Parameter Files:
# config/robot_params.yaml
physical_ai_robot:
camera_driver:
ros__parameters:
camera_name: "front_camera"
frame_rate: 30.0
image_width: 640
image_height: 480
imu_driver:
ros__parameters:
imu_name: "main_imu"
rate: 200.0
frame_id: "base_link"
object_detector:
ros__parameters:
model_path: "yolo_v5_weights.pt"
confidence_threshold: 0.5
use_gpu: true
input_topics: ["/front_cam/image_raw"]
3. Launch File Definitions:
# Inline parameter definition in launch files
Node(
package='camera_ros',
executable='camera_driver',
parameters=[
{'camera_name': 'front_camera'},
{'frame_rate': 30.0},
{'use_sim_time': LaunchConfiguration('use_sim_time')}
]
)
YAML Parameter Files (400 words)
YAML parameter files provide a structured way to manage complex configurations:
# config/physical_ai_config.yaml
physical_ai_robot:
/**: # Applies to all nodes
ros__parameters:
use_sim_time: false
log_level: "INFO"
camera_driver:
ros__parameters:
# Camera settings
camera_name: "front_camera"
frame_rate: 30.0
image_width: 640
image_height: 480
exposure_time: 10000 # microseconds
gain: 1.0
# Calibration parameters
calibration_file: "front_camera_calib.yaml"
rectify_images: true
# Operational settings
enable_auto_exposure: true
enable_auto_white_balance: true
lidar_driver:
ros__parameters:
# LiDAR settings
device_ip: "192.168.1.10"
port: 2368
scan_frequency: 10.0 # Hz
range_min: 0.1 # meters
range_max: 100.0 # meters
intensity_channel: true
# Processing parameters
enable_filter: true
filter_radius: 0.1 # meters
filter_min_neighbors: 3
physical_ai_controller:
ros__parameters:
# Control loop settings
control_frequency: 100.0 # Hz
enable_publish_diagnostics: true
# Walking parameters (for humanoid robots)
step_height: 0.1 # meters
step_length: 0.3 # meters
walking_speed: 0.5 # m/s
balance_margin: 0.05 # meters
# Safety parameters
max_joint_velocity: 2.0 # rad/s
max_joint_torque: 50.0 # N*m
emergency_stop_timeout: 0.1 # seconds
object_detector:
ros__parameters:
# Model settings
model_path: "/opt/models/yolov5s.pt"
confidence_threshold: 0.5
nms_threshold: 0.4
max_det: 100
# Performance settings
use_gpu: true
gpu_device_id: 0
batch_size: 1
# Input/output settings
input_topics: ["/front_cam/image_raw", "/rear_cam/image_raw"]
output_topic: "/detected_objects"
enable_visualization: true
# Object classes
target_classes: ["person", "robot", "obstacle", "ball"]
Loading Parameters in Nodes (300 words)
Nodes can access parameters through the ROS 2 node interface:
# params_example_node.py
import rclpy
from rclpy.node import Node
from rclpy.parameter import Parameter
class ParamExampleNode(Node):
"""Example node demonstrating parameter usage."""
def __init__(self):
super().__init__('param_example_node')
# Declare parameters explicitly with types and descriptions
self.declare_parameter('robot_name', 'physical_ai_bot',
Parameter.Type.STRING,
'Name of the robot for identification')
self.declare_parameter('control_loop_rate', 50.0,
Parameter.Type.DOUBLE,
'Rate of the main control loop in Hz')
self.declare_parameter('max_velocity', 0.5,
Parameter.Type.DOUBLE,
'Maximum linear velocity in m/s')
self.declare_parameter('enable_logging', True,
Parameter.Type.BOOL,
'Enable detailed logging')
# Access parameter values
self.robot_name = self.get_parameter('robot_name').value
self.control_rate = self.get_parameter('control_loop_rate').value
self.max_vel = self.get_parameter('max_velocity').value
self.enable_logging = self.get_parameter('enable_logging').value
# Create a timer with the control rate
self.timer = self.create_timer(1.0/self.control_rate, self.main_loop)
# Log initialization with parameter values
self.get_logger().info(
f'Initialized {self.robot_name} with control rate {self.control_rate}Hz, '
f'max velocity {self.max_vel}m/s, logging {self.enable_logging}'
)
# Register parameter callback for dynamic reconfiguration
self.add_on_set_parameters_callback(self.param_change_callback)
def param_change_callback(self, parameter_list):
"""Handle parameter changes at runtime."""
for param in parameter_list:
if param.name == 'max_velocity' and param.type_ == Parameter.Type.DOUBLE:
if param.value > 2.0: # Safety limit
return SetParametersResult(successful=False, reason='Max velocity too high')
else:
self.max_vel = param.value
self.get_logger().info(f'Max velocity updated to {param.value}m/s')
return SetParametersResult(successful=True)
def main_loop(self):
"""Main control loop that uses parameters."""
# This would be the main control logic
if self.enable_logging:
self.get_logger().debug(f'Control loop ticking at {self.control_rate}Hz')
# Implement control logic using parameters
# For example, use max_velocity in movement commands
pass
def main(args=None):
rclpy.init(args=args)
node = ParamExampleNode()
try:
rclpy.spin(node)
except KeyboardInterrupt:
node.get_logger().info('Shutting down parameter example node')
finally:
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
Always validate parameters at runtime to prevent unsafe configurations that could cause robot malfunctions.
3. Advanced Launch Concepts (800 words)
Composable Nodes and Composition (400 words)
Composable nodes allow multiple nodes to run within the same process, reducing communication overhead:
# launch/composed_nodes.launch.py
from launch import LaunchDescription
from launch_ros.actions import ComposableNodeContainer
from launch_ros.descriptions import ComposableNode
def generate_launch_description():
"""Launch composable nodes in a single container."""
# Create a container to host multiple nodes
container = ComposableNodeContainer(
name='perception_container',
namespace='physical_ai_robot',
package='rclcpp_components',
executable='component_container',
composable_node_descriptions=[
ComposableNode(
package='image_proc',
plugin='image_proc::RectifyNode',
name='rectify_node',
parameters=[{'use_sim_time': False}],
remappings=[
('image', '/front_cam/image_raw'),
('camera_info', '/front_cam/camera_info'),
('image_rect', '/front_cam/image_rect')
]
),
ComposableNode(
package='physical_ai_perception',
plugin='physical_ai_perception::ObjectDetectorComponent',
name='object_detector_component',
parameters=[
{'model_path': 'yolo_v5_weights.pt'},
{'confidence_threshold': 0.5}
],
remappings=[
('input_image', '/front_cam/image_rect'),
('detected_objects', '/detected_objects')
]
),
ComposableNode(
package='physical_ai_perception',
plugin='physical_ai_perception::FeatureExtractorComponent',
name='feature_extractor',
parameters=[
{'feature_type': 'orb'},
{'max_features': 1000}
],
remappings=[
('input_image', '/front_cam/image_rect'),
('features', '/extracted_features')
]
)
],
output='screen'
)
return LaunchDescription([container])
Launch File Parameterization (250 words)
Launch files themselves can be highly parameterized to support different configurations:
# launch/physical_ai_system.launch.py
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription, LogInfo
from launch.conditions import IfCondition, UnlessCondition
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare
def generate_launch_description():
"""Generate launch description with extensive parameterization."""
# Declare all possible launch arguments
robot_namespace_arg = DeclareLaunchArgument(
'robot_namespace',
default_value='physical_ai_robot',
description='Namespace for all robot topics and services'
)
use_sim_time_arg = DeclareLaunchArgument(
'use_sim_time',
default_value='false',
description='Use simulation time for all nodes'
)
enable_gui_arg = DeclareLaunchArgument(
'enable_gui',
default_value='false',
description='Launch GUI components (RViz, etc.)'
)
config_file_arg = DeclareLaunchArgument(
'config_file',
default_value=PathJoinSubstitution([
FindPackageShare('physical_ai_bringup'),
'config',
'default_params.yaml'
]),
description='Path to configuration file'
)
# Get launch configurations
robot_namespace = LaunchConfiguration('robot_namespace')
use_sim_time = LaunchConfiguration('use_sim_time')
enable_gui = LaunchConfiguration('enable_gui')
config_file = LaunchConfiguration('config_file')
# Include other launch files conditionally
bringup_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
PathJoinSubstitution([
FindPackageShare('physical_ai_bringup'),
'launch',
'robot_bringup.launch.py'
])
),
launch_arguments={
'namespace': robot_namespace,
'use_sim_time': use_sim_time,
'config_file': config_file
}.items()
)
# Conditional nodes based on parameters
rviz_node = Node(
package='rviz2',
executable='rviz2',
name='rviz',
arguments=['-d', PathJoinSubstitution([
FindPackageShare('physical_ai_viz'),
'rviz',
'physical_ai_config.rviz'
])],
condition=IfCondition(enable_gui)
)
# Log startup information
startup_log = LogInfo(
msg=["Starting Physical AI system with namespace: ", robot_namespace]
)
return LaunchDescription([
robot_namespace_arg,
use_sim_time_arg,
enable_gui_arg,
config_file_arg,
startup_log,
bringup_launch,
rviz_node,
])
Event Handling and Monitoring (150 words)
Launch files can monitor system events and respond accordingly:
from launch.event_handlers import OnProcessExit, OnProcessStart
from launch.actions import RegisterEventHandler, LogInfo
# Example: Restart a node if it exits unexpectedly
restart_on_exit_handler = RegisterEventHandler(
OnProcessExit(
target_action=node_to_monitor,
on_exit=[
LogInfo(msg="Node exited unexpectedly, restarting..."),
# Add restart action here
]
)
)
4. Parameter Best Practices (700 words)
Parameter Organizations (300 words)
By Functionality: Group parameters logically rather than randomly:
physical_ai_controller:
ros__parameters:
# Walking control parameters
walking:
step_height: 0.1
step_length: 0.3
step_duration: 1.0
balance_margin: 0.05
# Manipulation parameters
manipulation:
grip_force_min: 5.0
grip_force_max: 50.0
approach_distance: 0.1
# Safety parameters
safety:
max_joint_velocity: 2.0
emergency_stop_timeout: 0.1
stability_threshold: 0.1
By Node Type: Organize parameters by node function:
# Separate files for different system components
robot_drivers.yaml: # Sensor, actuator drivers
robot_control.yaml: # Control algorithms
robot_perception.yaml: # Vision, sensor processing
robot_planning.yaml: # Path planning, navigation
robot_hmi.yaml: # Human-machine interface
Parameter Validation (200 words)
Validate parameters to prevent unsafe configurations:
def validate_parameters(self):
"""Validate parameters before system initialization."""
# Validate velocity limits
max_vel = self.get_parameter('max_velocity').value
if max_vel <= 0 or max_vel > 5.0: # Reasonable limit
self.get_logger().fatal(f'Invalid max_velocity: {max_vel}. Must be between 0 and 5.0')
return False
# Validate joint limits
joint_limits = self.get_parameter('joint_limits').value
for joint_name, limit in joint_limits.items():
if limit['min'] >= limit['max']:
self.get_logger().fatal(f'Invalid joint limits for {joint_name}: min {limit["min"]} >= max {limit["max"]}')
return False
return True
Dynamic Reconfiguration (200 words)
Allow parameter changes during runtime where appropriate:
from rcl_interfaces.msg import SetParametersResult
class DynamicParamNode(Node):
def __init__(self):
super().__init__('dynamic_param_node')
# Register parameter callback
self.add_on_set_parameters_callback(self.parameters_callback)
# Declare parameters with constraints
self.declare_parameter('operating_mode', 'autonomous',
description='Operating mode: manual, autonomous, or test')
self.declare_parameter('safety_margin', 0.5,
description='Safety distance margin in meters')
def parameters_callback(self, params):
"""Handle parameter changes."""
for param in params:
if param.name == 'operating_mode' and param.value not in ['manual', 'autonomous', 'test']:
return SetParametersResult(successful=False, reason='Invalid operating mode')
elif param.name == 'safety_margin':
if param.value < 0.1 or param.value > 5.0:
return SetParametersResult(successful=False, reason='Safety margin out of range')
# Implement parameter change logic
self.update_behavior_for_new_safety_margin(param.value)
return SetParametersResult(successful=True)
Dynamic reconfiguration is powerful but should be used carefully in safety-critical systems. Always validate parameter combinations for safety.
5. Hands-On Exercise (400 words)
Exercise: Complex System Launch Configuration
Objective: Create a comprehensive launch system for a Physical AI humanoid robot with multiple sensors, perception, and control nodes.
Prerequisites:
- Completed previous chapters
- ROS 2 Humble with required packages
- Understanding of ROS 2 concepts
Steps:
Step 1: Create Launch Directory Structure
# Create launch directories in your package
mkdir -p physical_ai_launch/launch
cd physical_ai_launch/launch
Step 2: Create Parameter Files
Create config/physical_ai_full_system.yaml:
physical_ai_humanoid:
/**: # Global parameters
ros__parameters:
use_sim_time: false
log_level: "INFO"
camera_node:
ros__parameters:
camera_name: "front_fisheye"
frame_rate: 30.0
resolution: [1280, 720]
exposure: 10000
gain: 1.5
imu_node:
ros__parameters:
device_id: "imu_01"
sample_rate: 200.0
frame_id: "imu_link"
enable_filtering: true
lidar_node:
ros__parameters:
device_ip: "192.168.1.20"
port: 2368
scan_frequency: 10.0
range_min: 0.1
range_max: 30.0
perception_pipeline:
ros__parameters:
detection_model: "yolo_v5s_physical_ai.pt"
confidence_threshold: 0.6
nms_threshold: 0.4
target_classes: ["human", "obstacle", "goal"]
humanoid_controller:
ros__parameters:
# Walking parameters
walk_step_height: 0.05
walk_step_length: 0.25
walk_frequency: 0.8 # steps per second
balance_kp: 10.0
balance_kd: 1.0
# Safety parameters
max_tilt_angle: 15.0 # degrees
emergency_brake_timeout: 0.1 # seconds
joint_velocity_limits: [2.0, 2.0, 2.0, 3.0, 3.0, 3.0] # rad/s for each joint group
Step 3: Create Main Launch File
Create physical_ai_launch/launch/humanoid_full_system.launch.py:
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, LogInfo
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
from launch.substitutions import PathJoinSubstitution
from launch_ros.substitutions import FindPackageShare
def generate_launch_description():
"""Launch the complete Physical AI humanoid system."""
# Declare launch arguments
config_file_arg = DeclareLaunchArgument(
'config_file',
default_value=PathJoinSubstitution([
FindPackageShare('physical_ai_launch'),
'config',
'physical_ai_full_system.yaml'
]),
description='Path to configuration file'
)
namespace_arg = DeclareLaunchArgument(
'namespace',
default_value='physical_ai_humanoid',
description='Namespace for the robot nodes'
)
# Get configurations
config_file = LaunchConfiguration('config_file')
namespace = LaunchConfiguration('namespace')
# Create nodes
camera_node = Node(
package='physical_ai_camera',
executable='camera_driver',
name='camera_node',
namespace=namespace,
parameters=[config_file],
output='screen'
)
imu_node = Node(
package='physical_ai_sensors',
executable='imu_driver',
name='imu_node',
namespace=namespace,
parameters=[config_file],
output='screen'
)
lidar_node = Node(
package='physical_ai_sensors',
executable='lidar_driver',
name='lidar_node',
namespace=namespace,
parameters=[config_file],
output='screen'
)
perception_node = Node(
package='physical_ai_perception',
executable='perception_pipeline',
name='perception_pipeline',
namespace=namespace,
parameters=[config_file],
output='screen'
)
controller_node = Node(
package='physical_ai_control',
executable='humanoid_controller',
name='humanoid_controller',
namespace=namespace,
parameters=[config_file],
output='screen'
)
# Startup confirmation
startup_msg = LogInfo(
msg=["Physical AI Humanoid system launched with namespace: ", namespace]
)
return LaunchDescription([
config_file_arg,
namespace_arg,
startup_msg,
camera_node,
imu_node,
lidar_node,
perception_node,
controller_node,
])
Step 4: Create Specialized Launch Files
Create physical_ai_launch/launch/simulation_mode.launch.py:
from launch import LaunchDescription
from launch.actions import SetLaunchConfiguration, LogInfo
from launch.substitutions import TextSubstitution
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import IncludeLaunchDescription
from launch.substitutions import PathJoinSubstitution
from launch_ros.substitutions import FindPackageShare
def generate_launch_description():
"""Launch Physical AI system in simulation mode."""
# Set use_sim_time to true globally
set_sim_time = SetLaunchConfiguration(
'use_sim_time',
'true'
)
# Include the main system launch with additional simulation-specific nodes
main_system_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
PathJoinSubstitution([
FindPackageShare('physical_ai_launch'),
'launch',
'humanoid_full_system.launch.py'
])
),
launch_arguments={
'config_file': PathJoinSubstitution([
FindPackageShare('physical_ai_launch'),
'config',
'physical_ai_simulation.yaml'
])
}.items()
)
# Add simulation-specific nodes (gazebo, etc.)
sim_nodes = [
# Add gazebo spawn node, controllers, etc.
]
return LaunchDescription([
set_sim_time,
main_system_launch,
LogInfo(msg="Physical AI system launched in simulation mode")
])
Step 5: Test the Launch System
# Build your package
cd ~/ros2_ws
colcon build --packages-select physical_ai_launch
# Source the workspace
source install/setup.bash
# Launch the full system
ros2 launch physical_ai_launch humanoid_full_system.launch.py
# Launch with custom namespace
ros2 launch physical_ai_launch humanoid_full_system.launch.py namespace:=test_robot
# Launch with simulation mode
ros2 launch physical_ai_launch simulation_mode.launch.py
Expected Result: The launch system should start all nodes with the correct parameters and namespaces. You should see all nodes come up properly in ROS 2.
Troubleshooting:
- If nodes don't start, check that all required packages are built and sourced
- If parameters aren't loaded, verify the YAML file paths are correct
- Check that all the referenced packages and executables actually exist
Extension Challenge (Optional)
Design and implement a launch file that can switch between different robot hardware configurations (simulator, small robot, large humanoid) based on a single parameter.
6. Assessment Questions (10 questions)
Multiple Choice (5 questions)
Question 1: What is the main purpose of launch files in ROS 2? a) To store parameter values b) To start, configure, and manage groups of nodes c) To define message types d) To create GUI interfaces
Details
Click to reveal answer
Answer: b Explanation: Launch files are designed to start, configure, and manage groups of nodes simultaneously, eliminating the need to manually start each node individually.Question 2: In YAML parameter files, what does the /** pattern indicate? a) Root namespace b) Applies to all nodes in the file c) Wildcard for topic remapping d) Comment section
Details
Click to reveal answer
Answer: b Explanation: The /** pattern in ROS 2 YAML parameter files applies the parameters to all nodes defined in the file.Question 3: What is the advantage of using composable nodes? a) Faster compilation b) Reduced communication overhead between nodes c) Easier debugging d) Simplified launch files
Details
Click to reveal answer
Answer: b Explanation: Composable nodes run in the same process, reducing inter-process communication overhead, especially important for high-frequency communications between tightly coupled nodes.Question 4: How can ROS 2 nodes be notified of parameter changes during runtime? a) Periodic polling b) Using add_on_set_parameters_callback c) Restarting the node d) Launch file reload
Details
Click to reveal answer
Answer: b Explanation: The add_on_set_parameters_callback method registers a function that gets called when parameters are changed at runtime, enabling dynamic reconfiguration.Question 5: What is the correct syntax to pass arguments to a launch file? a) ros2 launch package node.launch --args b) ros2 launch package launch_file.launch.py argument_name:=value c) ros2 run package launch_file.launch.py --argument value d) ros2 launch package launch_file.launch.py --argument=value
Details
Click to reveal answer
Answer: b Explanation: Launch file arguments are passed using the syntax: argument_name:=value (similar to ROS 2 standard parameter setting).Short Answer (3 questions)
Question 6: Explain when you would use launch file conditions and provide an example scenario.
Details
Click to reveal sample answer
Launch file conditions are used to start or skip nodes based on runtime parameters. For example, you might use a condition to start RViz only when a "visualization" parameter is true:Node(condition=IfCondition(LaunchConfiguration('enable_visualization')), ...) This allows flexibility in system configurations for different scenarios (development with visualization vs. production without it).Question 7: Describe the advantages of using YAML parameter files over inline parameters in launch files.
Details
Click to reveal sample answer
YAML parameter files offer several advantages: 1) Separation of configuration from launch logic 2) Easy editing without touching launch code 3) Reusability across different launch files 4) Version control for parameter values 5) Complex data structures like arrays and nested dictionaries 6) Configuration validation and review by domain experts.Question 8: What's the difference between declaring a parameter in the node code versus in a YAML file?
Details
Click to reveal sample answer
Parameters declared in node code are required and can be type-checked at runtime, providing better error handling. Parameters in YAML files are externally configurable without rebuilding code. The node code should declare parameters it expects and provide default values, while YAML files override those defaults. This separation allows developers to define which parameters are available while allowing operators to configure values.Practical Exercises (2 questions)
Question 9: Configuration Design Exercise Design a parameter configuration system for a humanoid robot that includes:
- Different configurations for indoor vs outdoor use
- Different configurations for research vs production mode
- Parameter validation to prevent unsafe settings
- A launch file structure that allows switching between configurations
- Documentation for other team members about how to modify parameters
Document your configuration design with example YAML files and launch files that implement this structure.
Question 10: Launch System Optimization Exercise Analyze the performance of your launch system and optimize it by:
- Identifying nodes that could be combined using composition
- Determining which nodes must start before others
- Setting up proper shutdown sequences
- Adding monitoring to detect if nodes fail unexpectedly
- Creating a launch file that can restart failed nodes automatically
Create the optimized launch configuration and explain how it improves system reliability and performance.
7. Further Reading (5-7 resources)
-
ROS 2 Launch System Documentation Why read: Official guide to ROS 2 launch systems with comprehensive examples Link: https://docs.ros.org/en/rolling/Tutorials/Launch-system.html
-
"Programming Robots with ROS" - Morgan Quigley et al. Why read: In-depth coverage of ROS launch systems and system configuration Link: https://www.oreilly.com/library/view/programming-robots-with/9781449323899/
-
Parameter Handling in ROS 2 Why read: Detailed guide to parameter management and best practices Link: https://docs.ros.org/en/rolling/Tutorials/Parameters/Understanding-ROS2-Parameters.html
-
Composable Nodes Tutorial Why read: Learn how to maximize performance with node composition Link: https://docs.ros.org/en/rolling/Tutorials/Composition.html
-
Launch Configuration Best Practices Why read: Industry recommendations for organizing complex systems Link: https://index.ros.org/doc/ros2/Tutorials/Logging-and-parameters/
-
ROS 2 Design: Launch System Why read: Understanding the philosophy behind ROS 2 launch system Link: https://design.ros2.org/articles/launch_system.html
-
Event Handling in Launch Files Why read: Advanced launch techniques for responsive system management Link: https://github.com/ros2/launch/tree/master/launch
Recommended Order:
- Start with the official launch system tutorial
- Read the parameter handling documentation
- Implement a simple system
- Explore composition for performance
- Study event handling for advanced functionality
8. Hardware/Software Requirements
Software Requirements:
- ROS 2 Humble Hawksbill (or latest LTS)
- Python 3.8+ with launch libraries
- Text editor for YAML and Python files
- Terminal/shell access
Hardware Requirements:
- Computer with 4+ GB RAM (8+ GB recommended)
- Multi-core processor for running multiple nodes simultaneously
- Network access for package installation
9. Chapter Summary & Next Steps
Chapter Summary
In this chapter, you learned:
- How to create and structure launch files for complex systems
- Multiple parameter definition and management strategies
- How to implement dynamic reconfiguration for runtime parameter changes
- Advanced launch concepts like composition and event handling
- Best practices for organizing and validating parameter configurations
- How to design flexible launch systems that adapt to different scenarios
Next Steps
In Chapter 1.9, we'll explore the Robot Operating System 2 (ROS 2) tooling ecosystem, including command-line tools, visualization tools, and debugging utilities. This will give you the tools necessary to monitor and debug the complex systems you've learned to configure in this chapter.
Estimated Time to Complete: 2.5 hours Difficulty Level: Intermediate Prerequisites: Chapters 1.1-1.7