ROS的pluginlib学习总结一

在开发中需要使用到插件,因此学习了下pluginlib的一些使用,学习的还不够透彻,先记录一下这几天的学习结果。

关于ROS中pluginlib的使用主要参考的是《ROS的pluginlib的理解与实例》与《ROS专题----pluginlib简明笔记》这两篇文章。第一篇中讲述了一个示例,第二篇是ROS官方中对于pluginlib使用的一些解释的翻译。

简单实现一个ROS pluginlib可以参考第一篇文章中的示例,是可以直接跑通的,下述示例部分摘自该处,仅作记录:

示例

首先, 当然是在自己的工作空间中创建一个用于尝试的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

如果得到类似的输出, 则表示所有都是没问题的.
使用Plugin:在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

进一步思考

在跑通上面的示例的时候,同时也思考了一个问题:怎么实现让主程序与注册的插件处与不同的文件夹下?作为一个快插快换的存在,灵活性一定是最重要的。那么肯定是需要程序间调用,所以两者的拆分很重要,最后经过了一些尝试以及资料的查询总算是实现了这个需求。

这里最主要是要明确插件描述文件:插件描述文件是用于存储所有关于在机器可读格式的插件的重要信息的XML文件。它包含有关插件所在的库的信息,插件的名称,插件的类型等。我们需要这个文件除了代码宏,允许ROS系统自动发现,加载和推理插件。插件描述文件还包含重要信息,如插件的描述,不适合在宏中。也就是上面的这部分:

        <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>

为了让pluginlib查询跨所有ROS包的系统上的所有可用插件,每个包必须显式指定它导出的插件,以及哪些包库包含这些插件。一个插件提供者必须指向它的插件描述文件,在其package.xml中的内外销标签块。注意,如果您有其他导出,他们都必须在同一导出字段。对应上面的:

<plugin_test plugin="${prefix}/polygon_plugins.xml" />

这两块内容都是用于ROS中注册插件时使用的而不是调用插件时使用的,因此要写在注册的包内,这个在一开始自己写的时候没有理解因此一直不能跑起来,后面去看了第二篇文章后才略微理解了一些,后面修改完后实现了需要的功能。修改后的实现参见示例二:

示例2

建立一个插件文件夹

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

    $ roscd$ cd ../src$ catkin_create_pkg plugin_node roscpp pluginlib

在include/plugin_node文件夹下新建文件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_node文件夹下新建文件polygon_plugins.h, 将下述代码拷贝进去, 申明我们的插件:

        #ifndef PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_#define PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_#include <plugin_node/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_node/polygon_base.h>#include <plugin_node/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申明:

        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" />

这一部分跟前面第一部分的前面一半基本是一致的。

建立一个调用插件的文件

在前面部分我们已经完成了一个插件的建立,这里我们重新建立一个文件夹去调用上述的插件:

    $ roscd$ cd ../src$ catkin_create_pkg plugin_used roscpp pluginlib

在include/plugin_used文件夹下新建文件polygon_used.h, 将下述代码拷贝进去:

#ifndef PLUGINLIB_TUTORIALS__POLYGON_USED_H_
#define PLUGINLIB_TUTORIALS__POLYGON_USED_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_used.cpp文件, 用于测试, 复制下述内容:

#include <pluginlib/class_loader.h>
#include <plugin_used/polygon_used.h>int main(int argc, char** argv)
{pluginlib::ClassLoader<polygon_base::RegularPolygon> poly_loader("plugin_node", "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 is: %.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

按照上述的方式,可以把插件与执行文件隔离开,即使需要修改插件也不用重新编译执行文件,可以实现一个插件快速修改或者加载的功能。很大程序上的提高了程序的灵活性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/703159.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

react中修改state中的值无效?

// 初始化state state {personArr:[{name:张三,id:1},{name:李四,id:2},{name:王五,id:3}] }componentDidMount(){const newName 赵六const indexUpdate 1const newArr this.state.personArr.map((item,index)>{if(indexUpdate index){return {...item,name:newName}}e…

危险的代码!

//删除 getMatchmakers_delete() {this.isLoadingtrue;// Make an Axios POST request to your backend endpointaxios.delete(config_ipadministrator_id_and_matchmaker_name_delete, {administratorId: this.id,matchmakerName: this.matchmakerName_search}).then(response…

Nest.js权限管理系统开发(六)新建模块

本文相关文档&#xff1a;NestJS 中文网 创建模块 nest g命令 我们知道一个模块往往包含controller、module、service等文件&#xff0c;为了方便我们创建这些文件&#xff0c;nest cli提供了一些命令&#xff1a; 生成模块 (nest g mo) 以保持代码井井有条并建立清晰的边界…

适合新手博主站长使用的免费响应式WordPress博客主题JianYue

这款JianYue主题之所以命名为 JianYue&#xff0c;意思就是简单而不简约的。是根据Blogs主题优化而成&#xff0c;剔除了一些不必要的功能及排版&#xff0c;仅保留一种博客布局&#xff0c;让新手站长能够快速手上WordPress。可以说这款主题比较适合新手博主站长使用&#xff…

SpringCloud-Docker原理解析

Spring Cloud和Docker的结合为微服务架构的部署和管理提供了强大的支持。本文深入剖析Spring Cloud与Docker的集成原理&#xff0c;从服务注册与发现、配置管理、负载均衡到容器化部署等方面展开详细解析。探讨Spring Cloud如何利用Docker容器技术实现服务的弹性伸缩&#xff0…

【深度学习】CIFAR10图像分类

案例3&#xff1a;PyTorch实战: CIFAR10图像分类 1 任务目标 1.1 用多层感知机(MLP)和卷积网络(ConvNet)完成CIFAR10分类 使用PyTorch分别实现多层感知机(MLP)和卷积网络(ConvNet)&#xff0c;并完成CIFAR10数据集&#xff08;http://www.cs.toronto.edu/~kriz/cifar.html&a…

力扣:134. 加油站

1.分为三种情况&#xff0c;一种为总存储的油小于总消耗的油&#xff0c;这样不能跑一圈。二种为从0结点开始就没有断过油。三种为中间有断油过&#xff0c;从后面向前遍历后填过剩下油的最小值&#xff0c;这个点就是出发点。 class Solution {public int canCompleteCircui…

[C++]C++中memcpy和memmove的区别总结

这篇文章主要介绍了C中memcpy和memmove的区别总结,这个问题经常出现在C的面试题目中,需要的朋友可以参考下 变态的命名 我们在写程序时&#xff0c;一般讲究见到变量的命名&#xff0c;就能让别人基本知道该变量的含义。memcpy内存拷贝&#xff0c;没有问题;memmove&#xff…

测试环境搭建整套大数据系统(七:集群搭建kafka(2.13)+flink+hudi+dinky)

一&#xff1a;搭建kafka。 1. 三台机器执行以下命令。 cd /opt wget wget https://dlcdn.apache.org/kafka/3.6.1/kafka_2.13-3.6.1.tgz tar zxvf kafka_2.13-3.6.1.tgz cd kafka_2.13-3.6.1/config vim server.properties修改以下俩内容 1.三台机器分别给予各自的broker_id…

AIGC实战——扩散模型(Diffusion Model)

AIGC实战——扩散模型 0. 前言1. 去噪扩散概率模型1.1 Flowers 数据集1.2 正向扩散过程1.3 重参数化技巧1.4 扩散规划1.5 逆向扩散过程 2. U-Net 去噪模型2.1 U-Net 架构2.2 正弦嵌入2.3 ResidualBlock2.4 DownBlocks 和 UpBlocks 3. 训练扩散模型4. 去噪扩散概率模型的采样5. …

STM32 4位数码管和74HC595

4位数码管 在使用一位数码管的时候&#xff0c;会用到8个IO口&#xff0c;那如果使用4位数码管&#xff0c;难道要使用32个IO口吗&#xff1f;肯定是不行的&#xff0c;太浪费了IO口了。把四个数码管全部接一起共用8个IO口&#xff0c;然后分别给他们一个片选。所以4位数码管共…

✅技术社区项目—JWT身份验证

通用的JWT鉴权方案 JWT鉴权流程 基本流程分三步: ● 用户登录成功之后&#xff0c;后端将生成的jwt返回给前端&#xff0c;然后前端将其保存在本地缓存; ● 之后前端与后端的交互时&#xff0c;都将iwt放在请求头中&#xff0c;比如可以将其放在Http的身份认证的请求头 Author…

C语言编程安全规范

目的 本规范旨在加强编程人员在编程过程中的安全意识,建立编程人员的攻击者思维,养成安全编码的习惯,编写出安全可靠的代码。 2 宏 2.1 用宏定义表达式时,要使用完备的括号 2.2 使用宏时,不允许参数发生变化 3 变量 3.1 所有变量在定义时必须赋初值 变量声明赋予初值,可…

试验铁底板安装流程——北重厂家

试验台铁底板安装流程有哪些&#xff1a; 准备工作&#xff1a;将地面清理干净&#xff0c;并确认地面平整无明显障碍物。 安装定位桩&#xff1a;在地面上标出台铁的位置&#xff0c;并使用锤子和钉子或其他固定工具&#xff0c;将定位桩固定在地面上。 准备底板&#xff1a…

B端系统:导航机制设计,用户体验提升的法宝

Hi&#xff0c;大家好&#xff0c;我是贝格前端工场&#xff0c;从事8年前端开发的老司机。很多B端系统体验不好很大一部分原因在于导航设计的不合理&#xff0c;让用户无所适从&#xff0c;大大降低了操作体验&#xff0c;本文着重分析B端系统的导航体系改如何设计&#xff0c…

$attrs

一、概念 vue官网定义如下: 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过v-bind="$attrs"传入内部组件——在创建…

vscode 离线安装--扩展包

在很多情况下&#xff0c;我们不能联网下载 vscode 的扩展包&#xff0c;下面记录一下怎么离线安装和下载 扩展包的下载地址 下载地址 安装指令 code --install-extension 文件名wsl vscode 如果是 win wsl 的环境&#xff0c;除了在 win 的 vscode 下要安装一次扩展包&…

抖店是怎么运营做起来的?一文详解抖店的运营逻辑和流程,可收藏

我是王路飞。 很多人都知道现在的抖音有【商城】&#xff0c;进入之后就是一个个的抖音小店了&#xff0c;也知道抖店的红利。 但是抖店具体是怎么运营并且做起来的&#xff0c;就不太清楚了&#xff0c;因此很多新手明明眼馋抖店的红利&#xff0c;却又无从下手。 今天这篇…

Java 中常用的数据结构类 API

目录 常用数据结构API 对应的线程安全的api 高可用衡量标准 常用数据结构API ArrayList: 实现了动态数组&#xff0c;允许快速随机访问元素。 import java.util.ArrayList; LinkedList: 实现了双向链表&#xff0c;适用于频繁插入和删除操作。 import java.util.LinkedLis…

Spring综合漏洞利用工具

Spring综合漏洞利用工具 工具目前支持Spring Cloud Gateway RCE(CVE-2022-22947)、Spring Cloud Function SpEL RCE (CVE-2022-22963)、Spring Framework RCE (CVE-2022-22965) 的检测以及利用&#xff0c;目前仅为第一个版本&#xff0c;后续会添加更多漏洞POC&#xff0c;以及…