有错误或不足的地方还请大家指正
随着项目的不断进行,对ROS的学习也不断深入。ROS的一些基础操作已不能满足需求,所以最近开始学习ROS的一些更“好”的机制,首先介绍比较基础的插件机制pluginlib。ROS的很多项目都是用插件的形式来加载的,比如navigation这个包,里面的costmap_2d中的各个地图层,就是以插件的形式动态加载。采用插件的形式有什么好处呢,我个人理解就是可以在不改变原有基类的前提下,融入自己创建的类。这些类可以实现某种算法,也可以是简单的做一些操作。具体的实现方式就是类继承,只不过针对ROS系统做了封装,使我们用起来更方便。但问题也就容易出现在封装的过程中,所以这里对其进行详细的介绍。
关于pluginlib的详细说明,可以移步ROS Wiki pluginlib教程
其他博主对pluginlib也有过介绍,推荐这个
这里介绍具体实现过程,同样使用ROSWiki上的多边形实例,这里通过两个lib来实现加载:
1.创建plugin基类:
创建ROS包,在include文件夹下创建base.h,里面申明基类
namespace polygon_base
{
class RegularPolygon
{
public:
virtual void initialize(double side_length) = 0;
virtual double area() = 0;
virtual ~RegularPolygon(){}
protected:
RegularPolygon(){}
};
};
2.创建插件类:
为了使用两种lib分别加载,这里用两个文件申明两个基类:
square.h下 namespace:polygon_plugins class :Square
triangle.h下 namespace:polygon_plugins class :Triangle
namespace polygon_plugins
{
class Square : public polygon_base::RegularPolygon
{
public:
Square() : side_length_() {}
void initialize(double side_length)
{
side_length_ = side_length;
}
double area()
{
return side_length_ * side_length_;
}
private:
double side_length_;
};
};
namespace polygon_plugins
{
class Triangle : public polygon_base::RegularPolygon
{
public:
Triangle() : side_length_() {}
void initialize(double side_length)
{
side_length_ = side_length;
}
double area()
{
return 0.5 * side_length_ * getHeight();
}
double getHeight()
{
return sqrt((side_length_ * side_length_) - ((side_length_ / 2) * (side_length_ / 2)));
}
private:
double side_length_;
};
};
当然完全可以在同一个文件下实现这两个类,这里分开主要是为了在后面plugin描述文件中用新的方式实现。3.注册插件:
在plugins1.cpp中注册triangle插件:PLUGINLIB_EXPORT_CLASS(polygon_plugins::Triangle,polygon_base::RegularPolygon);
在plugins2.cpp中注册square插件:PLUGINLIB_EXPORT_CLASS(polygon_plugins::Square,polygon_base::RegularPolygon);
其中,第一个参数表示子类的命名空间加类,第二个参数表示基类的命名空间加类
4.修改Cmakelists,生成库,添加头文件
include_directories(
${catkin_INCLUDE_DIRS}
include
)
…
add_library(polygon_plugins1src/plugins1.cpp)
add_library(polygon_plugins2src/plugins2.cpp)
5.写插件描述文件
<class_libraries>
<librarypath="lib/libpolygon_plugins1">
<classtype="polygon_plugins::Triangle"base_class_type="polygon_base::RegularPolygon">
<description>Thisis a triangle plugin.</description>
</class>
</library>
<librarypath="lib/libpolygon_plugins2">
<classtype="polygon_plugins::Square"base_class_type="polygon_base::RegularPolygon">
<description>Thisis a square plugin.</description>
</class>
</library>
</class_libraries>
注意:这里library填写Cmakelists生成的库,当然前面加上lib
class type写第3步里面注册的子类,base_class_type写第3步里面注册的基类
具体的写法可以参考ROS Wiki上的介绍,里面有介绍同一个包加载不同lib以及同一个lib加载不同class的方法。
6.向ROS注册插件
在package.xml里面添加:
<export>
<mypluginlib plugin="${prefix}/plugins.xml" />
</export>
测试:
执行:rospack plugins --attrib=plugin mypluginlib 会看到输出的xml信息。注意 mypluginlib是pkg名称
7.使用pluginlib:
polygon_loader.cpp 使用pluginlib的一个代码实例
int main(int argc, char** argv)
{
pluginlib::ClassLoader<polygon_base::RegularPolygon> poly_loader("mypluginlib", "polygon_base::RegularPolygon");
try
{
boost::shared_ptr<polygon_base::RegularPolygon> triangle = poly_loader.createInstance("polygon_plugins::Triangle");
triangle->initialize(10.0);
ROS_INFO("Triangle area: %.2f", triangle->area());
}
catch(pluginlib::PluginlibException& ex)
{
ROS_ERROR("The plugin failed to load for some reason. Error: %s", ex.what());
}
try
{
boost::shared_ptr<polygon_base::RegularPolygon> square = poly_loader.createInstance("polygon_plugins::Square");
square->initialize(10.0);
ROS_INFO("Square area: %.2f", square->area());
}
catch(pluginlib::PluginlibException& ex)
{
ROS_ERROR("The plugin failed to load for some reason. Error: %s", ex.what());
}
return 0;
}
pluginlib::ClassLoader<polygon_base::RegularPolygon>poly_loader("mypluginlib", "polygon_base::RegularPolygon");//这一句是插件实例化,第一个是包名,第二个是基类。
boost::shared_ptr<polygon_base::RegularPolygon>square = poly_loader.createInstance("polygon_plugins::Triangle");
boost::shared_ptr<polygon_base::RegularPolygon>square = poly_loader.createInstance("polygon_plugins::Square");
上面两句是加载插件,<>里面是基类,()里面是要具体加载的插件类,也就是我们之前介绍的子类,