Programming

✨ ROS 2 C++ Debugging Setup with VS Code

For our developers working in robotics in Berlin with ROS 2, juggling multiple packages or frequently switching debug targets within a complex ROS 2 workspace is common. To make this process smoother, setting up a more dynamic launch.json and tasks.json in VS code can be a true game-changer. This advanced approach uses VS Code’s input variables to prompt you for details like ROS 2 package names and executables right when you start your debug session.

Let’s look at an example of a flexible configuration tailored for ROS 2 development:

1. Defining Inputs in launch.json for your ROS 2 Nodes

You can define inputs directly in your launch.json. This tells VS Code to prompt you for specific details needed to launch and debug your ROS 2 C++ nodes.

				
					// In your .vscode/launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Debug ROS 2 Node with Inputs", // Renamed for clarity
            "request": "launch",
            "type": "cppdbg",
            "preLaunchTask": "colcon_build_interactive_ros2_debug", // Task for ROS 2 builds
            "program": "${workspaceFolder}/install/${input:ros2PackageName}/lib/${input:ros2PackageName}/${input:executableName}",
            "args": [
                "--ros-args", // Standard way to pass arguments to ROS 2 nodes
                "--params-file",
                "${workspaceFolder}/${input:relativeParamsFilePath}"
            ],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}", // Common CWD for ROS 2 workspaces
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },
                {
                    "description": "Set Disassembly Flavor to Intel",
                    "text": "-gdb-set disassembly-flavor intel",
                    "ignoreFailures": true
                }
            ],
            "ros": { // ROS-specific configuration
                "distro": "<your_ros2_distro>" // e.g., "humble", "iron" - Important for the ROS extension
            }
        }
    ],
    "inputs": [ // Define the inputs VS Code will prompt for
        {
            "id": "ros2PackageName",
            "type": "promptString",
            "description": "Enter the ROS 2 package name",
            "default": "my_ros2_package"
        },
        {
            "id": "executableName",
            "type": "promptString",
            "description": "Enter the ROS 2 executable name within the package",
            "default": "my_ros2_node"
        },
        {
            "id": "relativeParamsFilePath",
            "type": "promptString",
            "description": "Enter the relative path to the ROS 2 params file (e.g., src/my_pkg/params/params.yaml)",
            "default": "src/my_ros2_package/params/default_params.yaml"
        }
    ]
}
				
			

Key Enhancements for ROS 2:

  • inputs section: Prompts for ros2PackageName, executableName, and relativeParamsFilePath. This makes the configuration incredibly reusable for any C++ ROS 2 node.
  • Dynamic Paths: The "program" and "args" paths are constructed using your inputs, pointing directly to your compiled ROS 2 node and its parameters.
  • --ros-args: Using --ros-args is the standard and recommended way to pass ROS-specific command-line arguments (like parameter files) to your ROS 2 nodes.
  • ros.distro: Added the "ros": { "distro": "<your_ros2_distro>" } field. While not always strictly necessary for GDB to function if your environment is sourced, it’s good practice for the VS Code ROS extension and helps ensure consistent behavior, especially if the extension uses this info for other purposes. Remember to replace <your_ros2_distro> with your actual ROS 2 distribution (e.g., “humble”, “iron”).
  • cwd: Set to ${workspaceFolder}. This is a sensible default for ROS 2 projects, as nodes often expect to be run from the root of the workspace or have paths resolved relative to it.
 

2. An Interactive preLaunchTask for Building Your ROS 2 Packages in tasks.json

This task will compile your ROS 2 code, prompting you to select which package to build.

				
					// In your .vscode/tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "colcon_build_interactive_ros2_debug",
            "type": "shell",
            // The command now explicitly sources your ROS 2 environment
            "command": "source /opt/ros/${config:ros.distro}/setup.bash && source install/setup.bash && PACKAGE_TO_BUILD=\"${input:packageToBuildInput}\"; if [ -z \"$PACKAGE_TO_BUILD\" ] || [ \"$PACKAGE_TO_BUILD\" = \"all\" ]; then echo '>>> Building all ROS 2 packages (Input was empty or 'all') with RelWithDebInfo...'; colcon build --symlink-install --cmake-args -DCMAKE_BUILD_TYPE=RelWithDebInfo; else echo \" >>> Building specific ROS 2 package: '$PACKAGE_TO_BUILD' with RelWithDebInfo...\"; colcon build --symlink-install --packages-select \"$PACKAGE_TO_BUILD\" --cmake-args -DCMAKE_BUILD_TYPE=RelWithDebInfo; fi",
            "group": "build",
            "presentation": {
                "reveal": "always",
                "panel": "dedicated",
                "clear": true
            },
            "problemMatcher": [],
            "options": {
                "cwd": "${workspaceFolder}" // Run colcon from your ROS 2 workspace root
              }
        }
        "inputs": [
            {
                "id": "packageToBuildInput",
                "type": "promptString",
                "description": "Enter ROS 2 package name to build for debugging (e.g., my_ros2_package, or 'all' / leave empty to build all).",
                "default": "" // Or perhaps a common package you work on
            }
        ]
    ]
}
				
			

Key Features of this ROS 2 Build Task:

  • Sourcing the ROS 2 Environment: The command now explicitly includes source /opt/ros/${config:ros.distro}/setup.bash && source install/setup.bash &&. This is crucial to ensure colcon and your build process can find all necessary ROS 2 dependencies. ${config:ros.distro} dynamically pulls your configured ROS distribution from VS Code’s settings (if the ROS extension is installed and configured).
  • User Prompt for ROS 2 Package: The task interactively asks which ROS 2 package to build.
  • Conditional Compilation: Builds either a specific ROS 2 package or all packages in your workspace.
  • RelWithDebInfo Build Type: Continues to use CMAKE_BUILD_TYPE=RelWithDebInfo, ideal for balancing optimization with debuggability for your ROS 2 nodes. For even more detailed debugging, especially if optimizations are obscuring variable states, you can switch this to Debug.

Streamlining Your ROS 2 Debugging Workflow:

  1. Ensure your .vscode/launch.json and .vscode/tasks.json are saved.
  2. Open the “Run and Debug” view in VS Code.
  3. Select “(gdb) Debug ROS 2 Node with Inputs” from the dropdown.
  4. Hit F5 or the green play button.
  5. VS Code will prompt you:
    • First, the colcon_build_interactive_ros2_debug task will ask for the “ROS 2 package name to build”.
    • After the ROS 2 package(s) build, the launch configuration will prompt for:
      • “Enter the ROS 2 package name” (input:ros2PackageName)
      • “Enter the ROS 2 executable name” (input:executableName)
      • “Enter the relative path to the ROS 2 params file” (input:relativeParamsFilePath)
  6. Provide these details, and the debugger will launch your specified ROS 2 C++ node!
 
 

This dynamic setup is a powerful way to enhance your ROS 2 development productivity. For the thriving robotics Berlin community, adopting such efficient workflows means more time for innovation and building amazing robots!

Related Article

Leave a Reply

Your email address will not be published. Required fields are marked *