Every plugin needs to export several functions as defined in Plugin Export Functions to notify OpenRAVE what interfaces it has. When a plugin is first loaded, it is validated by the environment and its OpenRAVEGetPluginAttributes function will be called in order so the OpenRAVE core can register the names of its provided interfaces. Plugins themselves can query functionality offer by other plugins through the environment's interface querying functions.
Example plugincpp.cpp creates a OpenRAVE::ModuleBase interface named MyModule and have it offer two commands: numbodies and load.
The first #include the compiler sees has to be openrave/openrave.h. Then for the main C++ file, we include openrave/plugin.h for several helper functions.
Now register the two commands of the module. boost::bind
is necessary for specifying member functions as callbacks.
Provide the implementations for the member functions:
It is recommend to plugin authors to include openrave/plugin.h in their main C++ file, this will provide implementations for the export functions and ask the user to provide a new set of functions CreateInterfaceValidated and GetPluginAttributesValidated.
Providing MyModule would look like:
In order to tell OpenRAVE what is provided, have to define:
The main build system of OpenRAVE is cmake, and FindOpenRAVE.cmake can be used to find the OpenRAVE installation. An example of the CMakeLists.txt
file for compiling a plugin using FindOpenRAVE.cmake is:
cmake_minimum_required (VERSION 2.6) project (plugincpp) find_package(OpenRAVE REQUIRED) include_directories(${OpenRAVE_INCLUDE_DIRS}) link_directories(${OpenRAVE_LIBRARY_DIRS}) add_library(plugincpp SHARED plugincpp.cpp) set_target_properties(plugincpp PROPERTIES COMPILE_FLAGS "${OpenRAVE_CXX_FLAGS}" LINK_FLAGS "${OpenRAVE_LINK_FLAGS}") target_link_libraries(plugincpp ${OpenRAVE_LIBRARIES})
If not using CMake, then here's how the development files are organized:
Linux Users
Depending on where openrave was installed, a openrave-config should have been created in the $OPENRAVE_INSTALL/bin
directory. It is possible to call openrave-config –cflags
to get the correct paths and flags to include in gcc to link with libopenrave.so
.
There are several ways to load the generated plugin.
openrave --listplugins
openrave --loadplugin $SOMEPATH/libplugincpp openrave --loadplugin $SOMEPATH/libplugincpp.so openrave --loadplugin ./libplugincpp.sowhere
$SOMEPATH
is the absolute/relative path of the shared object.RaveLoadPlugin('plugincpp')Octave
orEnvLoadPlugin('plugincpp');
Once the plugin is loaded, we can create the interface and call its commands to load an environment and return the number of bodies:
C++
Python
prob = RaveCreateModule(env,'MyModule') env.AddModule(prob,args='') cmdout = prob.SendCommand('load data/lab1.env.xml') if cmdout is None: raveLogWarn('command failed!') else: cmdout = prob.SendCommand('numbodies') print 'number of bodies are: ',cmdout
Octave (only simple commands possible)
prob = orEnvCreateProblem('MyModule'); orProblemSendCommand('load data/lab1.env.xml',prob); numbodies = orProblemSendCommand('numbodies',prob); disp(['number of bodies are: ' num2str(numbodies)])
The format of all interface documentation is the widely adopted standard reStructuredText. The description of an interface and all information about its usage should be provided by two places:
These descriptions are automatically parsed using Sphinx and put on the web.
The reason why doxygen and other commenting tools are not adopted for plugin documentation is because the Base Interface Classes are the only binding between plugins. Even if the header file or provided functions of a particular plugin were provided, other plugins would not be able to use them if not offered through the OpenRAVE's channels.
Many mechanisms have been put in place to prevent mismatching/old plugins to be loaded by the core. Using interfaces from stale plugins can lead to unexpected crashes that are very difficult to debug. It is possible to automatically come up with a unique hash of the interface functions and members by running each interface through a C++ lexer and then creating a 128bit unique md5 hash. In order to protect plugins compiled with a different version, OpenRAVE creates a md5 hash from each interface class definition using cpp-gen-md5 and stores them in openrave/interfacehashes.h.
The interface hash can be retrieved using OpenRAVE::RaveGetInterfaceHash. For an interface to be loaded successfully, the plugin has to check that the hash the core is using matches the hash compiled with the plugin. These types of checks ensure that stale plugins will never be loaded; helper functions are offered in openrave/plugin.h, which all plugin authors should use.