ROS2高效学习第四章 -- ros2 topic 编程之测试 DDS 的 QoS 其三

1 前言与资料

ROS2高效学习第一章 – ros2整体介绍及DDS引入中,我们系统介绍了 ros2 引入 DDS(Data Distribution Service,数据分发服务)的前因后果。作为 ros2 topic 编程第三篇,本文仍将复用第一篇ROS2高效学习第四章 – ros2 topic 编程之收发 string 并使用 ros2 launch创建的两个软件包,即 pubsub_cpp 和 pubsub_py,在此基础上开发 QoS(Quality of Service,服务质量) 样例,实际测试 ros2 DDS 的功能。
本文参考资料如下:
(1)ROS2高效学习第一章 – ros2整体介绍及DDS引入
(2)古月 ros2 DDS

2 正文

2.1 DDS QoS 引入

(1)QoS 含义:Quality of Service,服务质量,这是通信领域一个非常重要的概念,用于控制发布者和订阅者之间的通信策略。只看他的名字很难直接理解他的含义,但可以把 QoS 映射为几个对应的配置进行直观理解。请执行下面的命令,查看 QoS 默认配置。

# 随便发一个 topic
ros2 topic pub /chatter std_msgs/msg/Int32 "data: 42"
# 新开一个窗口,查看这个 topic 的默认 QoS profile
ros2 topic info /chatter --verbose

在这里插入图片描述
(2)QoS 配置逐项解析:

Reliability:消息传达的可靠性;
	RELIABLE(default): 保证传输所有消息,丢失的消息会重传,类似 TCP 。
	BEST_EFFORT: 尽最大努力传送消息,但不保证交付,不会重传丢失的消息,类似 UDP。
补充:机器人系统中,传感器数据通常使用BEST_EFFORT,而参数更新需要RELIABLE可靠性。

History:消息的历史记录方式,当订阅者由于忙碌错过了消息,其仍能收到历史消息。这个参数只有在 Reliability 为 RELIABLE 时才有用。
	KEEP_LAST(default): 缓冲区保留最后几条消息。
	KEEP_ALL: 缓冲区保留所有传递过的消息。
Depth:与 History 搭配使用,当 History 为 KEEP_LAST 时,指定需要保留的消息个数,默认是10个;

Durability:消息是否应该在网络中持久化,以便新加入的订阅者也能接收。这个参数只有在 Reliability 为 RELIABLE 时才有用
	TRANSIENT_LOCAL(default): 消息在发布者端持久化,新加入的订阅者可以接收到旧消息,接收个数由History和Depth决定。
	VOLATILE: 消息不在节点之间持久化,新加入的订阅者接收不到旧消息。

Lifespan:消息应该在缓存中保留多长时间。如果超过这个时间,消息会被丢弃,即使还没有被任何订阅者接收,默认值是 Infinite。
	提示:Lifespan 的设置要与 History 和 Depth 对应起来,两个配置遵循木桶原理,最短的起作用。

Deadline:确定消息应当被发布和接收的最大期限,超出后会执行特定的回调函数,默认值是 Infinite。这个参数一般用于实时系统。
	举例:deadline=Duration(seconds=2, nanoseconds=0),

Liveliness: 节点如何通告自己的活动状态,用来确定节点是否还活着。一般用于分布式系统
    AUTOMATIC(default): 节点自动报告其存活状态。
    MANUAL_BY_TOPIC: 发布者需要手动报告其针对特定话题的存活状态。
Liveliness lease duration: 与 Liveliness 搭配使用,表示节点或话题必须在此期限内报告其存活状态,否则认为已经不活跃,默认值是 Infinite。

(3)发布者和订阅者 QoS 配置要求:针对 topic 配置 QoS ,一般要求同一个 topic 收发两端的 QoS 配置要一致,不然就会有奇奇怪怪的问题。
(4)命令行测试 QoS 的方法:ros2 topic 命令行有一组qos选项,可以手动测试 QoS 。

# 使用 best_effort 发送 /chatter
ros2 topic pub /chatter std_msgs/msg/Int32 "data: 42" --qos-reliability best_effort
# 使用 reliable 订阅 /chatter,这样是收不到的!
ros2 topic echo /chatter  --qos-reliability reliable
# 使用 best_effort 订阅 /chatter,欧凯!
ros2 topic echo /chatter --qos-reliability best_effort

