【ROS-1】关于插件的编写与使用(pluginlib)

【场景描述】

pluginlib直译是插件库,所谓插件字面意思就是可插拔的组件,比如:以计算机为例,可以通过USB接口自由插拔的键盘、鼠标、U盘...都可以看作是插件实现,其基本原理就是通过规范化的USB接口协议实现计算机与USB设备的自由组合。同理,在软件编程中,插件是一种遵循一定规范的应用程序接口编写出来的程序,插件程序依赖于某个应用程序,且应用程序可以与不同的插件程序自由组合。在ROS中,也会经常使用到插件,场景如下:

  1. 导航插件:在导航中,涉及到路径规划模块,路径规划算法有多种,也可以自实现,导航应用时,可能需要测试不同算法的优劣以选择更合适的实现,这种场景下,ROS中就是通过插件的方式来实现不同算法的灵活切换的。
  2. rviz插件:在rviz中已经提供了丰富的功能实现,但是即便如此,特定场景下,开发者可能需要实现某些定制化功能并集成到rviz中,这一集成过程也是基于插件的。

 

 

 

 【官方定义】

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

【插件意义】

其实对于ROS-1初学者来说,写得最多的是什么?没错,是节点!因为ROSWIKI上的入门教程都是教你如何写节点程序的,比如一个发布者,或是一个服务器。但是随着你编写的程序越来越复杂,实现的功能模块越来越齐全,你就会发现写节点太过于分散了,每次需要启动一大堆的节点,而这些节点很可能在场景中的地位是平等且并行的,这时候你就会想到,有没有可能用一种方式把这些节点像浏览器书签一样管理,想用哪个就把哪个调出来,动态的进行实例化和加载使用。幸运的是,ROS-1开发者也预料到了这种使用场景,所以他们提供了pluginlib这个c++库,其底层就是帮我们实现了一套工厂模式!!

【编写插件】

  • 定义一个基类
namespace general_plugin
{
class BasePlugin
{
public:
  BasePlugin();
  virtual ~BasePlugin();

public:
  virtual void initialize(const std::string name) = 0;
  virtual void start() = 0;
  virtual void stop() = 0;
  virtual void interrupt() = 0;
  virtual void goon() = 0;
  virtual int get_status() = 0;

};
}
  • 定义一个插件类

头文件

namespace general_plugin
{
class MotionControl : public BasePlugin
{
public:
  MotionControl();
  ~MotionControl();

public:
  void initialize(const std::string name);
  void start();
  void stop();
  void interrupt();
  void goon();
  int get_status();

private:
  std::string plugin_name;
  std::atomic_int status;
}
}

源文件

#include <pluginlib/class_list_macros.h>

PLUGINLIB_EXPORT_CLASS(general_plugin::MotionControl, general_plugin::BasePlugin)

namespace general_plugin
{
}

CMakeLists.txt文件

cmake_minimum_required(VERSION 3.0.2)
project(motion_control)

add_compile_options(-std=c++11)

find_package(catkin REQUIRED COMPONENTS
  base_plugin
  pluginlib
  roscpp
  actionlib
)

catkin_package(
  INCLUDE_DIRS include
  LIBRARIES motion_control
  CATKIN_DEPENDS base_plugin pluginlib roscpp message_generation message_runtime actionlib
#  DEPENDS system_lib
)

include_directories(
 include
  ${catkin_INCLUDE_DIRS}
)

add_library(${PROJECT_NAME}
   src/motion_control.cpp
)

add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

target_link_libraries(${PROJECT_NAME}
  ${catkin_LIBRARIES}
)
add_executable(${PROJECT_NAME}_node test/node.cpp)
target_link_libraries(${PROJECT_NAME}_node
   ${catkin_LIBRARIES}
   ${PROJECT_NAME}
)

package.xml文件

<?xml version="1.0"?>
<package format="2">
  <name>motion_control</name>
  <version>0.0.0</version>
  <description>The motion_control package</description>

  <maintainer email="starlab@todo.todo">starlab</maintainer>

  <license>TODO</license>

  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>base_plugin</build_depend>
  <build_depend>pluginlib</build_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>actionlib</build_depend>
  <build_export_depend>base_plugin</build_export_depend>
  <build_export_depend>pluginlib</build_export_depend>
  <build_export_depend>roscpp</build_export_depend>
  <exec_depend>base_plugin</exec_depend>
  <exec_depend>pluginlib</exec_depend>
  <exec_depend>roscpp</exec_depend>
  <exec_depend>actionlib</exec_depend>

  <export>
    <base_plugin plugin="${prefix}/motion_control.xml" />
  </export>
</package>

motion_control.xml文件(放在功能包里,和package.xml同级目录)

<library path="lib/libmotion_control">
  <class name="general_plugin/MotionControl" type="general_plugin::MotionControl" base_class_type="general_plugin::BasePlugin">
    <description>
      A plugin demo.
    </description>
  </class>
</library>

【查询插件】

上面例子中,我们的插件隶属于 general_plugin ,所以可以这样查询

rospack plugins --attrib=plugin general_plugin

【使用插件】

通过下面的方式,即可在主程序中动态加载插件类

auto plugin_loader = new pluginlib::ClassLoader<general_plugin::BasePlugin>("base_plugin", "general_plugin::BasePlugin");

boost::shared_ptr<general_plugin::BasePlugin> derive_plugin = plugin_loader->createInstance("general_plugin/MotionControl");

【友情提示】

一般来说,我们可以自己写一个软件总线来管理调度所有的插件,每个功能插件应该是独立的,可控的,并且实现了启停等基本API,切记不可在插件构造函数中写能够造成阻塞的代码段!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值