A Decent Integration of VSCode to ROS
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.
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=Debug
to 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.
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.json
that 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
:
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 fromcd
andmake
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_tests
and 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.
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.
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.