This paper records 6 basic problems that I personally think are important in the learning process of launch file in ROS2. I hope it can help beginners.
Question 1: what is the use of the launch file?
Through the launch file, ROS2 can start many nodes at the same time, which simplifies starting different nodes multiple times with the command line.
Question 2: how to use the launch file?
Complete command:
ros2 launch <package_name> <launch_file_name>
You can also start the launch file directly, like this:
ros2 launch turtlesim_mimic_launch.py
turtlesim_mimic_launch.py is a python file that defines the contents of a launch file.
However, ROS1 launch does not support py files. In fact, there are three formats for launch files in ROS2:
- python script
- xml file
- yaml file
Question 3: what should be in the launch file?
node correlation
The most important part of the launch file file is the node information, which specifies the package information, the node name, and the path of the executable file.
<node pkg="turtlesim" exec="turtlesim_node" name="sim" namespace="turtlesim2"> <param name="background_r" value="$(var background_r)"/> <param name="background_g" value="$(var background_g)"/> <param name="background_b" value="$(var background_b)"/> </node>
include
Include can include another launch file in one launch file
group
group can combine multiple node s together
Question 4: how to write a launch file?
Whether it's python, xml or yaml, the steps to write the launch file are almost the same.
- Set the default values of command line parameters,
- Set the inclusion relationship of the launch file through the tag
- Set Node information, including name, namespace and parameter
- If you need to set remmaping, set the remapping relationship
The official document shows an example
# example.launch.py import os from ament_index_python import get_package_share_directory from launch import LaunchDescription from launch.actions import DeclareLaunchArgument from launch.actions import IncludeLaunchDescription from launch.actions import GroupAction from launch.launch_description_sources import PythonLaunchDescriptionSource from launch.substitutions import LaunchConfiguration from launch.substitutions import TextSubstitution from launch_ros.actions import Node from launch_ros.actions import PushRosNamespace def generate_launch_description(): # args that can be set from the command line or a default will be used background_r_launch_arg = DeclareLaunchArgument( "background_r", default_value=TextSubstitution(text="0") ) background_g_launch_arg = DeclareLaunchArgument( "background_g", default_value=TextSubstitution(text="255") ) background_b_launch_arg = DeclareLaunchArgument( "background_b", default_value=TextSubstitution(text="0") ) chatter_ns_launch_arg = DeclareLaunchArgument( "chatter_ns", default_value=TextSubstitution(text="my/chatter/ns") ) # include another launch file launch_include = IncludeLaunchDescription( PythonLaunchDescriptionSource( os.path.join( get_package_share_directory('demo_nodes_cpp'), 'launch/topics/talker_listener.launch.py')) ) # include another launch file in the chatter_ns namespace launch_include_with_namespace = GroupAction( actions=[ # push-ros-namespace to set namespace of included nodes PushRosNamespace(LaunchConfiguration('chatter_ns')), IncludeLaunchDescription( PythonLaunchDescriptionSource( os.path.join( get_package_share_directory('demo_nodes_cpp'), 'launch/topics/talker_listener.launch.py')) ), ] ) # start a turtlesim_node in the turtlesim1 namespace turtlesim_node = Node( package='turtlesim', namespace='turtlesim1', executable='turtlesim_node', name='sim' ) # start another turtlesim_node in the turtlesim2 namespace # and use args to set parameters turtlesim_node_with_parameters = Node( package='turtlesim', namespace='turtlesim2', executable='turtlesim_node', name='sim', parameters=[{ "background_r": LaunchConfiguration('background_r'), "background_g": LaunchConfiguration('background_g'), "background_b": LaunchConfiguration('background_b'), }] ) # perform remap so both turtles listen to the same command topic forward_turtlesim_commands_to_second_turtlesim_node = Node( package='turtlesim', executable='mimic', name='mimic', remappings=[ ('/input/pose', '/turtlesim1/turtle1/pose'), ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'), ] ) return LaunchDescription([ background_r_launch_arg, background_g_launch_arg, background_b_launch_arg, chatter_ns_launch_arg, launch_include, launch_include_with_namespace, turtlesim_node, turtlesim_node_with_parameters, forward_turtlesim_commands_to_second_turtlesim_node, ])
This is written in python. Finally, the LaunchDescription information is returned, which is equivalent to the content in the tag in xml
<!-- example.launch.xml --> <launch> <!-- args that can be set from the command line or a default will be used --> <arg name="background_r" default="0"/> <arg name="background_g" default="255"/> <arg name="background_b" default="0"/> <arg name="chatter_ns" default="my/chatter/ns"/> <!-- include another launch file --> <include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener.launch.py"/> <!-- include another launch file in the chatter_ns namespace--> <group> <!-- push-ros-namespace to set namespace of included nodes --> <push-ros-namespace namespace="$(var chatter_ns)"/> <include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener.launch.py"/> </group> <!-- start a turtlesim_node in the turtlesim1 namespace --> <node pkg="turtlesim" exec="turtlesim_node" name="sim" namespace="turtlesim1"/> <!-- start another turtlesim_node in the turtlesim2 namespace and use args to set parameters --> <node pkg="turtlesim" exec="turtlesim_node" name="sim" namespace="turtlesim2"> <param name="background_r" value="$(var background_r)"/> <param name="background_g" value="$(var background_g)"/> <param name="background_b" value="$(var background_b)"/> </node> <!-- perform remap so both turtles listen to the same command topic --> <node pkg="turtlesim" exec="mimic" name="mimic"> <remap from="/input/pose" to="/turtlesim1/turtle1/pose"/> <remap from="/output/cmd_vel" to="/turtlesim2/turtle1/cmd_vel"/> </node> </launch>
yaml is also easy to write.
# example.launch.yaml launch: # args that can be set from the command line or a default will be used - arg: name: "background_r" default: "0" - arg: name: "background_g" default: "255" - arg: name: "background_b" default: "0" - arg: name: "chatter_ns" default: "my/chatter/ns" # include another launch file - include: file: "$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener.launch.py" # include another launch file in the chatter_ns namespace - group: - push-ros-namespace: namespace: "$(var chatter_ns)" - include: file: "$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener.launch.py" # start a turtlesim_node in the turtlesim1 namespace - node: pkg: "turtlesim" exec: "turtlesim_node" name: "sim" namespace: "turtlesim1" # start another turtlesim_node in the turtlesim2 namespace and use args to set parameters - node: pkg: "turtlesim" exec: "turtlesim_node" name: "sim" namespace: "turtlesim2" param: - name: "background_r" value: "$(var background_r)" - name: "background_g" value: "$(var background_g)" - name: "background_b" value: "$(var background_b)" # perform remap so both turtles listen to the same command topic - node: pkg: "turtlesim" exec: "mimic" name: "mimic" remap: - from: "/input/pose" to: "/turtlesim1/turtle1/pose" - from: "/output/cmd_vel" to: "/turtlesim2/turtle1/cmd_vel"
Question 5: how to pass parameters when ros2 launch?
We notice that the launch file above contains args, such as background_r. When the command line is started, the data can be transmitted through the form of key:=value. For example:
ros2 launch <package_name> <launch_file_name> background_r:=255
Question 6: what does remap do?
remap is a very useful technique, which is generally used for Topic mapping.
In fact, it is to transfer flowers and trees, or to deceive the world.
<remap from="/different_topic" to="/needed_topic"/>
Convert the topic in from to the topic specified by to
There are 2 uses:
- Map the topic originally published by a node to another name
- Map the original topic published by other node s to the required topic
The example of the official ROS2 tutorial has the following code
Node( package='turtlesim', executable='mimic', name='mimic', remappings=[ ('/input/pose', '/turtlesim1/turtle1/pose'), ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'), ] )
practice
The official tutorial has very detailed guidelines. Here is a brief overview.
1. Create a launch file
turtlesim_mimic_launch.py
from launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): return LaunchDescription([ Node( package='turtlesim', namespace='turtlesim1', executable='turtlesim_node', name='sim' ), Node( package='turtlesim', namespace='turtlesim2', executable='turtlesim_node', name='sim' ), Node( package='turtlesim', executable='mimic', name='mimic', remappings=[ ('/input/pose', '/turtlesim1/turtle1/pose'), ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'), ] ) ])
2. Start
ros2 launch turtlesim_mimic_launch.py
You will see two turtle interfaces.

3. Commissioning
Send orders to make the tortoise move
Open a new terminal and click the following command.
ros2 topic pub -r 1 /turtlesim1/turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -1.8}}"
After careful observation, we can see that / turnlesim1 / turnle1 / CMD is sent_ Vel is the Topic, but the two turtles move. This is because we do the remap action in the mimic node, which is equivalent to the transparent transmission of messages.
We can use rqt_graph for more details.
Open a new terminal and enter rqt_graph.

The relationship between them is clear at a glance.