ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

First of all, you probably want to use the recommended python style for ROS.

Assuming these files are ros nodes:

scripts/knex_arduino_connector.py
scripts/knex_scratch_connector.py
scripts/range_filter.py
scripts/range_to_laser.py

the package directory style I follow for a ros package looks like this:

knex_pkg/
    CMakesLists.txt
    package.xml
    launch/ # roslaunch files go here
    msg/ # msg files go here
    nodes/ # installable python nodes go here
        knex_arduino_connector.py
        knex_scratch_connector.py
        range_filter.py
        range_to_laser.py
    src/ # this is where your python modules exported as libraries or used in your nodes go.
    urdf/ # urdf and xacro files go here -- basically your robot model stuff, if any.
    scripts/ # generally non-exported python scripts -- stuff that might be called to setup your package and code gen stuff
    srv/ # service descriptions go here
    __init__.py # only necessary if you want to use anything from the scripts directory in your package src and node files
    setup.py # more on this later

In your CMakesLists.txt you need to add a catkin_python_setup()(Handling of setup.py) line after your find_package() calls and before your service, message generation, and add messages calls:

cmake_minimum_required(VERSION 2.8.3)
project(knex_ros)

find_package(catkin REQUIRED COMPONENTS
  rospy
  std_msgs
  tf
  roscpp
  robot_state_publisher
  differential_drive
)
catkin_python_setup()
...

setup.py is the python distutils setup script. It's where you describe the structure of a python package. The python style guide for ros is pretty specific in how python packages should be layed out. Any modules used should go under src. If you are like me, and like a clearly defined source tree structure with directories as package names, your setup.py will look something like this:

## ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD

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

