目錄
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系統中所有的插件了,例如這個例子中的矩形和三角形。

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.
