Working With ROS pluginlib in ROS Noetic

2020-01-07-150618

In this tutorial, we’ll learn how to use ROS pluginlib.

What is ROS pluginlib?

Over the course of your work with ROS, there may be some situations where you want an application to have added functionality. However, you want that functionality to remain independent from the main application so that you can “plug it in” when you need it and unplug it when you don’t need it.

In short, the job of a plugin is to add some specific feature to an existing program.

The ROS pluginlib is a C++ library that enables you to load and unload plugins from within a package in ROS, giving your robot added capabilities.

How to Create and Load a Plugin

Let’s see how to create and load a plugin in ROS. We will follow the tutorial given on the ROS website.

What we’ll do is 

  • Create a base class for a polygon. This base class will be called RegularPolygon, and it will serve as the template for the plugins we’ll create.
  • Use that base class to create two new classes, Triangle and Square. These two classes inherit the properties of the RegularPolygon class.
  • Use pluginlib to register the Triangle and Square classes as plugins. 
  • Build the Plugin library using CMakeLists.txt.
  • Make the plugins available to ROS using a package.xml file.
  • Create a C++ program to actually use the plugins (Triangle and Square).
  • Run the code.

So those are all the steps. Let’s go through each step-by-step.

Open up a new terminal window, and create a new package.

cd ~/catkin_ws/src/
catkin_create_pkg pluginlib_tutorials_ roscpp pluginlib

Move into the pluginlib_tutorials_ package.

cd  pluginlib_tutorials_ 

Move into the include/pluginlib_tutorials_ folder.

Move into the directory.

cd include/pluginlib_tutorials_ 

Let’s create the RegularPolygon class.

gedit polygon_base.h

Copy and paste the following code into it.

#ifndef PLUGINLIB_TUTORIALS__POLYGON_BASE_H_
#define PLUGINLIB_TUTORIALS__POLYGON_BASE_H_

namespace polygon_base
{
  class RegularPolygon
  {
    public:
      virtual void initialize(double side_length) = 0;
      virtual double area() = 0;
      virtual ~RegularPolygon(){}

    protected:
      RegularPolygon(){}
  };
};
#endif

Save and close the editor.

Now let’s create our two plugins, Triangle and Square.

Open a new file, and copy and paste the code into it.

gedit polygon_plugins.h
#ifndef PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_
#define PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_
#include <pluginlib_tutorials_/polygon_base.h>
#include <cmath>

namespace polygon_plugins
{
  class Triangle : public polygon_base::RegularPolygon
  {
    public:
      Triangle(){}

      void initialize(double side_length)
      {
        side_length_ = side_length;
      }

      double area()
      {
        return 0.5 * side_length_ * getHeight();
      }

      double getHeight()
      {
        return sqrt((side_length_ * side_length_) - ((side_length_ / 2) * (side_length_ / 2)));
      }

    private:
      double side_length_;
  };

  class Square : public polygon_base::RegularPolygon
  {
    public:
      Square(){}

      void initialize(double side_length)
      {
        side_length_ = side_length;
      }

      double area()
      {
        return side_length_ * side_length_;
      }

    private:
      double side_length_;

  };
};
#endif

Click Save and close the editor.

Now let’s register the plugins we just created.  

Go to the src folder of the package.

roscd pluginlib_tutorials_/src

Create a new file named polygon_plugins.cpp.

gedit polygon_plugins.cpp

Copy and paste the following code into it.

#include <pluginlib/class_list_macros.h>
#include <pluginlib_tutorials_/polygon_base.h>
#include <pluginlib_tutorials_/polygon_plugins.h>

PLUGINLIB_EXPORT_CLASS(polygon_plugins::Triangle, polygon_base::RegularPolygon)
PLUGINLIB_EXPORT_CLASS(polygon_plugins::Square, polygon_base::RegularPolygon)

Save and close the editor.

Now let’s build the plugin library.

Go to your CMakeLists.txt file.

roscd pluginlib_tutorials_
gedit CMakeLists.txt

Add these two lines.

include_directories(include)
add_library(polygon_plugins src/polygon_plugins.cpp)

Save and close the editor.

Now compile the package.

cd ~/catkin_ws/
catkin_make

Let’s make the plugins available to ROS.

Go to your package.

roscd pluginlib_tutorials_

Create a new file.

gedit polygon_plugins.xml

Copy and paste the following code inside it.

<library path="lib/libpolygon_plugins">
  <class type="polygon_plugins::Triangle" base_class_type="polygon_base::RegularPolygon">
    <description>This is a triangle plugin.</description>
  </class>
  <class type="polygon_plugins::Square" base_class_type="polygon_base::RegularPolygon">
    <description>This is a square plugin.</description>
  </class>
</library>

Save and close the editor.

Go to the package.xml file.

gedit package.xml

Add this line between the <export> </export> tags at the bottom of the package.xml file.

  <pluginlib_tutorials_ plugin="${prefix}/polygon_plugins.xml" />

Save and close the editor.

Let’s check that everything is working properly. Type this command in your terminal window.

rospack plugins --attrib=plugin pluginlib_tutorials_

Here is what your output should look like:

24-here-is-what-output-should-look-likeJPG

Now, let’s create a C++ program that uses the plugin.

Go to the src file.

cd src

Open a new file.

gedit polygon_loader.cpp

Copy and paste the following code inside it.

#include <pluginlib/class_loader.h>
#include <pluginlib_tutorials_/polygon_base.h>

int main(int argc, char** argv)
{
  pluginlib::ClassLoader<polygon_base::RegularPolygon> poly_loader("pluginlib_tutorials_", "polygon_base::RegularPolygon");

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

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

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

  return 0;
}

Save and close the editor.

Now go to the CMakeLists.txt file.

cd ..
gedit CMakeLists.txt

Add these two lines to the bottom of the file.

add_executable(polygon_loader src/polygon_loader.cpp)
target_link_libraries(polygon_loader ${catkin_LIBRARIES})

Save and close.

Now we need to compile the code.

cd /~catkin_ws/
catkin_make

Let’s run the executable.

In a new terminal window, type:

roscore

In a new terminal tab, type:

rosrun pluginlib_tutorials_ polygon_loader

Here is the output:

25-here-is-the-outputJPG