Version: This tutorial is mainly for ROS Electric and earlier. While this is a valid way of wrapping libraries for ROS Fuerte, the best practice is to no longer wrap thirdparty libraries and instead install to a filesystem prefix. For more information, see the release documentation of bloom/Tutorials/ReleaseThirdParty

(!) Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags.

Wrapping an external library in ROS

Description: This tutorial explains how to package an external library for ROS.

Tutorial Level: INTERMEDIATE

You've found a great open-source robotics library, but there are no ROS packages for it yet. This tutorial will help you write wrappers for this package so that you can start using it with the rest of your ROS code.

This isn't a typical step-by-step tutorial: each external library you wrap in ROS will be a little different. We will, however, go over the basic steps and options that exist when creating these wrappers.

Create the Package

Please follow the creating a package tutorial to learn the basics of running roscreate-pkg. As we are wrapping an external library, the process is simpler:

roscreate-pkg your_package_name

Remember that ROS packages names have to start with a letter and should use underscores "_" instead of dashes "-".

Create the Makefile

NOTE: For now, we do most of our external library using make and Makefiles. In the future we will be switching over to use CMake.

You need to remove the CMakeLists.txt file as we will not need it:

rm CMakeLists.txt

Instead, we're going to just modify the Makefile. The mk package contains Makefile include files that let you automate the task of downloading external libraries. There are both options for downloading from tarball, as well as SVN, but we prefer tarballs.

Why? Although we support fetching the libraries directly from SVN source trees, we've found SVN servers to be too unreliable. They are also slower, and checkouts are larger.

Here is an example use of the download_unpack_build.mk include file for the "paramiko" library that handles most of the tarball fetching for us.

all: paramiko

TARBALL = build/paramiko-1.7.5.tar.gz
TARBALL_URL = http://pr.willowgarage.com/downloads/paramiko-1.7.5.tar.gz
SOURCE_DIR = build/paramiko-1.7.5
MD5SUM_FILE = paramiko-1.7.5.tar.gz.md5sum
UNPACK_CMD = tar xzf
include $(shell rospack find mk)/download_unpack_build.mk

paramiko: $(SOURCE_DIR)/unpacked
        mkdir -p src
        cd $(SOURCE_DIR) && python setup.py build 
        rm -rf src
        mv `python find_pylib.py paramiko $(SOURCE_DIR)/build/` src
        touch paramiko
clean:
        -rm -rf src $(SOURCE_DIR) paramiko
wipe: clean
        -rm -rf build

Most of this is boilerplate, though the 'paramiko' target contains the main code that you will need to write to integrate your library. Note that it depends on $(SOURCE_DIR)/unpacked, which means it will execute after the tarball has been extracted.

You will have to write your own version of this target, which does three main things:

  1. Build the downloaded source.
  2. Move the necessary build artifacts out of the build/ subdirectory. ROS installation tools assume it is safe to delete the build/ subdirectory.

  3. Make sure that the package does not rebuild (e.g. touch paramiko).

These are the variables you can set when using the download_and_unpack.mk include file:

  • TARBALL: local path to which the tarball should be downloaded; it must start with build/

  • TARBALL_URL: fully-qualified URL from which to retrieve the tarball

  • SOURCE_DIR: source directory that you want the tarball unpacked into; it must start with build/

  • INITIAL_DIR (optional): the name that the tarball will naturally unpack into, if different from SOURCE_DIR; it must start with build/

  • UNPACK_CMD (optional): the command to apply to the tarball to unpack it (default: tar xzf)

  • MD5SUM_FILE (optional, but highly recommended): The name of a file containing the md5 hash of the tarball, in the format produced by the UNIX command md5sum

  • TARBALL_PATCH (optional): a list of patch files to apply to the tarball after unpacking

After including download_unpack_build.mk, you can make targets depend on the $(SOURCE_DIR)/unpacked file; it will be created (and updated) after the tarball has been downloaded, unpacked, and (optionally) patched.

You can find other examples by examining the source of these packages:

Setup your code exports

Now that you've made sure your package can build, you'll have to make sure that the library is exported to other ROS packages. How you setup these exports depends on the language your library is written in.

C++ example

For C++, you will need to modify the <export> section of the manifest.xml file. In this export, you declare the cflags and lflags that you want others to use.

Here is an example from the bullet library:

  <export>
    <cpp cflags="-I${prefix}/include -DBT_USE_DOUBLE_PRECISION -DBT_EULER_DEFAULT_ZYX" lflags="-L${prefix}/lib -Wl,-rpath,${prefix}/lib -lBulletDynamics -lBulletCollision -lLinearMath" />
  </export>

Python example

You do not need to do any additional setup for Python if:

  1. Binary libraries (e.g. .so) go into lib

  2. Python files go into src

These are the default locations for Python binary libraries and source files.

If change this, you can use an the <export> section of your manifest.xml to setup your own Python sys.path modifications:

  <export>
    <python path="${prefix}/different_dir"/>
  </export>

Linking to external documentation

Most external libraries have their own documentation. In order to help users use this documentation directly, we need to tell the rosdoc tool where it is. This is as simple as adding <rosdoc> tag to the <export> section of the package's manifest.xml:

<export>
  <rosdoc external="http://link/to/api/docs" />
</export>

Final Advice

One final word of advice: try to keep any ROS-specific source code out of the package. It's nice to have a 'pure' version of the library to use, and it also makes it easier to upgrade the underlying library separately.

Wiki: ROS/Tutorials/Wrapping External Libraries (last edited 2013-03-18 08:08:09 by TullyFoote)