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
.msgand.srvfiles into code that can be called frompythonorc++ - Under the hood,
catkinuses cmake to generate build files. Thus, each package has a CMakeLists.txt file that is used bycmaketo configure the package. cmakeis a build-system generator. Catkin usescmaketo generateMakefiles. It then usesmaketo build your package.catkinalso usespackage.xmlto 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_makein the workspace builds it - A catkin workspace consists of four sub-directories
srcThis is the directory with all of your packages.- Each subdirectory of
srcis usually agitrepository containing one or more package. - This is the only directory containing files that you edit.
- The
srcdirectory is sometimes referred to as the source space.
- Each subdirectory of
buildAll the files generated bycmakego heredevelThe compiled files go here when thecatkinbuild tool has been run. This directory is often called the devel space. There are also scripts andinstallIf you install your packages (which can be done viacatkin_make install, the files are placed in the install directory. Ideally, theinstalldirectory 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_makeafter every change.- However, I recommend running
catkin_makeas a matter of course when debugging
- However, I recommend running
- The
installspace can be used to create and distribute your package as a binary. The ROS packages that you install usingapthave 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_makeThis 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_isolatedusesdevel_isolatedandinstall_isolatedfor the development and install spaces (respectively).catkin toolscan 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.bashfiles - When you installed ROS, you should have added
source /opt/ros/melodic/setup.bashto your.bashrcThis 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.bashin your.bashrcso 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_makeit 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_makeand 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 rospythenrospyshould 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_pkgis 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_packageline to include the name of yourcatkin packagedependencies - If you use custom
.msgor.srvfiles, there are further lines to uncomment so that the proper code will be generated. There are also lines inpackage.xmlthat should be edited. - If you were using C++, you would need to add files to the
add_executablestatement to compile your nodes, and theadd_librarystatement to compile your libraries. - There is a section in the auto-generated
CMakeLists.txtdedicated 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 python3and 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.txtand${ros_pkg}/package.xmlmarks a directory as a ROS package ${ros_pkg}/scriptsexecutable python scripts (useful utility scripts, not run as nodes).${ros_pkg}/nodesexecutable python nodes (do not end with.pyextension)- The distinction between
scriptsandnodesis not made in all packages, and is somewhat of a preference- Usually
scriptsis used for executable code that is not a ROS node - In ROS, Python nodes start with a
#!/usr/bin/env pythonand do not end in a.pyextension (generally). - They must be installed with
catkin_install_pythonin theCMakeLists.txt
- Usually
${ros_pkg}/srccontains python packages and C++ code.${ros_pkg}/msgMessage definitions${ros_pkg}/srvService 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.xmlfrom 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.pyand import it asimport ${py_pkg}.module catkintakes care of the python path for you. If you have trouble importing a module, it is likely an issue with thecatkinsetup
- 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
pythoninterpreter and work with it interactively - It is easier to test
- It is easier to document (
sphinx autodocgenerally 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
catkinmachinery required to generate messages in general - Make
catkinaware of all of the dependencies of your message/service - Tell
catkinto process your message/service files and turn them intoC++andpythoncode that can be used in your programs.
package.xml
- You must
<build_depend>onmessage_generation: this ROS package generates the required code from.msgand.srvfiles - 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.msgor.srvrequire- Any type that is not one of the built-in types (listed here) is specified
as
<pkg>/Typein the.msgor.srvfile. 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
CMakeaware 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
CMakeabout the files you want to generate- Uncomment
add_message_filesandadd_service_filesas needed. - These functions expect your
.msgfiles to be in<pkg>/msgand.srvfiles to be in<pkg>/srv
- Uncomment
- Tell
CMaketo generate the code- Uncomment the
generate_messagesline and add any message dependencies to theDEPENDENCIESin that call
- Uncomment the
- Add
message_runtimeand your message dependencies tocatkin_package(CATKIN_DEPENDS). This line enables othercatkinpackages 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.txtandpackage.xmlhave the required information and are synchronized. - Install via
apt install python-catkin-lint - There is much redundancy between
package.xmlandCMakeLists.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.xmlThis will have consequences when distributing your package, such asrosdepnot being aware of all dependencies. - The procedure to add custom messages and services is quite tedious, but
catkin_lintnot 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 srcwill 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 --explainoption
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 ROSpart filters for variables containing the word ROS - A scrollable list of environment variables is obtained using
env | less. Presshfor help andqfor quit. - The value of an individual variable can be printed using
printenv VARNAME unset VARNAMEclears 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
exportline to~/.bashrcThe commands in~/.bashrcare run whenever your shell (the program that runs your commands entered at the command-line) starts. Thus every time you open theTerminalthe variables that you set in.bashrcwill 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.bashin your~/.bashrcsets the ROS variables to their initial values every time you startbash. - When you activate the workspace using
source devel/setup.bashyou are primarily setting environment variables related to ROS ROS_ROOTstores the path to the core ROS packagesROS_MASTER_URIstores the location of rosmaster. By default this ishttp://localhost:11311.PYTHONPATHthis tells python where to find packages. Sourcingdevel/setup.bashsets 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_PATHtells 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_HOSTNAMEOptional variables used for running nodes over the network.ROS_IPspecifies the ip address for a node that is launched andROS_HOSTNAMEspecifies the hostname for a node that is launched. Never set both of these asROS_HOSTNAMEoverridesROS_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_PATHis 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. rosdeprelies 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
-sflagrosdepwill tell you what it will install without actually doing it.