Run, launch, and interrogate nodes

Requirements for this page:

TL;DR

Of course you did already read everything below, and the following TL;DR summary is just for convenience when you return to remind yourself of a small detail:

Use rosrun with 4 separate terminals:

# TERMINAL 1
roscore

# TERMINAL 2
rosrun my_robotics_pkg plain_cpp_node

# TERMINAL 3
rosrun my_robotics_pkg plain_py_node

# TERMINAL 4
rosnode list

Use roslaunch with 2 separate terminals:

# TERMINAL 1
roslaunch my_robotics_pkg plain.launch

# TERMINAL 2
rosnode list

Important

--help is your friend.

As for any command line tool, use the help display as the quickest reminder of usage: rosrun --help, roslaunch --help, rosnode --help

Important

The Tab key is also your friend. The tools rosrun, roslaunch, and rosnode all support tab completion. Save yourself some time and press Tab.

Contents for a “plain.launch” launch file:

<launch>

    <!-- EXAMPLE OF DEFINING AN INPUT ARGUMENT -->
    <arg name="alsopython" default="false" />

    <!-- START A GROUP WITH A NAMESPACE -->
    <group ns="mrp">
        <!-- LAUNCH A "Plain C++" NODE -->
        <node
            pkg    = "my_robotics_pkg"
            name   = "plain_cpp_node"
            output = "screen"
            type   = "plain_cpp_node"
        />

        <!-- USE THE INPUT ARGUMENT IN AN IF-STATEMENT  -->
        <group if="$(arg alsopython)">
            <!-- LAUNCH A "Plain Python" NODE -->
            <node
                pkg    = "my_robotics_pkg"
                name   = "plain_py_node"
                output = "screen"
                type   = "plain_py_node.py"
            />
        </group>
    </group>

</launch>

rosrun - run a single node

The syntax for using the rosrun command is:

rosrun <package> <executable>

where <package> is replaced by the name of your package, and <executable> is replaced by the name of the executable file (i.e., the node) that you want to run:

  • For C++: the executable is the name that you used in the add_executable line of the CMakeLists.txt (i.e., see Add the C++ node to the C Make List).

  • For Python: the executable is the name of the Python file including the extension.

Hence the commands to run the plain C++ and Python nodes are:

# RUN THE PLAIN C++ NODE
rosrun my_robotics_pkg plain_cpp_node

# RUN THE PLAIN PYTHON NODE
rosrun my_robotics_pkg plain_py_node.py

Important

rosrun can only start one node the terminal that you used cannot be used for anything else while the node is running.

Hence, to run multiple nodes at the same time, you need to open multiple terminals (or multiple ssh connections).

Important

rosrun can only start running a node if the ROS Master is already running, otherwise, you will get a message similar to the following will be displayed:

Unable to register with master node [http://localhost:11311]: master may not be running yet. Will keep trying.

Hence, before using rosrun you need to use a separate terminal to start the ROS Master node by using the command:

To kill a node that is running, go to the terminal from which you started the node with rosrun, and press ctrl+c to cancel the command and hence kill the node.

roslaunch - launch multiple nodes at once

Launch files allow multiple node to be run (i.e., launched) with a single command, and they allow specifying extra attributes for how the nodes should be launched, for example, namespace and parameters can be specified.

The syntax for using the roslaunch command is:

rosrun <package> <launch_file>

where <package> is replaced by the name of your package, and <launch_file> is replaced by the name of the launch file that you want to launch.

Important

In contrast to rosrun, the roslaunch command can be used whether or not the ROS Master and the rosout are already running:

  • If ROS Master is NOT already running, then roslaunch will also launch the ROS Master and rosout nodes.

  • If ROS Master is already running, then roslaunch will only launch the nodes specified in the given launch file.

Launch files use a html-like syntax with tags that are bespoke to ROS. You should keep you launch files in a launch folder of your package:

cd ~/my-robotics-system/catkin_ws/src/my_robotics_pkg
mkdir launch
cd launch

Note

The roslaunch command actually searches for launch files anywhere within the package, but keeping them in folder named launch/ is good practice

Start a launch file for editing

A launch file is simple a text file with the extension .launch:

nano plain.launch

Add the <launch> tag

<launch>

</launch>

All instructions inside the launch tag are executed when the launch file is roslaunch-ed. A launch file:

  • MUST have only one launch tag.

  • MUST have nothing outside of the launch tag.

Add a <group> with a namespace

<launch>
    <!-- START A GROUP WITH A NAMESPACE -->
    <group ns="mrp">

    </group>
</launch>

The group tag is a convenient way to group together the launching of multiple nodes that you want to put within the same namespace. The namespace property ns= can be given any string, for example, "mrp" is short for “my robotics package” and reflects an intention to launch all nodes from the package into the same namespace.

Note

For an application where you have multiple robots launching and operating on the same ROS network, then this group namespace attribute can be parameterised with the ID of the robot. This can enable launching all robots in an automated fashion, for example, with ns="mrp_robot001", ns="mrp_robot002", …, ns="mrp_robot042", …, etc.

Add a <node> or two

For adding a C++ node and a Python node:

<launch>
    <!-- START A GROUP WITH A NAMESPACE -->
    <group ns="mrp">
        <!-- LAUNCH A "Plain C++" NODE -->
        <node
            pkg    = "my_robotics_pkg"
            name   = "plain_cpp_node"
            output = "screen"
            type   = "plain_cpp_node"
        />

        <!-- LAUNCH A "Plain Python" NODE -->
        <node
            pkg    = "my_robotics_pkg"
            name   = "plain_py_node"
            output = "screen"
            type   = "plain_py_node.py"
        />
    </group>
</launch>

Add and use an input argument, <arg>

<launch>
    <!-- EXAMPLE OF DEFINING AN INPUT ARGUMENT -->
    <arg name="alsopython" default="false" />

    <!-- START A GROUP WITH A NAMESPACE -->
    <group ns="mrp">
        <!-- LAUNCH A "Plain C++" NODE -->
        <node
            pkg    = "my_robotics_pkg"
            name   = "plain_cpp_node"
            output = "screen"
            type   = "plain_cpp_node"
        />

        <!-- USE THE INPUT ARGUMENT IN AN IF-STATEMENT  -->
        <group if="$(arg alsopython)">
            <!-- LAUNCH A "Plain Python" NODE -->
            <node
                pkg    = "my_robotics_pkg"
                name   = "plain_py_node"
                output = "screen"
                type   = "plain_py_node.py"
            />
        </group>
    </group>
</launch>

The <arg> tag is used to declare the input argument, providing the attributes:

  • name= as any string that uniquely identifies the argument for this launch file.

  • default as the default value of the input argument, which is used if the argument is not specified as part of the launch command.

The value of an input argument is accessed within the launch file using $(arg alsopython).

In the example, a group with an if= attribute is used so that the nodes within that group are only launched if the input argument has the value true, i.e.:

<group if="$(arg alsopython)">
    <!-- THINGS HERE ONLY HAPPEN IF THE  -->
    <!-- ARGUMENT alsopython IS TRUE     -->
</group>

The value of an input argument is set using := on the launch command, for example:

roslaunch my_robotics_pkg plain.launch alsopython:=true

Use an environment variable for a default <arg> value

In case it suits the architecture of you robotics project, the default value for a launch file input argument can be taken from an environment variable:

<!-- INPUT ARGUMENT OF THE ROBOT'S ID -->
<arg name="robotID" default="$(optenv ROBOT_ID)" />

where the ROBOT_ID environment variable would be set in some fashion prior to launching the launch file, for example using:

..code-block:: bash

export ROBOT_ID=42

If you have one separate computer (e.g., Raspberry Pi) running on each separate robot, then this method can be used by setting a unique identifier into a ROBOT_ID environment variable. Then the group namespace attribute can be using the same launch file for all robots as follows:

<group ns="$(eval 'mrp_robot' + str(robotID).zfill(3))">

rosnode - command line tool for interrogating nodes

Sometime the --help display can seem because it seem “cluttered” by lots of options that you do not use. In the case of rosnode, the help display is succinct and all you need.

The available commands for interrogating nodes with rosnode:

# RUN THIS COMMAND
rosnode --help

# WHICH DISPLAYS THE FOLLOWING
rosnode is a command-line tool for printing information about ROS Nodes.

Commands:
  rosnode ping  test connectivity to node
  rosnode list  list active nodes
  rosnode info  print information about node
  rosnode machine list nodes running on a particular machine or list machines
  rosnode kill  kill a running node
  rosnode cleanup purge registration information of unreachable nodes

Type rosnode <command> -h for more detailed usage, e.g. 'rosnode ping -h'

Important

Note the last line in the console display above: Type rosnode <command> --help for more detailed usage information about any of the rosnode command, for example, rosnode ping --help

Use list to display all the nodes currently in existence and check that the namespaces and node names are as you expect:

# RUN THIS COMMAND
rosnode list

# WHICH MAY SOMETHING LIKE THE FOLLOWING
/mrp/plain_cpp_node
/mrp/plain_py_node

This simple listing allows you to see that when using a launch file, the node are indeed launched into the namespace mrp. If you rosrun the node, then you should see that mrp/ is no longer part of the nodes namespace, in fact, the nodes are run directly in the the root namespace /

References

The steps detailed on this page are mostly taken from:



Creative Commons License
Paul N. Beuchat, 2023