# fetch values from package.xml
setup_args = generate_distutils_setup(
    packages=['my_package],
    package_dir={'': 'src'},
    requires=['std_msgs', 'rospy', 'message_filters', 'gps_common', 'sensor_msgs']
)

setup(**setup_args)

In setup_args you are defining your package by calling generate_distutils_setup.

The packages argument is an array of package names. Use dot-delimited format (my_package.subpackage) if you wish to explicitly name more than one package. I generally just use one package root and let distutils figure it out from there, and I think this is the simplest practice.

The package_dir arg allows you to specify a source directory for a package name. If you have only one package, then you can omit the package name and give a relative path to the directory containing the modules for that package. If you follow the style guide, that directory will be src. If you have multiple packages in different source directories, you can specify them in this dictionary.

The requires arg is an array of python package names that are required by your package(s). In my example setup.py above, I use std_msgs so I've included it in the list. You will probably always have rospy. I don't think this is explicitly required for ros packages, but I think it is good practice to list them here.

The directory structure under src is important for the setup.py to work properly. If you have a package named my_package with submodules my_submodule_a and my_submodule_b, you need to set it up like this:

my_package/ # the root of the ros package
    setup.py
    src/
        my_package/ # here's your python module root
            __init__.py # put your python code for my_package here.
            my_submodule_a/ # I prefer directories for submodules, but some prefer just a python file named my_submodule_a.py instead
                __init__.py # this is your my_package.my_submodule_a source file.
            my_submodule_b/
                __init__.py # this is your my_package.my_submodule_b source file.

catkin_python_setup will allow you to use the modules in src in your executable node files by importing them from the my_package namespace. Similarly, service descriptions and msgs can be imported from this same namespace -- for example:

#!/usr/bin/env python
import rospy
import roslib
roslib.load_manifest('my_package')

from std_msgs.msg import Header
from my_package.msg import MyMsg
import my_package.my_submodule_a

def run_my_node():
    init_node("my_package_node")
    spin()

if __name__ == "__main__":
    run_my_node()

Don't forget to mark your nodes as executable with chmod +x nodes/my_package_node.py!

I recommend setting up roslaunch launch files for your nodes, and parameterizing any arguments to them with the ros parameter server. You can set up any number of launch files and stack them together by using the include tag in other launch files. Then run them with roslaunch my_package_name my_launchfile_name.launch. It works out very nicely.

After you've done all that, update your installables in your CMakesList.txt and you should get a better result.

First of all, you probably want to use the recommended python style for ROS.

Assuming these files are ros nodes:

scripts/knex_arduino_connector.py
scripts/knex_scratch_connector.py
scripts/range_filter.py
scripts/range_to_laser.py

the package directory style I follow for a ros package looks like this:

knex_pkg/
    CMakesLists.txt
    package.xml
    launch/ # roslaunch files go here
    msg/ # msg files go here
    nodes/ # installable python nodes go here
        knex_arduino_connector.py
        knex_scratch_connector.py
        range_filter.py
        range_to_laser.py
    src/ # this is where your python modules exported as libraries or used in your nodes go.
    urdf/ # urdf and xacro files go here -- basically your robot model stuff, if any.
    scripts/ # generally non-exported python scripts -- stuff that might be called to setup your package and code gen stuff
    srv/ # service descriptions go here
    __init__.py # only necessary if you want to use anything from the scripts directory in your package src and node files
    setup.py # more on this later

In your CMakesLists.txt you need to add a catkin_python_setup()(Handling of setup.py) line after your find_package() calls and before your service, message generation, and add messages calls:

cmake_minimum_required(VERSION 2.8.3)
project(knex_ros)

find_package(catkin REQUIRED COMPONENTS
  rospy
  std_msgs
  tf
  roscpp
  robot_state_publisher
  differential_drive
)
catkin_python_setup()
...

setup.py is the python distutils setup script. It's where you describe the structure of a python package. The python style guide for ros is pretty specific in how python packages should be layed out. Any modules used should go under src. If you are like me, and like a clearly defined source tree structure with directories as package names, your setup.py will look something like this:

## ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD

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

# fetch values from package.xml
setup_args = generate_distutils_setup(
    packages=['my_package],
packages=['my_package'],
    package_dir={'': 'src'},
    requires=['std_msgs', 'rospy', 'message_filters', 'gps_common', 'sensor_msgs']
)

setup(**setup_args)

In setup_args you are defining your package by calling generate_distutils_setup.

The packages argument is an array of package names. Use dot-delimited format (my_package.subpackage) if you wish to explicitly name more than one package. I generally just use one package root and let distutils figure it out from there, and I think this is the simplest practice.

The package_dir arg allows you to specify a source directory for a package name. If you have only one package, then you can omit the package name and give a relative path to the directory containing the modules for that package. If you follow the style guide, that directory will be src. If you have multiple packages in different source directories, you can specify them in this dictionary.

The requires arg is an array of python package names that are required by your package(s). In my example setup.py above, I use std_msgs so I've included it in the list. You will probably always have rospy. I don't think this is explicitly required for ros packages, but I think it is good practice to list them here.

The directory structure under src is important for the setup.py to work properly. If you have a package named my_package with submodules my_submodule_a and my_submodule_b, you need to set it up like this:

my_package/ # the root of the ros package
    setup.py
    src/
        my_package/ # here's your python module root
            __init__.py # put your python code for my_package here.
            my_submodule_a/ # I prefer directories for submodules, but some prefer just a python file named my_submodule_a.py instead
                __init__.py # this is your my_package.my_submodule_a source file.
            my_submodule_b/
                __init__.py # this is your my_package.my_submodule_b source file.

catkin_python_setup will allow you to use the modules in src in your executable node files by importing them from the my_package namespace. Similarly, service descriptions and msgs can be imported from this same namespace -- for example:

#!/usr/bin/env python
import rospy
import roslib
roslib.load_manifest('my_package')

from std_msgs.msg import Header
from my_package.msg import MyMsg
import my_package.my_submodule_a

def run_my_node():
    init_node("my_package_node")
    spin()

if __name__ == "__main__":
    run_my_node()

Don't forget to mark your nodes as executable with chmod +x nodes/my_package_node.py!

I recommend setting up roslaunch launch files for your nodes, and parameterizing any arguments to them with the ros parameter server. You can set up any number of launch files and stack them together by using the include tag in other launch files. Then run them with roslaunch my_package_name my_launchfile_name.launch. It works out very nicely.

After you've done all that, update your installables in your CMakesList.txt and you should get a better result.