ROS源代码阅读(13)——Plugin

2021SC@SDUSC
ROS源代码阅读(13)

这篇我们主要看一下插件机制(Plugin)

使用Plugin可以更加方便对一个节点、功能包进行修改,添加功能,而无需修改此节点、功能包的源代码,大大提升了代码复用的能力。

官方的解释是:pluginlib是一个C++库,用于从ROS包中加载和卸载插件。插件是从运行库(即共享对象、动态链接库)加载的动态可加载类。使用 pluginlib 时,您不必显式将其应用程序与包含类的库关联起来——相反, pluginlib 可以在任何时候打开包含导出类的库,而应用程序无需事先意识到库或包含类定义的标头文件。插件可用于扩展/修改应用程序行为,而无需应用程序源代码

ROS中应用Plugin的一个例子是在 move_base 节点中,通过插件机制选择不同的 Global planner Local planner 和 Recovery behavior,为什么要选择不同的planner? 因为plan的算法有很多种,常见的规划算法就有A*、Dj等,所以需要使用插件机制方便不同算法下的planner进行切换。

我们可以看Plugin的实现:

#include <pluginlib>/class_list_macros.h     
PLUGINLIB_EXPORT_CLASS(plugin class, base class)

申明基类,确定接口,注意基类的构造函数的参数应为空,所以为了对基类进行初始化,应该使用 如 initialized()等函数进行类的初始化,若使用已有接口类,则省略此步骤,创建插件,插件多以类的形式出现,所以即创建插件类,该类需要继承基类,并覆盖基类的共有接口。插件注册,通过使用Pluginlib中的宏定义,对新创建的插件进行注册

include_directories(include)  
add_library(my_plugins_lib src/my_plugins.cpp)

这里修改CMakeList文件,添加内容,构建插件动态链接库

<library path="lib/libmy_plugins_lib">
  <class name="{plugin class name}" type="{plugin class type}" base_class_type="{base class type}">
    <description>This is an example.</description>
  </class>
 </library>

编译文件,在devel/lib中生成库文件libmy_plugins_lib
添加插件描述文件 my_plugins.xml

<export>
 <{base_class_package_name} plugin="${prefix}/my_plugins.xml"/>
</export>

为了使Pluginlib在ROS的所有功能包中查询到plugin,需要在每个功能包中指出该功能包导出了哪些plugin和哪些功能包使用这些plugin

<build_depend>base_class_package_name</build_depend>
 <run_depend>base_class_package_name</run_depend>

在plugin所在功能包的package.xml中添加对基类的依赖

这样,一个plugin就实现了,下面我们看一下move_base对插件的使用

#include <pluginlib/class_loader.h>
 #include <nav_core/base_local_planner.h> //base class
 #include <nav_core/base_global_planner.h> //base class
 ...
 pluginlib::ClassLoader<nav_core::BaseGlobalPlanner> bgp_loader_;
 pluginlib::ClassLoader<nav_core::BaseLocalPlanner> blp_loader_;
 pluginlib::ClassLoader<nav_core::RecoveryBehavior> recovery_loader_;
 ...
 boost::shared_ptr<nav_core::BaseLocalPlanner> tc_;
 boost::shared_ptr<nav_core::BaseGlobalPlanner> planner_;
 ...
 bgp_loader_("nav_core", "nav_core::BaseGlobalPlanner"),
 blp_loader_("nav_core", "nav_core::BaseLocalPlanner"), 
 recovery_loader_("nav_core", "nav_core::RecoveryBehavior"),
 ...
 try {
   planner_ = bgp_loader_.createInstance(global_planner);
   planner_->initialize(bgp_loader_.getName(global_planner),    planner_costmap_ros_);
    } 
 catch (const pluginlib::PluginlibException& ex) {
   ROS_FATAL("Failed to create the %s planner, are you sure it is properly registered and that the containing library is built? Exception: %s", global_planner.c_str(), ex.what());
   exit(1);
 }
 try {
   tc_ = blp_loader_.createInstance(local_planner);
   ROS_INFO("Created local_planner %s", local_planner.c_str());
   tc_->initialize(blp_loader_.getName(local_planner), &tf_, controller_costmap_ros_);
} 
 catch (const pluginlib::PluginlibException& ex) {
   ROS_FATAL("Failed to create the %s planner, are you sure it is properly registered and that the containing library is built? Exception: %s", local_planner.c_str(), ex.what());
   exit(1);
 }

从上面可以看到,include pluginlib中的Classloader类,使用Classloader实例化一个基类对象,然后将my_loader指向插件对象,并初始化,这样就使用了插件。

对于插件的另一个例子参考ROS Global Planner

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值