A Decent Integration of VSCode to ROS

Tahsincan Kose
9 min readDec 18, 2018

Well, it is every newbie ROS developer’s desire to have the tools of everyday software developers. I remember saying myself “If only I could debug this shitty node with good old red dots fired through my left-click on a decent GUI” for countless times. Besides, I was thrown into a setting such that the only intelligent tool I had was Sublime Text to develop ROS code. When the enormous amount of URDF, SDF, YAML, ROS message/service/action and source files (and many more I could not recall now) are considered, it becomes intractable to manage all these stuff through bare Sublime Text (or your favorite text editor) and you could find yourself easily at a point of desperation. Debugging a ROS application with dozens of ROS_INFO statements is surely a tool that you should always have in your repertoire, but let’s be honest, it can be a pain in the back most of the times. Nonetheless a minimal IDE — in our case easily hackable VSCode — can profoundly increase your productiveness.

For instance, you might require to change some certain feature of a joint in your robot’s URDF file which might also require parameter adjustment in a launch file that effectively requires a change in your source… Let me cut it to the chase, you will definitely need an IDE.

I know there exists an abundance of resources on the web for each specific task a ROS user would demand from his/her IDE to fulfill. Yet none of them provide a comprehensive walk-through for both debugging, building, version control and etc.

Build & Clean & Test & Release Configuration

Before starting, I want to point the reader to the ROS plugin of VSCode. Although I’m not using it, it might be useful for someone else. In the past there were several commands such as rosbuild, rosmake and catkin_make for building ROS packages. Until recently I was using catkin_make, too. However all these commands lack heterogeneous workspace support and more importantly are not a comprehensive build tool. Therefore, I have migrated to catkin meta-build system. In fact, it is an amazing tool with great features that can be used in any C++ project. For example, it eliminates the burden of creating FindXXX.cmake files through automation which is a huge facility in terms of quick packaging.

So, from this point on I will assume you are using catkin tool as well. However, it should be trivial to integrate any other build system in VSCode. For those who are interested in direct result can scroll down to the end of page.

Catkins

Build

In order to build the system, a sequence of catkin commands are necessary. For instance, an uninitialized workspace will give an error. However we can solve this problem through extend mechanism of catkin. The combined command would be:

catkin config --extend /opt/ros/<your_ROS_DISTRO> && catkin build -j8

In my own projects, I also add the flag -DCMAKE_BUILD_TYPE=Debugto have debuggable executables as outcomes. If you want to debug your own nodes too, you can add this flag to the end of command line above. There are additional arguments that Catkin interfaces for the configuration of build environments. -jN is such an argument that denotes the number of cores that can build up to N packages in parallel. In my case, I have 8 cores and chose to use all of them. But in different hardware settings such as embedded devices, you may want to limit this number. Also, the memory used during the compilation becomes a problem in such settings that can easily result in an insufficient virtual memory error. In those cases, you will definitely need to limit the maximum memory amount used by the build system. For further information about possible arguments, you should refer to full CLI of build command.

After introducing how catkin build works, it is now the time to integrate it with VSCode.

Task Assignment in VSCode

It is extremely easy as can be seen in the GIF above. In fact, all the tasks that I will show in the upcoming parts of this story will follow the exact same pattern. Note that the file of interest is tasks.jsonthat is automatically created by Terminal>Configure Tasks if it does not exist. I will populate this file as time goes by. Actually, specifying build task suffices to call it via Terminal>Run Task>build or Terminal>Run Build Task or Ctrl+Shift+B . However, since I want a fully customized workspace, I will assign different shortcuts to the tasks specified in tasks.json . Since VSCode only provides a shortcut for build task, it will fall short for other tasks if I stick with it. Next, let’s assign a shortcut to this task in keybindings.json :

Shortcut Assignment to Task in VSCode

It is also straightforward to populate this file. Moreover, in a broader aspect, only the key and args field will change in the case of different tasks. If you don’t know where keybindings.json is, follow the path File>Preferences>Keyboard Shortcuts>keybindings.json in order to open it.

Clean

I will quickly introduce how clean behaves in catkin. It’s up to your taste adding additional arguments for partial cleaning, dependency cleaning or complete cleaning through workspace de-initialization. However, I simply use catkin clean --yes to remove devel, build and logs folders those produced as a result of build command. From now on, you should be able to embed this command in tasks.json and then assign a shortcut to it in keyboards.json file.

Test

