ROS进阶功能—plugin插件机制

ROS进阶功能—plugin插件机制

在ROS开发中,常常会接触到一个名词——plugin(插件)。这个名词在计算机软件开发中也经常提到。简单来说,ROS中的插件就是可以动态加载的扩展功能类。ROS中的pluginlib功能包提供了加载和卸载plugin的C++库,开发者在使用插件时,不需要考虑plugin类的链接位置,只需要将插件注册到pluginlib中,即可直接动态加载。这种插件机制非常方便,开发者不需要改动原软件的代码,直接将需要的功能通过插件进行扩展即可。

一、工作原理

在这里插入图片描述假设ROS功能包中已经存在一个polygon的基类(polygon_interface_package),可以通过插件机制实现两种polygon的功能支持:rectangle_plugin(rectangle_plugin_package)和triangle_plugin(triangle_plugin_package)。在这两个功能包的package.xml 中,需要声明polygon_interface_package中的基类polygon,在编译过程中会把插件注册到ROS中,用户可以直接通过rospack命令进行全局插件查询,也可以在开发中直接使用这些插件。

二、实现一个插件

pluginlib 利用了C++多态的特性,不同的插件只要使用统一的接口就可以替换使用。用户在使用过程中也不需要修改代码或者重新编译,选择需要使用的插件即可扩展相应的功能。一般来讲,要实现一个插件,主要分为以下几个步骤。
1)创建基类,定义统一接口(如果基于现有基类实现插件,则不需要这个步骤)。
2)创建plugin类,继承基类,实现统一的接口。
3)注册插件。
4)编译生成插件的动态链接库。
5)将插件加入ROS中。

三、创建基类

在include目录下,新建头文件polygon_base.h来创建基类。

#ifndef SRC_POLYGON_BASE_H
#define SRC_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 //SRC_POLYGON_BASE_H

其中,插件要求构造函数不可以带参数,所以使用initialize函数实现参数初始化。

四、创建plugin类

继承基类,实现统一接口

#ifndef SRC_POLYGON_PLUGINS_H
#define SRC_POLYGON_PLUGINS_H

#include <learn_plugin/polygon_base.h>
#include <cmath>

namespace polygon_plugins{

class Triangle: public polygon_base::RegularPolygon
{
public:
    // cnstructor
    Triangle(): side_length_() {}

    void initialize(double side_length){
        side_length_ = side_length;
    }

    double area(){
        return 0.5 * side_length_ * getHight();
    }

    double getHight(){
        return sqrt((side_length_ * side_length_) - ((side_length_/2) * (side_length_/2)));
    }

private:
    double side_length_;
};


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_;
};
}

#endif //SRC_POLYGON_PLUGINS_H

五、注册插件

#include <learn_plugin/polygon_base.h>
#include "../include/learn_plugin/polygon_plugins.h"
// use macros of plyginlib to register
#include <pluginlib/class_list_macros.h>

PLUGINLIB_EXPORT_CLASS(polygon_plugins::Triangle, polygon_base::RegularPolygon)
PLUGINLIB_EXPORT_CLASS(polygon_plugins::Square, polygon_base::RegularPolygon)

六、编译插件的动态链接库

修改CMakeLists文件,从而将之编译为动态链接库

include_directories(
 include
  ${catkin_INCLUDE_DIRS}
)

 add_library(polygon_plugins
   src/polygon_plugins.cpp
 )

七、将插件加入ROS

接下来,需要将插件加到ROS中,使得catkin系统能够查找到该插件。
分别在功能包下编辑插件对应的xml描述文件polygon_plugins.xml,然后修改package.xml 文件
新建polygon_plugins.xml 文件:

<library path="lib/libpolygon_plugins">
    <class name="learn_plugin/regular_triangle" type="polygon_plugins::Triangle" base_class_type="polygon_base::RegularPolygon">
        <description>This is a triangle plugin.</description>
    </class>
    <class name="learn_plugin/regular_square" type="polygon_plugins::Square" base_class_type="polygon_base::RegularPolygon">
        <description>This is a square plugin.</description>
    </class>
</library>

package.xml 文件修改:

  <export>
    <!-- Other tools can request additional information be placed here -->
    <learn_plugin plugin="${prefix}/polygon_plugins.xml" />
  </export>

测试ROS是否检索:
在这里插入图片描述

八、调用插件

在src目录下,新建文件polygon_loader.cpp,开始调用上述生成的插件。
最终的功能包目录如下图所示:
在这里插入图片描述


//
// Created by xu on 2021/1/11.
//

//

// include <boost/shared_ptr.hpp>

#include <pluginlib/class_loader.h>
#include <learn_plugin/polygon_base.h>

int main(int argc, char** argv)
{
    // 创建一个ClassLoader,用来加载plugin
 pluginlib::ClassLoader<polygon_base::RegularPolygon> poly_loader("learn_plugin", "polygon_base::RegularPolygon");

    try
    {
        // 加载Triangle插件类,路径在polygon_plugins.xml中定义
        boost::shared_ptr<polygon_base::RegularPolygon> triangle = poly_loader.createInstance("learn_plugin/regular_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("learn_plugin/regular_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;
}

注意:
加载Triangle插件类的时候,polygon_plugins.xml 中如果没有指定nametag(如本例中的learn_plugin/regular_triangle),直接使用类真实的type:polygon_plugins::Triangle也可以。

九、plugin描述文件

1、 class_libraries标签
该标签允许多个包含插件的libraries
2、library 标签
该标签允许包含多个插件
Attributes:

  • path : 从该功能包到library的相对路径

3、class标签
Attributes:

  • name : 类的查找名.作为插件的标志被插件库使用
  • type : 功能类的类型全名
  • base_class_type : 基类的类型全名
  • description :描述功能类的功能
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我不是“耀”神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值