【Nodelet】系列(一)——Nodelet介绍

目录

一、为什么需要nodelet

如果有多个进程需要使用包含大量数据(如图像或点云)的消息,则将消息打包、发送,然后解包可能需要一些时间。

图像和点云数据

Nodelets 旨在提供一种在单个机器上、单个进程中运行多个算法的方法,而不会在进程内传递消息时产生复制成本。roscpp中通过优化可以在同一节点内的发布和订阅调用之间进行零复制指针传递,可以直接传递指针,降低了拷贝内存的操作和降低网络流量。

如果两个进程在同一台计算机上,则只发送指向该数据(如图像或点云)的指针比通过 TCP 发送数据本身更快,Nodelet仅适用于同一台计算机上的不同进程,因为一台计算机的指针对另一台计算机没有意义。

nodelets 不会使进程更快,但它是一种从一个进程到另一个进程获取信息的更快方法。一个好的经验法则是始终使用node(因为它们更易于使用且更灵活),除非遇到消息传递对于应用程序来说太慢并导致问题的情况,那么才会考虑使用 nodelet。

二、nodelet如何实现多个节点通信

2.1 nodelet共享指针

ROS中不同节点以基于socket的发布/订阅模式(Publish/Subscribe)进行通讯时,存在消息数据的复制,从而增大了通信延迟。

Nodelet采用共享指针(shared_ptr)技术来实现节点之间的数据共享。在Nodelet中,一个节点可以将某个数据结构打包成一个共享指针,然后将这个共享指针传递给另一个节点,另一个节点可以通过共享指针来访问和修改这个数据结构,而不需要进行数据复制。这样,多个节点可以在同一份数据上进行操作,从而避免了数据复制带来的性能损失。

TCOROS与Nodelet

2.2 nodelet的消息类型

如果希望no-copy pub/sub工作,必须将ROS消息类型发布为shared_ptr共享指针类型,当消息被发布为shared_ptr,roscpp可以跳过序列化/反序列化步骤(可能节省大量的处理和延迟)。

示例:

ros::Publisher pub = nh.advertise<std_msgs::String>("topic_name", 5);
std_msgs::StringPtr str(new std_msgs::String);
str->data = "hello world";
pub.publish(str);

其中str变量类型为std_msgs::StringPtr,但是publisher的模板类仍为std_msgs::String类型,在ROS中,发布话题的类型通常不是指针类型。

当我们创建一个 std_msgs::StringPtr 类型的消息并发布它时,pub.publish()函数会自动地处理指针,将其解引用并获取实际的消息内容。

publish函数能够自动处理指针,主要是因为它是一个模板函数,可以根据提供的参数类型自动地推导消息类型。在处理指针类型的消息时,publish函数会自动解引用指针并获取实际的消息内容。

查看ROS的publish.h文件可以看到Publisher类有一个重载的publish函数,专门用于处理智能指针类型的消息,如下面代码的第一个函数。这个重载的publish函数会自动解引用智能指针,从而获取实际的消息内容。

template <typename M>
      void publish(const boost::shared_ptr<M>& message) const
    {// 其他代码...
     // 自动解引用指针并调用publish函数
      publish(boost::bind(serializeMessage<M>, boost::ref(*message)), m);
    }

template<typename M>
void Publisher::publish(const M& message) {
  // 其他代码...

      publish(boost::bind(serializeMessage<M>, boost::ref(message)), m);
}

这意味着它可以接受实际的消息类型,也可以接受指向消息类型的智能指针。当我们传递一个智能指针(如 boost::shared_ptr)时,编译器会自动推导参数类型为智能指针类型,然后调用实现的 publish 函数。

注意,当用这种方式发布,不可以修改发送后的消息,因为指针会直接传递到用户的任何进程内。

三、nodelet如何管理多个节点

3.1 ROS插件机制

ROS通过提供插件(pluginlib)的形式实现算法(算法类),作为插件动态加载以打破构建时间依赖性。而Nodelet通过动态加载这些插件,将算法类动态加载到同一个节点中,同时为这些类提供独立的名称空间,这样尽管不同的类在同一个进程中运行,但从外部看,nodelet就像一个单独的节点一样。

3.2 nodelet中各个节点关系

下图中/my_ros_node相机驱动节点,而/standalone_nodelet为nodelet的管理节点,这两个节点通过共享指针/standalone_nodelet/bond进行通信,可以看到节点与该话题存在双向箭头连接,即代表是nodelet共享指针通信!

nodelet通信

/standalone_nodelet是管理节点名称,作为nodelet整体,对外通过topic与其它普通节点进行通信,如下图中的其它节点通过订阅/my_ros_node/image_raw/image_topic话题,可以接收到/my_ros_node节点发出的话题,但是rqt_graph命令中,仍然是从/standalone_nodelet节点节点订阅!

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容