Robot Operating System——借用内存型消息

大纲

  • 功能和工作原理
  • 源码分析
    • POD
      • 特点
      • POD 类型的优点
    • 非POD
      • 特点
    • 生成并发布“借用内存型消息”
      • POD类型
      • 非POD类型

在ROS 2中,"loaned message"是一种消息传递机制,用于在发布者(publisher)和订阅者(subscriber)之间传递数据。它是一种高效的消息传递方式,可以避免不必要的数据复制。

在传统的ROS中,消息是通过复制的方式进行传递的,即发布者将消息复制一份发送给订阅者。这种方式在数据量较大或频繁传递消息时可能会导致性能问题。

而在ROS 2中,引入了"loaned message"的概念。当发布者发送消息时,它不会直接复制消息,而是将消息的所有权(ownership)转移给订阅者。这意味着发布者不再需要保留消息的副本,从而减少了数据复制的开销。

通过使用"loaned message",ROS 2可以更高效地传递消息,特别是在处理大量数据或高频率传输时。它可以提高系统的性能和响应速度。

功能和工作原理

  • 内存分配优化:LoanedMessage 允许从中间件直接借用内存来存储消息数据,而不是每次发送消息时都进行内存分配。这减少了内存分配和释放的开销,特别是在高频率消息传输的场景中。

  • 与发布者关联:它与特定的 rclcpp::Publisher 实例关联,允许直接在中间件层面上处理消息内存分配。这意味着,如果中间件支持消息借用,LoanedMessage 将利用这一点来优化内存使用;如果不支持,则使用传入的分配器实例在类的作用域内分配消息。

  • 透明的后备机制:对于不支持消息借用的中间件,LoanedMessage 类将使用传入的分配器来分配消息内存。这确保了即使在不同的中间件实现之间,用户代码也能保持一致性和可移植性。

源码分析

Talk is cheap,show me the code。
我们通过代码来学习和分析下“loaned message”。
我们要分析的代码是demo_nodes_cpp/src/topics/talker_loaned_message.cpp。它是一个消息发布者。

// Create a Talker class that subclasses the generic rclcpp::Node base class.
// The main function below will instantiate the class as a ROS node.
class LoanedMessageTalker : public rclcpp::Node
{
public:DEMO_NODES_CPP_PUBLICexplicit LoanedMessageTalker(const rclcpp::NodeOptions & options): Node("loaned_message_talker", options){// Create a function for when messages are to be sent.setvbuf(stdout, NULL, _IONBF, BUFSIZ);……// Create a publisher with a custom Quality of Service profile.rclcpp::QoS qos(rclcpp::KeepLast(7));pod_pub_ = this->create_publisher<std_msgs::msg::Float64>("chatter_pod", qos);non_pod_pub_ = this->create_publisher<std_msgs::msg::String>("chatter", qos);// Use a timer to schedule periodic message publishing.timer_ = this->create_wall_timer(1s, publish_message);}private:size_t count_ = 1;rclcpp::Publisher<std_msgs::msg::Float64>::SharedPtr pod_pub_;rclcpp::Publisher<std_msgs::msg::String>::SharedPtr non_pod_pub_;rclcpp::TimerBase::SharedPtr timer_;
};

我们会在这个消息发布者中,定时通过通过pod_pub_ 和non_pod_pub_ 来发送消息。
pod_pub_是用来发布POD类型消息的;non_pod_pub_ 是用来发布非POD类型消息的。

由于ROS 2绝大部分中间件是不支持非POD类型消息,所以区分 POD 和非 POD 类型的消息是重要的,因为一些中间件可能支持通过共享内存进行零拷贝传输的 POD 类型消息,这可以显著提高通信效率。

POD

POD 类型,即 Plain Old Data 类型,是一种简单的数据结构

特点

  • 内存布局简单:POD 类型的内存布局是连续的和简单的,没有任何构造、析构或虚函数。这意味着它们可以被直接复制(例如,使用 memcpy)而不会破坏对象的状态。

  • 兼容 C 语言的结构:POD 类型保持与 C 语言结构的兼容性,这意味着它们可以在 C++ 和 C 之间安全地传递。

  • 不含有指向动态分配内存的指针:POD 类型通常不包含指向动态分配内存的指针,所有数据都是自包含的。