Unit testing is an optional process when developing robotics projects with ROS. If it is not a core package, tests are generally omitted or superficial qualitative tests on simulations are used to validate the software. Honestly, most of the time they suffice for research projects or small-to-medium applications. However, there might be strict regulations that are enforced by your customer or one specific standard that you must conform to. In those cases, frequently articulated “test every single line” phrase becomes inevitable.

Luckily, catkin provides macros for test-aware compilation and verbs dedicated to test the project in its entirety. It is up to you to execute catkin run_tests or catkin build --verbose --catkin-make-args run_tests to run your tests. I’m leaving the question of which tests to run in here open. However, you can use Gtest for your unit tests, whose use in ROS is described in here. Also there is rostest for integration tests that you may want to use during the testing the behavior between several nodes. Links I have given should provide you with the adequate knowledge on how to write, compile and run tests.

Since I have been working with catkin, I have only encountered with one unresolved issue — that is, a lack of concise test suite output. The problem is related with the --verbose flag, which shows all the outputs from cd and make commands aside with test results. If you disable it, then you lose test results too. There is an open issue in catkin’s repository that reports this problem. For those who are interested, it might be an instructive practice to implement a dedicated catkin verb for this specific use case.

Nonetheless, until that feature is implemented, I have come up with a workaround. Using sed system stream editor, a one-liner extracts the necessary parts of the output of catkin build --verbose --catkin-make-args run_testsand prints to the standart output. You can then use tee to both have a test log in your permanent storage and see in the standart output. The final command is: catkin build --verbose --catkin-make-args run_tests | sed -n '/\[==========\]/,/\[==========\]/p'. I’m leaving to the reader as a practice to how to multiplex the output of above command to a file and to stdout. One final remark is on the necessity of roscore. If you are dealing with ROS nodes, then you have to have a working instance of roscore before testing process starts.

Release

Finally, I would like to explain how a ROS package can be released. Note that this is not the only way of doing it and basically outputs an install-able offline Debian package. The convention among ROS developers is to use ROS buildfarm to release binary packages, handle continuous integration of them and etc… I haven’t yet undergone such a process, since I’m participated in a proprietary project.

Let’s cut it to the chase! Catkin also provides native support for installing. Before anything, it is a good convention to clean up the workspace and then give a new configuration to it that we are going to have an installation:

catkin clean --yes && catkin config --install --merge-install

I’d like to have all the packages in workspace to be merged in install folder. Nevertheless, if you want their install-able targets to be located in their distinct folders, you can also specify --isolate-install flag instead of --merge-install. In this stage, a small application — checkinstall — is required. If you don’t have it in your system, simply run sudo apt-get install checkinstall. It will install a proper version of it. After that, a one-liner releases our workspace:

sudo checkinstall --install=no catkin build -j4 --cmake-args -DCMAKE_BUILD_TYPE=Release

The default behavior of checkinstall is to also install the produced Debian package to your system. If you don’t want that, you need to specify it explicitly as I did. After this command executes, it launches a CLI for you to fill meta-package information. Then a *.deb file is produced. You can install this package in any other system with ROS and directly use your launch files, nodes and etc. Naturally, they have to be specified as install() targets in corresponding CMakeLists.txt files.

Final Snap of tasks.json
Final Snap of keybindings.json

In above images, the final versions of both files reside. There is one final thing I would like to discuss, which is debugging.

Debugging

In ROS community, it is not the mainstream behavior to debug nodes. Rather ROS_DEBUG and ROS_INFO statements lead our paths to amazing, error-free Robotics software. As I mentioned, these are already great tools; however, one might also benefit from using breakpoints and other (honestly I don’t use other features other than simple variable lookup) great utilities of a debugger. The shortcut of debugging in VSCode is F5. If you don’t have a launch.json and attempt to trigger a debug session, it will automatically launch this file with an empty body. This stage requires a debugger to be ready in your system. I’m using GDB, but LLVM is ok, too. Note that, it is vital to have the workspace built with -DCMAKE_BUILD_TYPE=Debug. Otherwise, your breakpoints will be simply ignored.

Combined View of Launch and Tasks
Debug View in ROS Node

So yes! With above configurations, when you press F5, you would end up with an automatically stopped debug session in the entrance of the main function of your ROS node.

Conclusion

Finally it is finished… In conclusion, I have tried to illustrate the usage of well-known software engineering processes and integrate them with a relatively easier IDE for further ease of use. I also showed the way to debug a simple ROS node. If you have any questions regarding to any part of it or have things to say for improvement, you are greatly welcomed.

--

--