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.
- It used to be rosbuild. If you see commands floating around on the wiki
that involve
- 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 theCMakeLists.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 justcatkin_make
. This directory has its own "setup" files independent of thedevel
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:
- 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 thecatkin_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 thedevel
space, and then when we want to actually use the code that we've compiled, we could switch over to theinstall
space. - 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 ofdpkg
/apt-get
). - Python packages are handled quite differently when using the
devel
vs. theinstall
space. In thedevel
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 thesrc
directory of a workspace. This means that we can edit any Python script in thesrc
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 theinstall
space; in the install space, we'd have to re-runcatkin_make install
every time we edit any Python code. One common use case for theinstall
directory is to build Python C/C++ extensions using a setup.py file. As mentioned above, the
install
targets are used by the build farm when creating deb packages that can be installed viaapt-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 specialinstall
target that caused the launch file to be "installed" when runningcatkin_make install
. Effectively this would likely just copy the launch file to a location that ROS searches for launch files when "sourcing" thesetup.bash
file from theinstall
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 theturtlebot_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 theturtlesim
package's CMakeLists.txt file. Here they ensure that all of thesvg
andpng
files that are included in theimages
directory are added to the package when installed. On my system, I have theturtlesim
package installed fromapt-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
- There are other common shells people use in Linux/Unix:
- "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 abovesource
command - the dot at the beginning of the filename denotes this file as a "hidden file"
ls
won't show this file without anls -a
- in Nautilus (the built-in file browser)
C-h
will to toggle visibility of hidden files
- This file can be re-ran by "sourcing" it i.e.
- 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
orless
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
- "Pipe" to
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
orROS_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 theROS_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 theROS_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.
- 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.
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/
anddevel/
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
anddevel
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.