ROS学习笔记——关于nodelet先行一步

nodelet部分搞了两天,记录下初步的成果。更多实践的结果等真正把手上实际的项目搞定再来更新。

如果是自己动手写一个nodelet,建议先去看一下ros中的pluginlib,nodelet方面的资料较少,翻一翻,基本上都是翻译的wiki上的,内容不是很丰富,所以nodelet作为pluginlib的一种,先去看资料多的pluginlib,能了解整个写插件的过程。

如果只是体验一下nodelet的用法,继续向下看吧~~


1、为什么用nodelet

试想一个场景,在一个传统的node中,有发布者和订阅者,把接收到的消息发送出去,在数据量大的时候,为了避免数据的拷贝(耗时耗空间),可以通过指针或者一些智能指针来实现。但是如果是不同的节点之间那,在大数据量传输的情况下,如何来规避数据传输过程中的拷贝那?

nodelet便可以解决以上的问题,实现在多个nodelet之间的零拷贝传输。

2、如何实现

简单的说就是,我们可以把传统的node稍加改动成为nodelet,多个node之间的通信就可以转变为多个nodelet之间的通信。然后通过一个nodelet的manager来管理加载到其中的nodelets。

当然,严谨一点就是,一个进程(manager)中跑多个线程(nodelet)。

这样便可以实现节点间的零拷贝传输。

3、例子说明

改写了一个例子,以此说明,整个的实现过程。

  • 首先,要有一份改造完成的nodelet源码,编译成动态链接库(.so)形式

wiki上有现成的源码:http://wiki.ros.org/nodelet。为了便于观察数据拷贝的情况,改写了一下源码,onInit()类似main(),当load一个nodelet时,便会调用。

ROS学习笔记——关于nodelet先行一步

配置好cmake、xml、launch等文件之后(wiki这个是配置好的,直接可以编译使用),便可以编译生成动态链接库(也就是pluginlib)在devel下的lib中可以找到。如何进行配置这部分不展开了,有可以参考的资料。

关于修改的源码,主要就是将多个节点的input数据的指针打印出来,观察不同节点之间是不是实现了数据的零拷贝。

  • 编写launch文件

通过launch文件的方式来注册一个manager并向manager中加载2个nodelet。wiki上的launch文件不适用我们的目的,重写了两个launch文件,来对比。

第一个launch文件如下,目的是添加一个manager命名为nodelet_manager,向其中load一个名字为Plus的nodelet,再通过standalone方式添加第二个名字为Plus2的nodelet。需要说明的是,standalone方式添加的nodelet和manager没有直接的联系,相当于第一个和第二个nodelet是像传统的两个独立的node。

ROS学习笔记——关于nodelet先行一步

第二个launch文件如下,与第一个不同的地方就是,两个nodelet都是通过load的方式添加到同一个manager中,即实现了在一个manager管理两个nodelet,是我们主要的目的。

ROS学习笔记——关于nodelet先行一步

还需要说明的一点就是,两个nodelet使用的是同一个插件(就是开始的时候根据修改的源码编译生成的动态库),上述两个launch文件都通过remap,将第一个nodelet的输出topic映射到第二个nodelet的输入topic,这部分需要理解。

  • 结果对比

启动第一个launch文件,rqt_graph和输出结果如下。可以看到,当我们在terminal给第一个nodelet发布订阅话题的数据之后,中断便开始打印输出,input数据的指针信息。每个nodelet的input地址都不变,两个nodelet之间又不同,说明数据并没有指向同一地址,存在数据的拷贝。

ROS学习笔记——关于nodelet先行一步

ROS学习笔记——关于nodelet先行一步

 

启动第二个launch文件,rqt_graph和输出结果如下。对比上述,可以发现,打印的地址是完全一样的,说明两个nodelet之间真的实现了数据传输过程中的零拷贝。

ROS学习笔记——关于nodelet先行一步

ROS学习笔记——关于nodelet先行一步


以上就是针对nodelet的一个实际的应用对比,结合实际项目的更深入的内容下次再更新~~

欢迎交流指正~~