1 Introduction
Pluginlib is a C + + library that can be implemented as a dynamic load and unload plugin for a ROS package. The plug-ins here are usually functional classes and exist in the form of libraries that are dynamically loaded at run time, such as shared objects, dynamic-link libraries. With Pluginlib's help, users don't have to worry about how their application links to libraries that contain the class they want to use (such as where and how the header file defines the class), Because Pluginlib will automatically open the plugin library you need when you call it (Note: You need to register the plugin library with Pluginlib in advance). Using plug-ins to extend or modify the functionality of the application is very convenient, without changing the source code to recompile the application, through the dynamic loading of plug-ins to complete the extension and modification of the function.
2 Plugin Authoring
Pluginlib takes advantage of C + + polymorphism, and different plug-ins can be replaced using a unified interface. This allows the user to invoke the unified interface functions implemented in the plug-in, do not need to change the program, do not need to recompile, replace the plug-in to achieve functional correction.
The method of writing plug-ins with pluginlib roughly includes the following four steps: Create a plug-in base class, define a unified interface (if you write a plug-in for an existing interface, skip that step), write the plug-in class, inherit the plug-in base class, implement the unified interface export plug-in, and compile the plugin into a dynamic library. Make it recognizable and manageable
2.1 Creating a plug-in base class
First, create the workspace, as shown below
Next, start to write the plug-in base class, the base class header file Polygon_base.h placed under Include/my_plugin_test can be,
#ifndef polygon_base_h_
#define Polygon_base_h_
namespace Polygon_base
{
class polygon{
public :
Polygon () {};
Virtual ~polygon () {};
virtual void init (float side_len) = 0;
Virtual float area () = 0;
};
};
#endif
2.2 Creating a plug-in class
The header file of the plug-in class Polygon_plugin.h is placed in the Include/my_plugin_test directory.
#ifndef polygon_plugin_h_
#define Polygon_plugin_h_
#include <cmath>
#include <my_plugin_test /polygon_base.h>
namespace polygon_plugin{
class Square:public polygon_base::P olygon{public
:
Square () {};
Virtual ~square () {};
virtual void init (float side_len)
{
This->side_len = Side_len;
}
Virtual float area ()
{
return (Side_len * side_len);
}
Private:
float Side_len;
};
Class Triangle:public Polygon_base::P olygon{public
:
Triangle () {};
Virtual ~triangle () {};
virtual void init (float side_len)
{
This->side_len = Side_len;
}
Virtual float area ()
{
return 0.5 * (Side_len * (sqrt (Side_len * side_len)-(0.5 * side_len) * (0.5 * Side_len) ) ) ) );
}
Private:
float Side_len;};
};
#endif
3 Exporting the plugin and compiling it as a dynamic-link library
3.1 Exporting plugins
Use the macro actions provided by the Pluginlib Library to register the plug-in and compile it as a dynamic-link library.
Add Polygon_plugin.cpp in the SRC directory,
#include <pluginlib/class_list_macros.h>
#include <my_plugin_test/polygon_base.h>
#include <my_plugin_test/polygon_plugin.h>
//mark Square and Triangle as the exported class
Pluginlib_export_ CLASS (Polygon_plugin::triangle, polygon_base::P olygon)
Pluginlib_export_class (Polygon_plugin::square, Polygon_base::P Olygon)
If you want the class to be dynamically loaded, you must mark it as an exportable class. You can complete the export with a specific macro pluginlib_export_class, which is usually placed at the bottom of the CPP file. The first parameter of this macro is the full name of the plug-in class (including namespace), and the second parameter is the full name of the plug-in base class (including namespace).
3.2 Compiling as a dynamic link library
To compile the plug-in as a dynamic-link library, you need to modify the CMakeLists.txt file accordingly, adding the following lines:
Include_directories (
include
${catkin_include_dirs}
)
# # Declare a C + + library
add_library ( Polygon_plugin
src/${project_name}/polygon_plugin.cpp
)
4 Add plugins to the ROS system to identify and manage
4.1 Creating a plug-in description file
The plug-in profile is an XML-formatted file that stores important information about the plug-in (e.g., plug-in library path, plug-in name, plug-in class type, plug-in base class type).
We create a file named Polygon_plugin.xml in the My_plugin_test directory,
<library path= "Lib/libpolygon_plugin" >
<class type= "Polygon_plugin::triangle" base_class_type= " Polygon_base::P olygon ">
<description>this is a triangle plugin.</description>
</class >
<class type= "Polygon_plugin::square" base_class_type= "Polygon_base::P olygon" >
<description >this is a square plugin.</description>
</class>
</library>
Here the Tag Library and its properties path define the path to the main package relative to the plug-in library, and a plug-in library can contain several different plug-in classes (2 plug-in classes, for example).
The tag class here describes the plug-in class in the plug-in library, the attribute type specifies the type of the plug-in class (must be the full name), the attribute base_class_type specifies the type of the plug-in base class (must full name), and the property description describes the functionality of the plug
Note: The plugin description file also has a label class_libraries is not used here, it can be implemented in a plug-in description file containing multiple libraries, the tag has no attributes.
4.2 Registering plugins to the ROS system
To ensure that pluginlib can find all the plugins in the Ros system, the package that defines the plug-in must explicitly specify which packages are exported.
This is usually defined in the package.xml file,
<export>
<my_plugin_test plugin= "${prefix}/polygon_plugin.xml" >
</export>
Here the label My_plugin_test is the package name that defines the plug-in base class, and the property plugin is the plug-in descriptor file defined earlier.
Note: If the plug-in class is not in the same package as the base class, you must also add a dependency on the package that contains the plug-in base class in order for the plugin's export to take effect.
<build_depend>my_plugin_test</build_depend>
<run_depend>my_plugin_test</run_depend >
5 Check plugin can be viewed under Ros
After the Catkin_make executes successfully, source Develop/setup.bash, and then run the following command if the output polygon_plugin.xml is correctly seen OK.
Rospack Plugins--attrib=plugin My_plugin_test
6 Calling plug-ins
6.1 Create My_plugin_loader.cpp
in the SRC directory
#include <ros/ros.h> #include <pluginlib/class_loader.h> #include <my_plugin_test/polygon_base.h>
int main (int argc, char * * argv) {ros::init (argc, argv, "My_plugin_loader");
Ros::nodehandle NH;
float Side_len = 5.0;
std::string param_name = "Polygon_plugin";
Std::string Plugin_class;
if (!nh.getparam (Param_name.c_str (), Plugin_class)) {ros_error ("can ' t get param");
return 0;
}/** * Define plugin Loader object (polygon_loader) for loading my plugin. * Param1:the Path of plugin package, param2:the base class of plugin class with full name */pluginlib::classloader<
;p olygon_base::P olygon> polygon_loader ("My_plugin_test", "Polygon_base::P Olygon"); try {/*based on input param to create the corresponding plugin instance by classloader*/Boost::shared_ptr<polygo
N_base::P olygon> polygon_cal = polygon_loader.createinstance (Plugin_class);
Polygon_cal->init (Side_len); Ros_info ("Plugin class is%s, area is%f", pLugin_class.c_str (), Polygon_cal->area ());
}/*catch Exception Classlaoder object (Polygon_loader) exception*/catch (pluginlib::P luginlibexception& ex) { Ros_error ("The plugin failed to load for some reason.
Error:%s ", Ex.what ());
} return 0; }
6.2 modifying CMakeLists.txt, adding
# # Declare A C + + executable
add_executable (my_plugin_loader src/my_plugin_loader.cpp)
# # Add CMake target Dependencies of the executable
# Same as for the library above
# add_dependencies (My_plugin_test_node ${${projec T_name}_exported_targets} ${catkin_exported_targets})
# # Specify libraries to link a library or executable target Aga Inst
target_link_libraries (my_plugin_loader
${catkin_libraries}
)
6.3 Creating a startup file
Create the Launch folder in the My_plugin_test directory to add files My_plugin_loader.launch
<launch>
<!--plugin select-->
<!--<param name= "Polygon_plugin" value= "Polygon_plugin: : Square "/>--
<param name=" Polygon_plugin "value=" Polygon_plugin::triangle "/>
<node Name = "My_plugin_loader" pkg= "My_plugin_test" type= "My_plugin_loader" output= "screen"/>
</launch>
The final directory workspace directory structure looks like this:
6.4 Testing
mode one: through the startup file
roslaunch my_plugin_test my_plugin_loader.launch
Output:
... logging To/home/siriansu/.ros/log/f05ccba8-a4a7-11e6-9012-001fc69be782/roslaunch-siriansu-nuc-24328.log
Checking log directory for disk usage. This could take awhile.
Press Ctrl-c to interrupt
Done checking log file disk usage. Usage is <1GB.
Started Roslaunch server http://siriansu-nuc:40746/
SUMMARY
========
PARAMETERS
*/polygon_plugin:polygon_plugin::t ...
*/rosdistro:kinetic
*/rosversion:1.12.5
NODES
/
My_plugin_loader (My_plugin_test/my_plugin_loader)
ros_master_uri=http://localhost:11311
Core Service [/rosout] found
PROCESS[MY_PLUGIN_LOADER-1]: Started with PID [24346]
[INFO] [1478842570.904729245]: Plugin class is Polygon_plugin::triangle, area is 10.825317
[My_plugin_loader-1] process has finished cleanly
Log file:/home/siriansu/.ros/log/f05ccba8-a4a7-11e6-9012-001fc69be782/my_plugin_loader-1*.log
All processes on machine has died, roslaunch'll exit
Shutting down processing monitor ...
... shutting down processing monitor complete
Done
mode two: command line mode
Rosparam Set Polygon_plugin Polygon_plugin::square
Rosrun my_plugin_test My_plugin_loader
Output:
[INFO] [1478842687.012935017]: Plugin class ispolygon_plugin::square, area is25.000000
Rosparam Set Polygon_plugin Polygon_plugin::triangle
Rosrun my_plugin_test My_plugin_loader
Output:
[INFO] [1478844657.917205466]: Plugin class ispolygon_plugin::triangle, area is10.825317