ROS与C++入门教程-pluginlib-编写简单的插件
ROS与C++入门教程-pluginlib-编写简单的插件
说明:
- 介绍编写简单的pluginlib插件并加载使用
准备
- 安装pluginlib_tutorials包:
$ apt-get install ros-%ROS_DISTRO%-common-tutorials
- %ROS_DISTRO% 可以是fuerte, groovy,hydro,indigo,jade
- 创建pluginlib_tutorials_示例包:
cd ~/catkin_ws/src/
$ catkin_create_pkg pluginlib_tutorials_ roscpp pluginlib
创建基类
- 现在我们将创建一个基类,所有的插件都将从这个基类继承。
- 我们将创建一对RegularPolygon对象并使用它们,因此我们需要创建RegularPolygon类
- 创建polygon_base.h头文件
cd catkin_ws/src/pluginlib_tutorials_
mkdir -p include/pluginlib_tutorials_/
touch polygon_base.h
vim polygon_base.h
- 基类代码:
#ifndef PLUGINLIB_TUTORIALS__POLYGON_BASE_H_
#define PLUGINLIB_TUTORIALS__POLYGON_BASE_H_
namespace polygon_base
{
class RegularPolygon
{
public:
virtual void initialize(double side_length) = 0;
virtual double area() = 0;
virtual ~RegularPolygon(){}
protected:
RegularPolygon(){}
};
};
#endif
- 在pluginlib_tutorials包已经实现了,可以通过简单复制使用。
$ roscp pluginlib_tutorials polygon_base.h include/pluginlib_tutorials_/polygon_base.h
$ roscp pluginlib_tutorials polygon_plugins.h include/pluginlib_tutorials_/polygon_plugins.h
- 我们创建一个抽象类名为RegularPolygon。
- 需要注意的一点是初始化方法的存在。
- 使用pluginlib,类需要一个没有参数的构造函数,所以如果需要任何参数,我们使用initialize方法初始化对象。
创建插件
- 我们将创建两个RegularPolygon插件,第一个是三角形,第二个是一个正方形。
- 代码如下:
#ifndef PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_
#define PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_
#include <pluginlib_tutorials_/polygon_base.h>
#include <cmath>
namespace polygon_plugins
{
class Triangle : public polygon_base::RegularPolygon
{
public:
Triangle(){}
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_;
};
class Square : public polygon_base::RegularPolygon
{
public:
Square(){}
void initialize(double side_length)
{
side_length_ = side_length;
}
double area()
{
return side_length_ * side_length_;
}
private:
double side_length_;
};
};
#endif
注册插件
- 我们刚刚创建了一些标准的C++类。
- 我们将开始做pluginlib特定的工作,因为我们声明三角形和Square类作为插件
- 创建src/polygon_plugins.cpp :
cd catkin_ws/src/pluginlib_tutorials_/src
touch polygon_plugins.cpp
vim polygon_plugins.cpp
- 代码如下:
#include <pluginlib/class_list_macros.h>
#include <pluginlib_tutorials_/polygon_base.h>
#include <pluginlib_tutorials_/polygon_plugins.h>
PLUGINLIB_EXPORT_CLASS(polygon_plugins::Triangle, polygon_base::RegularPolygon)
PLUGINLIB_EXPORT_CLASS(polygon_plugins::Square, polygon_base::RegularPolygon)
代码解释:
- 代码:
#include <pluginlib/class_list_macros.h>
解释:包含pluginlib宏定义,允许注册类作为插件
代码:
PLUGINLIB_EXPORT_CLASS(polygon_plugins::Triangle, polygon_base::RegularPolygon)
- 解释:注册Triangle类作为插件
- PLUGINLIB_EXPORT_CLASS宏参数:
- 完全限定类型的插件类,polygon_plugins::Triangle
- 完全限定类型的基类,polygon_base::RegularPolygon
构建插件库
- 要实际构建库,请将以下行添加到CMakeLists.txt文件中:
add_library(polygon_plugins src/polygon_plugins.cpp)
- 编译:
cd ~/catkin_ws/
catkin_make
使插件可用于ROS工具链
- 上面的步骤使得我们的插件库被加载,就可以创建插件实例。
- 但插件加载器仍然需要一种方式来找到该库,并知道在该库中引用。
- 为此,我们还将创建一个XML文件,以及在包清单中的特殊导出行,将所有有关插件的必要信息提供给ROS工具链。
(1)插件XML文件
- 创建polygon_plugins.xml文件
- 代码如下:
<library path="lib/libpolygon_plugins">
<class type="polygon_plugins::Triangle" base_class_type="polygon_base::RegularPolygon">
<description>This is a triangle plugin.</description>
</class>
<class type="polygon_plugins::Square" base_class_type="polygon_base::RegularPolygon">
<description>This is a square plugin.</description>
</class>
</library>
代码解释:
- 代码:
<library path="lib/libpolygon_plugins">
- 解释:
- 该library标签给出的相对路径包含我们希望导出插件库。
- 在这种情况下,这是lib/libpolygon_plugins
- 代码:
<class name="pluginlib_tutorials_/regular_triangle" type="polygon_plugins::Triangle" base_class_type="polygon_base::RegularPolygon">
<description>This is a triangle plugin.</description>
</class>
- 解释:class标签声明我们希望从我们的库导出的插件。
- 参数含义:
- type,完全限定类型的插件,polygon_plugins::Triangle
- base_class,完全限定基类类型的插件, polygon_base::RegularPolygon
- description,插件的描述它做什么的
- name,(在上面的例子中不使用):这指的是插件的名称
- 我们输出为plugin_namespace/PluginName。
- 因为我们使用包名称作为我们的regular_triangle插件的命名空间
- 这导致我们使用pluginlib_tutorials_/regular_triangle。
- 之后的API改变,这个属性不再是必需的。
(2)导出插件
- 要导出我们创建的插件,我们必须以下行添加到我们的任何的manifest.xml(rosbuild包)或package.xml(catkin包):
<export>
<pluginlib_tutorials_ plugin="${prefix}/polygon_plugins.xml" />
</export>
- 名字的标签,上面为 pluginlib_tutorials_,应该更改为base_class所在的包,示例里基类和继承类都在同一包,但很多情况下是分别独立不同包里。
- plugin 属性应该指向上面创建的XML文件。
- 验证是否生效:
rospack plugins --attrib=plugin pluginlib_tutorials_
- 您应该看到输出给出polygon_plugins.xml文件的完整路径。
- 这意味着ROS工具链已经正确设置,可以使用您的插件。
使用插件
- 现在我们已经成功创建并导出了一些RegularPolygon插件,让我们使用它们。
- 打开src/polygon_loader.cpp并粘贴以下内容:
#include <pluginlib/class_loader.h>
#include <pluginlib_tutorials_/polygon_base.h>
int main(int argc, char** argv)
{
pluginlib::ClassLoader<polygon_base::RegularPolygon> poly_loader("pluginlib_tutorials_", "polygon_base::RegularPolygon");
try
{
boost::shared_ptr<polygon_base::RegularPolygon> triangle = poly_loader.createInstance("polygon_plugins::Triangle");
triangle->initialize(10.0);
boost::shared_ptr<polygon_base::RegularPolygon> square = poly_loader.createInstance("polygon_plugins::Square");
square->initialize(10.0);
ROS_INFO("Triangle area: %.2f", triangle->area());
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;
}
- 创建ClassLoader,加载插件。有两个参数:
- 第一个是包含基类的包名,如pluginlib_tutorials_,
- 第二个是基类,如polygon_base::RegularPolygon
- 实际加载pluginlib_tutorials_/regulare_triangle插件,插件构造器不带参数,可以调用initialize增加参数。
运行插件
- 要运行我们刚写的代码,我们将在CMakeLists.txt文件中添加以下行:
include_directories(include)
add_executable(polygon_loader src/polygon_loader.cpp)
target_link_libraries(polygon_loader ${catkin_LIBRARIES})
- 编译
cd ~/catkin_ws/
catkin_make
- 新终端,执行:
devel/lib/pluginlib_tutorials_/polygon_loader
- 效果:
[ INFO] [WallTime: 1279658450.869089666]: Triangle area: 43.30
[ INFO] [WallTime: 1279658450.869138007]: Square area: 100.00
- 至此,完成插件编写。
获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号