当前位置:网站首页>ROS设置plugin插件
ROS设置plugin插件
2022-08-04 12:50:00 【华为云】
为什么要设置plugin插件
因为很多时候我们需要对产品进行包装。核心的代码是只留下输入输出接口的,所以我们使用plugin来实现.so文件的封装以及动态调取。
在ROS的开发中,常常会接触到一个名词——插件(plugin)。这个名词在计算机软件开发中是常常会提到的,具体含义可以参考百度百科的插件词条。在ROS中,插件的概念类似,简单来讲,ROS中的插件(plugin)就是可以动态加载的扩展功能类。ROS中的pluginlib功能包,提供了加载和卸载plugin的C++库,开发者在使用plugin时,不需要考虑plugin类的链接位置,只需要将plugin注册到pluginlib中,即可直接动态加载。这种插件机制非常方便,开发者不需要改动原本软件的代码,直接将需要的功能通过plugin进行扩展即可。本文带你走近plugin,探索如何实现一个简单的plugin。
我们首先通过下边这张图来了解一下pluginlib的工作原理。
假设ROS的功能包中已经存在一个polygon的基类(polygon_interface_package),我们可以通过plugin来实现两种polygon的功能支持:rectangle_plugin(rectangle_plugin_package)和triangle_plugin(triangle_plugin_package),在这两个功能包的package.xml中,需要声明polygon_interface_package中的基类polygon,然后在编译的过程中,会把插件注册到ROS系统,用户可以直接通过rospack的命令进行全局的插件查询,也可以在开发中直接使用这些插件了。
详细流程
pluginlib利用了C++多态的特性,不同的插件只要使用统一的接口,就可以替换使用,用户在使用过程中也不需要修改代码或者重新编译,选择需要使用的插件即可扩展相应的功能。一般来讲,实现一个插件主要需要以下几个步骤:
- 创建基类,定义统一的接口。如果是基于现有的基类实现plugin,则不需要这个步骤。
- 创建plugin类,继承基类,实现统一的接口。
- 注册插件
- 编译生成插件的动态链接库
- 将插件加入ROS系统
1)创建基类
接下来,我们就根据这几个步骤来实现第一节图示中的plugin功能,在开始之前,你需要建立一个pluginlib_tutorials的功能包,添加依赖pluginlib。
catkin_create_pkg pluginlib_tutorials roscpp pluginlib此时,工程目录环境如下(注意这里有一些文件是后边步骤中才创建的):
catkin/|---src/ |---CMakeLists.txt -> /opt/ros/kinetic/share/catkin/cmake/toplevel.cmake |---pluginlib_tutorials_/ |---CMakeLists.txt |---include/ |---pluginlib_tutorials_/ |---package.xml |---polygon_plugins.xml |---src/在CMakeLists.txt和package.xml中如下图所示会出现pluginlib的库


创建catkin/src/pluginlib_tutorials_/include/pluginlib_tutorials_/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这里创建了个RegularPolygon抽象基类,后边的插件类就是继承该类。
2)创建插件
在include目录下创建include/pluginlib_tutorials_/polygon_plugins.h文件,并写入如下代码:
#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这里创建了两个继承自基础类RegularPolygon的插件子类Triangle和Square。
3)注册插件
在2)中已经创建了两个类Triangle和Square,接下来需要使用pluginlib将这两个类声明为插件。
创建src/polygon_plugins.cpp文件,并写入以下代码:
#include <pluginlib/class_list_macros.h>#include <pluginlib_tutorials_/polygon_base.h>#include <pluginlib_tutorials_/polygon_plugins.h> //注册插件,宏参数:plugin的实现类,plugin的基类PLUGINLIB_EXPORT_CLASS(polygon_plugins::Triangle, polygon_base::RegularPolygon)PLUGINLIB_EXPORT_CLASS(polygon_plugins::Square, polygon_base::RegularPolygon)这里前三行include分别引入的头文件,是为了以下内容PLUGINLIB_EXPORT_CLASS、polygon_base::RegularPolygon、polygon_plugins::Triangle、polygon_plugins::Square能够找到。
后边两行代码,使用pluginlib中提供的PLUGINLIB_EXPORT_CLASS来将polygon_plugins::Triangle、polygon_plugins::Square注册为插件,这两个类的父类为polygon_base::RegularPolygon。
4)编译插件
在CMakeLists.txt文件中写入下面两行代码:
include_directories(include)add_library(polygon_plugins src/polygon_plugins.cpp)#可以考虑下面的使用install实现将插件放置到可执行文件或者库文件中install(FILES blp_plugin.xml DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})install具体可以参照《CMakeLists文件install的使用》进行设置,ROS当中的CATKIN_PACKAGE_SHARE_DESTINATION可以参照下文。
此时,可以在命令行窗口的工作空间顶目录下输入catkin_make命令进行编译:

