Setting Up VSCode with ROS
Working from home? VSCode is one of the best IDEs out there (they claim it is an “editor”, but with proper extensions it becomes a full-blown IDE). Remote work with SSH is my favorite VSCode feature. It allows you to edit code locally but compile and run it on a remote server. All you need is an SSH connection. Everything works super smoothly.
General Instructions
- Open the catkin workspace root directory in VSCode, instead of individual packages. This will help in compiling everything together and code navigation.
- I had the habit of just symlinking various package directories in
catkin_ws/srcinstead of actually having the code thre. But VSCode has bugs that prevent Git change detection and code navigation for code that lives inside symlinks. So for ROS I now do not use symlinks insidesrc.
C++
Lately I have been developing ROS C++ code with this setup. The VSCode ROS extension does most of the legwork like setting up include paths and IntellSense databases for ROS (code navigation, auto-complete, etc.). However, it does not properly configure IntelliSense for the code within the package you are developing, so IntelliSense functions for navigating the code under development don’t work (as of 23 Jan, 2022).
This blog post by Erdal gives two crucial pieces of information:
- Those paths can be provided to IntelliSense using the
compileCommandsfield inc_cpp_properties.json. Its value should be the path to acompile_commands.jsonfile. - CMake i.e. the build system used under the hood by catkin can be configured to produce
compile_commands.jsonwith theCMAKE_EXPORT_COMPILE_COMMANDSvariable.
Next, we can use Tim Redick’s
merge_compile_commands.sh script to merge the
compile.commands.jsons from various packages in the whole catkin workspace. I have reproduced it below, put it in
the root of your workspace.
#!/usr/bin/env bash
printf '[' > compile_commands.json
find ./build -type f -name 'compile_commands.json' -exec sh -c "cat {} | tail -n+2 | head -n-1 && printf ','" >> compile_commands.json \;
sed -i '$s/.$//' compile_commands.json
printf '\n]\n' >> compile_commands.json
Below is my tasks.json that aliases catkin: build by renaming it to catkin_build and creating another task
named catkin: build that depends on catkin_build and executes merge_compile_commands.sh afterwards. It also
has the CMAKE_EXPORT_COMPILE_COMMANDS CMake directive, and a catkin: clean task.
{
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"command": "catkin build --cmake-args -DCMAKE_EXPORT_COMPILE_COMMANDS=1" // <- ADD OTHER CMAKE DIRECTIVES HERE
"problemMatcher": [
"$catkin-gcc"
],
"label": "catkin_build"
},
{
"type": "catkin",
"args": [
"clean",
"--yes"
],
"problemMatcher": [
"$catkin-gcc"
],
"label": "catkin_clean"
},
{
"command": "${workspaceFolder}/merge_compile_commands.sh",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"label": "catkin: build",
"problemMatcher": [],
"dependsOn": [
"catkin_build"
]
},
{
"command": "rm ${workspaceFolder}/compile_commands.json",
"type": "shell",
"problemMatcher": [],
"group": "build",
"label": "catkin: clean",
"dependsOn": [
"catkin_clean"
]
}
]
}
The only next step is to add "compileCommands": "PATH_TO_WORKSPACE_ROOT/compile_commands.json" to .vscode/c_cpp_properties.json.
Python
- Use the new Pylance Python language server. Microsoft has shifted its efforts to that instead of the default Python languager server.
- Make sure you follow ROS recommendations for Python
nodes and moduled inside packages, and build the workspace once (e.g. using the
catkin: maketask discussed above). - Add your package path to Pylance’s search paths in
.vscode/settings.json:"python.analysis.extraPaths" = ["<path_to_ws>/src/<package_name>/src/<package_name>"]. Currently (Dec 2020), variable substitution like${workspaceFolder}is not supported so you will have to use the full path. - Especially useful if your package generates messages, services, and actions: Add
FULL_PATH_TO_WS_ROOT/devel/lib/python2.7/dist-packagestopython.analysis.extraPathsandpython.autoComplete.extraPathsin.vscode/settings.json. - Disable linting:
"python.linting.enabled": false. I think linting is not very useful, and Pylance does a lot of convenience tasks anyway. If you do want linting, you will need to modify~/.pylintrcas mentioned in this SO comment.