  • 不含有用户定义的构造函数、析构函数或复制赋值运算符:这些特性保持了类型的简单性和传统的数据结构特性。

可以是标量类型或聚合类型:标量类型如 int、float 等基本数据类型都是 POD 类型。聚合类型,如结构体(struct)或联合体(union),只要它们的成员都是 POD 类型,且没有用户定义的构造函数、析构函数、复制赋值运算符、虚函数等,也是 POD 类型。

POD 类型的优点

  • 性能:由于内存布局的简单性和连续性,POD 类型的对象可以非常高效地进行内存操作和传递。
  • 互操作性:POD 类型的简单和兼容性使得它们在 C++ 和 C 之间,以及不同的编程环境和系统之间,可以轻松地进行数据交换。
  • 可预测性:POD 类型的行为非常直接和可预测,没有复杂的构造和析构逻辑,这使得它们在系统编程和资源受限的环境中非常有用。

非POD

非POD(Plain Old Data)类型是指那些不满足POD类型条件的数据类型。与POD类型相比,非POD类型具有更复杂的特性。

特点

  • 动态内存分配:非POD类型的对象可能会在运行时动态分配和释放内存。例如,标准库中的std::string或std::vector就是典型的非POD类型,它们根据需要动态调整存储空间。

  • 构造函数、析构函数和赋值运算符:非POD类型通常会定义自己的构造函数、析构函数和赋值运算符。这些特殊的成员函数允许对象在创建、销毁或复制时执行特定的逻辑。

  • 虚函数和继承:非POD类型可以包含虚函数,并且可以是类的继承体系的一部分。这使得非POD类型可以支持多态性,即在运行时根据对象的实际类型来调用相应的函数。

  • 不保证内存布局:由于非POD类型可能包含虚函数表指针、动态分配的成员等,它们的内存布局不像POD类型那样简单和可预测。这意味着不能简单地通过内存复制(如memcpy)来复制非POD类型的对象。

  • 不保证二进制兼容:非POD类型的对象不能保证在不同的编译器或编译选项之间保持二进制兼容性,因为它们的内部表示可能会有所不同。

非POD类型的特点使得它们在表达复杂数据结构和行为时更加灵活和强大,但这也意味着在处理这些类型的对象时需要更加小心,特别是在涉及底层内存操作、跨语言接口或网络通信等场景中。在ROS 2中,由于非POD类型的这些特性,大多数中间件可能无法提供对非POD数据类型的零拷贝消息传递支持。

生成并发布“借用内存型消息”

POD类型

我们首先调用rclcpp::Publisher的borrow_loaned_message生成一个借用内存型消息,然后将局部变量pod_msg_data设置到其data成员中。

        // We loan a message here and don't allocate the memory on the stack.// For middlewares which support message loaning, this means the middleware// completely owns the memory for this message.// This enables a zero-copy message transport for middlewares with shared memory// capabilities.// If the middleware doesn't support this, the loaned message will be allocated// with the allocator instance provided by the publisher.auto pod_loaned_msg = pod_pub_->borrow_loaned_message();auto pod_msg_data = static_cast<double>(count_);pod_loaned_msg.get().data = pod_msg_data;RCLCPP_INFO(this->get_logger(), "Publishing: '%f'", pod_msg_data);// As the middleware might own the memory allocated for this message,// a call to publish explicitly transfers ownership back to the middleware.// The loaned message instance is thus no longer valid after a call to publish.pod_pub_->publish(std::move(pod_loaned_msg));

从这段代码可以看出来,借用消息和rclcpp::Publisher是相关的。

非POD类型

像String这类会在运行时动态改变内存的结构就是非POD的。

下面代码可以看出来: 在顶层代码层,rclcpp::LoanedMessage对POD类型和非POD类型是无差别的。即我们可以不区分POD和非POD,用同样套路使用 rclcpp::LoanedMessage。这大大降低了我们编程过程中的“心智负担”。

        // Similar as in the above case, we ask the middleware to loan a message.// As most likely the middleware won't be able to loan a message for a non-POD// data type, the memory for the message will be allocated on the heap within// the scope of the `LoanedMessage` instance.// After the call to `publish()`, the message will be correctly allocated.auto non_pod_loaned_msg = non_pod_pub_->borrow_loaned_message();auto non_pod_msg_data = "Hello World: " + std::to_string(count_);non_pod_loaned_msg.get().data = non_pod_msg_data;RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", non_pod_msg_data.c_str());non_pod_pub_->publish(std::move(non_pod_loaned_msg));count_++;

但是之前不是说大部分ROS 2中间件不支持非POD的借用内存型消息吗?

这是因为Publisher::publish的底层做了兼容。它会看这个消息是否可以被借用,如果可以就直接调用do_loaned_message_publish发布这条消息;如果不能就走原始的publish方法。

