All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends
Creating Python bindings for a new planner

It is often convenient to test a planner through either the OMPL.app GUI or by using a minimal Python program that defines a simple motion planning problem of interest. In both cases you need to create Python bindings for your planner. We will use RRT* as an example planner to illustrate the steps involved. All the relevant code can be found in ompl/src/ompl/contrib/rrt_star. At a high level, the steps are:

Attention
Please note that it is difficult to create Python bindings for multi-threaded planners. The problem is that only one thread at a time can access the Pyhton interpreter. If a user creates an instance of a Python class derived from, e.g., ompl::base::StateValidityChecker or ompl::control::StatePropagator, the C++ code may call the Python interpreter simultaneously from multiple threads. In this case you need to modify you planner so that when called from Python it always runs in a single thread. In some cases, such as the ompl::geometric::PRM planner, this can be difficult. For PRM we wrote a special single-threaded version of the solve function (see ompl/py-bindings/PRM.SingleThreadSolve.cpp) that is used in the Python bindings instead of the default multi-threaded solve method.

Directory/file structure

It is a good idea to keep Python binding files separate from the rest of the code. For RRT* we have created a subdirectory called py-bindings. Within this directory, we use the following layout:

  • CMakeLists.txt - Build system file to generate and compile the python binding code, explained below
  • generate_bindings.py - A script that relies on the OMPL python module and Py++. It is fairly straightforward to tweak this file for your planners by replacing RRTstar and BallTreeRRTstar with the names of your planners. If you have a control-based planner, replace occurrences of geometric with control.
  • headers_rrtstar.txt - A plain text file that simply contains a list of all header files, one per line, for which Python bindings need to be generated.
  • ompl/rrtstar/__init__.py - Typically, this is a minimal module initialization file that just imports all the symbols of the binary module that will be created after compilation. It is, of course, possible to add any additional classes or functions that you might need.

Using the OMPL CMake macros

We have written our own CMake macros for generating python bindings. Although the RRT* code is distributed with OMPL, it should be possible to use the CMake macros even if your project simply uses OMPL as a dependency. You have to make sure that the macros are in the CMake module path by adding a line like this to your CMakeLists.txt:

set(CMAKE_MODULE_PATH "/path/to/ompl/CMakeModules")

The main steps to create python bindings in your own CMakeLists.txt are then:

include(PythonBindingUtils)
# path to python module
set(OMPL_RRTSTAR_BINDINGS_DIR "...")
# create target "update_rrtstar_bindings" to generate binding code
create_module_generation_targets(rrtstar "${CMAKE_CURRENT_SOURCE_DIR}")
# create target "py_ompl_rrtstar" to compile generated code
create_module_target(rrtstar ${CMAKE_CURRENT_SOURCE_DIR} "${OMPL_RRTSTAR_BINDINGS_DIR}/ompl")

Please look at py-bindings/CMakeLists.txt for a complete example.

Using your planner in Python (including the OMPL.app GUI)

As long as your planner derives from ompl::base::Planner, you can use your planner in Python just like any other planner:

1 from ompl import geometric, rrtstar
2 ...
3 ss = geometric.SimpleSetup(space)
4 planner = rrtstar(ss.getSpaceInformation())
5 ss.setPlanner(planner)
6 ...

Optionally, you can add your planners to the list of known geometric (or control-based) planners:

1 from ompl import geometric, rrtstar
2 import ompl
3 ompl.initializePlannerLists()
4 geometric.planners.addPlanner('ompl.rrtstar.RRTstar')
5 geometric.planners.addPlanner('ompl.rrtstar.BallTreeRRTstar')

This is already done in ompl_app.py for RRT*, but you can easily add similar lines for your own planners. Doing so will allow you to select your planners in the GUI.

Planner parameters

The OMPL Planner class a method called ompl::base::Planner::declareParam to define parameters that can be changed by the user. It is highly recommended that you use this method for all your planner parameters. It is possible to specify a suggested range of values as an optional argument to ompl::Planner::declareParam. This range will be used by the OMPL.app GUI to create the appropriate controls, so that users can change the parameter values through the GUI. See ompl::base::GenericParam::rangeSuggestion_ for the syntax used to specify parameter ranges.