【ROS】(基于现有类实现)插件plugin的编写及调用

        看到网上的各种方法都是wiki上的内容,先创建一个基类,再写插件类继承基类实现。那么,基于现有类是怎么实现的呢?其实也是一样的原理,只不过在实现的过程中稍微注意一下就可以了。在这里分享一下我写的一个基于现有类的例子,以供跟我一样有该需求的人进行参考。
        在看我这篇文章之前,推荐大家先看看wiki版本的插件编写,然后再反过来看看这两者有什么区别。基于手写一个基类的插件是怎么实现的,大家可以翻看一下wiki,或者查询一下古月大神等的博客都可以找到答案。我这里说的是不用创建基类的写法。在这里,我将一个简单的机器人运动控制类做成一个插件的形式为例,再用另外一个包调用这个插件(wiki是在同一个包中进行调用),实现简单的运动等。
一、编写插件
1.1 编写步骤
一般来说,插件的编写步骤分为以下几步:
1、创建一个基类(这个是wiki上的写法,在这里我不用这一步)
2、创建插件类,继承基类(由于我没有创建一个基类,所以这里也不需要继承了)
3、注册插件
4、编译生成动态链接库
5、加入插件到ros
1.2 创建插件类及注册插件
首先在src目录下创建一个插件包,比如我就在自己的~/catkin_ws/src下创建

catkin_create_pkg controller_plugins roscpp pluginlib

ps:这里这个包名最好不要这样命名。大家在命名的时候一定要注意,比如包名、插件名、命名空间、类名一定要是独一无二的。

接着,在include目录下新建插件类的头文件,我这里为move_controller.h,里面添加如下内容:

#ifndef __MOVE_CONTROLLER_H_
#define __MOVE_CONTROLLER_H_

#include 
namespace move_controller
{
  class MoveController
  {
    public:
      MoveController(){};
      ~MoveController(){};
      void set_line_velocity(const double& line_vel);
      void set_angular_velocity(const double& angular_vel);
      void print_sth();
    private:
      double line_velocity;
      double angular_velocity;

  };

}

#endif

很简单的一个类,这里有一点要注意的就是,插件类的构造参数不能够带参数的。

好了,接下来该写是怎么实现的了。

在插件包的src目录下新建move_controller.cpp文件,并添加如下内容:

#include "controller_plugins/move_controller.h"
//注册插件,这里的参数为:(实现类,基类)
PLUGINLIB_EXPORT_CLASS(move_controller::MoveController, move_controller::MoveController)

namespace move_controller
{
  void MoveController::set_line_velocity(const double& line_vel)
  {
    line_velocity = line_vel;
    printf("set line velocity to %f.\n",line_vel);
  }

  void MoveController::set_angular_velocity(const double& angular_vel)
  {
    angular_velocity = angular_vel;
    printf("set angular velocity to %f.\n",angular_vel);    
  }

  void MoveController::print_sth()
  {
    printf("line velocity %f, angular velocity %f.\n",line_velocity,angular_velocity);
  }

}

看出来了吧,跟wiki上的差别就在参数这里,这里的这些类名一定要注意正确填写。通过该宏,就可以注册插件了。

1.3编译插件动态链接库

修改CMakeLists.txt文件里面的内容:

cmake_minimum_required(VERSION 2.8.3)
project(controller_plugins)

find_package(catkin REQUIRED COMPONENTS
  pluginlib
  roscpp
)

catkin_package(
  INCLUDE_DIRS include
#  LIBRARIES controller_plugins
#  CATKIN_DEPENDS pluginlib roscpp
#  DEPENDS system_lib
)

include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)

## Declare a C++ library
add_library(controller_for_plugin
  src/move_controller.cpp
)

这里的动态库名一定要注意写好,我这里只是为了与包名做区别。如果还有其他需求可以在上述内容上做扩展。比如工程需要还可以install

install(TARGETS controller_for_plugin
        DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
)
install(DIRECTORY include/${PROJECT_NAME}/
        DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
)
install(DIRECTORY plugins
        DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
)

1.4将插件加入到ros

在插件包目录下建立plugins文件夹并新建controller_for_plugin.xml文件,内容如下:


	
			This is a MoveController plugin
		

ps:这里文件名、path中都用的是上一步生成的动态库的名称,也就是插件名。class标签的参数分别为插件类与基类。

修改package.xml文件,内容如下:

catkin
  pluginlib
  roscpp
  pluginlib
  roscpp
  pluginlib
  roscpp


  
  
    
    
  

我这里只展示了添加的地方,其余内容均是自动生成的。特别注意,export标签第一个是插件包名,后面跟的是插件的xml文件路径。

最终的插件包的目录图如下所示:

【ROS】(基于现有类实现)插件plugin的编写及调用_第1张图片

到这里,插件的编写就完成了。接下来直接catkin_make就可以编译插件包了。下面继续写如何用另外一个单独的包调用这个插件。

二、调用插件

2.1编写插件调用类

在~/catkin_ws/src目录下创建调用插件的包:

catkin_create_pkg use_plugins cpp pluginlib

在include/use_plugins文件夹下新建path_plan.h头文件,内容如下:

#ifndef __PATH_PLAN_H__
#define __PATH_PLAN_H__

#include 
#include 
#include 

namespace path_ctrl
{
  class PathPlan
  {
    public:
      PathPlan();
      ~PathPlan(){};
      void init();

    private:
      pluginlib::ClassLoader plugin_loader;
      boost::shared_ptr move_controller;
      double line_velocity;
      double angle_velocity;
  };

}

#endif

这里,plugin_loader创建一个插件加载对象,用于加载插件,其本来的参数为(含基类包名,插件类的基类全名),在这里我们写为(插件包名,插件类全名),即plugin_loader("controller_plugins","move_controller::MoveController")

在调用包src目录新建path_plan.cpp文件,并添加内容如下:

#include "use_plugins/path_plan.h"

namespace path_ctrl
{
  PathPlan::PathPlan():plugin_loader("controller_plugins","move_controller::MoveController")
  {
    line_velocity = 1.0;
    angle_velocity = 0.5;
  };

  void PathPlan::init()
  {
    //根据输入参数(插件类名),通过插件加载对象创建相应的插件实例
    move_controller = plugin_loader.createInstance("move_controller::MoveController");
    //现在可以调用插件类的函数了
    move_controller->set_line_velocity(line_velocity);
    move_controller->set_angular_velocity(angle_velocity);
    move_controller->print_sth();
  }

}

2.2编写执行文件

在调用包src目录下新建main.cpp,简单内容如下:

#include "use_plugins/path_plan.h"

int main(int argc, char *argv[])
{
  path_ctrl::PathPlan path_plan;
  path_plan.init();
  return 0;
}

如果有其他需求可以自己添加上去,这里就不做重复说明了。

2.3修改CMakeLists.txt文件

cmake_minimum_required(VERSION 2.8.3)
project(use_plugins)

#add_compile_options(-std=c++11)

find_package(catkin REQUIRED COMPONENTS
  pluginlib
  roscpp
  controller_plugins
)

catkin_package(
  INCLUDE_DIRS include 
  #LIBRARIES controller_plugins
  #CATKIN_DEPENDS pluginlib roscpp
 #DEPENDS system_lib
)
#添加头文件目录
include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)
#添加需要链接的库文件目录
link_directories(${CATKIN_DEVEL_PREFIX}/../lib)
#添加可执行文件
add_executable(${PROJECT_NAME}_node src/main.cpp src/path_plan.cpp)
#设置要链接的库文件的名称
target_link_libraries(${PROJECT_NAME}_node
  controller_for_plugin
  ${catkin_LIBRARIES}
)

这里库文件目录如果不是很清楚可以自己去devel目录下查找就知道了。

如果对大括号里面的变量路径感到疑惑,可以使用MESSAGE指令用于打印显示,例如:

MESSAGE(STATUS "This is CATKIN DEVEL PREFIX dir " ${CATKIN_DEVEL_PREFIX})

2.4修改package.xml文件

也就是把插件包包含进去,内容如下,只显示修改之后的内容:

catkin
  pluginlib
  roscpp
  controller_plugins
  pluginlib
  roscpp
  pluginlib
  roscpp
  controller_plugins

最终调用包的目录结构如下所示:

【ROS】(基于现有类实现)插件plugin的编写及调用_第2张图片

欧克。下面就可以开始catkin_make编译了。编译成功之后,就可以通过rosrun use_plugins use_plugins_node运行该节点了,效果如下,可以发现调用成功:

【ROS】(基于现有类实现)插件plugin的编写及调用_第3张图片

你可能感兴趣的:(ROS)