当前位置: 代码迷 >> 综合 >> ROS2 Quality of Service 服务质量 QoS 简介
  详细解决方案

ROS2 Quality of Service 服务质量 QoS 简介

热度:64   发布时间:2023-12-24 16:15:53.0

ROS2 Quality of Service 服务质量 QoS 简介

  • 背景介绍
  • QoS服务质量简介
  • 实例
  • 参考资料

ROS在使用过程中最常用的消息之一就是 sensor_msgs了,但是最近使用ROS2的过程中遇到一个问题,我要订阅一个消息类型为 sensor_msgs/msg/LaserScan的话题 scan,在代码中无法获取该消息,但是通过 ros2 topic info /scan可以看到该话题被订阅了,通过 ros2 topic echo /scan发现也可以正常的打印话题,就是在代码里面无法获取话题的消息,经过一番查阅资料发现原来是和ROS2的 (Quality of Service)服务质量 (QoS )有关,那到底什么是QoS服务质量,为什么它会导致代码里面无法接收话题的消息。

背景介绍

关于QoS的渊源就牵扯到ROS2的诞生,ROS1通过TCP实现底层数据的传输,TCP虽然比较可靠,但是如果对于网络情况不好的使用场景,经常发生丢包的现象,如果使用TCP进行传输可能一个消息都都不到,经常这个时候我们使用不可靠的UDP反而是一个比较好的选择,虽然这个时候网络不可靠,但是我们至少可以获取消息,保持消息不会中断,对于数据不可靠的问题可以通过其他算法来解决,所以我们平时的聊天软件:QQ、微信都是使用UDP传输。ROS2作为一个应用于DDS分布系统的产品,如何进行可靠的数据传输是一个关键点,而QoS就是对数据如何进行底层的传输进行配置的。

QoS服务质量简介

这里只是简单进行介绍,需要需要深入了解相关内容,请查看文末官网的链接。
在ROS2中QoS有如下的策略选择,我们可以对策略进行配置达到我们的使用需求。

  • 历史(History)

    • 保存最近的数据(Keep last):只保留N个数据,通过队列深度选项进行配置。

    • 保存全部的数据(Keep all):保留所有的数据,但要受限于底层中间件的资源限制。

  • 深度(Depth)

    • 队列大小:仅当与存最近的数据(Keep last)一起使用时才有效。
  • 可靠性(Reliability)

    • 尽力(Best effort):尝试提供样本,但如果网络不稳定,可能会丢失样本。

    • 可靠(Reliable):确保数据的可靠传输,可以多次重试。

  • 持久性(Durability)

    • 本地暂存:发布者负责为晚到的订阅者保留数据。

    • 易变:不尝试保留数据。

由于配置QoS还是比较麻烦的,我们通常对QoS的要求不是很高,这个时候一些默认的配置文件是很有必要的。

ROS2提供了如下的默认配置:

  • 发布者和订阅者的默认QoS配置(Default QoS settings for publishers and subscribers)

  • 服务(Services)

  • 传感器数据(Sensor data)

  • 参数服务器(Parameters)

  • 系统默认(System default)

在相应的编程语言的对应的头文件里面都有相应的定义。
例如在Python中我们可以在import rclpy使用这些默认的配置

rclpy.qos.qos_profile_sensor_data
rclpy.qos.qos_profile_system_default
rclpy.qos.qos_profile_services_default

实例

在ROS1中我们对于发布和订阅往往只需要指定消息缓冲池的大小即可。
我们使用ros2中gazebo的libgazebo_ros_ray_sensor插件发布一个消息类型为sensor_msgs/msg/LaserScan的话题scan,如果我们像下面这样使用ros1的那种方式来接收消息,这个时候我们就无法接收到消息。

import rclpy
from sensor_msgs.msg import LaserScandef main(args=None):rclpy.init(args=args)node = rclpy.create_node('laser_sub_node')sub = node.create_subscription(LaserScan, '/scan', lambda msg: node.get_logger().info('I get a msg'), 1)rclpy.spin(node)node.destroy_node()rclpy.shutdown()if __name__ == '__main__':main()

这个就是由于QoS的配置不对导致接收不到消息,我们只需要将QoS进行正确的配置就可以让我们正常的接收到消息了,只需对代码做出小小的修改就可以接收到消息了。

import rclpy
from sensor_msgs.msg import LaserScandef main(args=None):rclpy.init(args=args)node = rclpy.create_node('laser_sub_node')sub = node.create_subscription(LaserScan, '/scan', lambda msg: node.get_logger().info('I get a msg'), rclpy.qos.qos_profile_sensor_data)rclpy.spin(node)node.destroy_node()rclpy.shutdown()if __name__ == '__main__':main()

我们将该话题的QoS的配置为传感器推荐的一个配置,除此之外我们还可以使用qos_profile_system_default,在一般情况下,使用系统默认的是可以可以正常工作的,之前我们只输入了一个队列长度作为参数就会导致QoS配置出问题最终导致无法接收消息,现在我们采用专门为传感器设计的QoS配置文件或者系统默认的配置文件就可以正常工作了。

参考资料

  1. ROS2官方QoS配置简介https://index.ros.org/doc/ros2/Concepts/About-Quality-of-Service-Settings/.
  2. ROS2官方QoS设计简介https://design.ros2.org/articles/qos.html.
  相关解决方案