Files
Main/99 Work/0 OneSec/OneSecNotes/30 Engineering Skills/Robotics/ROS2/ROS2 - Pluginlib.md

4.1 KiB
Raw Blame History

The Pluginlib is a library for ROS2 that allows a very modular development. It is heavily used in the ROS2 - NAV2 Library Library. From the pluginlib tutorial:

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, you do not have to explicitly link your 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.

Basically it allows to define an abstract base class that defines the interface of the plugin. It defines what functions (virtual) need to be overwritten and what variables are there. You can then derive multiple packages with different implementations of this plugin base class which is used by an executor function. Those plugins can then be loaded at runtime without prior knowledge about them because they follow the same structure.

Requirements:

  1. Constructor without parameters -> use initialization function instead.
  2. Make header available to other classes
    1. Add the following snippet to CMakeLists.txt:
install(
   DIRECTORY include/
   DESTINATION include
)
...
ament_export_include_directories(
  include
)
  1. In the c++ file where you define your plugins you need to add the following macro at the very end. This creates the plugin instances when the corresponding library is loaded.
#include <pluginlib/class_list_macros.hpp>

PLUGINLIB_EXPORT_CLASS(polygon_plugins::Square, polygon_base::RegularPolygon)
PLUGINLIB_EXPORT_CLASS(polygon_plugins::Triangle, polygon_base::RegularPolygon)
  1. The plugin loader needs some information to find the library and to know what to reference in the libary. Thus an xml-file needs to be written as well as an export line in the package.xml file. With those 2 additions ROS knows everything it needs to know in order to use the plugins. In the following snippets we have the two Plugins: Square and Triangle defined in a plugin.xml file.
<library path="polygon_plugins">
  <class type="polygon_plugins::Square" base_class_type="polygon_base::RegularPolygon">
    <description>This is a square plugin.</description>
  </class>
  <class type="polygon_plugins::Triangle" base_class_type="polygon_base::RegularPolygon">
    <description>This is a triangle plugin.</description>
  </class>
</library>
# polygon_base: package with base class
# plugins.xml: relative path to plugin file defined above
pluginlib_export_plugin_description_file(polygon_base plugins.xml)

How to use the plugins The plugins can be used in any package that you want

#include <pluginlib/class_loader.hpp>
#include <polygon_base/regular_polygon.hpp>

int main(int argc, char** argv)
{
  // To avoid unused parameter warnings
  (void) argc;
  (void) argv;

  pluginlib::ClassLoader<polygon_base::RegularPolygon> poly_loader("polygon_base", "polygon_base::RegularPolygon");

  try
  {
    std::shared_ptr<polygon_base::RegularPolygon> triangle = poly_loader.createSharedInstance("polygon_plugins::Triangle");
    triangle->initialize(10.0);

    std::shared_ptr<polygon_base::RegularPolygon> square = poly_loader.createSharedInstance("polygon_plugins::Square");
    square->initialize(10.0);

    printf("Triangle area: %.2f\n", triangle->area());
    printf("Square area: %.2f\n", square->area());
  }
  catch(pluginlib::PluginlibException& ex)
  {
    printf("The plugin failed to load for some reason. Error: %s\n", ex.what());
  }

  return 0;
}

Important note: the polygon_base package in which this node is defined does NOT depend on the polygon_plugins class. The plugins will be loaded dynamically without any dependency needing to be declared. Furthermore, were instantiating the classes with hardcoded plugin names, but you can also do so dynamically with parameters, etc.