UP | HOME

Testing and Debugging in ROS and C++

Overview

Levels of ROS testing

Library-level unit tests

  • These tests are independent of ROS and are used for testing individual functions and libraries.
  • Each test should be small and (ideally) run quickly
  • Ideally these tests are designed to run every time you compile (or at least every time immediately prior to merging your code into the master)

Single Node Unit Tests

  • The goal is to validate the functionality of a single Node
  • Test its publishers, subscribers, and servers, and parameter usage
  • These tests should also be relatively small and self contained
  • They can be set up to run as part of the compilation process

Integration Test

These tests start multiple nodes and test how the whole system works together

  • These tests are made in the same way as single node unit tests, but launch more ROS nodes
  • Some integration tests can be done automatically as part of the compilation process
  • Some integration tests may require physical robot hardware

C++ Unit Testing Framework

There is no standard unit-testing framework for C++. We will use Catch2 (version 3) in this class, but these notes also discuss gtest.

Catch2

Overview

Quick Guide

  • The catch_ros2 documentation provides full usage instructions.
  • To do regular unit tests, right the Catch tests as usual, then link the executable with target_link_libraries(mytests catch_ros2::catch_ros2_with_main)
    • This automatically provides a main for the test, but there are other options
  • To do integration testing requires
    1. The nodes you want to test
    2. A Integration Testing Node
      • This node uses Catch2 to run test the node
    3. A Launch File
      • This node launches the nodes the node that should be tested and the test node itself
    4. Add catch_ros2_add_integration_test(MyTest LAUNCH_FILE my_launchfile TIMEOUT 60) to CMake if you want the test to run with colcon test.
      • TIMEOUT defaults to 60 and can be ommited, but it is useful to increase the timeout if running the test node in gdb
      • The test can also be run by running the test launch file
Google Test (GTest)

Overview

Debugging

  • Using gdb can greatly help you track down issues in your program
    • Among other features, it enables you to step through the code, examine variables, and break on certain lines
  • use ros2 run --prefix "gdb --args" package node to launch the node in gdb
  • Commands that may be useful are
    • tui enable to view a graphical interface with easier commands
    • run start running the program. Abbreviated with r
    • continue continue running a paused program. Abbreviated with c
    • break file:line or break function to put a breakpoint at a line or a function. Abbreviated with b
    • next go to the next line, skipping over functions. Abbreviated with n
    • step go to the next line, jumping into functions. Abbreviated with s
    • print display the value of a variable or memory address
  • To use gdb most effectively, the code must be compiled with Debugging symbols enabled
    • Use the Debug build type in CMake. See CMake Notes for how to set debugging mode

From Launchfiles

Launching a node in GDB from a launchfile requires extra consideration because you do not have access to a terminal for the node by default (the ros2 launch command controls input from the terminal). Instead we will use gdbserver, which allows remote debugging

  1. Use launch-prefix to start gdbserver:
    • XML Launch File: <node ... launch-prefix'gdbserver :3000'>=
    • Python Launch File ~Node(…, prefix=['gdbserver :3000'])
    • The :3000 is the port, the number is somewhat arbitrary (as long as it doesn't conflict with other open ports).
    • This same argument works when using the <catch_ros2_node> tag
  2. Run gdb and connect to the server using remote target :3000 (or the port you specified above)
    • You can now use gdb as usual.
  3. Alternatively, you can use a prefix command to run gdb in a new terminal window (e.g., xterm).
    • xterm -e gdb -ex run --args
    • This method is in some ways more straightforward: it will launch a new xterm window
    • However, it is also dependent on the availability of a gui (e.g., will not work over ssh).
  4. In a pinch, you can comment out the start of the node in the launchfile and manually run it with ros2 run

References

Author: Matthew Elwin.