在这里插入图片描述

2.2 pubsub_py – 测试新加入的节点能收到历史消息

(1)创建新的 python 和 launch 文件

cd ~/colcon_ws/src/pubsub_py
touch launch/pubsub_qos_launch.py
touch pubsub_py/pub_hello_qos.py pubsub_py/sub_hello_qos.py

(2)编写 pub_hello_qos.py

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import rclpy
from rclpy.node import Node

from std_msgs.msg import String
from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSHistoryPolicy, QoSDurabilityPolicy, LivelinessPolicy
from rclpy.duration import Duration

class Publisher(Node):
    def __init__(self):
        super().__init__('test_qos_publisher')

        qos_profile = QoSProfile(
            # RELIABLE(default), BEST_EFFORT
            reliability = QoSReliabilityPolicy.RELIABLE,
            # VOLATILE(default)
            # TRANSIENT_LOCAL(Only works when reliability is RELIABLE and needs history:KEEP_LAST and depth)
            # 新加入的节点能收到历史消息,这是最重要的配置!!!!!
            durability=QoSDurabilityPolicy.TRANSIENT_LOCAL,
            # history: only works when reliability is RELIABLE
            # KEEP_LAST(default), KEEP_ALL
            history = QoSHistoryPolicy.KEEP_LAST,
            # default is 10
            depth=10,
            # default is Infinite
            lifespan=Duration(seconds=5),

            # default is Infinite
            deadline=Duration(seconds=5, nanoseconds=0),
            # AUTOMATIC(default), MANUAL_BY_TOPIC
            liveliness=LivelinessPolicy.AUTOMATIC,
            # default is Infinite
            liveliness_lease_duration=Duration(seconds=5)
        )

        self._publisher = self.create_publisher(String, "hello_topic", qos_profile)
        self._timer = self.create_timer(0.5, self.timer_callback)
        self._i = 0

    def timer_callback(self):
        msg = String()
        msg.data = "hello, i am fine in python! %d" % self._i
        self._publisher.publish(msg)
        self.get_logger().info("publish: %s" % msg.data)
        self._i += 1

def main(args=None):
    rclpy.init(args=args)
    pub_node = Publisher()
    rclpy.spin(pub_node)
    pub_node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

(3)编写 sub_hello_qos.py

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import rclpy
from rclpy.node import Node

from std_msgs.msg import String
from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSHistoryPolicy, QoSDurabilityPolicy, LivelinessPolicy
from rclpy.duration import Duration
from time import sleep

class Subscriber(Node):
    def __init__(self):
        super().__init__('test_qos_subscriber')

        qos_profile = QoSProfile(
            # RELIABLE(default), BEST_EFFORT
            reliability = QoSReliabilityPolicy.RELIABLE,
            # VOLATILE(default)
            # TRANSIENT_LOCAL(Only works when reliability is RELIABLE and needs history:KEEP_LAST and depth)
            # 新加入的节点能收到历史消息,这是最重要的配置!!!!!
            durability=QoSDurabilityPolicy.TRANSIENT_LOCAL,
            # history: only works when reliability is RELIABLE
            # KEEP_LAST(default), KEEP_ALL
            history = QoSHistoryPolicy.KEEP_LAST,
            # default is 10
            depth=10,
            # default is Infinite
            lifespan=Duration(seconds=5),

            # default is Infinite
            deadline=Duration(seconds=5, nanoseconds=0),
            # AUTOMATIC(default), MANUAL_BY_TOPIC
            liveliness=LivelinessPolicy.AUTOMATIC,
            # default is Infinite
            liveliness_lease_duration=Duration(seconds=5)
        )

        self._subscriber = self.create_subscription(String, "hello_topic", self.topic_callback, qos_profile)

    def topic_callback(self, msg):
        self.get_logger().info("subscribe: %s" % msg.data)
        # sleep(2)        # test qos history and depth parameters

def main(args=None):
    rclpy.init(args=args)
    sub_node = Subscriber()
    rclpy.spin(sub_node)
    sub_node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

(4)编写 pubsub_qos_launch.py

