ROS2-016-ROS2 Tools: An Introduction to the launch File and Its Basic Use
Overview
In a robot operating system, nodes are the basic building blocks of a program. A complete, systematic functional module is made up of several nodes, and starting that module may mean starting all those nodes one after another.
Take a robot's navigation function as an example — the nodes involved are mainly these:
- chassis driver;
- lidar driver;
- camera driver;
- imu driver;
- map service;
- path planning;
- motion control;
- environmental perception;
- localization;
- etc.
And starting different nodes may also involve importing all sorts of parameters, dealing with the execution logic between nodes, and so on.
If you keep running the nodes one at a time with the ros2 run command at that point, it gets far too tedious. That is where the launch module ROS2 provides comes in — it lets you start a whole batch of nodes at once.
The launch module usually consists of two parts: the launch file and the ros2 launch command. The former packs up and configures the nodes; the latter executes the launch file.
Preparing the files
Create a workspace in a terminal:
mkdir -p ws02_tools/src
cd ws02_tools/src
colcon buildGo into the workspace's src directory:
cd src/Run the following two commands to create a C++ package and a Python package respectively:
C++:
ros2 pkg create cpp01_launch --build-type ament_cmake --dependencies rclcppPython:
ros2 pkg create py01_launch --build-type ament_python --dependencies rclpyThe basic launch workflow
In ROS2, launch files can be written in Python, XML or YAML, and the basic workflow is the same whichever format you use.
To make writing Python launch files easier later on, you can…
When you use the Python flavour of launch files, there are a lot of APIs involved, so to code more efficiently you can set up a snippet for launch files in VScode. See here. In VScode's python.json config file you can add the following:
"ros2 launch py": {
"prefix": "ros2_launch_py",
"body": [
"from launch import LaunchDescription",
"from launch_ros.actions import Node",
"# Classes for wrapping terminal commands------",
"# from launch.actions import ExecuteProcess",
"# from launch.substitutions import FindExecutable",
"# Declaring and getting arguments------",
"# from launch.actions import DeclareLaunchArgument",
"# from launch.substitutions import LaunchConfiguration",
"# File inclusion------",
"# from launch.actions import IncludeLaunchDescription",
"# from launch.launch_description_sources import PythonLaunchDescriptionSource",
"# Grouping------",
"# from launch_ros.actions import PushRosNamespace",
"# from launch.actions import GroupAction",
"# Events------",
"# from launch.event_handlers import OnProcessStart, OnProcessExit",
"# from launch.actions import ExecuteProcess, RegisterEventHandler, LogInfo",
"# Get the share directory path of the package------",
"# from ament_index_python.packages import get_package_share_directory",
"",
"def generate_launch_description():",
" ",
" return LaunchDescription([])"
],
"description": "ros2 launch"
}Next, a case study to walk through writing and building a launch file. The requirement: write and run a launch file that starts two nodes.
The steps are usually these:
- Write the launch file;
- Edit the config file;
- Build;
- Run.
We will split the case into a C++ implementation and a Python implementation.
The C++ implementation
1. Write the launch file
Create a launch directory inside the cpp01_launch package. A launch file can be a Python file, an xml file or a yaml file; the different types can all sit directly in the launch directory, or, to keep things tidy, you can create three folders under it — py, xml and yaml — to hold each type of launch file separately.
When naming launch files in those formats, people generally use _launch.py, _launch.xml, _launch.yaml, or .launch.py, .launch.xml, .launch.yaml as the suffix. Examples of names for each type of launch file:
- Python file:
py00_base_launch.pyorpy00_base.launch.py - xml file:
py00_base_launch.xmlorxml00_base.launch.xml - yaml file:
py00_base_launch.yamloryaml00_base.launch.yaml
Examples of the contents of each type of launch file:
Python file: taking
py00_base.launch.pyas the examplefrom launch inport LaunchDescription from launch_ros.actions import Node def generate_launch_description(): turtle1 = Node(package = "turtlesim", executable = "turtlesim_node", name = "t1") turtle2 = Node(package = "turtlesim", executable = "turtlesim_node", name = "t2") return LaunchDescription([turtle1, turtle2])xml file: taking
xml00_base.launch.xmlas the example<launch> <node pkg="turtlesim" exec="turtlesim_node" name="t1"/> <node pkg="turtlesim" exec="turtlesim_node" name="t1"/> </launch>yaml file: taking
yaml00_base.launch.yamlas the examplelaunch: - node: pkg: "turtlesim" exec: "turtlesim_node" name: "sim" namespace: "t1" - node: pkg: "turtlesim" exec: "turtlesim_node" name: "sim" namespace: "t2"
2. Edit the config file
You have to edit the config file before the launch file will work properly. If you build straight away without touching the config, the launch files simply will not be picked up by the system during the build.
You must explicitly say, via install(DIRECTORY ...) in CMakeLists.txt, that the launch files are to be installed into ROS2's shared resource directory (that is, share/${PROJECT_NAME}). Only once they are installed there can the ros2 launch command or a launch description file call them.
The first time you configure the package, add the following line at the 👈 spot in CMakeLists.txt:
......
find_package(rclcpp REQUIRED)
install(DIRECTORY launch DESTINATION share/${PROJECT_NAME}) 👈
if(BUILD_TESTING)
......This config only needs setting up once per package — however many launch files you later put in that package's launch directory, this one bit of config covers them all.
Once you have done this, build it in advance
To make sure the config is right, it is worth running colcon once after adding it. If it is, the launch directory structure appears under install/${PROJECT_NAME}/share/${PROJECT_NAME} as it should.
Further reading
${PROJECT_NAME} means the directory with the same name as the package — put simply, another directory that shares the name of the package you are building.
Of course, for a package with launch files it is best to add an execution dependency, ros2launch, to the package's package.xml:
<exec_depend>ros2launch</exec_depend>This makes sure the ros2 launch command works once the package is built, and that launch files in different formats get recognized. In practice the impact is not all that big anyway (
3. Build
In a terminal, go to the current workspace and build the package:
colcon build --package-select cpp01_launch
4. Run
In a terminal in the current workspace, run it with: (taking py00_base.launch.py as the example)
. install/setup.bash
ros2 launch cpp01_launch py00_base.launch.pyThe Python implementation
Writing and using a launch file in Python is actually pretty much the same flow as in C++ — the main difference is in editing the config file.
I. Write the launch file
Same as above.
II. Edit the config file
In this step you edit setup.py. In its data_files attribute, add the file paths of the launch files you wrote.
......
from glob import glob
......
setup(
name=package_name,
...
data_files=[
('share/ament_index/resource_index/packages', ['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
# Launch file related config
# Depends on how you named your files. If it is "_launch", use "_launch"
('share/' + package_name, glob("launch/py/*.launch.py")),
('share/' + package_name, glob("launch/xml/*.launch.xml")),
('share/' + package_name, glob("launch/yaml/*.launch.yaml")),
],
...
)As above, for a package with launch files it is best to add the execution dependency ros2launch to the package's package.xml:
<exec_depend>ros2launch</exec_depend>This makes sure the ros2 launch command works once the package is built, and that launch files in different formats get recognized.
III. Build
In a terminal, go to the current workspace and build the package:
colcon build --package-select py01_launch
IV. Run
In a terminal in the current workspace, run it with: (taking py00_base.launch.py as the example)
. install/setup.bash
ros2 launch py01_launch py00_base.launch.pyMore on launch files
You can refer to the next post, where I go through the syntax involved in writing launch files in the python language in detail.
Because XML & YAML have no event-trigger functions of their own to adapt, unless you are going to write the code only in C++, I would basically not recommend XML/YAML as the first language for writing launch files. If you do need them, see this post on XML/YAML and the official docs
Important
This article was translated by Hermes Agent; the original text can be found at here. The translation is for reference only. Translation time: 2026-11-05
