ROS的pluginlib的理解与实例

TGK-planner编译报错PLUGINLIB_EXPORT_CLASS解决 TGK-planner编译报错解决。 阅读详情

1. 写在最前面

由于在一个源码中, 关于在ROS平台上的具体实现, 用到了Plugin. 为了更加深入的理解到底是一个什么鬼, 所以对pluginlib进行了一些学习, 下面的内容, 大部分在网站上是能够找到的, 是综合Wiki上的介绍, 以及从源码中看到的内容和自己的尝试. 希望对大家都一点点帮助.

pluginlib是一个使用C++实现的库, 用于在ROS包里面动态的加载或卸载plugin. plugin满足一些条件的, 可以从运行库(例如共享对象, 动态链接库)中动态加载的类. Plugin在扩展或修改应用的行为上很有优势, 并不需要知道原始类的源码, 也许你在编写代码时, 也并不知道你将会用到哪个plugin, 而是在运行时通过参数载入才确定具体的plugin, 在后面有一点相关的示例, 可以体会一下使用plugin的feeling(感觉很一般, 哈哈哈…).

2. 示例

想象一个场景, 假设现在有一个ROS包polygon_interface_package, 里面包含一个polygon基类, 同时, 另外还有两个不同的polygon, 一个是rectangle, 存在于rectangle_plugin包, 另外一个是triangle, 存在于triangle_plugin包. 我们希望rectangle和triangle都被系统支持.

2.1 registering/Exporting a Plugin

为了能够动态加载一个类, 那么, 这个类必须是一个被标注的, 并且导入到系统的一个类. 这个过程, 需要使用宏PLUGINLIB_EXPORT_CLASS来完成. 一般情况下, 这个宏放在实现文件(.cpp)的末尾. 类似如下:

    #include <pluginlib/class_list_macros.h>
    #include <polygon_interface_package/polygon.h>
    #include <rectangle_package/rectangle.h>

    // 具体参数意义, 见下文
    PLUGINLIB_EXPORT_CLASS(rectangle_namespace::Rectangle, polygon_namespace::Polygon)

2.2 The Plugin Description File

每个Plugin都需要由一个插件描述文件, 是一个XML格式机器可读的文件. 包含一些必要的信息, 例如路径, 插件类型, 插件名称等. 类似如下:

    <library path="lib/librectangle">
      <class type="rectangle_namespace::Rectangle" base_class_type="polygon_namespace::Polygon">
      <description>
      This is a rectangle plugin
      </description>
      </class>
    </library>

更多详细的介绍, 可以查看: http://wiki.ros.org/pluginlib/PluginDescriptionFile

2.3 向ROS Package System中注册插件

为了使pluginlib能够查询到所有可用的插件, 需要在package.xml文件中添加export的tag块. 类似如下:

    <export>
      <polygon_interface_package plugin="${prefix}/rectangle_plugin.xml" />
    </export>

一个值得注意的地方, 为了使上述export命令正确执行, 还需要在build和run依赖项中添加如下信息:

    <build_depend>polygon_interface_package</build_depend>
    <run_depend>polygon_interface_package</run_depend>

2.4 Querying ROS Package System For Available Plugins

可以使用rospack命令来查询, 就很简单的一条命令, 类似如下:

    $ rospack plugins --attrib=plugin nav_core

将会返回所有nav_core包中导入的插件.

2.5 Step by Step

2.5.1 创建Plugin

首先, 当然是在自己的工作空间中创建一个用于尝试的ROS Package. 依次输入下述命令.

    $ roscd
    $ cd ../src
    $ catkin_create_pkg plugin_test roscpp pluginlib
OK, 现在可以开始写代码了. 在include/plugin_test文件夹下新建文件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

在include/plugin_test文件夹下新建文件polygon_plugins.h, 将下述代码拷贝进去, 申明我们的插件:

    #ifndef PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_
    #define PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_
    #include <plugin_test/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