from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import TimerAction

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='pubsub_py',
            namespace='qos',
            executable='talker_qos',
            name='talker_qos'
        ),
        TimerAction(
            period=3.0,   # test qos durability:TRANSIENT_LOCAL
            # period=0.0,
            actions=[
                Node(
                    package='pubsub_py',
                    namespace='qos',
                    executable='listener_qos',
                    name='listener_qos'
                )
            ]
        )
    ])

(5)添加 setup.py

    entry_points={
        'console_scripts': [
            'talker = pubsub_py.publisher:main',
            'talker_diy = pubsub_py.pub_diy_msg:main',
            'listener = pubsub_py.subscriber:main',
            'listener_diy = pubsub_py.sub_diy_msg:main',
            'talker_qos = pubsub_py.pub_hello_qos:main',
            'listener_qos = pubsub_py.sub_hello_qos:main'
        ],
    },

(6)编译并运行

~/colcon_ws
colcon build --packages-select diy_interface pubsub_py
source install/local_setup.bash
ros2 launch pubsub_py pubsub_qos_launch.py

在这里插入图片描述

2.3 pubsub_cpp – 测试订阅者能接收错过的消息

代码链接:pubsub_cpp,这里不再详述,基本就是用 cpp 实现上面的 python 版本。不同的是,cpp 样例重点测试:订阅者因忙碌错过了一些消息,但通过 QoS 仍能接收。
在这里插入图片描述

3 总结

本文的代码托管在本人的github上:pubsub_pypubsub_cpp

  • 26
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ROS2编程基础课程文档 ROS 2(机器人操作系统2)是用于机器人应用的开源开发套件。ROS 2之目的是为各行各业的开发人员提供标准的软件平台,从研究和原型设计再到部署和生产。 ROS 2建立在ROS 1的成功基础之上,ROS 1目前已在世界各地的无数机器人应用中得到应用。 特色 缩短上市时间 ROS 2提供了开发应用程序所需的机器人工具,库和功能,可以将时间花在对业务非常重要的工作上。因为它 是开源的,所以可以灵活地决定在何处以及如何使用ROS 2,以及根据实际的需求自由定制,使用ROS 2 可以大幅度提升产品和算法研发速度! 专为生产而设计 凭借在建立ROS 1作为机器人研发的事实上的全球标准方面的十年经验,ROS 2从一开始就被建立在工业级 基础上并可用于生产,包括高可靠性和安全关键系统。 ROS 2的设计选择、开发实践和项目管理基于行业利 益相关者的要求。 多平台支持 ROS 2在Linux,Windows和macOS上得到支持和测试,允许无缝开发和部署机器人自动化,后端管理和 用户界面。分层支持模型允许端口到新平台,例如实时和嵌入式操作系统,以便在获得兴趣和投资时引入和推 广。 丰富的应用领域 与之前的ROS 1一样,ROS 2可用于各种机器人应用,从室内到室外、从家庭到汽车、水下到太空、从消费 到工业。 没有供应商锁定 ROS 2建立在一个抽象层上,使机器人库和应用程序与通信技术隔离开来。抽象底层是通信代码的多种实现, 包括开源和专有解决方案。在抽象顶层,核心库和用户应用程序是可移植的。 建立在开放标准之上 ROS 2中的默认通信方法使用IDL、DDSDDS-I RTPS等行业标准,这些标准已广泛应用于从工厂到航空 航天的各种工业应用中。 开源许可证 ROS 2代码在Apache 2.0许可下获得许可,在3条款(或“新”)BSD许可下使用移植的ROS 1代码。这两个 许可证允许允许使用软件,而不会影响用户的知识产权。 全球社区 超过10年的ROS项目通过发展一个由数十万开发人员和用户组成的全球社区,为机器人技术创建了一个庞大 的生态系统,他们为这些软件做出贡献并进行了改进。 ROS 2由该社区开发并为该社区开发,他们将成为未 来的管理者。 行业支持 正如ROS 2技术指导委员会成员所证明的那样,对ROS 2的行业支持很强。除了开发顶级产品外,来自世界 各地的大大小小公司都在投入资源为ROS 2做出开源贡献。 与ROS1的互操作性 ROS 2包括到ROS 1的桥接器,处理两个系统之间的双向通信。如果有一个现有的ROS 1应用程序, 可 以通过桥接器开始尝试使用ROS 2,并根据要求和可用资源逐步移植应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值