ROS知识(18)----Pluginlib原理

 

目录

  1. Overview
  2. Example
  3. Providing a Plugin
    1. Registering/Exporting a Plugin
    2. The Plugin Description File
    3. Registering Plugin with ROS Package System
    4. Querying ROS Package System For Available Plugins
  4. Using a Plugin
  5. Changes from Pre-Groovy pluginlib
    1. Simplified Export Macro
    2. Legacy "Lookup Name"
  6. Report a Bug


Overview

pluginlib 是一个C++ 类库,用于从一个ROS包中加载和卸载插件 plugins. 插件plugins是一种能从运行库(例如:共享对象,动态链接库)中动态导入的类. 使用 pluginlib, 我们就不必在程序中显式地声明或定义类库,而是可以在代码中的任何位置动态的导入外部的类,甚至我们不需要知道类库或头文件或类定义。Plugins在扩展和修改应用程序(这汇总程序不需要修改应用程序的源码)的时候是非常有用的。例如代价地图层中需要添加一层新的代价地图,用于表示车辆或行人,就需要用到pluginlib导入这一层心的代价地图(一个已经被导出的类,这个类称为插件)。

Example

为了更好的理解plugin是如何工作的,我们来看一个小例子。首先,假设已经有了一个多边形接口包“polygon_interface_package”的ROS包,它包含有一个多边形生成的ploygen基类。在假定我们的系统支持两种多边形,一种是矩形,包含在“rectangle_plugin”中;另一种是三角形,,包含在“triangle_plugin”中。rectangle_plugin 和 triangle_plugin必须在package.xml中声明注册,以便于rosbuild系统能够从polygon_interface_package包里索引到这些多边形插件。这样就可以通过rospack命令来查看ros系统中所有的插件了,例如这个例子中的矩形和三角形。

pluginlib/plugin_model.png

 

Providing a Plugin

 

Registering/Exporting a Plugin

为了能够让一个类能够被动态的导入,它必须被标记为一个导出类。这可以通过特定的宏PLUGINLIB_EXPORT_CLASS来实现。该宏可以放到任何源文件(.cpp)中,这样该源文件定义的类就能变成一个插件库了,注意这个宏一般放在源文件的最后来导出类。对于该例子,我们可以在“example_pkg"中创建class_list.cpp文件,这样就可以把矩形rectangle类编译到librectangle库中。

#include <pluginlib/class_list_macros.h>
#include <polygon_interface_package/polygon.h>
#include <rectangle_package/rectangle.h>

//Declare the Rectangle as a Polygon class
PLUGINLIB_EXPORT_CLASS(rectangle_namespace::Rectangle, polygon_namespace::Polygon)
 

The Plugin Description File

 plugin 描述文件是一个XML文件,用于存储了plugin所有重要信息,这种信息格式是可读的。主要包含了插件的名字,插件的类型等等。以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>

 插件描述文件及其关联的tags/attributes的详细介绍请参考documentation.

 

Why Do We Need This File

除了代码宏,我们需要这个文件以便于让ROS系统自动发现,加载和推理插件。插件描述文件也包含重要信息,如插件的描述,这是宏所不能做到的

Registering Plugin with ROS Package System

为了让pluginlib在ROS包中查询到所有有效的插件,每个包都必须显式地声明导出了哪些插件,这就是通过package.xml来实现了,以rectangle_plugin为例子,只需要在文件中添加一下的代码即可:

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

关于插件导出的详细讨论,请参考documentation

 重要提示:为了能够正确导出类,必须要提供该包的接口依赖,例如rectangle_plugin插件必须在package.xml添加以下的依赖:

  <build_depend>polygon_interface_package</build_depend>
  <run_depend>polygon_interface_package</run_depend>

  

Querying ROS Package System For Available Plugins

我们可以使用rospack查询ROS系统包(包括自行开发的插件包)中的所有有效的插件,例如:

rospack plugins --attrib=plugin nav_core

这将会返回 nav_core导出的所有插件。结果如下:

global_planner /opt/ros/indigo/share/global_planner/bgp_plugin.xml
dwa_local_planner /opt/ros/indigo/share/dwa_local_planner/blp_plugin.xml
rotate_recovery /opt/ros/indigo/share/rotate_recovery/rotate_plugin.xml
move_slow_and_clear /opt/ros/indigo/share/move_slow_and_clear/recovery_plugin.xml
clear_costmap_recovery /opt/ros/indigo/share/clear_costmap_recovery/ccr_plugin.xml
carrot_planner /opt/ros/indigo/share/carrot_planner/bgp_plugin.xml
base_local_planner /opt/ros/indigo/share/base_local_planner/blp_plugin.xml
navfn /opt/ros/indigo/share/navfn/bgp_plugin.xml

 

Using a Plugin

pluginlib在class_loader.h中提供了一个ClassLoader类,用于导入外部的插件。更详细的API文档,请参见。下面我们展示一个简单的例子,实现ClassLoader创建一个rectangle的实例:

 1 #include <pluginlib/class_loader.h>
 2 #include <polygon_interface_package/polygon.h>
 3 
 4 //... some code ...
 5 
 6 pluginlib::ClassLoader<polygon_namespace::Polygon> poly_loader("polygon_interface_package", "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.

注意 在使用的插件的时候,ClassLoader必须在域范围内。因此,如果在类中加载插件对象,请确保ClassLoader是该类的成员变量。

 

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

posted @ 2017-06-07 09:59  horsetail  阅读(3546)  评论(0编辑  收藏  举报