ROS从入门到精通5-3:插件库与开发+实例分析

目录

  • 0 专栏介绍
  • 1 什么是插件?
  • 2 ROS插件库Pluginlib
  • 3 自定义插件开发
    • 3.1 插件开发基本流程
    • 3.2 实例:多边形插件

0 专栏介绍

本专栏旨在通过对ROS的系统学习,掌握ROS底层基本分布式原理,并具有机器人建模和应用ROS进行实际项目的开发和调试的工程能力。

详情:《ROS从入门到精通》

1 什么是插件?

插件可实现插拔式管理的组件,举个例子

在计算机系统中,所有USB设备——键盘、鼠标、U盘,都可以看作硬件插件的实现。

插件的基本原理是通过规范化协议实现的基类与功能类间的自由组合,在硬件上可能是USB等接口协议;在软件上则大多为API的多态实现——插件程序依赖于某个应用程序,且应用程序可以与不同的插件程序自由组合。

插件的优势有:

  • 插件可以自由增减,降低系统耦合,增强可维护性
  • 插件可移植性强,更具复用性
  • 系统结构清晰,易于调整

2 ROS插件库Pluginlib

ROS中也会经常使用插件的概念,例如

  • 导航

    在导航中涉及到路径规划模块,其中路径规划算法有多种:A*、蚁群算法、遗传算法等。因此可能需要测试不同算法的优劣以选择更合适的实现,或是自研设计新算法。此时,ROS允许使用插件来实现在同一个导航体系下,不同算法的快速、灵活切换

  • Rviz或Gazebo等工具

    在这些工具中虽然已经提供了丰富的功能实现,但在特定场景下可能存在某些定制化的需求,此时可通过插件集成功能到工具中

ROS中提供了Pluginlib包来帮助开发者在ROS构建的基础结构上编写、动态加载、卸载插件。Pluginlib是从运行时库(或称为动态链接库)加载的动态类。使用Pluginlib,不必显式地将其应用程序与包含类的库链接,因为Pluginlib可以在任何时候打开包含导出类的库,从而在无需应用程序源代码的情况下扩展或修改应用程序行为

3 自定义插件开发

3.1 插件开发基本流程

  • 选择基类或创建基类
  • 创建由该基类派生的插件类
  • 注册插件
  • 构建插件库.so
  • 集成插件库到ROS
  1. 配置插件库描述文件xml
  2. 导出插件
  • 使用插件

3.2 实例:多边形插件

创建功能包polygon_lab用于生成多边形插件

  1. 构造基类:在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
    
  2. 构造插件类:在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
    

    这两个插件类就是今后要使用的扩展功能。

  3. 注册插件:在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)
    
  4. 构建插件库.so:编译此功能包plygon_lab将会在根目录devel/lib中生成插件libpolygon_lab.so

  5. 集成插件库到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_labpackage.xml中导出polyPlugin.xml

    <export>
    	<polygon_lab plugin="${prefix}/polyPlugin.xml" />
    export>
    

    编译后,可以调用

    rospack plugins --attrib=plugin xxx
    

    命令查看配置是否正常,其中xxx应与基类所属的功能包名称一致。如无异常,会返回.xml文件的完整路径

  6. 使用插件:任意新建一个功能包进行测试

    #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:详解路径规划插件+代码实现

本文的完整工程代码联系下方博主名片获取


更多精彩专栏

  • 《ROS从入门到精通》
  • 《机器人原理与技术》
  • 《机器学习强基计划》
  • 《计算机视觉教程》

源码获取 · 技术交流 · 抱团学习 · 咨询分享 请联系

你可能感兴趣的:(ROS从入门到精通,人工智能,ROS,机器人)