ROS2 Launch Files - Uvic-Robotics-Club/uvic-rover-2027 GitHub Wiki
Launch files are how you start multiple nodes at once with a single command. Instead of opening a new terminal for every node, a launch file defines everything that needs to run and starts it all together. They are used for testing, debugging and running the action system.
ROS2 supports Python, XML, and YAML launch files. We use Python because it is the standard and gives you actual programming logic like conditionals and the ability to compose launch files together.
Launch files are always named with a .launch.py suffix and live in a launch/ folder inside the package.
drive_package/
└── launch/
└── drive_launch.py
Minimal Example
This launches two nodes and passes a parameter file to one of them:
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
# Every launch file must have this function — ROS2 calls it to get the launch description
return LaunchDescription([
# Launch the drive node with a parameter file
Node(
package='drive_package', # The ROS2 package the node lives in
executable='drive_node', # The compiled executable name
name='drive_node', # The name this node registers with in the ROS2 network
parameters=['path/to/params.yaml'] # Parameter file to load — see ROS2 Basics for YAML format
),
# Launch a second node alongside the first
# Both start at the same time
Node(
package='comms_package',
executable='comms_node',
name='comms_node',
),
])
To run it:
ros2 launch drive_package drive_launch.py
Composing Launch Files
Each package have its own launch file. A top level launch file then brings everything together by including each package's launch file. This keeps things modular.
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from ament_index_python.packages import get_package_share_directory
import os
def generate_launch_description():
# get_package_share_directory finds the installed path of a package
# This is the correct way to reference other packages — never hardcode paths
drive_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(get_package_share_directory('drive_package'), 'launch', 'drive_launch.py')
)
)
arm_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(get_package_share_directory('arm_package'), 'launch', 'arm_launch.py')
)
)
comms_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(get_package_share_directory('comms_package'), 'launch', 'comms_launch.py')
)
)
return LaunchDescription([
drive_launch,
arm_launch,
comms_launch,
])
Launch Arguments
Launch arguments let you change behaviour at launch time without editing the file. The most common use case is switching between simulation and real hardware (which ties directly to the HAL pattern).
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 an argument named "sim" with a default value of "true"
# This means simulation mode is on by default unless told otherwise
sim_arg = DeclareLaunchArgument(
'sim',
default_value='true',
description='Set to true to run in simulation, false for real hardware'
)
# LaunchConfiguration retrieves the value of the argument at launch time
sim_mode = LaunchConfiguration('sim')
return LaunchDescription([
sim_arg,
Node(
package='drive_package',
executable='drive_node',
name='drive_node',
parameters=[{
'use_sim': sim_mode # Passed into the node as a parameter
}]
),
])
To run in simulation mode (default):
ros2 launch drive_package drive_launch.py
To run with real hardware:
ros2 launch drive_package drive_launch.py sim:=false
The node reads the use_sim parameter at startup and loads the appropriate HAL backend accordingly without any code changes.
Launch files need to be registered in
CMakeLists.txtto be installed and discoverable by ROS2.