|
| 1 | +Debugging |
| 2 | +^^^^^^^^^ |
| 3 | + |
| 4 | +All controllers and hardware components are plugins loaded into the ``controller_manager``. Therefore, the debugger must be attached to the ``controller_manager``. If multiple ``controller_manager`` instances are running on your robot or machine, you need to attach the debugger to the ``controller_manager`` associated with the hardware component or controller you want to debug. |
| 5 | + |
| 6 | +How-To |
| 7 | +****************** |
| 8 | + |
| 9 | +* Install ``xterm``, ``gdb`` and ``gdbserver`` on your system |
| 10 | + |
| 11 | + .. code-block:: bash |
| 12 | +
|
| 13 | + sudo apt install xterm gdb gdbserver |
| 14 | +
|
| 15 | +* Make sure you run a "debug" or "release with debug information" build: |
| 16 | + This is done by passing ``--cmake-args -DCMAKE_BUILD_TYPE=RelWithDebInfo`` to ``colcon build``. |
| 17 | + Remember that in release builds some breakpoints might not behave as you expect as the the corresponding line might have been optimized by the compiler. For such cases, a full Debug build (``--cmake-args -DCMAKE_BUILD_TYPE=Debug``) is recommended. |
| 18 | + |
| 19 | +* Adapt the launch file to run the controller manager with the debugger attached: |
| 20 | + |
| 21 | + * Version A: Run it directly with the gdb CLI: |
| 22 | + |
| 23 | + Add ``prefix=['xterm -e gdb -ex run --args']`` to the ``controller_manager`` node entry in your launch file. |
| 24 | + Due to how ``ros2launch`` works we need to run the specific node in a separate terminal instance. |
| 25 | + |
| 26 | + * Version B: Run it with gdbserver: |
| 27 | + |
| 28 | + Add ``prefix=['gdbserver localhost:3000']`` to the ``controller_manager`` node entry in your launch file. |
| 29 | + Afterwards, you can either attach a gdb CLI instance or any IDE of your choice to that ``gdbserver`` instance. |
| 30 | + Ensure you start your debugger from a terminal where you have sourced your workspace to properly resolve all paths. |
| 31 | + |
| 32 | + Example launch file entry: |
| 33 | + |
| 34 | + .. code-block:: python |
| 35 | +
|
| 36 | + # Obtain the controller config file for the ros2 control node |
| 37 | + controller_config_file = get_package_file("<package name>", "config/controllers.yaml") |
| 38 | +
|
| 39 | + controller_manager = Node( |
| 40 | + package="controller_manager", |
| 41 | + executable="ros2_control_node", |
| 42 | + parameters=[controller_config_file], |
| 43 | + output="both", |
| 44 | + emulate_tty=True, |
| 45 | + remappings=[ |
| 46 | + ("~/robot_description", "/robot_description") |
| 47 | + ], |
| 48 | + prefix=['xterm -e gdb -ex run --args'] # or prefix=['gdbserver localhost:3000'] |
| 49 | + ) |
| 50 | +
|
| 51 | + ld.add_action(controller_manager) |
| 52 | +
|
| 53 | +
|
| 54 | +Additional notes |
| 55 | +***************** |
| 56 | + |
| 57 | +* Debugging plugins |
| 58 | + |
| 59 | + You can only set breakpoints in plugins after the plugin has been loaded. In the ros2_control context this means after the controller / hardware component has been loaded: |
| 60 | + |
| 61 | +* Debug builds |
| 62 | + |
| 63 | + It's often practical to include debug information only for the specific package you want to debug. |
| 64 | + ``colcon build --packages-select [package_name] --cmake-args -DCMAKE_BUILD_TYPE=RelWithDebInfo`` or ``colcon build --packages-select [package_name] --cmake-args -DCMAKE_BUILD_TYPE=Debug`` |
| 65 | + |
| 66 | +* Realtime |
| 67 | + |
| 68 | +.. warning:: |
| 69 | + The ``update/on_activate/on_deactivate`` method of a controller and the ``read/write/on_activate/perform_command_mode_switch`` methods of a hardware component all run in the context of the realtime update loop. Setting breakpoints there can and will cause issues that might even break your hardware in the worst case. |
| 70 | + |
| 71 | +From experience, it might be better to use meaningful logs for the real-time context (with caution) or to add additional debug state interfaces (or publishers in the case of a controller). |
| 72 | + |
| 73 | +However, running the controller_manager and your plugin with gdb can still be very useful for debugging errors such as segfaults, as you can gather a full backtrace. |
| 74 | + |
| 75 | +References |
| 76 | +*********** |
| 77 | + |
| 78 | +* `ROS 2 and GDB <https://juraph.com/miscellaneous/ros2_and_gdb/>`_ |
| 79 | +* `Using GDB to debug a plugin <https://stackoverflow.com/questions/10919832/how-to-use-gdb-to-debug-a-plugin>`_ |
| 80 | +* `GDB CLI Tutorial <https://www.cs.umd.edu/~srhuang/teaching/cmsc212/gdb-tutorial-handout.pdf>`_ |
0 commit comments