本专栏旨在通过对ROS的系统学习,掌握ROS底层基本分布式原理,并具有机器人建模和应用ROS进行实际项目的开发和调试的工程能力。
详情:《ROS从入门到精通》
插件可实现插拔式管理的组件,举个例子
在计算机系统中,所有USB设备——键盘、鼠标、U盘,都可以看作硬件插件的实现。
插件的基本原理是通过规范化协议实现的基类与功能类间的自由组合,在硬件上可能是USB等接口协议;在软件上则大多为API的多态实现——插件程序依赖于某个应用程序,且应用程序可以与不同的插件程序自由组合。
插件的优势有:
ROS中也会经常使用插件的概念,例如
导航
在导航中涉及到路径规划模块,其中路径规划算法有多种:A*、蚁群算法、遗传算法等。因此可能需要测试不同算法的优劣以选择更合适的实现,或是自研设计新算法。此时,ROS允许使用插件来实现在同一个导航体系下,不同算法的快速、灵活切换
Rviz或Gazebo等工具
在这些工具中虽然已经提供了丰富的功能实现,但在特定场景下可能存在某些定制化的需求,此时可通过插件集成功能到工具中
ROS中提供了Pluginlib
包来帮助开发者在ROS构建的基础结构上编写、动态加载、卸载插件。Pluginlib
是从运行时库(或称为动态链接库)加载的动态类。使用Pluginlib
,不必显式地将其应用程序与包含类的库链接,因为Pluginlib
可以在任何时候打开包含导出类的库,从而在无需应用程序源代码的情况下扩展或修改应用程序行为。
- 选择基类或创建基类
- 创建由该基类派生的插件类
- 注册插件
- 构建插件库
.so
- 集成插件库到ROS
- 配置插件库描述文件
xml
- 导出插件
- 使用插件
创建功能包polygon_lab
用于生成多边形插件
构造基类:在polygon_lab/include
中新建polyBase.h
,注意插件的构造函数不能带参数
#ifndef POLY_BASE_H
#define POLY_BASE_H
namespace polyBase
{
class Polygon
{
public:
virtual void initialize(double sideLength) = 0;
virtual double calArea() = 0;
virtual ~Polygon(){}
protected:
Polygon(){}
};
};
#endif
构造插件类:在polygon_lab/include
中新建polyPlugin.h
#ifndef POLY_PLUGIN_H
#define POLY_PLUGIN_H
#include
#include
namespace polyPlugin
{
class Triangle : public polyBase::Polygon
{
public:
Triangle(){}
void initialize(double sideLength)
{
this->sideLength = sideLength;
}
double calArea()
{
return 0.5 * this->sideLength * getHeight();
}
private:
double sideLength;
double getHeight()
{
double temp = this->sideLength * this->sideLength;
return sqrt(temp - 0.25 * temp);
}
};
class Square : public polyBase::Polygon
{
public:
Square(){}
void initialize(double sideLength)
{
this->sideLength = sideLength;
}
double calArea()
{
return this->sideLength * this->sideLength;
}
private:
double sideLength;
};
};
#endif
这两个插件类就是今后要使用的扩展功能。
注册插件:在polygon_lab/src
中新建polyPlugin.cpp
使用PLUGINLIB_EXPORT_CLASS
宏注册插件
#include
#include
#include
//参数1:插件类 参数2:基类
PLUGINLIB_EXPORT_CLASS(polyPlugin::Triangle, polyBase::Polygon)
PLUGINLIB_EXPORT_CLASS(polyPlugin::Square, polyBase::Polygon)
构建插件库.so
:编译此功能包plygon_lab
将会在根目录devel/lib
中生成插件libpolygon_lab.so
集成插件库到ROS:在功能包plygon_lab
下创建polyPlugin.xml
描述插件信息和库路径
<library path="lib/libpolygon_lab">
<class type="polyPlugin::Triangle" base_class_type="polyBase::Polygon">
<description>This is a triangle plugin.description>
class>
<class type="polyPlugin::Square" base_class_type="polyBase::Polygon">
<description>This is a square plugin.description>
class>
library>
在功能包polygon_lab
下package.xml
中导出polyPlugin.xml
<export>
<polygon_lab plugin="${prefix}/polyPlugin.xml" />
export>
编译后,可以调用
rospack plugins --attrib=plugin xxx
命令查看配置是否正常,其中xxx
应与基类所属的功能包名称一致。如无异常,会返回.xml
文件的完整路径
使用插件:任意新建一个功能包进行测试
#include
#include
#include
int main(int argc, char** argv)
{
//类加载器 -- 参数1:基类功能包名称 参数2:基类全限定名称
pluginlib::ClassLoader<polyBase::Polygon> polyLoader("polygon_lab", "polyBase::Polygon");
try
{
//创建插件类实例 -- 参数:插件类全限定名称
boost::shared_ptr<polyBase::Polygon> triangle = polyLoader.createInstance("polyPlugin::Triangle");
triangle->initialize(10.0);
boost::shared_ptr<polyBase::Polygon> square = polyLoader.createInstance("polyPlugin::Square");
square->initialize(10.0);
ROS_INFO("Triangle area: %.2f", triangle->calArea());
ROS_INFO("Square area: %.2f", square->calArea());
}
catch(pluginlib::PluginlibException& ex)
{
ROS_ERROR("The plugin failed to load for some reason. Error: %s", ex.what());
}
return 0;
}
插件开发的另一个实例请参考ROS从入门到精通5-4:详解路径规划插件+代码实现
本文的完整工程代码联系下方博主名片获取
更多精彩专栏: