ROS的数据通信在graph结构中以topic,service和param的方式传输数据,数据交互存在一定的延时和阻塞。Nodelet 包就是为改善这一状况设计的, 使得多个算法运行在同一个进程中,并且算法间数据传输无需拷贝就可实现。 详见http://wiki.ros.org/nodelet。 简单的讲就是可以将以前启动的多个node捆绑在一起manager,使得同一个manager里面的topic的数据传输更快,数据通讯中roscpp采用boost shared pointer方式进行publish调用,实现zero copy。Nodelet是借助pluginlib来实现插件动态加载的,文章pluginlib特别通俗易懂的说明了pluginlib的工作原理,在理解pluginlib的基础上看nodelet会更容易。
说明
nodelet的工作原理类似于pluginlib,可以参考上边所说的博客中的原理图。
实现一个nodelet插件类
nodelet的实现因为借助了pluginlib的插件动态加载,因此nodelet的实现遵循pluginlib的使用规则,主要步骤如下:
- 创建基类,定义统一的接口。如果是基于现有的基类,则不需要这个步骤
- 创建nodelet插件类,继承基类,实现统一的接口
- 注册nodelet插件类
- 编译生成插件的动态链接库
- 将nodelet加入ROS系统
接下来,我们就根据这几个步骤来实现一个简单的nodelet功能,在开始之前需要建立一个example_pkg的功能包。
1 | catkin_create_pkg example_pkg |
完整的功能包代码可以在github上下载。
创建基类
其中基类nodelet是现有的,所以我们不需要创建基类,只需要继承nodelet基类即可。
创建nodelet插件类并注册插件类
接下来我们来创建MyNodeletClass类(MyNodeletClass.h)定义,放置于目录example_pkg/include/example_pkg/下。
1 |
|
创建MyNodeletClass类实现(MyNodeletClass.cpp),放置于目录example_pkg/src/下。
1 | // this should really be in the implementation (.cpp file) |
创建插件类的描述符(nodelet_plugins.xml),放置于目录example_pkg/plugins/下。
1 | <library path="lib/libexample_pkg"> |
可以看到,这个xml文件主要描述了nodelet的动态库路径,实现类,基类,描述等信息。
编译插件的动态连接库并将插件加入ROS系统
为了编译插件的功能包,需要修改CMakeLists.txt文件,修改一下内容,将插件编译为动态连接库。
1 | cmake_minimum_required(VERSION 2.8.3) |
对package.xml文件进行修改,添加构建和运行依赖项(nodelet和roscpp)。
1 | <buildtool_depend>catkin</buildtool_depend> |
然后我们可以通过下面的命令来查看该功能包是否编译为nodelet的插件:
1 | rospack plugins --attrib=plugin nodelet |
如果没有问题,会出现一系列nodelet的插件路径,其中应该有上边添加的插件的路径,我的插件路径为:
1 | ... |
插件的路径比较多,没有全列出来。
编写启动文件(mynodelet.launch):
1 | <launch> |
编译并测试
根目录下编译后,运行launch文件,如果没有问题,可以看到如下结果:
1 | username@username-HP-ProBook-440-G3:~/catkin_turtlebot$ roslaunch example_pkg mynodelet.launch |
成功后会显示Nodelet is Ok for test!!
这样,我们就完成了nodelet插件的实现和调用。