ROS2 XML Launch File Example

In this tutorial I will show you how to write, install and run a ROS2 XML launch file.

Whenever you start to have multiple nodes (with parameters, arguments, …) in your application, creating a launch file becomes an almost mandatory step to be able to scale and go beyond 2-3 nodes without creating a huge mess.

And in ROS2, you have the choice: you can create a launch file in Python, XML, and even YAML. The default was first Python, but XML is coming back strongly (XML was the default in ROS1). I’ll compare XML and Python for launch files quickly in this tutorial.

>> Watch this video as an additional resource to this article:

After watching the video, subscribe to the Robotics Back-End Youtube channel so you don’t miss the next tutorials!


You want to learn ROS2 efficiently?

Check out ROS2 For Beginners and learn ROS2 step by step, in 1 week.


Setup – Create a package for your launch files

You could theoretically create a launch file in any package you want (ex: an existing C++ or Python package), but that’s not recommended. You’d have nodes, param files, and launch files all in one place. And it will quickly become a mess, with unecessary dependencies between packages that are not related.

So, what we’ll do here is to create a package dedicated to launch files – and where you can also add some param/config files, but no nodes.

Let’s create a package and an empty XML launch file.

cd ~/ros2_ws/src
ros2 pkg create my_robot_bringup
cd my_robot_bringup/
rm -rf include/
rm -rf src/
mkdir launch
touch launch/demo.launch.xml

Go to your ROS2 workspace (in the src/ folder), and create a new package with no build type.

To follow a quite common convention, we’ll name the package “my_robot_bringup”. If your robot name is “abc”, then you’ll name the package “abc_bringup”.

With no built type, the package will have the structure of a C++ package. We’ll remove the include/ and src/ folder, and add a launch/ folder instead.

Finally, in the launch/ folder, we create a launch file. For XML, make sure to have the “.launch.xml” extension.

Write a minimal ROS2 XML launch file

The XML launch file

For this example we will do a very simple application. We will just launch 2 nodes from the official demo packages. And as you will see, it will be super, super simple.

<launch>
    <node pkg="demo_nodes_cpp" exec="talker"/>
    <node pkg="demo_nodes_py" exec="listener"/>
</launch>

First, you need to create a “launch” tag in which you’ll write the entire launch instructions.

Then, to start a node, just add a “node” tag with at least 2 arguments:

  • pkg: the package of the node you want to start.
  • exec: the name of the executable that was created during compilation.

And that’s it! With just 4 lines of code and a very straightforward syntax you have a basic launch file.

XML vs Python launch files

Here is the same launch file written in Python.

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    ld = LaunchDescription()

    talker_node = Node(
        package="demo_nodes_cpp",
        executable="talker",
    )

    listener_node = Node(
        package="demo_nodes_py",
        executable="listener"
    )

    ld.add_action(talker_node)
    ld.add_action(listener_node)

    return ld

Way more complex, for the exact same thing. And wait until you want to start multiple nodes with arguments, parameters, other launch files, etc.

Now, there are some cases when using Python for launch files might be necessary, as XML launch files are a bit more limited – but from personal experience, 95% of the time you’ll be fine with XML.

Also, as a more personal opinion, I first thought that Python launch files would be a great idea, as you could add some real programming logic into it. But then (theory vs practice), I realized that I didn’t see any programming logic anywhere, and it was just another (more complex and difficult) way to write a description, which is basically why XML exists in the first place.

I could go on and on with this, but 1. I’m not going to write a book, and 2. we are starting to get off topic. As you can see I’m heavily biased towards using XML for ROS2 launch files, but feel free to use whatever you prefer!

Install the ROS2 XML launch file

Add dependencies to other packages

As we are launching some nodes from other packages – here “demo_nodes_cpp” and “demo_nodes_py”, we need to specify those dependencies in the package where we have our launch file.

Open the package.xml and add those 2 lines.

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>my_robot_bringup</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="ed@todo.todo">ed</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <exec_depend>demo_nodes_cpp</exec_depend>
  <exec_depend>demo_nodes_py</exec_depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

Then, for every new package that you use in a launch file, make sure to add a new line with “exec_depend”.

Installation instructions

To tell colcon (the build tool for ROS2) to install the launch files, we need to add a few lines in the CMakeLists.txt file.

Here is the file (a bit cleaned up), with the extra lines to install the launch files correctly.

cmake_minimum_required(VERSION 3.8)
project(my_robot_bringup)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)

install(DIRECTORY
  launch
  DESTINATION share/${PROJECT_NAME}/
)

ament_package()

