[Documentation] [TitleIndex] [WordIndex

Overview

pluginlib is a C++ library for loading and unloading plugins from within a ROS package. Plugins are dynamically loadable classes that are loaded from a runtime library (i.e. shared object, dynamically linked library). With pluginlib, one does not have to explicitly link their application against the library containing the classes -- instead pluginlib can open a library containing exported classes at any point without the application having any prior awareness of the library or the header file containing the class definition. Plugins are useful for extending/modifying application behavior without needing the application source code.

Example

To understand how pluginlib works, let's consider a small example. First, suppose that a ROS package exists containing a polygon base class ("polygon_interface package"). Let's also say that there are two different kinds of polygons supported in the system: a rectangle which lives in the "rectangle_plugin" package and a triangle that lives in the "triangle_plugin" package. The implementers of both the rectangle_plugin and triangle_plugin packages would include special export lines in their package.xml file telling the build system that they intend to provide plugins for the polygon class in the polygon_interface package. These export lines, in effect, register the classes with the ROS build/packaging system. This means that someone wishing to see all polygon classes available in the system can run a simple rospack query which will return a list of available classes, in this case, rectangle and triangle.

pluginlib/plugin_model.png

Providing a Plugin

Registering/Exporting a Plugin

In order to allow a class to be dynamically loaded, it must be marked as an exported class. This is done through the special macro PLUGINLIB_EXPORT_CLASS. This macro can be put into any source (.cpp) file that composes the plugin library, but is usually put at the end of the .cpp file for the exported class. For the example above, we might create a class_list.cpp file in package 'example_pkg' that looks as follows and compile it into the librectangle library:

   1 #include <pluginlib/class_list_macros.h>
   2 #include <polygon_interface/polygon.h>
   3 #include <rectangle_plugin/rectangle.h>
   4 
   5 //Declare the Rectangle as a Polygon class
   6 PLUGINLIB_EXPORT_CLASS(rectangle_namespace::Rectangle, polygon_namespace::Polygon)

The Plugin Description File

The plugin description file is an XML file that serves to store all the important information about a plugin in a machine readable format. It contains information about the library the plugin is in, the name of the plugin, the type of the plugin, etc. If we consider the rectangle_plugin package discussed above, the plugin description file (e.g. rectangle_plugin.xml), would look something like this:

<library path="lib/librectangle">
  <class type="rectangle_namespace::Rectangle" base_class_type="polygon_namespace::Polygon">
  <description>
  This is a rectangle plugin
  </description>
  </class>
</library>

For a detailed description of plugin description files and their associated tags/attributes please see the following documentation.

Why Do We Need This File

We need this file in addition to the code macro to allow the ROS system to automatically discover, load, and reason about plugins. The plugin description file also holds important information, like a description of the plugin, that doesn't fit well in the macro.

Registering Plugin with ROS Package System

In order for pluginlib to query all available plugins on a system across all ROS packages, each package must explicitly specify the plugins it exports and which package libraries contain those plugins. A plugin provider must point to its plugin description file in its package.xml inside the export tag block. Note, if you have other exports they all must go in the same export field.

Considering the rectangle_plugin package again, the relevant lines would look as follows:

<export>
  <polygon_interface plugin="${prefix}/rectangle_plugin.xml" />
</export>

For a detailed discussion of exporting a plugin, please see the following documentation.

In order for the above export command to work properly, the providing package must depend directly on the package containing the plugin interface. For example, the rectangle_plugin must have the line below in its catkin/package.xml:

  <build_depend>polygon_interface</build_depend>
  <run_depend>polygon_interface</run_depend>

Querying ROS Package System For Available Plugins

One can query the ROS package system via rospack to see which plugins are available by any given package. For example:

rospack plugins --attrib=plugin nav_core

This will return all plugins exported from the nav_core package.

Using a Plugin

pluginlib provides a ClassLoader class available in the class_loader.h header that makes it quick and easy to use provided classes. For detailed documentation of the code-level API for this tool please see pluginlib::ClassLoader documentation. Below, we'll show a simple example of using the ClassLoader to create an instance of a rectangle in some code that uses a polygon:

   1 #include <pluginlib/class_loader.h>
   2 #include <polygon_interface/polygon.h>
   3 
   4 //... some code ...
   5 
   6 pluginlib::ClassLoader<polygon_namespace::Polygon> poly_loader("polygon_interface", "polygon_namespace::Polygon");
   7 
   8 try
   9 {
  10   boost::shared_ptr<polygon_namespace::Polygon> poly = poly_loader.createInstance("rectangle_namespace::Rectangle");
  11 
  12   //... use the polygon, boost::shared_ptr will automatically delete memory when it goes out of scope
  13 }
  14 catch(pluginlib::PluginlibException& ex)
  15 {
  16   //handle the class failing to load
  17   ROS_ERROR("The plugin failed to load for some reason. Error: %s", ex.what());
  18 }

Important Note: The ClassLoader must not go out scope while you are using the plugin. So, if you are loading a plugin object inside a class, make sure that the class loader is a member variable of that class.

Changes from Pre-Groovy pluginlib

Simplified Export Macro

Prior to pluginlib 1.9 (Groovy), the macros PLUGINLIB_REGISTER_CLASS and PLUGINLIB_DECLARE_CLASS were used to register exported classes. These have been deprecated in favor of the new PLUGINLIB_EXPORT_CLASS. The new macro is simpler as it only takes two arguments.

A script has been provided with pluginlib which can be run in the root of your source folder to automatically update the legacy macros to utilize the new one:

 plugin_macro_update

Legacy "Lookup Name"

Pre-Groovy versions of pluginlib required specifying a "lookup name" for exported classes in both the plugin description file and export macro. This lookup name acted as an alias for the true class name -- the true class name was not used in the user facing interface. The reason why this lookup alias was used instead of the real name was due to a technical limitation in older versions.

One can now use the real name of a class instead of the lookup name. However, if users want to still use the lookup name, they can add it in their plugin description file. For example:

<library path="lib/librectangle">
  <class name="rviz/Rectangle" type="rectangle_namespace::Rectangle" base_class_type="polygon_namespace::Polygon">
  <description>
  This is a rectangle plugin
  </description>
  </class>
</library>

pluginlib will now utilize "rviz/Rectangle" instead of "rectangle_namespace::Rectangle" to refer to the class. The real class name cannot be used to refer to the class if a lookup name alias is used. If no lookup name is provided, the lookup name and true class name are equivalent.

Report a Bug


2023-10-28 12:52