[ROS] How To Import a Python Module From Another Package

In this tutorial I’ll show you how to import a Python module from another package. ROS allows you to do that, and as you’ll see it’s quite simple.

If you have a package which contains some common tools, helper functions, utils, or other stuff like that, you may want to be able to write the code once in this package, and then be able to import it in any other package you create.

At the end of this tutorial you’ll be able to:

  1. Create a package which contains a Python module.
  2. Install this Python module in your ROS environment.
  3. In another package, import the previously created module and use it.

If you’re here, you might have already tried but were not successful, getting an error such as “ImportError: No module named another_package.module_to_import”.

Let’s fix that!

Note: this tutorial also works when you put all Python files in the same package, but in different folders. Ex: your node is in scripts/ and your Python module in src/package_name/, inside the same package. In this case you’ll also have issues when trying to import the module from your node.


You are learning ROS?

Check out ROS For Beginners and learn ROS step by step.


Related: For the Cpp version of this tutorial, check out how to import a Cpp header from another ROS package.

Setup a package with a Python module

Let’s first see how to organize your package’s internal structure. Here I’ll start a package from scratch so you get every details to make it work. For the ROS package I’ll use the name my_robot_common, which can be a good name for common tools required by several other packages.

Execute those commands to create all necessary files.

$ cd ~/catkin_ws/src
$ catkin_create_pkg my_robot_common rospy
$ cd my_robot_common
$ touch setup.py
$ mkdir -p src/my_robot_common
$ cd src/my_robot_common
$ touch __init__.py
$ touch import_me_if_you_can.py
  • Create a package my_robot_common with rospy as a dependency.
  • Inside this package, create a setup.py file. We’ll use this file to install the Python module.
  • Then, create a src/ folder (if not existing), and inside src/, create a folder with the same name as the package. You’ll put your module(s) here.
  • In this new folder, create an empty __init__.py file.
  • Finally, you can create all your Python modules files here.

At the end the my_robot_common package will look like that:

my_robot_common/
└── src
    └── my_robot_common
        ├── __init__.py
        └── import_me_if_you_can.py
├── CMakeLists.txt
├── package.xml
├── setup.py

Let’s first write the code/configuration for all files, and then install the Python module.

Write your Python module

Now, it’s your turn to write what you need to write in your Python module.

For the sake of simplicity, I’ll make it very short for this tutorial.

import rospy

def say_it_works():
    rospy.loginfo("Success! You just have imported a Python module in another package.")

Basically this module just contains one function that prints a success message. Perfect for our test.

You can let the __init__.py file empty.

Install the Python module in your ROS environment

setup.py

from distutils.core import setup
from catkin_pkg.python_setup import generate_distutils_setup

d = generate_distutils_setup(
    packages=['my_robot_common'],
    package_dir={'': 'src'}
)

setup(**d)

There are only two important lines here, the rest will be the same every time:

  • packages=['my_robot_common'],: name of your package (and also the name you used for the folder which contains the Python module).
  • package_dir={'': 'src'}: the folder where the module to install is located. Here we use ‘src’ because the module is inside the src/ folder of the my_robot_common package.

This code will be used to install your module. Note: don’t execute this script yourself! This will be done by catkin. (If you run the script yourself, the module will be installed in a different location, and thus you’ll have multiple installations of the same module, which is… not recommended).

CMakeLists.txt

cmake_minimum_required(VERSION 2.8.3)
project(my_robot_common)

find_package(catkin REQUIRED COMPONENTS
  rospy
)

catkin_python_setup()

catkin_package()

You can notice the catkin_python_setup(). This function will call the setup.py file that you created just before, so the installation can be done.

package.xml

<?xml version="1.0"?>
<package format="2">
  <name>my_robot_common</name>
  <version>0.0.0</version>
  <description>The my_robot_common package</description>
  <maintainer email="your@email.here">Your Name</maintainer>
  <license>TODO</license>

  <buildtool_depend>catkin</buildtool_depend>
  <exec_depend>rospy</exec_depend>

  <export>
  </export>
</package>

Here we have almost the minimum content we have to put in a package.xml file. You can see the <exec_depend>rospy</exec_depend>, because we are importing rospy in the code of the Python file.

For every ROS package or Python – non core – module you import, add a <exec_depend>module</exec_depend> here. Note: if you’re still using package.xml version 1 (<package format="1">), use <run_depend>module</run_depend> instead.

Install the Python module

All right, you have written all necessary code: the Python module itself, a setup.py file to install the module, a line in CMakeLists.txt to actually call setup.py, and the required dependencies in the package.xml.

Let’s now install the library. To do that, simply execute catkin_make in your catkin workspace folder.

$ cd ~/catkin_ws
$ catkin_make

Your Python module is now installed, you can use it from any other ROS package.

Use your module in another ROS package

Everything is now correctly setup, you should be able to use your module in any other package.

Important: before you try to import the module, make sure you have sourced the catkin_ws/devel/setup.bash file, either directly or from your “.bashrc” (source ~/.bashrc). This tip mostly applies when you’ve just installed the Python module, and you don’t understand why importing it from another package doesn’t work!

Here is a simple code for a ROS node that imports and uses the Python module.

#!/usr/bin/env python

import rospy
from my_robot_common.import_me_if_you_can import say_it_works

if __name__ == '__main__':
    rospy.init_node('test_node')
    say_it_works()

To import the module, you simply have to put the name of the ROS package where the module was installed, followed by the name of the file. That’s it!

If you run this node (call roscore in another terminal before):

$ rosrun my_robot_tutorials test_import.py 
[INFO] [1571557439.181637]: Success! You just have imported a Python module in another package.

It works!

You are now able to import a Python module from another package.

Important Note: if you place your main node into the scripts/ folder of your package, and a Python module in the src/your_package/ folder of this same package, the same rules apply. You’ll have to do all the previous steps, even if everything is in the same package.

Did you find this tutorial useful?

Do you want to learn how to program with ROS?

If yes, this course is for you:

ROS For Beginners - A Step By Step Course

>> ROS For Beginners - A Step By Step Course <<