ROS has a good number of tools which allow the user and the developer to visualize and debug their code in order to detect and solve issues with both hardware and software. This comprises a message logging system similar to log4cxx
, diagnostic messages, and also visualization and inspection tools, which provide a comprehensive list of the running nodes as well as how are they interconnected.
In this chapter, we will also show you how to debug an ROS node with the GDB debugger. The message logging API will be explained, and advice will be given on how to choose the logging level. Then, we will explain the set of ROS tools that allows us to inspect which processes are running and what information is communicated between them. For instance, the following figure shows a tool that visualizes the graph of the system, where the nodes are the processes running and the edges represent the data workflow through communication topics. This tool is rqt_graph
, and in this case, it shows the nodes and topics which compose the REEM robot software system running on a Gazebo simulation.
You can see multiple controllers for the arms, torso, head, MoveIt! move_group
node, pick and place action servers, and the play_motion
node for pre-recorded movements. Other nodes publish joint_states
, spawn the robot controllers, and control the joystick to move the mobile base.
Similarly, this chapter will show you how to plot scalar data in a time series, visualize images from a video stream, and represent different types of data in a 3D representation using (the widely known) rviz
(or rqt_rviz
), as shown in the following screenshot:
The preceding screenshot shows the REEM robot, which can be run in simulation with the following command:
$ roslaunch reem_2dnav_gazebo reem_navigation.launch
Note that before you install it, you need to follow the instructions provided at http://wiki.ros.org/Robots/REEM. The following sections in this chapter will cover the following topics on visualization and debugging: debugging our code in ROS; using logging messages in our code, with different severity levels, names, conditions, and throttling options. Here, we will explain the rqt_logger_level
and rqt_console
interfaces, which allow you to set the severity level of a node and visualize the message, respectively. We will also inspect the state of the ROS system by listing the nodes running, the topics, services, and actions they use to transfer messages among them, and the parameters declared in the ROS master server. We will explain rqt_graph
, which shows nodes and topics in a directed graph representation, and rqt_reconfigure
, which allows you to change dynamic parameters. We will also take a look at visualizing diagnostics information using the runtime_monitor
and robot_monitor
interfaces, as well as plotting scalar data from messages using rqt_plot
.
For non-scalar data, we will explain other rqt
tools available in ROS, such as rqt_image_view
to visualize images and rqt_rviz
to show multiple data in a 3D representation. We will also show you how to visualize markers and interactive markers, and what frames are and how they are integrated into ROS messages and visualization tools. We will also explain how to use rqt_tf_tree
to visualize the Transform Frame (tf) tree, along with how to save messages and replay them for simulation or evaluation purposes. We will also cover the rqt_bag
interface.
Finally, other rqt_gui
interfaces will be explained, as well as how to arrange them in a single GUI.
Most of the rqt
tools can be run by simply inputting their name in the terminal, such as rqt_console
, but in some cases this does not work and we must use rosrun rqt_reconfigure rqt_reconfigure
, which always works; note that the name seems to be repeated, but it is actually the package and node names, one after the other.
ROS nodes can be debugged as regular programs. They run as a process in the operating system and have a PID. Therefore, you can debug them as with any program using standard tools, such as gdb
. Similarly, you can check for memory leaks with memcheck
or profile the performance of your algorithm with callgrind
. However, remember that in order to run a node, you must run the following command:
$ rosrun chapter3_tutorials example1
Unfortunately, you cannot simply run the command through gdb
in the following way:
$ gdb rosrun chapter3_tutorials example1
In the following sections, we will explain how to call these tools for an ROS node to overcome this issue. Later, we will see how to add logging messages to our code in order to make it simple to diagnose problems; in practice, using logging messages helps to diagnose basic (and not so basic) problems without the need to debug the binaries. Similarly, we will discuss ROS introspection tools, which allow you to easily detect broken connections between nodes. Finally, even though we will provide a bottom-up overview, in practice we usually follow a top-down approach to diagnosing issues.
In order to debug a C/C++ node with the gdb
debugger, all we need to know is the location of the node executable. With the ROS Kinetic and catkin
packages, the node executable is placed inside the devel/lib/<package>
folder within the workspace. For example, in order to run the example1
node from the chapter3_tutorials
package in gdb
, we have to proceed as follows, starting from the workspace folder (/home/<user>/book_ws
):
$ cd devel/lib/chapter3_tutorials
If you have run catkin_make install
, you can also navigate to the install/lib/chapter3_tutorials
directory using the following command:
$ cd install/lib/chapter3_tutorials
Now we can run the node executable inside gdb
with the following command:
$ gdb example1
Once roscore
is running, you can start your node in gdb
by pressing the R key (and Enter), and you can also list the associated source code with the L key as well as set breakpoints or any of the functionalities that gdb
comes with. If everything is correct, you should see the following output in the gdb
terminal after running the node:
In many cases, we might get a launch
file that takes care of starting the node, as you can see in the following example:
<launch> <node pkg="chapter3_tutorials" type="example1" name="example1"/> </launch>
In order to attach it to gdb
, we must add launch-prefix="xterm -e gdb --args"
as follows:
<launch> <node pkg="chapter3_tutorials" type="example1" name="example1" launch-prefix="xterm -e gdb --args"/> </launch>
Similarly, you can also add output="screen"
to make the node output appear on the terminal. With this launch prefix, a new xterm
terminal will be created with the node attached to gdb
. Set breakpoints if needed, and then press the C or R key to run the node and debug it. One of the common uses you will find of this simple workflow is to obtain a
backtrace (bt) if the node crashes.
Additionally, we can use the same attribute to attach the node to diagnosis tools. For example, we can run our program through valgrind
(see http://valgrind.org for further information) to detect memory leaks using memcheck
and perform profiling analysis using callgrind
. Contrary to attaching to gdb
, we do not need to start xterm
:
<launch> <node pkg="chapter3_tutorials" type="example1" name="example1" output="screen" launch-prefix="valgrind"/> </launch>
Although ROS nodes are actually regular executables, there is a tricky point to enabling core dumps, which can later be used in a gdb
session. First of all, we have to set an unlimited core size; the current value can be checked with ulimit -c
. Note that this is also required for any executable and not just ROS nodes:
$ ulimit -c unlimited
Then, to allow core dumps to be created, we must set the core filename to use the pid
process by default. Otherwise, they will not be created because at $ROS_HOME
, there is already a core
directory to prevent core dumps. Therefore, in order to create core dumps with the name and path $ROS_HOME/core.PID
, we must run the following command:
$ echo 1 | sudo tee /proc/sys/kernel/core_uses_pid