RobWorkProject  21.8.23-
RobWork Plugins

# Introduction

RobWork is an extensible framework that allows addition of functionality through the use of plugins. Plugins can be dynamically loaded at runtime, and makes it possible to reduce the coupling and complexity. Furthermore, the framework provides the concept of lazily loaded plugins. Functionality in a lazy-loaded plugin will not be loaded before it is needed. To make the framework extensible, RobWork provides a bunch of ExtensionPoints . Each extension point has a unique identifier, and by referring to the identifier, it is possible for Extension(s) to extend the extension point. A Plugin can provide one or more extensions, and these do not need to be extensions for the same extension point. To keep track of all plugins and extensions, the ExtensionRegistry is used. On this page, some of the existing extension points and extensions will be discussed to give a better understanding of how they can be used to produce better and more modular code. After that, there is more in-depth examples of how a user can write a plugin that provides one or more extensions, and how this plugin is actually loaded and used in a program.

# Extension Points in the RobWork Framework

We will here try to give an overview of extension points currently available in the RobWork framework. Notice that the Extension Points group should always contain a up-to-date comprehensive list of all the extension points.

RobWork has various loaders, for XML files, images, geometry data and workcells. These are defined as extension points, such that the framework can be easily extended to support new formats and loaders.

Extension PointDescriptionKnown Extensions
rw::common::DOMParser::FactoryDifferent parsers understanding the Document Object Model.
• rw::common::BoostXMLParser

## Proximity

It is possible to use different strategies for detecting collisions and calculating distance between geometries. Typically the Proximity Query Package (PQP) is used. RobWork allows other algorithms to be supported by the framework, as there are extension points defined for each of the different proximity strategy types. Notice that the ProximityStrategy is a superclass of CollisionStrategy, CollisionToleranceStrategy, DistanceStrategy and DistanceMultiStrategy. An extension to any of the four subtypes, should therefore also be available in the ProximityStrategy extension point.

Extension PointDescriptionKnown Extensions
rw::proximity::ProximityStrategy::FactoryProximity strategies.
rw::proximity::CollisionStrategy::FactoryProximity strategies that supports the rw::proximity::CollisionStrategy interface.
rw::proximity::CollisionToleranceStrategy::FactoryProximity strategies that supports the rw::proximity::CollisionToleranceStrategy interface.
rw::proximity::DistanceMultiStrategy::FactoryProximity strategies that supports the rw::proximity::DistanceMultiStrategy interface.
rw::proximity::DistanceStrategy::FactoryProximity strategies that supports the rw::proximity::DistanceStrategy interface.

## Assembly Strategies

RobWork has a framework for defining assembly operations and the result of performing assembly operations. It is the intention that a library of different assembly strategies will be built with time. The framework can easily be extended with new user-specified control strategies using this extension point.

Extension Point Description
rwlibs::assembly::AssemblyRegistry Strategies for assembly rwlibs::assembly::AssemblyControlStrategy

## SWIG

The script interface can be extended with custom LUA commands, using the extension point for LUA.

Extension Point Known Extensions
rwlibs::swig::LuaState::Factory RobWork, RobWorkStudio and RobWorkSim all extends this extension point with their own LUA interfaces.

## Dynamic Simulation and Physics Engines

RobWorkSim defines an extension point for physics engines. This way it is possible to add new engines for dynamic simulation in a modular way. Furthermore, a hierarchic logging structure is provided for debugging simulation engines. As different engines can have different data that is relevant to log, the logging structure is extensible. On top of the logging structure, there is also a graphical layer, that can be extended with specific Qt widgets for graphical visualisation of the log. The engine test framework also allows extension with new custom tests.

Extension PointDescriptionKnown Extensions
rwsim::simulator::PhysicsEngine::FactoryPhysics engines rwsim::simulator::PhysicsEngine.
rwsim::log::SimulatorLogEntry::FactoryLogging types for simulators rwsim::log::SimulatorLogEntry, making it possible for specific physics engines to add more specific log types.
rwsimlibs::gui::SimulatorLogEntryWidget::Factoryrwsimlibs::gui::SimulatorLogEntryWidget::Dispatcher for a Qt Widget that is able to show a rwsim::log::SimulatorLogEntry graphically. Physics engines can make engine specific log types and graphical representation.
rwsimlibs::test::EngineTest::FactoryTests of physics engines rwsimlibs::test::EngineTest. Makes it possible to extend the test suite with new tests.

# Writing a Plugin - ImageLoader Example

Most plugins will have a very similar structure. In this example a plugin named MyPlugin is created, by implementing the rw::common::Plugin interface. The MyPlugin.hpp file will look as follows:

#include <rw/common/Plugin.hpp>
class MyPlugin: public rw::common::Plugin {
public:
MyPlugin();
virtual ~MyPlugin() {};
std::vector<rw::common::Extension::Descriptor> getExtensionDescriptors();
};

By default, RobWork has the ability to load images in PGM, PPM and RGB formats. If, for instance, a user needs support for JPG or JPEG formats, it is possible to implement the rw::loaders::ImageLoader interface with a specific loader for these formats. Assume that such an implementation, MyImageLoader, is already developed. Now, the user could just use this loader directly in its program. Instead, the loader should be provided in a plugin, as it will then be possible to use the loader in all programs based on the RobWork framework, such as RobWorkStudio. The implementation of the Plugin interface would then look similar to the following example:

#include "MyPlugin.hpp"
using namespace rw::common;
MyPlugin::MyPlugin():
Plugin("MyPlugin", "My Lovely Plugin", "1.0")
{
}
std::vector<Extension::Descriptor> MyPlugin::getExtensionDescriptors() {
std::vector<Extension::Descriptor> exts;
exts.back().getProperties().set<std::string>("JPG", true);
exts.back().getProperties().set<std::string>("JPEG", true);
return exts;
}
Extension::Ptr MyPlugin::makeExtension(const std::string& id) {
extension->getProperties().set<std::string>("JPG", true);
extension->getProperties().set<std::string>("JPEG", true);
return extension;
}
return NULL;
}

Compilation of the plugin will typically just require a couple of lines to be added to the CMakeLists.txt file:

TARGET_LINK_LIBRARIES(MyPlugin.rwplugin ${MyImageLoader_Library}${ROBWORK_LIBRARIES})

Notice that the MyPlugin.cpp should never be included in other targets than the MyPlugin.rwplugin target. If a target has source files containing more than one RW_ADD_PLUGIN definition, compilation will fail.

On Linux the plugin will have the name libMyPlugin.rwplugin.so. When this plugin is loaded dynamically, rw::loaders::ImageLoader::Factory will be able to provide a loader for the JPG and JPEG image formats. In fact, RobWorkStudio provides the rws::RWSImageLoaderPlugin that does exactly this for a wide range of image formats. The RWSImageLoaderPlugin basically uses Qt to load the images, and support the formats that Qt supports. This is an example of how the functionality of RobWork can be extended, without RobWork having to know about anything called Qt. Hence, dependencies are reduced, and code should be easier to maintain and modularize.

There are different ways to actually load the plugins after creation. RobWork will look in various default directories where it will try to load all libraries with the correct rwplugin extension. If plugins lie in other directories, the user must point RobWork to these plugins. Currently, RobWork will automatically do the loading. In the future this behaviour is likely to change, so if program is written that depends on plugins being loaded, an explicit statement should be used to initialize the RobWork framework.

Every program that needs to use plugins, should initialize RobWork in the main function using rw::RobWork::init() or rw::RobWork::init(int argc, const char *const * argv) :

#include <rw/RobWork.hpp>
int main(int argc, char** argv) {
RobWork::init(argc,argv);
...
return 0;
}

RobWork will automatically search for plugins using the first of the following rules that succeeds:

1. If the RW_ROOT environment variable is set, RW_ROOT, RWS_ROOT, RWIM_ROOT and RWHW_ROOT is used to search the libs directory for each project.
2. Else, if a configuration file exists with the name robwork-BUILD_TYPE-VERSION.cfg.xml (for instance robwork-release-0.7.0.cfg.xml), the directories specified in this file is used.
• First, the current working directory is used to look for the configuration file.
• Second, the home folder is searched, which is specific to the operating system.
• Windows: APPDATA/robwork/robwork-BUILD_TYPE-VERSION.cfg.xml
• Mac: HOME/Library/Preferences/com.robwork-BUILD_TYPE-VERSION.cfg.xml
• Linux: HOME/.config/robwork/robwork-BUILD_TYPE-VERSION.cfg.xml
3. Finally, the directory where RobWork was built is searched for libs folder for each of the projects RobWork, RobWorkStudio, RobWorkSim and RobWorkHardware. Notice that If additional directories are given with the –rwplugin program option, RobWork will also search in these directories.

ExtensionRegistry::Ptr reg = ExtensionRegistry::getInstance();
if (!plugin.isNull()) {
reg->registerExtensions(plugin);
}

When RobWork encounters finds files with the ending .rwplugin.so or .rwplugin.dll, it will try to load these plugins immediately. There can, potentially, be many plugins to load, which can take up unnecessary resources as they might not be needed by a specific application. For this reason, there is also the concept of lazy-loaded plugins. When RobWork encounters a file with the extension .rwplugin.xml, it will recognize this as a specification of a plugin that should only be loaded at the time where it is needed. To make a plugin lazy-loaded, create a file with a filename ending in .rwplugin.xml and give it a similar content as the following:

<?xml version="1.0" encoding="UTF-8" ?>
<plugin id="MyPlugin" name="My Lovely Plugin" version="1.0"
xmlns="http://www.robwork.dk/Plugin" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.robwork.dk/Plugin file:///path/to/RobWork/xml-schemas/rwxml_plugin.xsd">
<runtime library="/path/to/libMyPlugin.rwplugin.so" />
</plugin>

In this example, it is clear to see that the same meta-information is provided as in the extension descriptor discussed in Writing a Plugin - ImageLoader Example .

rw::core::Plugin::makeExtension
virtual rw::core::Ptr< Extension > makeExtension(const std::string &id)=0
get a specific extension using the unique extendion ID
rw::core::RobWork
RobWork instance which holds objects to be shared among multiple plugins.
Definition: core/RobWork.hpp:66
rw::core::Plugin
an interface for defining dynamically loadable plugins that define extensions and extension points.
Definition: core/Plugin.hpp:30
rw::core::Ptr::ownedPtr
Ptr< T > ownedPtr(T *ptr)
A Ptr that takes ownership over a raw pointer ptr.
Definition: core/Ptr.hpp:387
rw::core::Ptr
Ptr stores a pointer and optionally takes ownership of the value.