在src文件夹下创建文件polygon_plugins.cpp, 并拷贝下述代码进去, 注册我们的插件.
    #include <pluginlib/class_list_macros.h>
    #include <plugin_test/polygon_base.h>
    #include <plugin_test/polygon_plugins.h>

    PLUGINLIB_EXPORT_CLASS(polygon_plugins::Triangle, polygon_base::RegularPolygon)
    PLUGINLIB_EXPORT_CLASS(polygon_plugins::Square, polygon_base::RegularPolygon)
在CMakeLists.txt文件中, 加入下述add_library申明. 值得注意的是, 在CMakeLists.txt文件中, 需要在include_directories中添加include目录, 否则我们前面写的两个头文件将会找不到.
    include_directories(
      ${catkin_INCLUDE_DIRS}
      include
    )

    ... ...

    add_library(polygon_plugins src/polygon_plugins.cpp)
如前所述, 咱还需要编辑关于插件的信息内容, 在plugin_test主目录下, 创建一个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>
在同目录下的package.xml文件中export tag块中添加下述内容:
      <plugin_test plugin="${prefix}/polygon_plugins.xml" />

在命令行中运行下述指令, 对应的输出信息如下所示:

    $ rospack plugins --attrib=plugin plugin_test
    plugin_test /home/silence/WorkSpace/catkin_ws/src/plugin_test/polygon_plugins.xml
如果得到类似的输出, 则表示所有都是没问题的.

2.5.2 使用Plugin

2.5.2.1 基本使用体验

