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 load
ROS_ERROR("The plugin failed to load for some reason. Error: %s", ex.what());
}
注意:在你使用這個插件的時候,ClassLoader必須不能超過範圍。因此,如果你想在一個類中加載插件,你要確保這個類的loader必須是這個類的成員變量。