You just need to do this once, then no need to add anything for other launch files that you add in this package.

Build your ROS2 XML launch file

Let’s now build the package so that the launch files can be installed correctly.

Go into your ROS2 workspace (not in the src/ folder!) and build with colcon.

~/ros2_ws$ colcon build --packages-select my_robot_bringup 
Starting >>> my_robot_bringup
Finished <<< my_robot_bringup [1.00s]                  

Summary: 1 package finished [1.26s]

Start the launch file

Now that the launch file is installed, let’s launch it!

First things first, make sure you have sourced your ROS2 workspace, otherwise the ros2 launch command won’t find the launch file.

source ~/ros2_ws/install/setup.bash #just modify with the path to your actual workspace

Then let’s start the launch file.

$ ros2 launch my_robot_bringup demo.launch.xml 
[INFO] [launch]: All log files can be found below /home/ed/.ros/log/2023-05-04-13-22-52-227020-ed-vm-3935
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [talker-1]: process started with pid [3936]
[INFO] [listener-2]: process started with pid [3938]
[talker-1] [INFO] [1683199373.896389433] [talker]: Publishing: 'Hello World: 1'
[listener-2] [INFO] [1683199373.908972110] [listener]: I heard: [Hello World: 1]
^C[WARNING] [launch]: user interrupted with ctrl-c (SIGINT)

Great, with just one command you have started 2 nodes!

As you can see, each executable will be started as a process. You can see the PID for each process. Also they will be given a name with a number, for example “talker-1” and “listener-2”. Note: the node name (!= executable name) is the one defined in the node itself, so here “talker” and “listener”.

All the logs will be printed here, and if you want to stop everything that’s been started with the launch file, you can press CTRL + C.

Customize your nodes in your ROS2 XML launch file

We have started 2 basic nodes, but what if you want to customize the nodes a bit? In this section you will see that it’s quite easy with an XML launch file.

Note: if you modify the launch file, make sure you then build again and source the environment before you start the launch file.

Node renaming

If you want to rename a node, you can simply add a “name” argument in the “node” tag.

<launch>
    <node pkg="demo_nodes_cpp" exec="talker" name="my_talker"/>
    <node pkg="demo_nodes_py" exec="listener" name="my_listener"/>
</launch>

Topic/service remapping

To rename a topic or a service, you need to first open and close the “node” tag. In the tag, add a “remap” tag. Then it’s super easy, you have to fill a “from” argument, which is the topic/service you want to remap, and a “to” argument, which is going to be the new name.

<launch>
    <node pkg="demo_nodes_cpp" exec="talker" name="my_talker">
        <remap from="/chatter" to="/my_chatter" />
    </node>
    <node pkg="demo_nodes_py" exec="listener" name="my_listener">
        <remap from="/chatter" to="/my_chatter" />
    </node>
</launch>

In this example, as I remapped the “/chatter” topic to “/my_chatter”, I made sure to remap the topic in both nodes, so they can still communicate between each other.

Parameters

Let’s also see how to provide some parameters to a node through an XML launch file. As your nodes grow, you’ll want to make them more dynamic and thus, add some parameters.

To set a parameter’s value from the launch file, simply add a “param” tag inside the “node” tag. Then, you’ll have to provide the “name” of the param, and the “value”. The type will be automatically set at run time.

<launch>
    <node pkg="turtlesim" exec="turtlesim_node">
        <param name="background_r" value="200" />
        <param name="background_g" value="200" />
        <param name="background_b" value="200" />
    </node>
</launch>

In this example I’ve used the Turtlesim node from the turtlesim package. If you don’t have the turtlesim package installed: sudo apt install ros-<distro>-turtlesim.

Note: as we use yet a different package inside the launch file, you’ll have to add it to your package.xml: <exec_depend>turtlesim</exec_depend>.

Conclusion

Launch files are a very important concept in ROS2. They will allow you to make your application much more scalable.

One thing to consider when creating a launch file is, which language to use (Python, XML, YAML). As I already wrote previously, Python is usually way more complicated and longer to write than XML. So, if it can be done with XML, I would choose XML any time.

You could also consider YAML if you prefer this instead of XML. The complexity is the same, here it’s just a matter of preference.

But one good news: you can include other launch files in your launch file, even if it’s not written in the same language! This way, you can use mainly XML (or YAML), and only use Python if you really need to. Then, in your XML launch file, you can include the Python launch file.

More resources:

Want to learn how to program with ROS2?

Don't miss this opportunity:

ROS2 For Beginners - Step by Step Course


[NEW] ROS 2 Book


Or, learn with a video course