首页 > 系统相关 >Robot Operating System——借用内存型消息

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

时间:2024-07-22 09:25:35浏览次数:12  
标签:System Robot loaned Operating 内存 类型 POD message 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_PUBLIC
  explicit 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.
   */
  void
  publish(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());
    }
  }

标签:System,Robot,loaned,Operating,内存,类型,POD,message,pod
From: https://blog.csdn.net/breaksoftware/article/details/140477215

相关文章

  • Robot Framework 数据库库调用 Oracle 存储过程失败,并出现字符到数字转换错误
    我有一个OraclePL/SQL程序,我可以直接调用如下,没有问题:BEGINexample_package_name.example_procedure(p_item_no=>123456,p_send_now=>true);END;(注意:p_item_no期望aNUMBER和p_send_now期望aBOOLEAN)我正在......
  • Robot Framework安装与使用
    RobotFramework是一个基于Python的通用自动化测试框架,采用关键字驱动测试(Keyword-DrivenTesting)方法。官网:https://robotframework.org/安装RobotFrameworkpipinstallrobotframework#Web测试,还需要安装SeleniumLibrarypipinstallrobotframework-seleniumlibrary......
  • 在实际应用中,systemverilog相比vefilog2000有哪些重大的提升
    SystemVerilog相较于Verilog-2000有多项重大提升,这些提升使得SystemVerilog成为更强大的硬件描述和验证语言。以下是一些关键的改进:数据类型扩展:SystemVerilog引入了 logic 数据类型,可以替代Verilog-2000中的 wire 和 reg 类型,提供更灵活的使用方式。支持更广......
  • robotframework关键字库的定义
    学习总结,有错误欢迎指出。总结:robotframework关键字库定义包含两种方式:模块(不建议)和类。1.关键字定义1)模块(略)2)类定义     模块名和类名需要一致,模块名和类名需要一致,模块名和类名需要一致。引入     如果初始函数含有变量,引入关键字库时需要......
  • 自动化测试-Robotframework项目结构示例
    学习总结,有错误欢迎指出。总结:项目要有自己的一套结构,形成自己的体系,应对不同的项目。1.项目结构2.目录说明......
  • Distilling System 2 into System 1
    本文是LLM系列文章,针对《DistillingSystem2intoSystem1》的翻译。将系统2蒸馏成系统1摘要1引言2相关工作3将系统2蒸馏到系统14实验5结论6局限性摘要大型语言模型(LLM)可以在推理过程中花费额外的计算来生成中间思想,这有助于产生更好的最终响应。自......
  • MiniRHex:一种开源的六足机器人 by DYNAMIXEL Robotis
    原文链接:https://www.youtube.com/watch?v=ldLXVDNCCzc  At#IROS 2023,weranintotheCarnegieMellonUniversity RobomechanicsLab.TheyhadsomereallycoolrobotstherethatwerePoweredby#DYNAMIXEL XLseriesmotors.Oneoftherobotstheyhadfeat......
  • Cisco NX-OS System Software - ACI 16.0(6c)M
    CiscoNX-OSSystemSoftware-ACI16.0(6c)M适用于ACI模式下的CiscoNexus9000系列交换机系统软件请访问原文链接:https://sysin.org/blog/cisco-aci-16/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.orgCiscoNX-OS网络操作系统软件CiscoNX-OS操作系统助力......
  • 安装Windows subsystem Linux
    1.启用功能在系统设置里面,启用子系统功能。2.安装从商店安装或者命令行安装3.初始化报错1: ​造成该问题的原因是WSL版本由原来的WSL1升级到WSL2后,内核没有升级,前往微软WSL官网下载安装适用于x64计算机的最新WSL2Linux内核更新包即可。报错2:Windows子系统初始化......
  • 【THM】Mr Robot CTF练习
    【THM】MrRobotCTF练习基于电视剧《黑客军团》,你能得到这个靶机的根权限吗?你能得到这台黑客军团风格靶机的根权限吗?这是一个适用于初学者/中级用户的虚拟机。机器上有3个隐藏的钥匙,你能找到它们吗?感谢LeonJohnson创造了这台靶机。本机器在创建者的明确许可下在此处使用......