目录
一、创建包
在工作空间创建功能包时候需要依赖pluginlib
catkin_create_pkg my_plugin_package roscpp pluginlib
二、创建插件接口(父类)
- 在包中创建一个插件接口,这通常是一个抽象类,定义了插件必须实现的方法。
- 在
my_plugin_package/include
下创建my_plugin_interface.h
文件:
#ifndef MY_PLUGIN_INTERFACE_H
#define MY_PLUGIN_INTERFACE_H
namespace my_plugin_package {
class MyPluginInterface {
public:
virtual void doSomething() = 0;
virtual ~MyPluginInterface() {}
};
} // namespace my_plugin_package
#endif // MY_PLUGIN_INTERFACE_H
virtual void doSomething() = 0;
virtual
关键字表明这是一个虚函数,可以在派生类中被重写。= 0
告诉编译器这是一个纯虚函数,即没有实际的实现,任何派生类都必须提供其实现。- 当一个类包含至少一个纯虚函数时,它就变成了抽象类。抽象类不能被实例化,而只能被用作派生其他类的基类。子类必须提供对基类中所有纯虚函数的实现,否则它们也会成为抽象类。
- 基类需要无参构造函数
- 派生类构造函数调用:创建派生类的对象时自动调用基类的构造函数。如果基类没有无参数构造函数,需要在派生类的成员初始化列表中显式调用基类的构造函数。
三、创建插件的实现
1. 插件的头文件实现
- 在
my_plugin_package/include
下创建my_plugin_Implementation.h
文件:
#ifndef MY_PLUGIN_IMPLEMENTATION_H
#define MY_PLUGIN_IMPLEMENTATION_H
//包含插件接口类的头文件,因为要继承接口类
#include "my_plugin_package/my_plugin_interface.h"
namespace my_plugin_package {
//基类和实现类都在一个namespace下,可不用写 my_plugin_package::MyPluginInterface
class MyPluginImplementation : public MyPluginInterface {
public:
//重写基类的纯虚函数
//函数的实现在cpp文件里
void doSomething() override;
};
} // namespace my_plugin_package
#endif // MY_PLUGIN_IMPLEMENTATION_H
- 当一个类包含至少一个纯虚函数时,它就变成了抽象类,它不能被实例化,只能被用作派生其他类的基类。子类需重写基类中所有纯虚函数,否则它们也会成为抽象类。
override
:会让编译器判断此函数是否在重写基类中的虚函数,如果基类中没有相应的虚函数,或者函数签名不匹配,编译器将产生错误。
2. 插件的源文件实现
- 在
my_plugin_package/src
下创建my_plugin_Implementation.cpp
文件- 包含头文件
pluginlib/class_list_macros.h
- 并添加
PLUGINLIB_EXPORT_CLASS()
注册插件
- 包含头文件
#include <pluginlib/class_list_macros.h>
#include "my_plugin_pkg/my_plugin_interface.h"
#include "my_plugin_pkg/my_plugin_Implementation.h"
//插件库导出操作,需要包含基类和派生类的头文件
PLUGINLIB_EXPORT_CLASS(my_plugin_pkg::MyPluginImplementation, my_plugin_pkg::MyPluginInterface)
namespace my_plugin_package {
//派生类的函数的具体实现
void MyPluginImplementation::doSomething() override {
// 实现插件的具体功能
}
} // namespace my_plugin_package
PLUGINLIB_EXPORT_CLASS
将派生类注册为插件
四、修改包下的CMakeLists.txt
文件
构建插件库,文件中添加插件库的构建和链接:
include_directories(
include
${catkin_INCLUDE_DIRS}
)
add_library(my_plugin_library src/my_plugin_Implementation.cpp)
修改cmakeLists.txt
之后catkin_make
,会在工作空间下生成devel/lib/libmy_plugin_library.so
五、创建插件描述文件:
1. 插件描述文件
在功能包
下创建my_plugin.xml
文件:
<!-- 插件库的相对路径 文件不用写.so-->
<library path="lib/libmy_plugin_library">
<!-- type="插件类" base_class_type="基类" -->
<class name="my_plugin_package::MyPluginImplementation" type="my_plugin_package::MyPluginInterface" base_class_type="my_plugin_package::MyPluginInterface">
<!-- 描述信息 -->
<description>A description of your plugin.</description>
</class>
</library>
2. 导出插件
在功能包下的pakage.xml
尾部设置如下:
<export>
<!--基类所属的功能包名字 plugin=""本包下插件的描述文件位置-->
<my_plugin_package plugin="${prefix}/my_plugin.xml" />
</export>
${prefix}
可以定位到功能包路径
rospack plugins --attrib=plugin my_plugin_package
查看功能包下的插件
六、使用插件
新建use_plugin.cpp
文件包含类加载器
头文件pluginlib/class_loader.h
#include "ros/roscpp.h"
#include "pluginlib/class_loader.h"
#include "my_plugin_package/my_plugin_interface.h"
int main(int argc, char** argv) {
ros::init(argc, argv, "my_plugin_node");
ros::NodeHandle nh;
// 使用插件库加载插件
pluginlib::ClassLoader<my_plugin_package::MyPluginInterface> plugin_loader("my_plugin_package", "my_plugin_package::MyPluginInterface");
// 创建插件实例
boost::shared_ptr<my_plugin_package::MyPluginInterface> plugin_instance = plugin_loader.createInstance("my_plugin_package::MyPluginImplementation");
// 使用插件
plugin_instance->doSomething();
return 0;
}
其中CMakeLists.txt
文件需要添加:
add_excutable(use_plugin src/use_plugin.cpp)
add_dependencies(use_plugin ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(use_plugin
$(catkin_LIBRARY)
)