UP | HOME

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 from python or c++
  • Under the hood, catkin uses cmake to generate build files. Thus, each package has a CMakeLists.txt file that is used by cmake to configure the package.
  • cmake is a build-system generator. Catkin uses cmake to generate Makefiles. It then uses make to build your package.
  • catkin also uses package.xml to resolve dependencies during installation and make sure that packages are built in the correct order. Most dependencies need to be listed both in CMakeLists.txt (so they can be used during the build process) and in package.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 a git 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.
    • build All the files generated by cmake go here
    • devel The compiled files go here when the catkin build tool has been run. This directory is often called the devel space. There are also scripts and
    • install If you install your packages (which can be done via catkin_make install, the files are placed in the install directory. Ideally, the install 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 run catkin_make after every change.
    • However, I recommend running catkin_make as a matter of course when debugging
  • The install space can be used to create and distribute your package as a binary. The ROS packages that you install using apt 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.

  1. 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.
  2. 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 uses devel_isolated and install_isolated for the development and install spaces (respectively).
  3. catkin tools can be installed with apt 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 running catkin_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.

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.

  1. 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.
  2. Modify the source code to suit your needs.
  3. 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 then rospy should be an exec_depend
  • <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 as std_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 your package.xml
  • You should also change the catkin_package line to include the name of your catkin 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 in package.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 the add_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.

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 and nodes 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 the CMakeLists.txt
  • ${ros_pkg}/src contains python packages and C++ code.
  • ${ros_pkg}/msg Message definitions
  • ${ros_pkg}/srv Service definitions

Python Packages

  1. 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
  2. Let ${ros_pkg} be the name of a ROS package, and ${py_pkg} be the name of the python package.
  3. Python packages go under ${ros_pkg}/src/${py_pkg}. Each ROS package can contain multiple python packages.
  4. Create your python package under ${ros_pkg}/src/${py_pkg}. Everything in ${py_pkg} works as it does for any other python package.
  5. Create a ${ros_pkg}/setup.py. It looks like the following and reads information from the package.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)
    
  6. Uncomment the catkin_python_setup() line in CMakeLists.txt
  7. ${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 as import ${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 the catkin setup
  8. Moving code into a python package (as opposed to leaving all code in the node) has several advantages
    1. You can import it into the python interpreter and work with it interactively
    2. It is easier to test
    3. It is easier to document (sphinx autodoc generally only documents packages not executable python files)
  9. 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:

  1. Bring in all of the catkin machinery required to generate messages in general
  2. Make catkin aware of all of the dependencies of your message/service
  3. Tell catkin to process your message/service files and turn them into C++ and python code that can be used in your programs.

package.xml

  1. You must <build_depend> on message_generation: this ROS package generates the required code from .msg and .srv files
  2. You must <exec_depend> on message_runtime: this ROS package allows your code to use custom messages at runtime
  3. 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

CMakeLists.txt

  1. 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
  2. Tell CMake about the files you want to generate
    • Uncomment add_message_files and add_service_files as needed.
    • These functions expect your .msg files to be in <pkg>/msg and .srv files to be in <pkg>/srv
  3. Tell CMake to generate the code
    • Uncomment the generate_messages line and add any message dependencies to the DEPENDENCIES in that call
  4. Add message_runtime and your message dependencies to catkin_package(CATKIN_DEPENDS). This line enables other catkin packages to easily import your messages
  5. 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 and package.xml have the required information and are synchronized.
  • Install via apt install python-catkin-lint
  • There is much redundancy between package.xml and CMakeLists.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 as rosdep 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.
  • 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. Press h for help and q 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 the Terminal 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 start bash.
  • 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 packages
  • ROS_MASTER_URI stores the location of rosmaster. By default this is http://localhost:11311.
  • PYTHONPATH this tells python where to find packages. Sourcing devel/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 by setup.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 and ROS_HOSTNAME specifies the hostname for a node that is launched. Never set both of these as ROS_HOSTNAME overrides ROS_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 flag rosdep will tell you what it will install without actually doing it.

Author: Matthew Elwin