Names and Launch Files
Table of Contents
1 ROS Name Concepts
Every item in the ROS Computation Graph must have a unique name referred to as the Graph Resource Name. This includes things like nodes, parameters, topics, and services. The names are defined in a hierarchical structure that allows one to build up a very complex ROS system by re-using many common pieces of code.
Imagine you were working with a network of swarm robots where each individual robot has a Linux computer running ROS. Ideally every robot would run the exact same code for navigation, control, communication, etc. Names would enable this coordination by ensuring that even though every robot is running identical code, there would be no confusion about which robot was publishing which topics, which robot is offering services, what coordinate frames are associated with each robot, etc.
Understanding the Name concepts below is central to working with ROS for any nontrivial system. Further, many packages that exist that you will find yourself wanting to use require understanding how to manipulate names to even be able to use the package's functionality
The Names documentation and the Remapping documentation on the ROS Wiki are both very good, and should be considered essential reading.
1.1 Name resolution and namespaces
Every resource on the ROS Computation Graph has a unique name, and each name
is defined within a namespace. This is how ROS provides encapsulation.
Imagine you have a publisher pub_node_a
and a subscriber sub_node_a
that
must be in communication with each other via topic_a
. Now imagine that, as
in the example above, we want to start up a second instance each of these
nodes i.e. we would like a second copy of both pub_node_a
and sub_node_a
communicating on topic_a
, but we don't want these second instances to cause
ambiguity with the initial instances. ROS naming concepts are how we can
intelligently address this issue.
One solution to the above problem would be to manually create two copies of the source code for each of the nodes and change the names to avoid the ambiguity. This clearly isn't a very good option because we would always have to keep both copies of the code synchronized. Additionally, this is not at all extensible. What if we now wanted 20 copies of the nodes?
Another option would be to write the nodes such that they accept arguments that would define the names of the nodes and topics. This is somewhat extensible, and it avoids having multiple copies of the source code, but it is a lot of work. Additionally, if the requirements of the nodes change after their initial development, then switching these arguments may be very annoying.
ROS already provides a great way of handling a scenario like
this. We can simply run the pairs of linked nodes in different namespaces and
use relative naming when creating publishers and subscribers. When we
create the topic_a
publisher inside of pub_node_a
we specifically use the
name topic_a
instead of /topic_a
. This sets the publisher to use relative
naming (the preceding /
indicates the global namespace). Similarly when
we create the subscriber inside of sub_node_a
we should specifically
subscribe to topic_a
not /topic_a
. Then if we set the first pair of
pub/sub to run inside of /namespace_1
and the second pair to run inside of
/namespace_2
we will automatically avoid any ambiguity. In this scenario,
we would have the following name resolution scenario:
Namespace | Node | Resolved Node Name | Publisher/Subscriber Name | Resolved Pub/Sub Name |
---|---|---|---|---|
namespace_1 |
pub_node_a |
/namespace_1/pub_node_a |
topic_a (publisher) |
/namespace_1/topic_a |
namespace_1 |
sub_node_a |
/namespace_1/sub_node_a |
topic_a (subscriber) |
/namespace_1/topic_a |
namespace_2 |
pub_node_a |
/namespace_2/pub_node_a |
topic_a (publisher) |
/namespace_2/topic_a |
namespace_2 |
sub_node_a |
/namespace_2/sub_node_a |
topic_a (subscriber) |
/namespace_2/topic_a |
More about name resolution and namespaces can be read here: http://wiki.ros.org/Names#Resolving
1.2 Valid names
When defining Names, there are several restrictions on what can be considered a valid name.
- The first character must either be a letter ([a-z|A-Z]), a tilde (
~
), or a forward slash/
. A letter indicates you are using either relative naming or a base name. A~
indicates you are using a private name reference. A/
indicates you are using a global name. - Subsequent characters can be alphanumeric ([a-z|A-Z|0-9]), underscores
(
_
), or slashes (/
)
Never start names with anything other than a letter unless you really mean to do so. I try to avoid using capital letters in my names to stick with common conventions.
Note that when remapping (discussed below) things on the command line the ~
for the
first character should instead be an underscore _
.
1.2.1 Base, relative, global, and private names
The ROS wiki has an excellent section on the difference between base, relative, global, and private names. This section should be read and understood before proceeding. Since I feel that the ROS wiki does a great job of explaining the four different types of names, I thought rather than trying to re-explain I would instead try to provide context and rules-of-thumb on when you might use each of these types of names.
- Base Name
- Realistically, this will almost always be the right choice
when referring to topics and services. By not explicitly
including the leading
/
we are ultimately supporting flexibility. We can change a node's namespace and the name resolution will still find the correct topics. This was used in the example above. - Relative Name
- The most common application of this comes when you have
nested or hierarchical namespaces. If you have one namespace
child
within another namespaceparent
then you can refer to topics or services in thechild
namespace from nodes within the parent namespace using a relative name (e.g.child/topic_name
). This will continue to work even if you change the namespace thatparent
is in. - Global Name
- Basically, you only want to be using this type of name you
are very explicitly referring to a topic, service, or
parameter that will always have the same name and namespace.
A common example of this is if you have many nodes running in
different namespaces and you want all of these nodes to listen
to the same topic in the global namespace. So let's say you
have a bunch of robots running identical sets of nodes, but
the nodes for each robot are running in different namespaces.
Then in the global namespace you have a topic named
/operating_status
that is used to indicate to all of the robots what the status of the complete system is. For example, let's say the/operating_status
topic is astd_msgs/String
with only 2 possible values'IDLE'
or'RUNNING'
. Then if all of the robots subscribe to this/operating_status
topic they will all agree on what the state of the system is. You could architect the nodes such that a robot stops running if it ever hears that the status is'IDLE'
. Then to change the status for all robots you would only have to publish a single message on the/operating_status
topic and all robots would stop running. Note, this is just an example, and likely not a great way to architect any sort of safety-critical stopping mechanism. - Private Name
- Very commonly in ROS, we use ROS parameters rather than
command line arguments to control how a node behaves. That
way the parameters are known in the ROS world and we can read
and log their values automatically. One of the most common
ways to use parameters specific to a node is via private
names. When using a
~
character at the beginning of a string referencing a name, the tilde will automatically be expanded to be the fully qualified name of the node using the string. So we can set parameters in a node's private namespace, and the node can read the parameters using its private namespace, and this would continue working even if we renamed the node or changed the node's namespace. The private namespaces also help remind people using your package that, likely, the parameters in a node's private namespace are specific to that node. Note that using private names doesn't actually provide any privacy – any node could read any other node's private parameters by using relative or global names.
1.3 Name remapping
Any graph resource name that is defined in source code can be switched to a
different name at runtime. This is referred to as "remapping". Both rosrun
and roslaunch
have mechanisms for remapping. This is one of the most common
ways that you can adapt a package written by someone else to work with your
system without ever editing their source code.
If you are interested in remapping something within a launch file, check out the roslaunch XML remap tag documentation.
If you want to remap topics at the command line using rosrun
, you should
read about rosrun
Remapping Arguments. Note that this technique can also be
used to set private parameters for a node.
2 roslaunch and Launch File Overview
- Remember
roslaunch
is a tool for easily doing many tasks with a single command- Start many nodes
- Start nodes on other ROS machines
- Respawn processes that may have automatically died
- Set parameters
- Parse command line arguments
- Automatically start ROS master
- Include other launch files
- A launch file is nothing more than an xml file with a special schema
- Typically launch files have a .launch extension and they are located within a launch/ subdirectory of a package
The command line tool
roslaunch
can be executed in one of 2 ways:# The following works regardless of your current working directory, as # long as the package containing the launch file that you are trying to # run is in an active workspace. roslaunch package_name filename.launch [arg_name:=value...] # In the following, you must provide the path to the launch file that # you are trying to launch roslaunch path_to_launch/filename.launch [arg_name:=value...]
- You can always type
roslaunch --help
to see all of the options - Properly using launch files is one of the best things you can do when developing complex ROS system
2.1 Important concepts in roslaunch
- Lines of the XML file are evaluated sequentially
- Evaluation order
- Last setting wins
- Substitution arguments
- There are several supported arguments that
roslaunch
will automatically resolve prior to launching nodes - They are all enclosed in
$()
- Currently supported args are as follows:
$(env ENVIRONMENT_VARIABLE)
replace the value with a value from an environment variable; roslaunch fails is variable is not set$(optenv ENVIRONMENT_VARIABLE default)
same as above, but it uses default if variable is not set. If default is not provided, it falls back to an empty string$(find pkg)
Replace with the path to pkg. This is used for portability of launch files.$(anon name)
automatically generate an anonymous id based on name$(arg foo)
replaced with the value specified by an <arg> tag. This is how you provide arguments to launch files.
- There are several supported arguments that
- if and unless attributes
- All tags support these attributes.
- Tags with if are only evaluated if the value provided with if is true
- Tags with unless are not evaluated if the value provided with unless is true
Example:
<group if="$(arg foo)"> <!-- stuff that will only be evaluated if foo is true --> </group> <param name="foo" value="bar" unless="$(arg foo)" />
2.2 roslaunch XML specification
- The reference for roslaunch XML tags is here: http://wiki.ros.org/roslaunch/XML#Tag_Reference
- Below you will find a brief description of each tag
- <launch>
- This is the root element of every launch file. Every launch file must have one. Its only purpose is to act as a container for all of the other elements.
- <node>
- This is how you launch a node. You are required to provide the pkg, type, and name attributes. The most important optional attributes are respawn, required, output, and launch-prefix. There are others that may be useful.
- <machine>
- This is used for defining a remote machine that may run ROS nodes. You need to define a machine if you want to start ROS nodes on a remote machine.
- <include>
- This is how you import other roslaunch files.
- <remap>
- This is the nice way of remapping arguments within roslaunch. Read about remapping arguments on the wiki.
- <env>
- This allows you to set environment variables for use in nodes that are started after the creation of the <env> element
- <param>
- Defines a parameter to be set on the parameter server. You can either specify the parameter directly, or load a parameter from a file.
- <rosparam>
- Can load, delete, or dump sets of parameters from/into YAML files.
- <group>
- This setting makes it easy to apply settings to groups of nodes.
- <test>
- Basically the same as the <node> tag, except it is used for running rostest nodes
- <arg>
- This is how you specify arguments that can be passed to your launch file from the command line
2.3 Helpful roslaunch
commands
At the command line, the roslaunch
tool has a variety of arguments that can
be used for helping you inspect and understand launch files. As mentioned
earlier, typing roslaunch --help
is an easy way to see all of the possible
arguments to roslaunch
. However, in this section, I wanted to provide a few
commands that I use regularly when trying to understand launch files.
I'm going to use the trep_puppet_demo package (that we've already seen), and
the moveit_robots package. We'll focus on the puppet_sim.launch and the
demo_baxter.launch files to illustrate a few of these commands. If you'd like
to follow along, be sure that you've cloned these packages into a workspace's
src/
directory, and that you've sourced the workspaces setup.bash
file.
- Displaying nodes
You can see all of the nodes that a launch file will start with the
--nodes
argument.jarvis@vedauwoo:~⟫ roslaunch trep_puppet_demo puppet_sim.launch --nodes /robot_state_publisher /puppet_simulator /marker_controls /keyboard_interface
The behavior of this command is dependent on the arguments that are passed to the launch file:
jarvis@vedauwoo:~⟫ roslaunch trep_puppet_demo puppet_sim.launch vis:=true --nodes /robot_state_publisher /puppet_simulator /marker_controls /keyboard_interface /rviz # note that rviz is added because I set 'vis:=true'
- Displaying run command for a node
You can see the exact command that will be used to start a node with the
--args
switch. This is useful for verifying that your substitution arguments are being handled correctly, verifying that the right version of a node is found, and checking that the right arguments are being passed to your node (via theargs
attribute of the<node>
tag).jarvis@vedauwoo:~⟫ roslaunch trep_puppet_demo puppet_sim.launch vis:=true --args /rviz /opt/ros/indigo/lib/rviz/rviz -d /home/jarvis/demo_ws/src/trep_puppet_demo/launch/puppet_sim_view.rviz __name:=rviz
- Displaying arguments to launch file
It is not uncommon for a launch file to have many arguments that will be expanded via the
$(arg)
substitution argument to control how the launch file behaves. We can view all of the arguments and the values of theirdoc
attribute with the--ros-args
command. Note that this feature was added in ROS Indigo so it won't work on older ROS versions.jarvis@vedauwoo:~⟫ roslaunch trep_puppet_demo puppet_sim.launch vis:=true --ros-args Optional Arguments: legs (default "false"): if true, add controls for the puppet's knees shoulders (default "false"): if true, independently control each of the shoulders vis (default "false"): if true, we will start rviz
- Displaying included launch
Often a launch file will include many other launch files. Navigating all of these files can be complicated. The
--files
switch can be used to show all launch files that are included by a single launch file. In the following example, this isn't very interesting, but in a launch file like this one more than a dozen other launch files are eventually included.jarvis@vedauwoo:~⟫ roslaunch trep_puppet_demo puppet_sim.launch vis:=true --files /home/jarvis/demo_ws/src/trep_puppet_demo/launch/puppet_sim.launch # here's another example: jarvis@vedauwoo:~⟫ roslaunch baxter_moveit_config demo_baxter.launch --files /home/jarvis/demo_ws/src/moveit_robots/baxter/baxter_moveit_config/launch/moveit_rviz.launch /home/jarvis/demo_ws/src/moveit_robots/baxter/baxter_moveit_config/launch/move_group.launch /home/jarvis/demo_ws/src/moveit_robots/baxter/baxter_moveit_config/launch/baxter_moveit_sensor_manager.launch /home/jarvis/demo_ws/src/moveit_robots/baxter/baxter_moveit_config/launch/baxter_moveit_controller_manager.launch /home/jarvis/demo_ws/src/moveit_robots/baxter/baxter_moveit_config/launch/planning_pipeline.launch /home/jarvis/demo_ws/src/moveit_robots/baxter/baxter_moveit_config/launch/warehouse_settings.launch /home/jarvis/demo_ws/src/moveit_robots/baxter/baxter_moveit_config/launch/warehouse.launch /home/jarvis/demo_ws/src/moveit_robots/baxter/baxter_moveit_config/launch/planning_context.launch /home/jarvis/demo_ws/src/moveit_robots/baxter/baxter_moveit_config/launch/sensor_manager.launch /home/jarvis/demo_ws/src/moveit_robots/baxter/baxter_moveit_config/launch/demo_baxter.launch /home/jarvis/demo_ws/src/moveit_robots/baxter/baxter_moveit_config/launch/trajectory_execution.launch /home/jarvis/demo_ws/src/moveit_robots/baxter/baxter_moveit_config/launch/default_warehouse_db.launch /home/jarvis/demo_ws/src/moveit_robots/baxter/baxter_moveit_config/launch/ompl_planning_pipeline.launch
- Finding which launch file starts a node
In the case that a launch file includes many other launch files it can be difficult to tell exactly which launch file is responsible for starting a given node. We can find the answer to this question with the
--find
switch.jarvis@vedauwoo:~⟫ roslaunch trep_puppet_demo puppet_sim.launch vis:=true --find /rviz /home/jarvis/demo_ws/src/trep_puppet_demo/launch/puppet_sim.launch jarvis@vedauwoo:~⟫ roslaunch baxter_moveit_config demo_baxter.launch --find /move_group /home/jarvis/demo_ws/src/moveit_robots/baxter/baxter_moveit_config/launch/move_group.launch
2.4 Useful resources
- Main roslaunch wiki page
- roslaunch XML specification site
- roslaunch command line usage
- Tips for roslaunch usage in large projects
- How to launch nodes in GDB or Valgrind (also useful to see how to get a node to run in a separate terminal)
- XML Syntax rules
- rqt_launchtree This is a very powerful
rqt
plugin that is used for visualizing all launch files, parameters, arguments, and YAML files associated with a givenroslaunch
command. If you're faced with a new, complex launch file that you've never seen before, this can be a very good way to help begin to understand what's going on. - rqt_launch This is a tool for interactively launching individual parts of launch files. I personally have not used this much, but I know many people do like to use it.
3 Examples
For all of the examples in this section, we will be using a special node
developed to illustrate concepts with remapping and launch files. This node is
part of a package named ros_names_and_remapping and the primary node is a node
called fake_robot.py. This node has one Subscriber that uses controls
as its
topic of type geometry_msgs/Twist
, one Publisher that uses range
of type
std_msgs/UInt8
, and one service named ros_introspection
of type
std_srvs/Empty
. When this service is called, a callback is triggered that
prints out a variety of information related to names and remappings. Each
section will describe several commands to run, and then you should call this
service to see how the output changes. This service can be called with
rosservice call /ros_introspection
3.1 Remapping topics with rosrun
First run the node using the standard command:
rosrun ros_names_and_remapping fake_robot.py
Running rostopic list
:
jarvis@vedauwoo:~⟫ rostopic list /controls /range /rosout /rosout_agg
Now we will remap each of the topics.
rosrun ros_names_and_remapping fake_robot.py controls:=new_controls range:=sensor_output
Now running rostopic list
:
jarvis@vedauwoo:~⟫ rostopic list /new_controls /rosout /rosout_agg /sensor_output
You should compare the output of the introspection service with both versions
of the rosrun
command.
3.2 Setting private parameters with rosrun
rosrun
can be used to set private parameters. The example node looks for a
private parameter ~timestep
to tell it how often to publish on the range
topic. It has a default value of 0.1 seconds. We can set this at runtime:
jarvis@vedauwoo:~⟫ rosrun ros_names_and_remapping fake_robot.py _timestep:=0.2 timestep = 0.2 robot name = DEFAULT_ROBOT
Note that we can't directly set a non-private parameter at runtime:
jarvis@vedauwoo:~⟫ rosrun ros_names_and_remapping fake_robot.py _timestep:=0.2 robot_name:=test timestep = 0.2 robot name = DEFAULT_ROBOT
If you check out the output of the introspection service in the second
example, you'll see that the robot_name
argument is interpreted as a topic
remapping argument.
3.3 Setting parameters at the command line
While rosrun
can't set non-private parameters, we can still set private
parameters from the command line:
jarvis@vedauwoo:~⟫ rosparam set /robot_name "test"
jarvis@vedauwoo:~⟫ rosrun ros_names_and_remapping fake_robot.py
timestep = 0.2
robot name = test
3.4 Special rosrun
keys
As described on the Remapping Arguments ROS wiki page, there are several
special keys that we can use to override ROS environment variables and calls
to rospy.init_node
. These are not used often, but it is good to know that
you can have control over these settings at the command line. Try running the
following and inspect how the introspection service output is modified:
rosrun ros_names_and_remapping fake_robot.py __name:=new_name
3.5 ROS environment variables and remapping
We can control the namespace of a node when using rosrun
by setting the
ROS_NAMESPACE
environment variable.
jarvis@vedauwoo:~⟫ export ROS_NAMESPACE=robot1
jarvis@vedauwoo:~⟫ rosrun ros_names_and_remapping fake_robot.py
timestep = 0.1
robot name = DEFAULT_ROBOT
jarvis@vedauwoo:~⟫ rostopic list
/robot1/controls
/robot1/range
/rosout
/rosout_agg
jarvis@vedauwoo:~⟫ rosservice list
/robot1/fake_robot/get_loggers
/robot1/fake_robot/set_logger_level
/robot1/ros_introspection
/rosout/get_loggers
/rosout/set_logger_level
Notice that both the topics and services have been pushed into the robot1
namespace. Now if you want to call the introspection service, you'd need to
modify the command to be rosservice call /robot1/ros_introspection
because
the service name has been changed.
3.6 Launch file examples
The ros_names_and_remapping
package has a series of launch files. These
launch files illustrate concepts such as launch file arguments, launch file
includes, remapping, and more. Below is a summary of each launch file and a
link to the source code. You should study the launch files to ensure you
understand all of the concepts, and you should run each launch file and use
tools such as rosnode
, roslist
, and the introspection service to make
sure you understand what is happening in each case.
- single_node.launch
- This is the simplest launch file. It just starts a
single instance of the
fake_robot.py
node. - single_node_with_params.launch
- This builds upon the previous launch file
by setting both the global and private parameter that the
fake_robot.py
node looks at. - single_node_with_params_and_args.launch
- This launch file additionally adds launch file arguments that allow you to set the values for parameters at the command line when launching the files.
- multiple_nodes.launch
- This launch file shows how to use two separate
namespaces to start two separate instances of the
fake_robot.py
node and ensure that their topics, services, and parameters don't interfere with each other. - multiple_with_include.launch
- This starts three instances of the
fake_robot.py
node by including three copies of thesingle_node_with_params_and_args.launch
file inside of three different namespaces. This also illustrates how arguments can be passed from one launch file into an included launch file. - multiple_remapping.launch
- This launch file starts three instances of the
fake_robot.py
node, and three instances of theturtle_teleop_key
node from the turtlesim package. All topics and services are manually remapped.