  /// Publish an instance of a LoanedMessage./*** When publishing a loaned message, the memory for this ROS message will be deallocated* after being published.* The instance of the loaned message is no longer valid after this call.** \param loaned_msg The LoanedMessage instance to be published.*/voidpublish(rclcpp::LoanedMessage<ROSMessageType, AllocatorT> && loaned_msg){if (!loaned_msg.is_valid()) {throw std::runtime_error("loaned message is not valid");}// verify that publisher supports loaned messages// TODO(Karsten1987): This case separation has to be done in rclcpp// otherwise we have to ensure that every middleware implements// `rmw_publish_loaned_message` explicitly the same way as `rmw_publish`// by taking a copy of the ros message.if (this->can_loan_messages()) {// we release the ownership from the rclpp::LoanedMessage instance// and let the middleware clean up the memory.this->do_loaned_message_publish(loaned_msg.release());} else {// we don't release the ownership, let the middleware copy the ros message// and thus the destructor of rclcpp::LoanedMessage cleans up the memory.this->publish(loaned_msg.get());}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/48778.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS应用开发者高级认证,Next版本发布后最新题库 - 单选题序号2

基础认证题库请移步&#xff1a;HarmonyOS应用开发者基础认证题库 注&#xff1a;有读者反馈&#xff0c;题库的代码块比较多&#xff0c;打开文章时会卡死。所以笔者将题库拆分&#xff0c;单选题20个为一组&#xff0c;多选题10个为一组&#xff0c;题库目录如下&#xff0c;…

NFT革命:数字资产的确权、营销与元宇宙的未来

目录 1、NFT&#xff1a;数字社会的数据确权制度 2、基于低成本及永久产权的文化发现 3、PFP&#xff1a;从“小图片”到“身份表达”&#xff0c;再到社区筛选 4、透明表达&#xff1a;NFT 在数字化营销中的商业价值 5、可编程性&#xff1a;赋予 NFT 无限可能的应用 5.…

PTA - 输出元组内指定值

输入一序列数字&#xff0c;以空格分隔开&#xff0c;将其转换为元组进行操作&#xff0c;输出元组内7的倍数及个位是7的数。 输入格式: 输入多个自然数&#xff0c;以空格分隔。 输出格式: 查找元组内7的倍数及个位是7的数输出&#xff0c;以空格分隔。 输入样例: 在这里…

【Vue3】组合式 API

【Vue3】组合式 API 背景简介开发环境开发步骤及源码setup 语法糖setup 扩展组件总结 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪…

HCIP笔记[第4章-重发布+路由策略]

重发布 作用&#xff1a; 在两种路由协议之间&#xff0c;或者一个协议的不同进程之间&#xff0c;借助ASBR&#xff08;同时工作在两种协议或者协议的不同进程中&#xff09;学习到两个网络的路由信息&#xff0c;并且通过重发布进行路由共享&#xff0c;最终实现全网可达。 …

springSecurity学习之springSecurity流程

springSecurity流程 认证流程 登录请求进入UsernamePasswordAuthenticationFilter&#xff0c;父类是AbstractAuthenticationProcessingFilter&#xff0c;执行AbstractAuthenticationProcessingFilter的doFilter方法 authResult attemptAuthentication(request, response);确…

springcloud-远程调用超时问题

1、报错信息&#xff1a; 09:06:34.992 [PollingServerListUpdater-0] INFO c.n.config.ChainedDynamicProperty - Flipping property: device-managmet.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnection…

PYTHON学习笔记(四、pyhton数据结构--列表)

&#xff08;1&#xff09;list列表 列表的含义是指&#xff1a;&#xff08;1&#xff09;一系列的按特定顺序排列的元素组成。&#xff08;2&#xff09;python中内置的可变序列。&#xff08;3&#xff09;在python中使用[]定义列表&#xff0c;元素与元素之间使用英文的逗…

含有罗马字母的txt转换为csv文件读取-报错

r语言绘图二&#xff08;输入复杂的数学符号&#xff0d;&#xff0d;希腊字母表&#xff09; - R语言论坛 - 经管之家(原人大经济论坛) (pinggu.org) CSV读取报错 gcmeta <- read.csv("metadata.csv") > head(gcmeta)Sample Patient Tissue Platform Subty…

CentOS(7.x、8)上安装EMQX

EMQX 是一个高度可扩展的分布式 MQTT 消息服务器&#xff0c;适用于 IoT、M2M 和移动应用程序。以下是在 CentOS 系统上安装 EMQX 的基本步骤&#xff1a; 在 CentOS 上安装 EMQ X 步骤 1: 添加 EMQ X YUM 源 首先&#xff0c;你需要添加 EMQ X 的官方 YUM 源到你的 CentOS 系…

NNOM训练环境搭建(Windows)

目录 一、安装Anaconda 二、安装nnom编译环境 1. 创建并激活虚拟环境 2. 统一安装所有安装包 三、编译NNOM 一、安装Anaconda windows版本&#xff1a;Anaconda3-2019.10-Windows-x86_64.exe 勾选添加进系统环境变量&#xff0c;其他使用默认选项进行安装。 二、安装nnom…

Dubbo 的服务降级

在分布式系统中&#xff0c;服务的高可用性是至关重要的。然而&#xff0c;由于网络故障、服务器宕机等原因&#xff0c;服务不可用的情况时有发生。为了确保系统的稳定性和用户体验&#xff0c;Apache Dubbo 提供了服务降级功能。服务降级可以在远程服务不可用时&#xff0c;自…

pycharm报错:No module named pip/No module named pytest

1、问题概述? 今天在执行一个python脚本的时候,控制台提示:No module named pytest,就是没有pytest模块,于是我使用pip命令进行安装,命令如下; pip install pytest 结果又提示No module named pip,说我没有pip模块,没办法,再安装pip 2、安装pip-方式1 在pycharm的T…

【python基础知识】整除

熟练使用你所常用的开发语言是一个非常基本的要求。如果你日常需要使用Python&#xff0c;但是你对向上取整&#xff0c;向下取整&#xff0c;以及Python中的默认实现方式是什么都不知道的话&#xff0c;那么我就需要怀疑你的专业能力了。 1. 整除 讲解这个整除的知识&#xf…

因果推断 | 双重机器学习(DML)算法原理和实例应用

文章目录 1 引言2 DML算法原理2.1 问题阐述2.2 DML算法 3 DML代码实现3.1 策略变量为0/1变量3.2 策略变量为连续变量 4 总结5 相关阅读 1 引言 小伙伴们&#xff0c;好久不见呀。 距离上次更新已经过去了一个半月&#xff0c;上次发文章时还信誓旦旦地表达自己后续目标是3周更…

C#中的Func

1.Func委托的定义和使用步骤 Func委托在C#中用于表示一个具有指定参数和返回类型的方法。‌Func委托的定义允许你指定参数的类型和返回值的类型&#xff0c;‌它可以有多达16个参数。‌第一个泛型参数表示方法的参数类型&#xff0c;‌最后一个泛型参数表示方法的返回类型。‌…

VINS介绍

VINS&#xff08;Visual-Inertial Navigation System&#xff09;是一个视觉惯性导航系统&#xff0c;通常用于机器人、无人机或任何需要在未知环境中自主导航的移动平台。VINS结合了视觉传感器&#xff08;通常是相机&#xff09;和惯性测量单元&#xff08;IMU&#xff09;的…

【BUG】已解决:AttributeError: ‘WindowsPath‘ object has no attribute ‘rstrip‘

AttributeError: ‘WindowsPath‘ object has no attribute ‘rstrip‘ 目录 AttributeError: ‘WindowsPath‘ object has no attribute ‘rstrip‘ 【常见模块错误】 【错误原因】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&…

Elasticsearch数据迁移

前言 近期在搞ES集群的迁移&#xff0c;以及日常ES运维中也涉及到同集群内索引的重命名、迁移等实际场景。就考虑把实际场景模拟一下&#xff0c;侧重不同集群间的数据迁移&#xff0c;对比观察一下目前主流的数据迁移方式的优点和缺点。为之后真实迁移场景提供参考。 这次对…

Linux(openwrt)下iptables+tc工具实现网络流量限速控制(QoS)

基础介绍 Netfilter是Linux操作系统核心层内部的一个数据包处理模块&#xff0c;它具有如下功能&#xff1a;网络地址转换(Network Address Translate)数据包内容修改以及数据包过滤的防火墙功能。Netfliter框架不仅仅在ipv4中有应用&#xff0c;bridge&#xff0c;ipv4&#…