1. 概述
pluginlib是一个C++库,用来从ROS包中加载或者卸载插件。插件是一个动态的可加载的类,能够从运行时库(也就是分享的物体,动态链接库)中进行加载。有了pluginlib,不需要显式的将他们的应用程序和包含他们类的库进行链接,pluginlib可以在任何时候打开一包含导出类的库,而不需要应用程序预先知道库或者包含类定义的头文件。插件对那些不需要应用程序的源码和扩展或者是改变的应用程序行为是非常有用的。
2. 案例
为了理解pluginlib是怎么样工作的,我们来思考这样一个小案例。首先,假设一个ROS包存在一个多边形的基类(polygon_interface_package)。系统中还存在两个不同类型的多边形:“rectangle_plugin”包下的一个矩形和“triangle_plugin”包下的一个三角形。rectangle_plugin和triangle_plugin在他们各自的package.xml文件中包含特殊的导出行(export lines),用来告诉rosbuild系统,他们将为在polygon_interface_package包下的多边形类提供插件(见3.3)。这些导出行,有效地使用ROS 编译/打包系统注册这些类。这意味着,如果有人希望去看到系统中所有可使用的插件类,可以运行一个简单的rospack指令进行查询,这个指令将会返回一系列可使用的类,在这个案例中,将会返回rectangle和triangle类。
3. 提供一个插件
3.1 注册/导出一个插件
为了能够让一个类可以动态的加载,这个类必须被标记为是一个可导出的类。这一操作是通过特殊的宏PLUGINLIB_EXPORT_CLASS导出类来完成的。这个宏可以放在任意一个组成这个插件库的源文件(.cpp)文件中,但是,它通常放在可导出类的源文件(.cpp)的底部。例如上面所说的那个例子,我们在example_pkg包中创建一个class_list.cpp的文件,正如下面所示,接着我们对这个文件进行编译:
//导入pluginlib包中的相关头文件
#include <pluginlib/class_list_macros.h>
//导入polygon_interface_package包相关的头文件
#include <polygon_interface_package/polygon.h>
//导入rectangle_package相关的头文件
#include <rectangle_package/rectangle.h>//Declare the Rectangle as a Polygon class
//这是一个宏定义,将Rectangel声明为一个插件类
PLUGINLIB_EXPORT_CLASS(rectangle_namespace::Rectangle, polygon_namespace::Polygon)
3.2 插件的描述文件
这个插件的描述文件(plugin description file)是一个XML类型的文件,它以一个机器能够读懂的格式保存所有重要的信息。它包含插件所在的库,插件的名称,插件的类型等等。我们拿上面的rectangle_plugin包举例,插件的描述文件(rectangle_plugin.xml)就会是像这样:
<library path="lib/librectangle"><class type="rectangle_namespace::Rectangle"base_class_type="polygon_namespace::Polygon"><description>This is a rectangle plugin</description></class>
</library>
3.2.1我们为什么需要这个文件?
除了代码宏之外,我们需要这个文件是让ROS系统能够自动地发现,加载和推理插件。插件描述文件包含一些重要的信息,例如插件的描述信息,这些在宏中不能够很好的描述。
3.3 使用ROS包系统注册插件
为了让pluginlib能够在一个系统下的所有ROS包中查询所有可以使用的插件,每一个包都必须显示指出这个插件导出到哪里,哪个包包含这些插件。一个插件提供者必须指向它的在package.xml文件中的export标签块中的插件描述信息。注意,如果你有其他的到处,他们必须在相同的导出区域。
假设又是rectangel_plugin 包,相关的行应该像下面这样:
<export><!--将告诉编译系统,这个包将为polygon_interface_package提供插件--><polygon_interface_package plugin="${prefix}/rectangle_plugin.xml" />
</export>
3.4 查询ROS包系统的可用插件
通过任意给定的包名,我们可以通过rospack指令去查询ROS包系统去查找哪些插件可以使用,例如:
rospack plugins --attrib=plugin nav_core
这将会返回所有从nav_core包导出的插件。
3.5 使用一个插件
pluginlib提供了一个在class_loader.h头文件中可以使用的ClassLoader类,这能够让我们更快速和更方便的使用提供的类。其次,我们将会显示一个简单的案例,这个案例使用ClassLoader去创建rectangle的实例对象。
#include <pluginlib/class_loader.h>
#include <polygon_interface_package/polygon.h>//... some code ...pluginlib::ClassLoader<polygon_namespace::Polygon> poly_loader("polygon_interface_package", "polygon_namespace::Polygon");try
{boost::shared_ptr<polygon_namespace::Polygon> poly = poly_loader.createInstance("rectangle_namespace::Rectangle");//... use the polygon, boost::shared_ptr will automatically delete memory when it goes out of scope
}
catch(pluginlib::PluginlibException& ex)
{//handle the class failing to loadROS_ERROR("The plugin failed to load for some reason. Error: %s", ex.what());
}
注意:在你使用这个插件的时候,ClassLoader必须不能超过范围。因此,如果你想在一个类中加载插件,你要确保这个类的loader必须是这个类的成员变量。