通过编译日志可以看出,编译完成后生成了动态库libpolygon_plugins.so,存放在devel/lib下面。这个也就是我们创建成功的插件文件。
至此,插件创建成功了,下面徐亚创建插件描述文件以让ROS中插件加载器找到这个插件并提供给每个应用程序中来使用。
5)将创建的插件添加到ROS的工具链当中
(1)创建插件描述文件
在catkin/src/pluginlib_tutorials_/路径下创建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>可以仔细看一下这个xml文件中的内容。
<library path="lib/libpolygon_plugins"> library标签写明了要输出的lib文件所在的相对路径;
<class></class> class标签内容写明了插件的信息。
type:插件的完整类型,例如polygon_plugins::Triangle;
base_class_type:插件完整类型的父类,例如polygon_base::RegularPolygon;
description:描述插件是做什么的;
(2)导出插件
在package.xml文件中写入以下代码,将创建的插件导出:
<export> <pluginlib_tutorials_ plugin="${prefix}/polygon_plugins.xml" /></export>可以看出,这里使用export标签将插件导出,里边指定了以上创建的插件描述文件的路径,其中pluginlib_tutorials_为基类所在的包名称。
此时,再次进行编译:

验证创建的插件是否有效:
这里,先source一下setup.bash文件,然后输入以下命令:
rospack plugins --attrib=plugin pluginlib_tutorials_可以看出输出结果为创建的插件polygon_plugins.xml的绝对路径,这表明ROS工具链设置正确,可以和创建的插件一起使用。
在ROS程序中使用插件
插件已经创建好了,怎么使用插件呢?这里需要写一个插件测试程序来使用插件。
打开src/polygon_loader.cpp文件,并写入以下内容:
#include <pluginlib/class_loader.h>#include <pluginlib_tutorials_/polygon_base.h> int main(int argc, char** argv){ // 创建一个ClassLoader,用来加载plugin pluginlib::ClassLoader<polygon_base::RegularPolygon> poly_loader("pluginlib_tutorials_", "polygon_base::RegularPolygon"); try { // 加载Triangle插件类,路径在polygon_plugins.xml中定义 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;}从上边的代码中我们可以看到,plugin可以在程序中动态加载,成功加载之后就可以调用plugin的接口来实现相应的功能了。
修改CMakefile.txt,添加上边代码的编译规则:
add_executable(polygon_loader src/polygon_loader.cpp) target_link_libraries(polygon_loader ${catkin_LIBRARIES})然后编译并运行,可以看到如下结果:

参考链接
https://blog.csdn.net/moyu123456789/article/details/107907196?spm=1001.2014.3001.5501
边栏推荐
猜你喜欢

【黑马早报】尚乘数科上市13天,市值超阿里;北大终止陈春花聘用合同;新东方花近200亿退学费和遣散费;张小泉75%产品贴牌代工...

使用SQLServer复制数据库

手搓一个“七夕限定”,用3D Engine 5分钟实现烟花绽放效果

为什么密码云服务平台是云时代的必然之选?

Focusing on data sources, data quality and model performance to build a credit profile of small and micro enterprises

MySQL-数据类型

如何治理资源浪费?百度云原生成本优化最佳实践

Arduino框架下I2S控制ADC采样以及PWM输出示例解析

情人节浪漫3D照片墙【附源码】
![Valentine's Day Romantic 3D Photo Wall [with source code]](/img/a9/2c26f4f048f3c0a9a65551bc734233.png)
Valentine's Day Romantic 3D Photo Wall [with source code]
随机推荐
持续交付(三)Jenkinsfile语法使用介绍
双目立体视觉笔记(三)三角测量、极线校正
Focus!2022 interview must brush 461 interview questions summary + interview + resume template
d不要直接用转串
Do you understand the various configurations in the project?
1314元的七夕礼盒,收割了多少直男?
使用COLMAP初步三维重建
什么是 DevOps?看这一篇就够了!
Motion Rule (16)-Union Check Basic Questions-Grid Game
The head module of the yolo series
Two years of independent development experience Programmers tell us the experience of making money (listen to the masters who really make money)
新SCADA 系统:集成边缘计算、MQTT 和云平台
LeetCode_3_无重复字符的最长子串
“蔚来杯“2022牛客暑期多校训练营4 N
Systemui qsSetting添加新图标
ReentrantLock 原理
做项目管理有且有必要了解并学习的重要知识--PMP项目管理
Chinese valentine's day of young people crazy to make money, earn 140000 a week
leetcode 48. Rotate Image 旋转图像(Medium)
倒计时 3 天|一起看云原生 Meetup 的六大议题
