< >
Home » ROS与C++入门教程 » ROS与C++入门教程-pluginlib-编写简单的插件

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
  • 至此,完成插件编写。

纠错,疑问,交流: 请进入讨论区点击加入Q群

获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号


标签: ROS与C++入门教程