在src目录下, 新建polygon_loader.cpp文件, 用于测试, 复制下述内容:

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

    int main(int argc, char** argv)
    {
      pluginlib::ClassLoader<polygon_base::RegularPolygon> poly_loader("plugin_test", "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;
    }
并在CMakeLists.txt中加入下述申明, 然后 $ catkin_make.
    add_executable(polygon_loader src/polygon_loader.cpp)
    target_link_libraries(polygon_loader ${catkin_LIBRARIES})
编译成功后, 运行节点, 应该会得到下述类似的输出.
    $ rosrun plugin_test polygon_loader
    [ INFO] [1477584281.637794959]: Triangle area: 43.30
    [ INFO] [1477584281.637923253]: Square area: 100.00
上述代码都比较简单, 就不做过多说明了.
2.5.2.2 另一种体验

在src目录下, 新建polygon_loader_v1.cpp文件, 用于测试, 复制下述内容:

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

    #include <ros/ros.h>
    #include <sstream>
    #include <string>
    #include <vector>

    template <typename T>
    std::string to_string(T value) {
        std::ostringstream os ;
        os << value ;
        return os.str() ;
    }

    int main(int argc, char** argv)
    {
      ros::init(argc, argv, "polygon_loader_v1");
      ros::NodeHandle n_;

      std::vector<std::string> class_names;
      int class_index = 1;
      while (true)
      {
        std::string class_name;
        std::string param_name = std::string("polygon_loader_v1/derive_class_" + to_string(class_index++));
        if(!n_.getParam(param_name.c_str(), class_name))
            break;
        class_names.push_back(class_name);
      }

      if (class_names.empty()) {
        ROS_ERROR("ros parameter error");
        return 0;
      }

      pluginlib::ClassLoader<polygon_base::RegularPolygon> poly_loader("plugin_test", "polygon_base::RegularPolygon");

      try
      {

        for (class_index = 0; class_index < class_names.size(); ++class_index) {
          std::string class_name = class_names[class_index];
          boost::shared_ptr<polygon_base::RegularPolygon> plugin = poly_loader.createInstance(class_name);
          plugin->initialize(10.0);
          ROS_INFO("The polygon (%d / %d) area: %.2f", class_index + 1, class_names.size(), plugin->area());
        }
      }
      catch(pluginlib::PluginlibException& ex)
      {
        ROS_ERROR("The plugin failed to load for some reason. Error: %s", ex.what());
      }

      ROS_INFO("Waiting \"Ctrl + C\"");
      while (ros::ok()) {
        ;
      }

      return 0;
    }
并在CMakeLists.txt中加入下述申明, 然后 $ catkin_make.
    add_executable(polygon_loader_v1 src/polygon_loader_v1.cpp)
    target_link_libraries(polygon_loader_v1 ${catkin_LIBRARIES})
在plugin_test目录下新建launch文件夹, 创建class_loader.launch文件, 复制下述内容.
    <launch>

        <!-- plugin params -->
        <param name="polygon_loader_v1/derive_class_1" value="polygon_plugins::Triangle" />
        <param name="polygon_loader_v1/derive_class_2" value="polygon_plugins::Square" />

        <node name="polygon_loader_v1"
             pkg="plugin_test" type="polygon_loader_v1" output="screen" />

    </launch>
编译成功后, 运行launch文件, 因为在代码中, 我们初始化了ros节点, 并且在launch文件中我们添加了ros parameter, 发起launch文件后, 会自动开启 roscore, 输出会比较混乱, 应该会得到下述类似的输出.
    $ roslaunch plugin_test class_loader.launch

    ... ...

    auto-starting new master
    process[master]: started with pid [16890]
    ROS_MASTER_URI=http://localhost:11311

    setting /run_id to bfd33a96-9cf8-11e6-a0bb-78acc03c5a93
    process[rosout-1]: started with pid [16903]
    started core service [/rosout]
    process[polygon_loader_v1-2]: started with pid [16906]
    [ INFO] [1477650287.294727014]: The polygon (1 / 2) area: 43.30
    [ INFO] [1477650287.294864723]: The polygon (2 / 2) area: 100.00
    [ INFO] [1477650287.294899464]: Waiting "Ctrl + C"
上述代码都比较简单, 就不做过多说明了.

3. 进阶

pluginlib的源码见链接: https://github.com/ros/pluginlib . 打开include文件夹, 可以看得到, 其中仅包含少量的文件. 截图如下:


include

3.1 class_list_macros.h

其结构很清晰, 其中几个重要的宏申明于class_list_macros.h中, 定义如下:

    #include <class_loader/class_loader.h>
    /** 
     * @macro This version was deprecated in favor of PLUGINLIB_DECLARE_CLASS
     * @param - class_name - An alias for the class (no special characters allowed)  (IGNORED AS OF PLUGINLIB 1.9)
     * @param - class_type - The real class name with namespace qualifier (e.g. Animals::Lion)
     * @param - base_class_type - The real base class type from which class_type inherits
     */
    #define PLUGINLIB_REGISTER_CLASS(class_name, class_type, base_class_type) \
      CLASS_LOADER_REGISTER_CLASS_WITH_MESSAGE(class_type, base_class_type, "In file " __FILE__ " pluginlib WARNING: PLUGINLIB_REGISTER_CLASS is deprecated, please use PLUGINLIB_EXPORT_CLASS instead. You can run the script 'plugin_macro_update' provided with pluginlib in your package source folder to automatically and recursively update legacy macros. Base = base_class_type, Derived = derived_class_type")

    /** 
     * @macro This version is the most in use and requires package name in addition to fields in PLUGINLIB_REGISTER_CLASS 
     * @param - pkg - The package that exports the plugin (IGNORED AS OF PLUGINLIB 1.9)
     * @param - class_name - An alias for the class (no special characters allowed)  (IGNORED AS OF PLUGINLIB 1.9)
     * @param - class_type - The real class name with namespace qualifier (e.g. Animals::Lion)
     * @param - base_class_type - The real base class type from which class_type inherits
     */
    #define PLUGINLIB_DECLARE_CLASS(pkg, class_name, class_type, base_class_type) \
      CLASS_LOADER_REGISTER_CLASS_WITH_MESSAGE(class_type, base_class_type, "pluginlib WARNING: In file " __FILE__ " PLUGINLIB_DECLARE_CLASS is deprecated, please use PLUGINLIB_EXPORT_CLASS instead. You can run the script 'plugin_macro_update' provided with pluginlib in your package source folder to automatically and recursively update legacy macros.  Base = base_class_type, Derived = derived_class_type")

    /** 
     * @macro This version was only made possible with pluginlib 1.9 series. It's the easiest to use and now the official way of exporting classes.
     * @param - class_type - The real class name with namespace qualifier (e.g. Animals::Lion)
     * @param - base_class_type - The real base class type from which class_type inherits
     */
    #define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type) \
      CLASS_LOADER_REGISTER_CLASS(class_type, base_class_type);
3.2 class_desc.h

class_desc.h文件的定义如下, 其主要是用于保存前述xml文件中所编辑的关于plugin的内容.

      class ClassDesc
      {
        public:
          /**
           * @brief  Constructor for a ClassDesc
           * @param lookup_name The lookup name of the class 
           * @param derived_class The type of the derived class of the class
           * @param base_class The type of the class, corresponds to the type of the base class
           * @param package The package the class lives in
           * @param description A description for the class
           * @param library_name The name of the containing library for the class (not a full path!)
           * @param plugin_manifest_path The path to the plugin manifest file
           */
          ClassDesc(const std::string& lookup_name, const std::string& derived_class, const std::string& base_class, const std::string& package, 
              const std::string& description, const std::string& library_name, const std::string& plugin_manifest_path):
            lookup_name_(lookup_name), 
            derived_class_(derived_class),
            base_class_(base_class),
            package_(package),
            description_(description), 
            library_name_(library_name),
            resolved_library_path_("UNRESOLVED"),
            plugin_manifest_path_(plugin_manifest_path){}

          std::string lookup_name_;
          std::string derived_class_;
          std::string base_class_;
          std::string package_;
          std::string description_;
          std::string library_name_;
          std::string resolved_library_path_; //This is set by pluginlib::ClassLoader at load time
          std::string plugin_manifest_path_;
      };
3.2 class_loader

除了上述两部分外, 另外一个是与违例相关的类申明文件, pluginlib_exceptions.h. 当然, 其中最重要的部分, 是class loader. class_loader是pluginlib中最基础的部分. 完成在运行时从运行库中动态的加载已导入的C++类, 即插件, 以及创建这些类的对象. 一般而言, 当插件是为了non-ROS package所创建的时, 应用使用class loader; 而将插件导入到ROS package时, 应该使用pluginlib. class loader主要提供两个接口, 分别是class_loader::ClassLoaderclass_loader::MultiLibraryClassLoader. 都提供了类似的接口, 不同之处在于, 前者仅能绑定单个库, 而后者可以绑定多个库. 基本应用示例如下:

    #include <class_loader/class_loader.h> // 包含头文件
    #include "MyBase.h" // 引入已声明的基类

    int main()
    {
      // 实例化一个class_loader::ClassLoader对象, 传入参数是需要导入库的完整路径以及名称
      class_loader::ClassLoader loader("libMyLibrary.so");
      // 获取由基类MyBase所定义接口的类
      std::vector<std::string> classes = loader.getAvailableClasses<MyBase>();
      for(unsigned int c = 0; c < classes.size(); ++c)
      {
        boost::shared_ptr<MyBase> plugin = loader.createInstance<MyBase>(classes[c]);
        plugin->someMethod();
        // plugin是局部变量, 离开花括弧作用域后将会自动析构
      }
    }
值得说明的几点:
  1. ClassLoader可以查询到具有某个基类的插件(或类), 并且实例化这些插件, 前提条件是这些插件提前注册并导入了, 即在实现文件末尾加入下述宏定义.

        CLASS_LOADER_REGISTER_CLASS(Derived, Base)
    • 1
  2. 从上述示例用法中可以看到, 客户端的代码, 虽然不需要子类的具体定义, 但不可避免的是需要共同基类(即MyBase)的定义. 上述代码中可以看到, 查询可用插件和创建实例的两个接口, 均是模板函数. 如果你所给定的基类不对, 是不能够成功获取到任何东西.

  3. 允许某个类多次申明, 并具有不同的基类申明

  4. class_loader::ClassLoaderclass_loader::MultiLibraryClassLoader的所有接口都是线程安全的.

  5. 模板函数中的模板, 都是静态判定的, 保证获取到的接口是类型准确的. 不会出现加载到具有不兼容接口的无效插件.

最后, 如果对class loader的具体实现感兴趣的朋友, 可以参看下述链接, http://wiki.ros.org/class_loader/Design , 并配合前面给出的Github上的源码进行理解.

原文地址:http://blog.csdn.net/sunbibei/article/details/52958724

ROS-1】关于插件的编写使用(pluginlib pluginlib是一个c++库, 用来从一个ROS功能包中加载和卸载插件(plugin)。插件是指从运行时库中动态加载的类。通过使用Pluginlib,不必将某个应用程序显式地链接到包含某个类库,Pluginlib可以随时打开包含类的库,而不需要应用程序事先知道包含类定义的库或者头文件。 阅读详情

相关推荐

Navigation 2,插件机制,行为树,以及动作服务器解析

上面的每个节点都有自己的参数可以配置,下一节我们就对个个节点的配置进行介绍并进行适配。2. 运行示例环境配置。2. 运行示例环境配置。1. 总体框架功能汇总。1. 总体框架功能汇总。

weixin_50084948的博客 490

ROSpluginlib学习总结一

在开发中需要使用到插件,因此学习了下pluginlib的一些使用,学习的还不够透彻,先记录一下这几天的学习结果。关于ROSpluginlib的使用主要参考的是《》《》这两篇文章。第一篇中讲述了一个示例,第二篇是ROS官方中对于pluginlib使用的一些解释的翻译。

YiYeZhiNian的博客 1405

ROS2高级教程使用pluginlib自定义插件

ROS 2功能包中,我们首先定义一个插件接口,即一个纯虚基类,用于规定插件的基本方法。

生活不止眼前的苟且 1631

ROS pluginlib步骤

1.创建插件 一般情况是有基类的,以move_base导航栈为例。其nav_core包下有几个头文件,这就是基类所在,其具体实现由继承类完成,基类的构造函数是protected 2.新建软件包 catkin_create_pkg package_name roscpp 基类包名 ...... 3. 继承类头文件要包含 基类 #include <基类包名/基类头文件名.h> 这里是因为头文件在/include/包名/头文件名。如果就在include文件夹里 不用包名就可以了 .cpp文件..

dwell548560的博客 727

ROS-----pluginlib使用总结

pluginlib是一个C++库,可以实现为一个ROS包动态的加载和卸载插件。

倔强不倒翁的博客 1万+

ros pluginlib理解

为了防止链接都是,故而把内容转载了过来,感谢原创。 原创地址: https://blog.csdn.net/sunbibei/article/details/52958724 https://blog.csdn.net/jinking01/article/details/79414486 1. 写在最前面 由于在一个源码中, 关于在ROS平台上的具体实现, 用到了Plugin. 为了更加深入的理解到底是一个什么鬼, 所以对pluginlib进行了一些学习, 下面的内容, 大部分在网站上是能够找到的, 是综合

ABC_ORANGE的博客 466

android ros 节点编写_ROS编程入门系列小结

一. 系列简介ROS编程入门系列至此共22篇,通过本系列学习,基本上可以看得懂ROS程序,以及可以编写简单的ROS程序,这也是本系列的两个基本目标。本系列除第一篇和本篇外,每篇都以一个ROS概念为主题,以实践为主,包含编写代码、编译、运行以及调试,通过实际写代码的方式,相信更容易理解掌握。每一篇基本上都是以上一篇为基础,逐渐深入,对于初学者,建议按照顺序学习,有一定基础的同学可以直接查...

weixin_39679370的博客 145

第 10 章 ROS进阶

ROS入门 第 10 章 ROS进阶 《ROS入门-理论实践》视频教程镇楼 在本教程的第二章内容介绍了ROS的核心实现:通信机制 ——话题通信、服务通信和参数服务器。三者结合可以满足ROS中的大多数数据传输相关的应用场景,但是在一些特定场景下可能就有些力不从心了,本章主要介绍之前的通信机制存在的问题以及对应的优化策略,本章主要内容如下: action通信; 动态参数; pluginlib; nodelet。 本章预期达成的学习目标: 了解服务通信应用的局限性(action的应用场景),熟练掌握

赵虚左 624

ROS系列之Nodelet---示例nodelet-Node封装为Nodelet

介绍如何将节点封装为Nodelet 处理过程 添加必要的#includes #include <nodelet/nodelet.h> #include <pluginlib/class_list_macros.h> 去掉int main() 继承子类 nodelet::Nodelet namespace systemExample { class SystemNodelet : public nodelet::Nodelet { public:

zhaodeming000的博客 981

ROS全局路径规划插件实战:从零构建固定路线导航核心

本文详细介绍了如何从零开始构建一个ROS全局路径规划插件,以实现固定路线导航。针对AGV等重复性任务场景,该插件通过加载预定义路径并忽略目标点,解决了通用规划器路径不固定、计算冗余的问题,显著提升了导航的稳定性和效率。

weixin_29056781的博客 181

Mesh Navigation插件开发教程:自定义网格层规划器

Mesh Navigation是一个高效的移动机器人导航堆栈,专为不平坦地形设计。本教程将指导你如何开发自定义网格层和规划器插件,扩展Mesh Navigation的功能,让你的机器人在复杂环境中实现更智能的导航。 ## 一、了解Mesh Navigation架构 Mesh Navigation采用模块化设计,主要包含以下核心组件: - **网格地图(Mesh Map)**:提供地形的三维网

gitblog_00099的博客 990

<ROS> pluginlib理解示例

该Blog的内容, 大部分在网站上是能够找到的, 是综合Wiki上的介绍, 以及从源码中看到的内容和自己的尝试. 文中手把手自己配置一个ROS包, 并实现通过两种方式示例使用Plugin, 希望对大家都一点点帮助.

小贝也沉默的博客 1万+

ROSpluginlib 包的详细解析

pluginlibROS 提供的一个强大的 C++ 库,旨在简化插件的编写、动态加载卸载过程。插件在 ROS 中指的是可以在运行时加载的类,这些类被编译到动态链接库(如.so文件)中。使用pluginlib动态性:无需在编译时将插件类链接到应用程序中,可以在运行时根据需要加载。模块化:允许开发者在不修改应用程序源代码的前提下,扩展或修改应用行为。灵活性:支持多种插件类型,适用于不同的应用场景。通过pluginlib,开发者可以轻松地实现插件架构,使得系统更具扩展性和可维护性。

m0_73640344的博客 1180

pluginlibROS Wiki

1. 概述 pluginlib是一个C++库,用来从ROS包中加载或者卸载插件。插件是一个动态的可加载的类,能够从运行时库(也就是分享的物体,动态链接库)中进行加载。有了pluginlib,不需要显式的将他们的应用程序和包含他们类的库进行链接,pluginlib可以在任何时候打开一包含导出类的库,而不需要应用程序预先知道库或者包含类定义的头文件。插件对那些不需要应用程序的源码和扩展或者是改变的应...

oreo的博客 353

ROS pluginlib笔记

概述 pluginlib可以用来创建和加载plugin。 思想: pluginlib是一个用于从ROS包中加载和卸载插件的C++库。 插件是从运行时库(即共享对象,动态链接库)加载的动态可加载类。 使用pluginlib,不必显式地将其应用程序包含类的库链接。 pluginlib可以在任何时候打开包含导出类的库,而应用程序不必预先知道库或包含类定义的头文件。 插件可用于扩展/修改应用程序行为,...

qq_41986495的博客 548

ROSpluginlib详解

1. 写在最前面 由于在一个源码中, 关于在ROS平台上的具体实现, 用到了Plugin. 为了更加深入的理解到底是一个什么鬼, 所以对pluginlib进行了一些学习, 下面的内容, 大部分在网站上是能够找到的, 是综合Wiki上的介绍, 以及从源码中看到的内容和自己的尝试. 希望对大家都一点点帮助. pluginlib是一个使用C++实现的库, 用于在ROS包里面动态的加载或卸

ZXQHBD的博客 1468

ROS2】从零到一:基于pluginlib的插件化控制器实战指南

本文详细介绍了如何在ROS2中使用pluginlib实现插件化控制器开发,从环境配置、接口设计到动态加载热切换实战。通过具体案例展示如何构建旋转控制插件,并分享进阶技巧调试方法,帮助开发者提升机器人运动控制算法的灵活性和可维护性。

weixin_29209801的博客 412
上一篇: ROS中的pluginlib使用总结
下一篇: ROS基础内容1
土豆西瓜大芝麻
博客等级 码龄18年 1150粉丝 238原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值