Catkin and Packages
Catkin, the build system for ROS
- catkin is used to build ROS packages
- In-depth documentation is here
- By following examples you can "get it working" with catkin, but there are many subtleties
- Reading the documentation is important for learning the proper way to package programs
- The build process consists of compiling code and converting
.msg
and.srv
files into code that can be called frompython
orc++
- Under the hood,
catkin
uses cmake to generate build files. Thus, each package has a CMakeLists.txt file that is used bycmake
to configure the package. cmake
is a build-system generator. Catkin usescmake
to generateMakefiles
. It then usesmake
to build your package.catkin
also usespackage.xml
to resolve dependencies during installation and make sure that packages are built in the correct order. Most dependencies need to be listed both inCMakeLists.txt
(so they can be used during the build process) and inpackage.xml
(so they can be used by the installation process and other ROS tools).
Catkin Workspaces
- Catkin uses workspaces to find your packages
- Calling
catkin_make
in the workspace builds it - A catkin workspace consists of four sub-directories
src
This is the directory with all of your packages.- Each subdirectory of
src
is usually agit
repository containing one or more package. - This is the only directory containing files that you edit.
- The
src
directory is sometimes referred to as the source space.
- Each subdirectory of
build
All the files generated bycmake
go heredevel
The compiled files go here when thecatkin
build tool has been run. This directory is often called the devel space. There are also scripts andinstall
If you install your packages (which can be done viacatkin_make install
, the files are placed in the install directory. Ideally, theinstall
directory contains a full directory tree with all the files that come with your project and are needed to run your program. This is called the install space.
install
vs devel
- Both spaces (referred to as result spaces) contain files generated from the build
- The devel space is designed for quick iteration during development while install is for releases.
- The devel space can use different compilation flags (such as debugging) than the install space
- The devel space is configured to access python scripts directly from the
src
. This means you don't need to rebuild every time your python code changes. With the install space, you would need to runcatkin_make
after every change.- However, I recommend running
catkin_make
as a matter of course when debugging
- However, I recommend running
- The
install
space can be used to create and distribute your package as a binary. The ROS packages that you install usingapt
have been built by the ROS build farm and packaged as binaries from the install space. - In this class, we will mostly be using the devel space.
Building the Workspace
There are three ROS 1 tools that can be used to build the workspace.
catkin_make
This is the original tool and the one referred to most commonly. It is fast because it combines all the packages in the workspace into a single CMake project before compiling. We will use this because most documentation still refers to it and it is the fastest.catkin_make_isolated
: This tool was created due to REP-0134. Essentially, this builds each package as separate CMake projects, enabling projects that do not use catkin but rather just use CMake to be built as well. Some projects only build using this tool, and there is a slight preference for it.catkin_make_isolated
usesdevel_isolated
andinstall_isolated
for the development and install spaces (respectively).catkin tools
can be installed withapt install python3-catkin-tools
.- It has the cleanest interface of the methods. This tool is technically in Beta and development has stopped; however it works well in practice.
Creating a workspace
- Workspaces can be created using
mkdir -p <ws_name>/src
. When you run the build tool for the first time, the result spaces will be created. - It makes sense to have separate workspaces for every project you are working on.
Activating Workspaces
- Workspaces are activated by sourcing their
setup.bash
files - When you installed ROS, you should have added
source /opt/ros/melodic/setup.bash
to your.bashrc
This line, conceptually, activates a workspace containing all ROS packages that have been installed globally on your system. - Multiple workspaces can be activated at once. This is called overlaying. See workspace_overalying for details
- If multiple workspaces have the same packages, the package in the latest activated workspace takes precedence
- To activate your workspace (in particular your devel space),
source devel/setup.bash
(this is what you will usually do) - You can also activate the install space using
source install/setup.bash
. - Usually, you will have only two workspaces active, the global system workspace and the one you are working on.
It is recommended to
source /opt/ros/melodic/setup.bash
in your.bashrc
so the global workspace is always active - However, the overlay mechanism allows for advanced uses where different packages/versions can be mixed and matched. This feature is useful when, for example, trying to fix a bug in a package that is already installed on your system
- We may also use this feature if we need to compile some basic ROS packages that are not yet released for
noetic
- ROS workspaces remember the state they were in when you built the workspace (e.g., ran
catkin_make
)- When you run
catkin_make
it generates the setup script (e.g.setup.bash
). This script sets your ROS path (i.e.,CMAKE_PREFIX_PATH
) to contain all the paths already on it at the time of runningcatkin_make
and a path to the current workspace. - Therefore, you need to make sure you have all workspaces you need sourced prior to running
catkin_make
.
- When you run
Modifying existing packages
Sometimes, ROS packages have bugs and you want to help fix them. Sometimes you need a new feature or slightly different behavior from a different package. The workspace mechanism provides a useful means of handling this case without needing to modify your base system.
- Clone the repository you want to work on into the source space of a workspace.
- Your packages that depend on that package will now use the compiled version, not the version installed on your system.
- Modify the source code to suit your needs.
- You can now submit a patch or, if the project is on github, you can fork the main repository, push your changes to your fork, and submit a pull request.
Packages
Creating
You create a package using catkin_create_pkg
.
After using this command, you usually need to edit the package.xml
and CMakeLists.txt
.
package.xml
The package.xml
is a file describing meta-data about the package.
It is an XML document,
which is specified here.
There is also more information about how to properly write a package.xml
in the catkin documentation.
Required elements:
<name>
The package name<version>
The package Version<description>
A description of the package<maintainer>
One or more people who are responsible for the package<license>
One or more legal ways the package may be distributed
Dependencies
There are multiple types of dependencies. The most important are
<exec_depend>
- Packages needed at runtime. If your python package imports code from another package, or a launchfile runs a node from another package, then it should be an<exec_depend>
, thus this is the most common dependency for a python-only package.- For example, if you
import rospy
thenrospy
should be anexec_depend
- For example, if you
<build_depend>
- Package needed at build time. In python, code is not compiled, so you usually do not need this. An exception is when you depend upon messages or services in another package.
<depend>
- This is the most common dependency type for a C++ package. It should also be used by python packages when depending on packages containing custom messages such asstd_msgs
. Using<depend>
automatically creates an<exec_depend>
and a<build_depend>
(also a<build_export_depend>
). In python especially, whenever you have a<build_depend>
you almost always also have an<exec_depend>
, so you can just use<depend>
.
CMakeLists.txt
- Information on the CMakeLists.txt is found here.
- The file generated by
catkin_create_pkg
is well commented, so reading the file helps explain what you need to do. - Change the line with
find_package(catkin REQUIRED COMPONENTS <dependencies>...)
so that the <dependencies> match whatever is declared as a<depend>
in yourpackage.xml
- You should also change the
catkin_package
line to include the name of yourcatkin package
dependencies - If you use custom
.msg
or.srv
files, there are further lines to uncomment so that the proper code will be generated. There are also lines inpackage.xml
that should be edited. - If you were using C++, you would need to add files to the
add_executable
statement to compile your nodes, and theadd_library
statement to compile your libraries. - There is a section in the auto-generated
CMakeLists.txt
dedicated to installation. Lines in this section must be modified to properly be able to install your package. For each python node and executable script, you should add
catkin_install_python(PROGRAMS nodes/prog1 nodes/prog2 ... DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
- This allows you to start your python scripts with the shebang
#!/usr/bin/env python3
and have catkin replace it with the proper shebang for the system.
- This allows you to start your python scripts with the shebang
Package Layout
For a ROS packages, the general layout is as follows, where ${ros_pkg}
is the base directory of the package
- The presence of two files,
${ros_pkg}/CMakeLists.txt
and${ros_pkg}/package.xml
marks a directory as a ROS package ${ros_pkg}/scripts
executable python scripts (useful utility scripts, not run as nodes).${ros_pkg}/nodes
executable python nodes (do not end with.py
extension)- The distinction between
scripts
andnodes
is not made in all packages, and is somewhat of a preference- Usually
scripts
is used for executable code that is not a ROS node - In ROS, Python nodes start with a
#!/usr/bin/env python
and do not end in a.py
extension (generally). - They must be installed with
catkin_install_python
in theCMakeLists.txt
- Usually
${ros_pkg}/src
contains python packages and C++ code.${ros_pkg}/msg
Message definitions${ros_pkg}/srv
Service definitions
Python Packages
- ROS packages can contain one or more python packages. This is useful to allow the distribution of python packages that are tightly related to your ROS code
- Let
${ros_pkg}
be the name of a ROS package, and${py_pkg}
be the name of the python package. - Python packages go under
${ros_pkg}/src/${py_pkg}
. Each ROS package can contain multiple python packages. - Create your python package under
${ros_pkg}/src/${py_pkg}
. Everything in${py_pkg}
works as it does for any other python package. Create a
${ros_pkg}/setup.py
. It looks like the following and reads information from thepackage.xml
from setuptools import setup from catkin_pkg.python_setup import generate_distutils_setup d = generate_distutils_setup( packages=['${py_pkg}'], package_dir={'': 'src'} ) setup(**d)
- Uncomment the
catkin_python_setup()
line inCMakeLists.txt
${ros_pkg}/src/${py_pkg}
is just like any other python package- It has a
src/<pkg>/__init__.py
, which can be a blank file most of the time - The package can be imported with
import ${py_pkg}
. - You can define a python module as
src/${py_pkg}/module.py
and import it asimport ${py_pkg}.module
catkin
takes care of the python path for you. If you have trouble importing a module, it is likely an issue with thecatkin
setup
- It has a
- Moving code into a python package (as opposed to leaving all code in the node) has several advantages
- You can import it into the
python
interpreter and work with it interactively - It is easier to test
- It is easier to document (
sphinx autodoc
generally only documents packages not executable python files)
- You can import it into the
- See the catkin documentation for more details:
Custom Messages and Services
To create custom ROS message and service types, edit CMakeLists.txt
and package.xml
.
Conceptually there are three pieces required to generate messages and services:
- Bring in all of the
catkin
machinery required to generate messages in general - Make
catkin
aware of all of the dependencies of your message/service - Tell
catkin
to process your message/service files and turn them intoC++
andpython
code that can be used in your programs.
package.xml
- You must
<build_depend>
onmessage_generation
: this ROS package generates the required code from.msg
and.srv
files - You must
<exec_depend>
onmessage_runtime
: this ROS package allows your code to use custom messages at runtime - You must
<depend>
on any of the packages that your.msg
or.srv
require- Any type that is not one of the built-in types (listed here) is specified
as
<pkg>/Type
in the.msg
or.srv
file. These<pkg>
names are the dependencies
- Any type that is not one of the built-in types (listed here) is specified
as
CMakeLists.txt
- Make
CMake
aware of message generation and your message dependencies- Modify the
find_package(catkin REQUIRED)
line to list these dependencies as components - It should look like
find_package(catkin REQUIRED message_generation <dep1> ... <depn>)
, where the dependencies are the dependencies for the messages that you want to generate
- Modify the
- Tell
CMake
about the files you want to generate- Uncomment
add_message_files
andadd_service_files
as needed. - These functions expect your
.msg
files to be in<pkg>/msg
and.srv
files to be in<pkg>/srv
- Uncomment
- Tell
CMake
to generate the code- Uncomment the
generate_messages
line and add any message dependencies to theDEPENDENCIES
in that call
- Uncomment the
- Add
message_runtime
and your message dependencies tocatkin_package(CATKIN_DEPENDS)
. This line enables othercatkin
packages to easily import your messages - See the ROS tutorial on Creating ROS msg and srv.
catkin lint
- catkin_lint is a tool used to help check that your
CMakeLists.txt
andpackage.xml
have the required information and are synchronized. - Install via
apt install python-catkin-lint
- There is much redundancy between
package.xml
andCMakeLists.txt
, and these files must be kept synchronized- It is very easy, for example, to require a dependency in CMakeLists.txt but not put it in your
package.xml
This will have consequences when distributing your package, such asrosdep
not being aware of all dependencies. - The procedure to add custom messages and services is quite tedious, but
catkin_lint
not only detects errors in this setup but often tells you exactly what you need to do to fix them.
- It is very easy, for example, to require a dependency in CMakeLists.txt but not put it in your
catkin_lint src
will check all the packages in your source space, or you can check an individual package by providing the path to that package- I recommend using this tool on all your packages and fixing any errors it points out
- Most of the time, your package, especially if written in python, will work even if failing these checks; however, heeding checks helps ensure that other people won't have problems when trying to use your package.
- You can see an explanation for the warnings with the
catkin_lint --explain
option
Environment Variables
Environment Variables are used in Linux to control the behavior of programs.
Environment Variable Basics
- See all environment variables using
env
- See all ROS environment variables using
env | grep ROS
, the| grep ROS
part filters for variables containing the word ROS - A scrollable list of environment variables is obtained using
env | less
. Pressh
for help andq
for quit. - The value of an individual variable can be printed using
printenv VARNAME
unset VARNAME
clears an environment variable.The value can also be retrieved by prefixing the name with a
$
.> export VAR = 2 > echo "Hello $VAR" Hello 2
- Each terminal has a different set of variables. Changing a variable in one terminal does not affect the other terminals.
- To set an environment variable "globally", add an
export
line to~/.bashrc
The commands in~/.bashrc
are run whenever your shell (the program that runs your commands entered at the command-line) starts. Thus every time you open theTerminal
the variables that you set in.bashrc
will be set. - For more information see Linux Introduction
ROS Environment Variables
ROS relies on several environment variables to work.
- Running
source /opt/ros/melodic/setup.bash
in your~/.bashrc
sets the ROS variables to their initial values every time you startbash
. - When you activate the workspace using
source devel/setup.bash
you are primarily setting environment variables related to ROS ROS_ROOT
stores the path to the core ROS packagesROS_MASTER_URI
stores the location of rosmaster. By default this ishttp://localhost:11311
.PYTHONPATH
this tells python where to find packages. Sourcingdevel/setup.bash
sets this up properly for use with ROS. Modifying the python path to fix a problem is likely the incorrect action when using ROS.CMAKE_PREFIX_PATH
tells CMake where to find everything required to build a cmake project. This is also used by catkin to find all of your packages and is set bysetup.bash
.ROS_IP/ROS_HOSTNAME
Optional variables used for running nodes over the network.ROS_IP
specifies the ip address for a node that is launched andROS_HOSTNAME
specifies the hostname for a node that is launched. Never set both of these asROS_HOSTNAME
overridesROS_IP
. If the computer you are running nodes on is accessible via hostname lookup from other computers on your network, you do not need to set these at all.- My recommendation is to always set up the network properly.
- When buying a router, find one supported by https://openwrt.org/, which automatically allows name resolution on a local network.
- If all computers in a network run the
avahi-daemon
, then they should be able to resolve each other as<hostname>.local
.
ROS_PACKAGE_PATH
is a legacy variable that is not actually used; however, it will show the paths to your overlayed workspaces and is useful for debugging
rosdep
rosdep is ROS's tool for installing system dependencies and released ROS packages.
- It is installed with
sudo apt install python3-rosdep
. rosdep
relies on keys, generic names for packages that it can then download using various system package managers.- The list of keys is defined according to the rosdep YAML specification.
- The YAML files for each ROS distribution are stored here
- To automatically install system dependencies for a package whose source code you have downloaded
you would do
rosdep install --from-paths <workspace>/src --ignore-src --rosdistro=melodic
. - If you add the
-s
flagrosdep
will tell you what it will install without actually doing it.