\(\def\dt{\Delta t}\)
\(\newcommand{\transpose}[0]{^\mathrm{T}}\)
\(\newcommand{\half}[0]{\tfrac{1}{2}}\)
\(\newcommand{\Half}[0]{\frac{1}{2}}\)
\(\newcommand{\norm}[1]{\left\lVert#1\right\rVert}\)
\(\newcommand\given[1][]{\:#1\vert\:}\)
UP | HOME

Catkin, Workspaces, and Environment Variables

Table of Contents

1 What is catkin?

  • catkin is the official ROS build tool.
    • It used to be rosbuild. If you see commands floating around on the wiki that involve rosmake be aware that you are looking at old documentation.
    • You will sometimes encounter documentation referring to dry and wet packages. This is referring to packages using the old build system vs. the new build system, and a plan that was put in place during migration. This concept is not really used much any more as migration is nearly totally complete.
  • catkin is used to generate "targets" from source code. The primary uses are:
    • Convert *.msg and *.srv files into code that can be used by ROS client libraries, usually using automated code-generation utilities
    • Compile C++ code into executables and libraries (or possibly compilation tasks for other languages)
  • This page on the catkin conceptual overview is full of good information
  • catkin is basically just a wrapper around the CMake build tool
    • it includes extra tools for finding ROS-related packages at compile time
    • it can automatically build multiple, dependent projects simultaneously
  • The package.xml and the CMakeLists.txt files inside of a package tell catkin how to build all of your package targets.

2 Catkin Workspaces

  • A catkin workspace is a directory where you create, modify, build, and install ROS packages.
  • There are 4 different key directories used by the workspace
    src
    This is where your packages actually go. You should only ever be editing code in here.
    build
    This is where CMake intermediate files go.
    devel
    This is where the built files go when a user runs catkin_make. This directory also contains "setup" files that control which workspaces are active. Read more in the overlays section below. Typically in this course, we will be dealing only with this directory for holding our compiled targets.
    install
    This is the default location where targets get installed to. Built targets would be sent to this directory if a user ran catkin_make install instead of just catkin_make. This directory has its own "setup" files independent of the devel directory setup files. We won't typically need to use this directory in this course.

2.1 devel vs install

Both the devel directory and the install directory contain setup files and compiled targets. In fact, the generic ROS term is that they are both result spaces. So a natural question one might ask is "why do we need both a devel and an install directory"? The easy answer is that catkin allows you to specify different sets of rules to follow when installing targets. These special rules may optionally be used to for developer convenience (examples described below), but they are also an important part of the ROS build farm automatically building packages that can be installed via apt-get. Here are a few examples of how one could effectively use these result spaces:

  1. Let's say we are actively developing and debugging complex C++ code that takes a long time to compile. We could configure catkin to build the code in the devel space with no compiler optimizations (to save compilation time), and to include debug flags in the compiled binary (to allow a debugger to be able to trace errors in the compiled binary back to particular lines in the source code). Then, we could configure the catkin_make install targets to add compiler optimizations (to compile more efficient binaries at the expense of greater compilation time), and to remove debug flags (to produce smaller binaries). With this setup, we could do all of our development and debugging in the devel space, and then when we want to actually use the code that we've compiled, we could switch over to the install space.
  2. Let's say we have a ROS package that's primary purpose is not to provide ROS nodes, but rather to provide generically useful libraries that other ROS packages would be able to link against. Maybe the libraries are so useful that other non-ROS projects might also want to link against them. Well we could, in principle, configure our install targets to actually move these compiled libraries to somewhere that is natively used by non-ROS projects, e.g., /usr/local/lib/. This is not done regularly in practice, because uninstalling targets that are installed this way is can be difficult if you don't take precautions (this is one of the purposes of dpkg / apt-get).
  3. Python packages are handled quite differently when using the devel vs. the install space. In the devel space, there are special "relaying" scripts (e.g. this one) that help Python automatically access the actual copies of the Python scripts, packages, and modules located in the src directory of a workspace. This means that we can edit any Python script in the src directory, and re-run whatever ROS thing we are doing, and we will automatically be using the updated version of the Python code. This is not true in the install space; in the install space, we'd have to re-run catkin_make install every time we edit any Python code. One common use case for the install directory is to build Python C/C++ extensions using a setup.py file.
  4. As mentioned above, the install targets are used by the build farm when creating deb packages that can be installed via apt-get. Let's say that you have a package that you'd like to distribute that contained not only nodes, but also a launch file to use those nodes. Then you could create a special install target that caused the launch file to be "installed" when running catkin_make install. Effectively this would likely just copy the launch file to a location that ROS searches for launch files when "sourcing" the setup.bash file from the install space. Then when you submit your package to the build farm for auto-generation of the debian package, the build farm will also call your install target, which will result in your launch file being included in the deb package. For one example of this, check out the CMakeLists.txt file of the turtlebot_bringup package. Note they don't even compile any code, all they do is distribute launch files, configuration files, and images. For another example, check out the last few lines of the turtlesim package's CMakeLists.txt file. Here they ensure that all of the svg and png files that are included in the images directory are added to the package when installed. On my system, I have the turtlesim package installed from apt-get, and I can demonstrate the impact of this install target on the generated deb file with the following snippet:

    jarvis@test2018:~⟫ rospack find turtlesim
    /opt/ros/melodic/share/turtlesim
    jarvis@test2018:~⟫ ls /opt/ros/melodic/share/turtlesim/images/
    box-turtle.png   electric.png  groovy.png  hydro.svg   indigo.svg  kinetic.png  lunar.png  melodic.png  robot-turtle.png  turtle.png
    diamondback.png  fuerte.png    hydro.png   indigo.png  jade.png    kinetic.svg  lunar.svg  palette.png  sea-turtle.png
    

2.2 Environment variables

  • These are simply variables that applications can use to control their configurations
  • In Ubuntu, some are set to default "global" values when you login. There should be very little reason to ever change these.
  • Bash is a "shell" for interacting with the operating system. When you are typing in a terminal, you are interacting with bash.
    • There are other common shells people use in Linux/Unix:
      • zsh
      • sh
      • csh and tcsh
  • "source" command is used to execute a piece of bash code
    • It is just like "pasting" the contents of a file into the terminal
    • ROS variables are controlled by "sourcing" appropriate setup files
      • source /opt/ros/melodic/setup.bash
      • source ~/catkinws/devel/setup.bash
  • User-specific variables are typically set in the ~/.bashrc file. This file contains lines of bash code that are executed every time a new terminal is opened.
    • This file can be re-ran by "sourcing" it i.e. source ~/.bashrc. This can be useful if you are trying to test edits to the file.
    • Every terminal has its own environment. Editing ~/.bashrc will not take effect in your current terminal unless you re-run the file using the above source command
    • the dot at the beginning of the filename denotes this file as a "hidden file"
    • ls won't show this file without an ls -a
    • in Nautilus (the built-in file browser) C-h will to toggle visibility of hidden files
  • There are other relevant bash configuration files that will be run in various situations.
    • ~/.profile
    • ~/.inputrc
    • ~/.bash_profile
    • Read about these files by typing man bash and navigating to the INVOCATION section
    • The important point right now is that if you need to edit any environment variables (in Ubuntu at least), you should be editing the ~/.bashrc file
  • Every terminal has a different set of environment variables
  • "env" command prints all environment variables in current terminal
    • "Pipe" to grep or less to view more conveniently
    • env |grep ROS will show all environment variables with "ROS" in them.
      • Issues with environment variables and workspace setups is one of the most common issues that new ROS users encounter. Commit the above command to memory (or even alias it) and always check the output as one of your initial debugging attempts.
    • env |less will show all environment variables in the program less.
      • less is a "pager" that supports searching
      • press "h" to see all keyboard shorcuts
      • press "q" to quit
  • export is used to set environment variables
    • Without export a bash variable is only visible to parent process
    • See this stack overflow post for more information
  • unset can be used to remove variables

2.3 ROS Environment Variables

  • See this page for the complete documentation on ROS environment variables
  • We generally do not need to use "export" to set these manually as the workspace setup files manage most of these variables. The notable exceptions are ROS_IP/ROS_HOSTNAME and ROS_MASTER_URI
  • The following is a list of a few of the most important ROS environment variables.
    • ROS_ROOT This sets where the ROS core packages are located. The "setup.bash" file included with a ROS destroy automatically sets this i.e. source /opt/ros/melodic/setup.bash takes care of this variable for you.
    • ROS_MASTER_URI This variable is required, and it tells nodes where to look for master. The default value is http://localhost:11311; this basically tells all nodes that the master should be running on the same computer. We modify this value for networking ROS computers together.
    • ROS_IP/ROS_HOSTNAME These variables are optional variables that facilitate networking multiple ROS computers. These variables are often misunderstood and used incorrectly. In short, both of these variables are used to tell master where any node needing to communicate with a node running on your machine can find your machine. You could think of these variables as an important part of the address for all nodes on your machine. You should only ever set either ROS_IP or ROS_HOSTNAME – you should never set both. If you are planning to use a name server to be able to refer to the computers on your ROS network using their hostnames, then you would set the ROS_HOSTNAME environment variable to be the hostname of your machine. Note that you often see .local appended to the hostname when the computers are on a local network. This is because adding a .local suffix for local machines is a common setup for many router's DNS services. The advantage of using hostnames is that you don't need to rely on static IP addresses. This is more flexible, and usually requires less up-front configuration. However, you are relying on name resolution to work properly; if that isn't working properly your ROS system won't work. The other option is to use IP addresses instead of hostnames, and in this case you would need to know your IP address and you would set the ROS_IP variable to be equal to your IP address. This is generally a more reliable but less flexible option. You don't require name resolution to work, but you do need to know the IP addresses of all of the machines, and if you want your setup to be persistently reliable, you would want to figure out how to ensure all machines had long-term static IPs.
    • PYTHONPATH This is a standard Python environment variable that tells Python where to search for modules when calling import statements. ROS requires this to be set as many core ROS tools require Python. The "setup.bash" files automatically modify this variable.
    • ROS_PACKAGE_PATH This variable isn't actually used by catkin, but it was used by rosbuild (catkin's predecessor); so it is kept around for legacy purposes. That being said, this is still a convenient variable to look at to verify that your environment is configured properly.
    • CMAKE_PREFIX_PATH This is a standard CMake variable that CMake uses when looking for libraries, executables, and objects that are required for building a CMake project. This is the most important variable for catkin, as it is what catkin uses when looking for ROS packages. It is automatically set by "setup.bash" files, and should never require manual editing.

2.3.1 A note on caching

As we know, rospack is a command-line tool (there's also a Python API and C++ API) for retrieving information about packages. These tools use environment variables and metadata in the manifests of packages to provide information like where is package X found? or what plugins does package X provide?. These libraries are also used by tools like rosrun to be able to determine where to search for executables when starting nodes. For example, typing rosrun package_a node_a causes rosrun to use rospack to figure out where to look for package_a nodes, it then looks in that location for an executable named node_a.

Very often, users encounter errors such as the following:

jarvis@test2018:~⟫ rosrun me495_hw1 ros_cl_demo
[rospack] Error: package 'me495_hw1' not found
jarvis@test2018:~⟫ roslaunch me495_hw1 test.launch
RLException: [test.launch] is neither a launch file in package [me495_hw1] nor is [me495_hw1] a launch file name
The traceback for the exception was written to the log file
jarvis@test2018:~⟫ rosrun me495_hw1 nonexistent_node
[rosrun] Couldn't find executable named nonexistent_node below /home/jarvis/me495_indigows/src/me495_hw1

The most common causes of such errors are typos, accidental use of incorrect names (e.g. using a directory name to refer to a package instead of a package name), or improperly setup workspaces. Failing to properly source the correct setup.bash file is an extremely common problem that can lead to the above errors, especially when new ROS users are trying to use multiple workspaces. Even worse, sometimes if a user has been regularly adding and removing packages from a workspace, terminating in-process builds, or trying to build packages with malformed manifests or CMakeLists.txt files it is certainly possible to end up with a setup.bash file that incorrectly sets up your environment. In this case, the best option is usually just to wipe your build/ and devel/ directory and rebuild your workspace (catkin_tools is mentioned below, and it helps to clear up these issues in a less extreme way, but it is more complicated to use on a day-to-day basis).

The purpose of this whole section is to point out, that sometimes, you may run into an issue where you have already wiped your build/ and devel/ directories, you are positive you are using the right names and that there are no typos, but you are still getting errors like the one above. What is going on? The answer may lie in the caching mechanisms used by rospack. In the main rospack documentation, they mention right at the top that it uses the environment variables as a guide to build a cache of what packages are available, and this cache is actually used to answer package queries rather than constantly re-crawling your filesystem. However, sometimes your cache is out-of-date and not being automatically re-built for some reason. If you read the previously-linked documentation, you can read about how the cache is re-built and how you can control the frequency with which it is re-built, but I think the most important thing to know is that you can force the cache to be re-built if you are ever having these types of inexplicable package errors.

To force rebuilding of the cache you can simply use rospack profile. This is mentioned in the official documentation and on the rospack Troubleshooting page, but it seems people often miss this.

2.4 Workspace overlays

  • ROS allows users to combine workspaces in a very flexible way
  • This concept is called "overlaying", and has a decent tutorial here
  • Which workspaces are active, and which order they are traversed is controlled by environment variables
  • The relevant environment variables for catkin and ROS in general are controlled by setup files
  • Rebuilding a workspace with other workspaces active automatically regenerates the setup files for that workspace i.e. the next time you want to use that workspace structure, there is no need to separately "activate" each workspace setup file
    • The setup files override each other. there is never a need to source multiple setup files.
  • If you are having issues with your environment setup files, or if your workspace isn't building correctly, it is often a good idea to remove the build/ and devel/ directory

2.4.1 Workspace Overlay Example

Check out the animation below that has me illustrating how to create a workspace, how it gets overlaid on top of a base ROS Indigo install (behavior would be the same in Kinetic). Then I create a second workspace that overlays the first and show how the setup.bash files can be used to control which workspaces are active. Animation can also be accessed here, and here is a link to the custom function I use to clear out my ROS environment.

3 Resources

Catkin Tutorials
The official catkin tutorials on the ROS wiki. Also check out the official catkin documentation. The most valuable tutorial is likely the using a workspace tutorial.
demo_install_devel
This is a small package that I put together to demonstrate the differences between the install and devel result spaces. There is a README that contains detailed setup instructions and a few exercises to show the effects of using each different result space. Let me know if you have questions or issues.
Catkin Workspaces
The official documentation on catkin workspaces.
A Gentle Introduction to Catkin
This is a great walkthrough of CMake, Make, and Catkin written by Jonathan Bohren. It is for an older version of ROS, but basically everything he discusses still holds true today. Highly recommended reading.
Catkin Tools
This is a non-required package written by several core ROS developers to make working with catkin easier. This package is officially installed with sudo apt-get install python-catkin-tools. Basically, this package allows you much more powerful control over common operations in a workspace. It includes features like fine-grained building and cleaning of individual packages, dry runs that illustrate what would be built, stored profiles of common build configurations, and tools for managing workspace overlaying/underlaying. Caution, generally a given workspace can only be setup as a traditional catkin workspace or a catkin-tools workspace (not both). Since this tool was released, I've used it full-time, and I think it's great. However, since all of the documentation on the wiki is specifically based around the standard catkin package, I'm not going to recommend using this unless you are really interested in learning it just for the sake of learning it.
Environment Variables
This is the official documentation page on all of the environment variables that are used by ROS.
Networking Video
This is a great presentation that Austin Hendrix gave at ROSCon a few years ago focused on education users about networking in ROS.
Network Setup
This is a tutorial on the ROS wiki that describes how to setup the network and environment variables on two computers to allow ROS to communicate between the machines.
CMake Tutorial
CMake is the underlying build tool of catkin. Understanding how it works will make it much easier to understand the CMakeLists.txt files created in your packages. This tutorial is CMake's official tutorial on their site.
Creative Commons License
ME 495: Embedded Systems in Robotics by Jarvis Schultz is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.