\(\def\dt{\Delta t}\)
\(\newcommand{\transpose}[0]{^\mathrm{T}}\)
\(\newcommand{\half}[0]{\tfrac{1}{2}}\)
\(\newcommand{\Half}[0]{\frac{1}{2}}\)
\(\newcommand{\norm}[1]{\left\lVert#1\right\rVert}\)
\(\newcommand\given[1][]{\:#1\vert\:}\)
UP | HOME

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.

  1. 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.
  2. 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 namespace parent then you can refer to topics or services in the child 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 that parent 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 a std_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.
  • 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 the args 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 their doc 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

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 the single_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 the turtle_teleop_key node from the turtlesim package. All topics and services are manually remapped.
Creative Commons License
ME 495: Embedded Systems in Robotics by Jarvis Schultz is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.