ROS2 Quality of Service 服務質量 QoS 簡介

ROS2 Quality of Service 服務質量 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 LaserScan

def 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 LaserScan

def 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.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章