1.QoS (Quality of Service)

1.1 概述

ROS2提供了一套非常丰富的服务质量QoS策略用于调整节点之间的通信。众所周知,在TCP与UDP之间存在着无数的折中设置,QoS既可以设置为像TCP一样可靠(reliable),也可以设置为像UDP一样高效(best effort)。

一套QoS策略形成了一个QoS Profile。考虑到为特定的场景选择正确QoS策略较为复杂,ROS2提供了一套预定义的QoS Profiles,用于常见场景(如传感器数据)。同时,也提供了特定的Profiles给使用者设置QoS策略。发布器、订阅器、服务端和客户端可以指定Profile,且它们的每个实例都可以单独指定Profile,但不兼容的Profiles可能导致无法通信

1.2 QoS策略

QoS Profile提供了对以下QoS策略的设置:

(1)可靠性(Reliability) 消息传达的可靠性

  • 可靠的(Reliable):反复重传以保证数据成功传输。
  • 尽力的(Best effort):尝试传输数据但不保证成功传输(当网络不稳定时可能丢失数据)。极低延迟,适合 LiDAR、图像、高频传感器。

(2)历史记录(History)    消息的历史记录方式

当订阅者由于忙碌错过了消息,其仍能收到历史消息。这个参数只有在 Reliability 为 RELIABLE 时才有用。

  • 保留近期记录(Keep last):缓存最多N条记录,可通过队列长度选项来配置。
  • 保留所有记录(Keep all):缓存所有记录,但受限于底层中间件可配置的最大资源。

 (3)深度(Depth)

  • 队列深度(Size of the queue):只能与Keep last配合使用,指定需要保留的消息个数。

 (4)持续性(Durability)

消息是否应该在网络中持久化,以便新加入的订阅者也能接收。这个参数只有在 Reliability 为 RELIABLE 时才有用。  

  • Transient local:消息在发布者端持久化,新加入的订阅者可以接收到旧消息,接收个数由History和Depth决定。
  • Volatile:不保留任何数据。
rclcpp::QoS custom_qos_profile(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_default));
    
// 设置 QoS 策略
custom_qos_profile
    .keep_last(10)                    // History: Keep last 10 条
    .reliable()                       // Reliability: Reliable
    .transient_local();               // Durability: Transient Local

SensorDataQoS 是 ROS2 中一个 预定义的 QoS配置,专门用于处理传感器数据(如摄像头图像、激光雷达点云等)的 发布-订阅通信。它被设计为在高频、低延迟但可容忍丢包的场景中使用。

  • History: Keep last,
  • Depth: 5,
  • Reliability: Best effort,  不保证每条消息传达成功(适用于实时要求高的传感器数据)
  • Durability: Volatile,
  • Deadline: Default,
  • Lifespan: Default,
  • Liveliness: System default,
  • Liveliness lease duration: default,
  • avoid ros namespace conventions: false

ROS2学习日志:QoS要点总结 - dzyBK - 博客园

2.DDS

DDS (Data Distribution Service) 是一种中间件协议,用于支持分布式系统中的数据通信。在 ROS 2 中,DDS 作为通信中间件,负责节点之间的数据交换和消息传递。它提供了可靠、高效、可扩展的通信机制,支持实时数据传输。

一般而言默认使用的是FAST DDS ,可通过 ros2 doctor --report 查看

RMW MIDDLEWARE
middleware name    : rmw_fastrtps_cpp

有个需求:两个docker需要相互话题通信,需要把DDS改为cyclone dds(适合多机通信和生产环境)

export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp

此外,只有设置相同 domain_id 的 ROS 节点,才能发现彼此、进行通信。

export ROS_DOMAIN_ID=3

Eclipse Cyclone DDS — ROS 2 Documentation: Jazzy documentation

3. 节点进程通信

3.1 单进程

intra-process 也叫 IPC,当多个节点合并启动时,如果开启 IPC,数据将直接通过进程内的指针传递,绕过中间件,这样可以大大降低通信开销。

demo

// LIO-SAM ros2 code
int main(int argc, char** argv)
{   
    rclcpp::init(argc, argv);

    rclcpp::NodeOptions options;
    options.use_intra_process_comms(true);
    rclcpp::executors::MultiThreadedExecutor e;

    auto ImuP = std::make_shared<IMUPreintegration>(options);
    auto TF = std::make_shared<TransformFusion>(options);
    e.add_node(ImuP);
    e.add_node(TF);

    RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "\033[1;32m----> IMU Preintegration Started.\033[0m");

    e.spin();

    rclcpp::shutdown();
    return 0;
}

总结:同一个进程内的两个 ROS 节点间通信,零拷贝,减少CPU负载。

3.2 多进程

上一小节只是单进程内多个节点通信,但 LIO-SAM是多个进程间通信,这个时候需要使用 component 合并进程。(类似于ROS1 的 nodelet

具体参考 demo 即可,注意需要把  add_library声明的动态库 install 到 lib目录下。

对比LIO-SAM代码修改为单进程的CPU负载:

①独立进程:

②合并进程:

CPU占用 下降了大约 25.53%

使用 component 后launch也需要进行修改,具体参考官方文档:使用 ROS 2 launch 启动可组合节点 

Logo

立足具身智能前沿赛道,致力于搭建全球化、开源化、全栈式技术交流与实践共创平台。

更多推荐