VSCode

Debugging ROS2 Projects, Remote SSH, Latex Support

Posted by Rico's Nerd Cluster on August 1, 2018

Useful Shortcuts

Debugger;

  • F11: step into;
  • Shift f11: step out
  • F5 continue
  • F10: step over
  • ctrl-shift-y to open debug console

Set Up VSCode For ROS2 Development In Docker

Reference This feature really is an UI of running gdb on ROS2 projects.

  1. Have your container running on your local machine.

  2. Install Dev Containers by microsoft. Once installed, select “dev containers”. Then you should be able to attach an instance to your container.
  3. Install C/C++, CMake Tools in the running container

  4. Make sure to set the workspace folder correctly "workspaceFolder": "/home/mumble_robot", in devcontainer.json

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
     {
         "extensions": [
             "github.copilot",
             "github.copilot-chat",
             "github.vscode-pull-request-github",
             "ms-vscode.cmake-tools",
             "ms-vscode.cpptools",
             "ms-vscode.cpptools-extension-pack",
             "ms-vscode.cpptools-themes",
             "twxs.cmake"
         ],
         "workspaceFolder": "/home/mumble_robot"
     }
    
    • Press Ctrl+Shift+P (or Cmd+Shift+P on macOS) to open the Command Palette, then type and select “Dev Containers: Open Dev Container Configuration File”. This command will open your devcontainer.json directly.
  5. Create ${"workspaceFolder"}/.vscode, then add launch.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Debug My Executable",
      "type": "cppdbg",
      "request": "launch",
      "program": "${workspaceFolder}/build/halo/halo_tests",
      "args": [],
      "stopAtEntry": false,
      "cwd": "/home/mumble_robot", // explicitly set your working directory here
      "environment": [],
      "externalConsole": false,
      "MIMode": "gdb",
      "miDebuggerPath": "/usr/bin/gdb",
      "preLaunchTask": "colcon build"
    }
  ]
}
  • Note that if you have args, like -s data/ch7/EPFL/aquarius_source.pcd, add to "args": ["-s", "data/ch7/EPFL/aquarius_source.pcd"]
  1. And ${"workspaceFolder"}/tasks.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "colcon build",
            "type": "shell",
            "command": "colcon build --cmake-args -DCMAKE_BUILD_TYPE=Debug --symlink-install",
            "options": {
                "cwd": "/home/mumble_robot"
            },
            "group": "build",
            "presentation": {
                "reveal": "always",
                "echo": true
            },
            "problemMatcher": []
        },
        {
            "type": "cppbuild",
            "label": "C/C++: gcc build active file",
            "command": "/usr/lib/ccache/gcc",
            "args": [
                "-fdiagnostics-color=always",
                "-g",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "detail": "Task generated by Debugger."
        }
    ]
}
1
- **REMEMBER to set path to your executable** 6. Set break points in a file, then hit `<F5>` to start the debug program. (the triangular button for debugging did not work)

More ROS Path Resolution

Issue with the above method is: ROS environment seems not being passed into it successfully. Like, path resolution to /install would fail.

  • If you run into such a case, you can switch to gdb

    1
    2
    3
    4
    
      gdb --args <PATH_TO_MY_BINARY> \
          --ros-args -r__ns:=/commander -r __node:=foo \
          --params-file My_PARAM.yaml \
          --log-level debug
    
  • use “lc” to force executing bash command/

    • Example launch.json configuration using lc:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      
      ```json
      {
          "version": "0.2.0",
          "configurations": [
              {
                  "name": "Run with lc (source setup.bash)",
                  "type": "cppdbg",
                  "request": "launch",
                  "program": "/bin/bash",
                  "args": ["-c", "lc 'source /my_ws/install/setup.bash && ./my_ws/install/node.../lib/my_pub/my_pub_node --ros-args -r __ns:=/commander --log-level debug --params-file my_yaml.yaml'"],
                  "stopAtEntry": false,
                  "cwd": "/ws",
                  "environment": [],
                  "MIMode": "gdb",
                  "miDebuggerPath": "/usr/bin/gdb",
                  "externalConsole": false
              }
          ]
      }
      ```
      

ROS2 Launch File

In a (roslaunch data structure) Node or ComposableNodeContainer, add the property prefix. It is an array with one string, containing space-separated commands.

Launch GDB and run program. This will “attach” to the terminal but output won’t really be very usable.

Example: ['gdb -ex=r --args']

Example with basic Node launch:

1
2
3
4
5
6
7
ld = LaunchDescription([
 launch_ros.actions.Node(
     package='demo_nodes_cpp',
     output='screen',
     prefix=['gdb -ex=r --args']
 )
])

GDB Server

Launch GDB server and block execution until a client connects. Example: ['gdbserver localhost:9000'] Example with composable nodes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ComposableNodeContainer(
            name='my_node_container',
            namespace='my_namespace',
            package='rclcpp_components',
            executable='component_container_mt',
            output='screen',
            prefix=['gdbserver --once localhost:9000'],
            composable_node_descriptions=[
                ComposableNode(
                    name='my_first_node',
                    package='my_package',
                    namespace='my_namespace/sub',
                    plugin='my_ns::MyClass',
                )
            ]
        )

VSCode launch configuration to connect to above:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Attach to my_pub (gdbserver:9000)",
            "type": "cppdbg",
            "request": "launch",
            "program": "ws/install/my_pub/lib/my_pub/my_pub_node",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerServerAddress": "localhost:9000",
            "miDebuggerPath": "/usr/bin/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
                }
            ]
        }
    ]
}

Remote SSH Configuration

  • Configuration ~/.ssh/config
1
2
3
4
Host <HOSTNAME>
    HostName <IP>
    User <USER_NAME>
    Port 22
  • To enable Python module clicking, go to extensions -> click "install on <HOST>" on python extension (10-15MB, typically less than 1-2%)

Latex Support

  • $| x |$ works with Jekyll. Without escape, it won’t