Launchfiles
Launchfiles and ROS
- ROS programs consist of many nodes communicating over topics and services
- For non-trivial programs, manually running nodes using
ros2 run
becomes tedious and hard to reproduce - Launchfiles provide a method for having a single command start the robot and enable specifying
- Which nodes are run
- What parameters they use
- What topics are named
- and more!
- These Launchfile Tutorials will help get you started.
Documentation Note
- As of 10/2024 the API Documentation for launch files is not fully populated: this means links here point to empty documentation
- To build complete documentation locally:
- Clone https://github.com/ros2/launch
- Run
rosdoc2 build --package-path launch/launch
- Open
doc_output/launch/index.html
in your browser
Types of Launchfiles
In ROS 2 (unlike ROS 1) there are multiple types of launchfiles:
- Python launchfiles: these launchfiles are python scripts that use the ROS 2 Launch API to declare what actions should be taken on Launch
- These launchfiles allow more complex launch descriptions than the alternatives
- XML launchfiles: these are closer to ROS 1 launchfiles and they declare the nodes that should be running
- Less flexible than python but easier for simple cases. However, in ROS 1 launchfiles often got complicated to the point of basically being programming without a real programming language. In these situations python launchfiles would be preferred.
- YAML launchfiles: An alternative syntax to XML launchfiles
Using ros2 launch
- The command-line tool for using launch files is ros2 launch
- There are two ways of invoking a launchfile:
ros2 launch package file.launch.{xml,py} [arg_name:=value]...
- Here, the launch file must be installed into the install space (e.g., by setting up
setup.py
)
- Here, the launch file must be installed into the install space (e.g., by setting up
ros2 launch package /path/to/launch/file.launch [arg_name:=value...]
- Here, the launch file at the given location is directly used.
- The main advantage is that you do not need to rebuild the workspace when you change the launchfile.
- You can pass arguments to a launch file using the
arg_name:=value
syntax, which is shared with the remapping arguments syntax.
Ros2 launch options
- Use
ros2 launch --help
for a complete list of the options. -s
or--show-arg
You can pass arguments to a launchfile (usingarg_name:=value
) to change the behavior of the launchfile. This flag shows all the possible arguments and their documentation.--debug
shows debugging information, which is useful if the launchfile is not working.
XML Launchfiles
- The ROS 1 Launchfile format relies on XML, along with a special enhanced substitution argument syntax.
- Most easily understood in conjunction with ROS 2 Launchfile Migration Guide.
- The launchfile system in ROS 2 is highly extendable
- The basic launch functionality is implemented in the launch package. This repository contains generic tools for running processes on a system
- ROS specific functionality is implemented in the launch_ros package.
- For example, the
Node
launch action oflaunch_ros
uses theExecuteProcess
launch action oflaunch
.
- For example, the
- The architecture of ROS 2 Launchfiles explains the concepts behind the design.
- API Documentation contains XML examples for the python functions that have XML equivalents.
- This Design Document lays out the format of ROS 2 XML launchfiles
- Launchfiles should be installed by adding them to the
data_files
section ofsetup.py
.- Install the files to
share/package_name/launch
.
- Install the files to
- Projects that use launchfiles should add
ros2launch
as an<exec_depend>
inpackage.xml
(becauseros2 launch
is required to use them). - Launchfiles list nodes to be launched; however, the order in which they start is non-deterministic.
- Important Launchfile XML elements:
- <launch> - the root element, every launchfile starts with this.
- <node> - Used to run a node.
Attributes:
- pkg: the package the node is in.
- exec (type in ROS 1): the name of the node executable file.
- name: the basename of the node.
- namespace (ns in ROS 1): the node's namespace.
- output: determine where to send the output to (a log file or the screen).
- required: if the node dies, the whole launch is terminated.
- <include> - Lets you include a launchfile in another launchfile
- <remap> - Used for Remapping arguments
- <param> - Sets an individual parameter for a node (or on the parameter server in ROS 1).
- In ROS 2 the
"command"
attribute does not exist. To set a parameter to the output of a command use the$(command)
substitution.
- In ROS 2 the
- <group> - Groups nodes together and allows you to easily apply common settings
- To put all nodes within a
group
in the same namespace use the <push_ros_namespace namespace="ns"> tag
- To put all nodes within a
- <arg> - Used to specify arguments which can be used to change the behavior of the launchfile from the command-line.
- You should always provide documentation for Launchfile arguments using the
description
attribute (calleddoc
in ROS 1).
- You should always provide documentation for Launchfile arguments using the
- <let> - used to define a constant (ROS 2 only, handled by
<arg>
in ROS 1) - <env> - Used to set environment variables for the underlying node
- Conditionals:
- Conditional Attributes All elements have attributes
if
andunless
to be conditionally included.
- Conditional Attributes All elements have attributes
- Substitution arguments:
- The following items can be used within attribute values to perform a computation and expand into the result of that computation
- The general syntax uses
$()
(just like bash substitution arguments). - Within XML, a substitution argument would be used like
<tag attribute ="$()" />
. - A list of some possible substitution arguments is below:
$(env ENVIRONMENT_VARIABLE)
Expands into the value of the environment variable or is an error if that variable is not set.$(env ENVIRONMENT_VARIABLE default)
Expands into the value of an environment variable ordefault
if it is not set. (In ROS 1 this was$(optenv)
)$(find-pkg-share)$
expands to the location of a given package's share directory. Useful for finding configuration and data files associated with the package$(find-pkg-prefix)$
expands$(var myarg)
expands into the value ofmyarg
, as specified by an<arg>
element and passed in on the call toroslaunch
$(eval <expression>)
Runs python code<expression>
and expands to the result of the code evaluation- This does not yet behave exactly like the ROS 1 version:
<expression>
should be a single-quoted string- If the expression itself uses single-quotes, those need to be escaped (e.g., 'mystring' becomes \'mystring\')
- Some ROS 1 shortcuts for accessing launchfile arguments are not supported: instead the substitution must be used:
(e.g.,
$(var argname)
will literally transform into the value ofargname
- This does not yet behave exactly like the ROS 1 version:
$(command '<expression>')
runs a command and returns the output (ROS 2 only).
- Loading Parameters from a file:
In
<pkg>/config
, create a<myconfig>.yaml
file- Each key at the top level is the name of a node (or a wildcard pattern for a node name)
- The next subkey is
ros__parameters
(note the double_
) - Then the next keys are parameters and their values
node_name_here: ros__parameters: param1: value pram2: value
ros2 param load
can load these files- You must install the data by editing
setup.py
and adding it todata_files
insetup.py
3.In an xml launchfile use
<param from="$(find-pkg-share pkgname)/installed/path/to/configfile>
- You must install the data by editing
- More information on how ROS handles
.yaml
files can be found in the rcl_yaml_param_parser library
Python Launchfiles
General Concepts
- In ROS 2,
launch
was first implemented as a python API. Ultimately the XML and YAML launch files use this API. python
launchfiles are therefore the most feature-complete version of launch files- Overall, you should view python launch files as a template language for generating a description of what happens
when
ros2 launch <yourlaunchfile>
is executed.- Theoretically (though not in actuality) you can view the description that you write in a
python
launchfile as generating a file that contains instructions forros2 launch
- Theoretically (though not in actuality) you can view the description that you write in a
- Launchfile tutorials
- Read the Launch API Documentation to gain a better understanding of how launch files work and the details of their API.
- This documentation is for the
launch
package, which explains both the design and low-level launch API.
- This documentation is for the
- Comments in the Launch ROS source code is currently the best place to find API documentation for most of the ROS 2 Launch API calls you will actually use.
- The
launch
package contains generic launchfile components for working with processes - The
launch_ros
package contains ros-specific launchfile components.
Theory of Launchfiles
- Python launchfile programming is meant to be declarative rather than imperative.
- What this means is that generally you should be declaring what will be happening when
ros2 launch yourlaunchfile
is called rather than directly executing the commands
- What this means is that generally you should be declaring what will be happening when
- Launchfiles are based on an object-oriented design pattern called the Visitor Pattern
- Ultimately, a python launchfile returns a collection of objects (itself a LaunchDescription object) that describe what will happen during the launch
- A program (like
ros2 launch
) can iterate over the LaunchDescription and perform various tasks, for example:- Return a list of arguments that the launchfile accepts
- Return a list of nodes that the launchfile will run
- Actually run the nodes
- Any python code that is not inside the hierarchy of objects is imperative code that will execute immediately whenever
ros2 launch
loads the launchfile description.- This means that any actions taken are not tracked by the launch system and cannot be introspected or queried
- Overall it is best to do as much as possible in the declarative style, as this opens everything up to launchfile introspection methods and also is less prone to bugs, however there are some things that can only be done in python and others (when launchfiles get more complicated) that can only be done in python.
- See Which Should I Use python or xml or yaml?
Declarative Python Launchfiles
Here are some properties of purely declarative Python launchfiles. These launchfiles represent a subset of the potential functionality available in
python
but following these principles generally makes it easier to understand what a launchfile is doing (for experienced ROS users), enables the full power of ROS 2 introspection tools
to be used on the Launchfile, and makes the launchfile more similar and translatable to XML.
generate_launch_description
consists of a single return statement returning aLaunchDescription
object.- No variables are used.
- The only imports are to
launch
(and submodules)launch_ros
(and submodules) and other python packages that implement launch objects (e.g., Actions, Substitutions, etc).- In particular, importing and using functionality from
os
,yaml
, and other packages makes breaks declarative purity. - For example, you do not explicitly read a
yaml
file: instead you compute the path to the file using substitutions and pass that path to a Node action
- In particular, importing and using functionality from
- Substitution and Conditions are used rather than python control-flow (e.g.,
if
,while
) statements
There are cases where using imperative code makes a launchfile more clear: particularly if the goal is to provide generic functionality to multiple LaunchFiles. In many of these cases, such code could be converted into a custom Action or Substitution, which would then enhance the functionality of declarative launchfiles and also make that functionality available to XML and YAML launchfiles.
Description
launch.LaunchDescription
is the object that describes what LaunchActions should be taken when running the Launchfile- All python launchfiles have a
generate_launch_description()
function that returns alaunch.LaunchDescription
Object - The
LaunchDescription
object takes a list of LaunchActions that should be executed by the launchfile - The
launch.LaunchDescription
object is roughly equivalent to the<launch>
tag in anxml
launchfile
Actions
- When executing
ros2 launch
, all of the Actions listed in theLaunchDescription
object returned bygenerate_launch_description()
are executed- The launch_ros.actions.Node action causes a Node to run. Roughly corresponds to a
<node>
tag- When creating a
launch_ros.actions.Node
, parameters can be specified using theparameters
keyword argument - Equivalent to the
<node>
tag in XML.
- When creating a
- The launch.actions.DeclareLaunchArgument action causes the launchfile to look for an argument to be specified (optionally with a default value). Roughly corresponds to an
<arg>
tag- Equivalent to the
<arg>
tag in XML. - Always fill in the
description
to provide documentation for the argument
- Equivalent to the
- The launch.actions.IncludeLaunchDescription enables including one launchfile in another
- This action includes a launchfile as described by a launch.LaunchDescriptionSource object or a string
- Equivalent to the
<include>
tag in XML - There is also
IncludePythonLaunchDescription
. This is entirely unnecessary to use:IncludeLaunchDescription
will load anylaunchfile
regardless of type.
- The launch.actions.ExecuteProcess enables running a (non-node) process in the launchfile
- Equivalent to the
<executable>
tag in XML (ROS 2 only)
- Equivalent to the
- The launch.actions.RegisterEventHandler enables the launch file to respond to events (see Events)
- There are not methods for handling events in XML or YAML launchfiles.
- The launch.actions.EmitEvent enables the launch file to trigger an event
- There are not methods for emitting events in XML or YAML launchfiles.
- The launch_ros.actions.Node action causes a Node to run. Roughly corresponds to a
Substitutions
- Substitutions allow values that are computed during
ros2 launch
time to be used, inspected, and substituted when thelaunchfile
is running. - Remember, when declaring the launchfile several values are not yet known:
- Locations of package install directories.
- Output of commands that are run.
- The value of arguments specified by the user.
- Roughly, substitutions are similar in use to the
$()
syntax in XML launch files. - A few useful substitutions are:
- launch.substitutions.LaunchConfiguration accesses the value of a DeclareLaunchArgument. Roughly equivalent to
$(var Varname)
in xml - launch_ros.substitutions.FindPackageShare locates the packages
share/
directory in the install space. Roughly equivalent to$(find-pkg-share package)
in xml - launch_ros.substitutions.ExecutableInPackage locates an executable file within a package. Roughly equivalent to
$(exec-in-pkg package exec)
in xml - launch.substitutions.PathJoinSubstitution concatenates paths (accounting for differences between platforms)
- launch.substitutions.TextSubstitution wraps a string in the substitution system (see Why substitutions?)
- launch.substitutions.IfElseSubstitution conditionally expands to text depending on a condition.
- launch.substitutions.TextSubstitution wraps a string in the substitution system (see Why substitutions?)
- launch.substitutions.Command runs a command (e.g.,
xacro
) and substitutes in the output of the command. Roughly equivalent to$(command cmd)
in xml.
- launch.substitutions.LaunchConfiguration accesses the value of a DeclareLaunchArgument. Roughly equivalent to
- Substitutions can be concatenated by putting them all in a list (i.e., a list of substitutions is a substitution containing the concatenation of each element of the list)
Conditions
- Conditions allow branching during
ros2 launch
time - launch.conditions.IfCondition when passed as a
condition
keyword argument to certain actions (e.g., Node), the action will execute if the provided expression is True or 1 (roughly equivalent to theif=""
attribute) - launch.conditions.UnlessCondition when passed as a
condition
keyword argument to certain actions, the action will execute if the provided expression is False or 0 (roughly equivalent to theunless=""
attribute) - In ros2 rolling launch.substitutions.EqualsSubstitution allows testing conditions for equality by doing
IfCondition(EqualsSubstitution(LaunchConfiguration("config"), "comparison"))
- In humble or earlier, use the deprecated launch.conditions.LaunchConfigurationEquals instead of
IfCondition(EqualsSubstitution(LaunchConfiguration("config"), "comparison"))
- In humble or earlier, use the deprecated launch.conditions.LaunchConfigurationEquals instead of
Events
- Python Launchfiles provide access to certain events in the lifecycle of a node
- Launchfiles can respond to events (via the RegisterEventHandler action)
- Launchfiles can trigger events (via the EmitEvent action)
- The launch.events.Shutdown event is emitted when the launch system is terminated
- See the Event Handler Tutorial for details
- To have a node terminate the whole launchfile when it exits:
Set
on_exit
to theShutdown()
action.
Parameter Files
- Parameter files can be created using launch_ros.parameter_descriptions.ParameterFile
- These objects represent a yaml file and can be passed directly to the
parameters
keyword of thelaunch.action.Node
- Setting the keyword argument
allow_susbt
to true lets you use substitution rules in the.yaml
file.- For example
$(var launchvar)
will substitute the value of the variable in the launchfile
- For example
- These objects represent a yaml file and can be passed directly to the
Best Practices
Launchfile best practices in ROS 2 are still up in the air, the only "official" guidance I've found is here: Which Launch Format to Use?. So here are some opinions:
- Prefer XML launch files in most cases
- Closer to ROS 1 (so it will help you with ROS 1, which is still very much in use)
- More declarative (that is no changing state) so it is easier to see what is going on and harder to make mistakes
- Since ROS 2 Iron, we can do everything we do in this class with XML launchfiles
- Use python launch files either when
- Features are not yet in XML launch files (such as storing the value of a command in a parameter)
- You begin doing lots of logic substitutions and
if
attributes in XML and need more code-reuse and more complex actions
- In python launchfiles, stick to a declarative style unless what you are trying to accomplish would be impossible or significantly more cumbersome.
- Remember that python launchfiles can include XML launchfiles and vice versa
- Yaml launch files seem to be rare in practice. As far as I can tell it has no features that XML does not have, other than it's not XML (and yaml is typically used as an alternative to XML). It is mainly a syntactic stylistic preference between the two.
References
- ROS 2 Launchfile Tutorials
- Migrating from ROS1
- Contains useful information about ROS 2 Launchfiles that I have not found elsewhere.
- Launchfile XML Specification