当前位置: 首页 > news >正文

ros2_topic_hz_命令实现_实时统计频率不准问题

1.问题与需求

问题: ros2 topic hz 命令实时统计频率不准确

验证步骤:

  1. 实现一个动态频率发布topic 的节点node
  2. 发布频率从10Hz, 切换到 100Hz
  3. ros2 topic hz 统计话题频率变化

5_pub_动态频率发布.py

#!/usr/bin/env python3
# coding:utf-8
import time
import threadingimport rclpy
from rclpy.node import Nodefrom std_msgs.msg import String, Float64, Float64MultiArray, Int64, UInt64MultiArray
from nobloack_key_input import Noblock_terminalclass MinimalPublisher(Node):def __init__(self):super().__init__('minimal_publisher')self.pub_str = self.create_publisher(String, '/hz_string', 1)self.pub_int = self.create_publisher(Int64, '/hz_int', 1)self.pub_int_array = self.create_publisher(UInt64MultiArray, '/hz_int_array', 1)self.pub_float = self.create_publisher(Float64, '/hz_float', 1)self.pub_float_array = self.create_publisher(Float64MultiArray, '/hz_float_array', 1)self.delay_time = 0.1self.thread_init()self.dynamic_rate_pub()def thread_init(self):t1 = threading.Thread(target=self.change_delay_time, daemon=True)t1.start()def dynamic_rate_pub(self):data_str = 'hello world'data_int_array = [1, 2, 3, 4, 5]data_float_array = [1.0, 2.0, 3.0, 4.0, 5.0]while True:# self.get_logger().info('Publishing: "%s"' % msg.data)self.pub_str.publish(String(data=data_str))self.pub_int.publish(Int64(data=1))self.pub_int_array.publish(UInt64MultiArray(data=data_int_array))self.pub_float.publish(Float64(data=1.0))self.pub_float_array.publish(Float64MultiArray(data=data_float_array))time.sleep(self.delay_time)def change_delay_time(self):help_str="""
\033[80D w +0.01s
\033[80D s -0.01s
\033[80D q 退出
\033[80D
"""print(help_str)noblock_term = Noblock_terminal()time_stamp = time.time()while True:key = noblock_term.select_cmd(timeout=0.5)if key == 'w':self.delay_time += 0.01elif key == 's':self.delay_time -= 0.01if self.delay_time <= 0:self.delay_time = 0.01elif key == 'q':breakelif key == '0':continueelse:print("\033[80D 未知指令")print(f"\033[80D delay_time: {self.delay_time:.2f}")# 定时打印 使用帮助cur_time = time.time()if int(cur_time - time_stamp) % 10 == 0:print(help_str)print("退出 控制")noblock_term.stop_no_block()def main(args=None):rclpy.init(args=args)minimal_publisher = MinimalPublisher()rclpy.spin(minimal_publisher)minimal_publisher.destroy_node()rclpy.shutdown()if __name__ == '__main__':main()

完整代码链接: gitee在线代码

  • nobloack_key_input.py
  • 5_pub_动态频率发布.py

代码解析:

  1. 发布多个话题 /hz_int, /hz_string, /hz_float
  2. 变量 self.delay_time, 是发布间隔时间
  3. 通过键盘命令 w增加/ s减少 self.delay_time的值, 从而修改发布间隔时间

在这里插入图片描述
如图:
当delay_time 从 0.1s -->变为–> 0.01s
频率 对应从 10hz -->变为–> 100hz
实际情况却是, ros2 topic hz 统计频率为 10, 15, 27,36,43…99.8hz
即ros2 topic hz 统计频率变化时, 是有一套统计中值方案

需求

实现一个能够实时反应当前真实频率的统计方式

2.代码实现

1.参考ros2 topic hz命令源代码

linux系统安装ros2 humble之后, 本地代码: /opt/ros/humble/lib/python3.10/site-packages/ros2topic/verb/hz.py
在线代码: https://github.com/ros2/ros2cli/blob/rolling/ros2topic/ros2topic/verb/hz.py

    def get_hz(self, topic=None):if not self.get_times(topic=topic):returnelif self.get_msg_tn(topic=topic) == self.get_last_printed_tn(topic=topic):returnwith self.lock:# Get frequency every one secondtimes = self.get_times(topic=topic)n = len(times)mean = sum(times) / nrate = 1. / mean if mean > 0. else 0# std devstd_dev = math.sqrt(sum((x - mean)**2 for x in times) / n)# min and maxmax_delta = max(times)min_delta = min(times)self.set_last_printed_tn(self.get_msg_tn(topic=topic), topic=topic)return rate, min_delta, max_delta, std_dev, n

源码解析:

  1. 每隔1s, 执行 get_hz()
  2. times 是列表, 统计1s内, 每帧时间间隔
  3. 获取统计值 帧率n, 平均间隔mean, 最大延迟 max, 最小延迟min
  4. 计算 平均帧率rate, 标准差延迟std_dev

具体 为什么ros2 topic hz统计是递增/递减, 可以看代码统计方法实现

2.实时更新统计版本

3_subscribe_hz_订阅统计_模板版.py

@dataclass
class Sub_Topic_Hz:name: str  # 话题名value_name: str # 去除特殊符号, 话题名 --> 用作python 动态变量,动态函数名 创建fixed_hz: int  # 固有频率fixed_hz_diff_time: float  # 固定帧时间差msg_type: any = None# 记录时间, 数据hz: float = 0.0min_time: float = 1000.0max_time: float = 0.0new_start_time: float = 0.0  # 上一秒开始统计时间last_time: float = 0.0  # 上一条topic话题时间times: List[float] = field(default_factory=list)# 统计时间accum_dev_time: float = 0.0  # 积累偏差std_dev_time: float = 0.0  # 标准偏差Config = {"record_path": "/tmp","csv_record": True,"csv_filed": ["time","topic","rate","min","max","accum_dev","std_dev",],
}sub_topic_list = [Sub_Topic_Hz("/hz_string", "hz_string", 100, 1.0 / 100, msg_type=String),Sub_Topic_Hz("/hz_int", "hz_int", 100, 1.0 / 100, msg_type=Int64),Sub_Topic_Hz("/hz_int_array", "hz_int_array", 50, 1.0 / 50, msg_type=UInt64MultiArray),Sub_Topic_Hz("/hz_float", "hz_float", 100, 1.0 / 100, msg_type=Float64),Sub_Topic_Hz("/hz_float_array", "hz_float_array", 50, 1.0 / 50, msg_type=Float64MultiArray),
]# 完整代码, 看gitee
# ...
# 完整代码, 看giteedef callback_hz_string(self, msg):hz = self.hz_stringself.cal_hz(hz)def callback_hz_float(self, msg):hz = self.hz_floatself.cal_hz(hz)

代码解析:

参考ros2 hz.py 代码实现,

  1. 统计每秒内 rate, min, max, std_dev
  2. 新增统计 accum_dev_time: float = 0.0 # 积累偏差
    解释: 假如一个topic 预订发布频率 10hz
    第1帧预订接受时间: 0.10s
    第2帧预订接受时间: 0.20s
    第3帧预订接受时间: 0.30s

    第10帧预订接受时间: 1.00s
    accum_dev_time计算过程:
    将每一帧的接受时间, 与预订接受时间, 作差取绝对值, 统计累计偏差之和
    即统计系统调度的精准性
  3. 新增话题统计, 按模板添加到 sub_topic_list, 并实现一个回调函数,如 callback_xxxx

3.测试验证

终端1: 运行动态频率发布脚本

./5_pub_动态频率发布.py

终端2: ros2 topic hz统计

 ros2 topic hz /hz_int

终端3: 运行测试程序

./3_subscribe_hz_订阅统计_模板版.py

测试1: 发布频率10hz

终端1:
默认0.1s, 即10hz

./5_pub_动态频率发布.py

w +0.01s
s -0.01s
q 退出

终端2

ros2 topic hz /hz_int
average rate: 9.926
min: 0.100s max: 0.101s std dev: 0.00014s window: 11
average rate: 9.926
min: 0.100s max: 0.101s std dev: 0.00011s window: 21

终端3

./3_subscribe_hz_订阅统计_模板版.py
/hz_string hz:9.0 rate:9.92 min:0.101 max:0.101 accum_dev:5.086 std dev:0.000
/hz_int hz:9.0 rate:9.92 min:0.101 max:0.101 accum_dev:5.086 std dev:0.000
/hz_int_array hz:9.0 rate:9.94 min:0.099 max:0.101 accum_dev:4.617 std dev:0.001
/hz_float hz:9.0 rate:9.94 min:0.099 max:0.101 accum_dev:5.069 std dev:0.001

测试结论:
3_subscribe_hz_订阅统计_模板版.py 统计结果正确

测试2: 发布频率100hz

终端1
s 减少delay_time 到 0.01

./5_pub_动态频率发布.py

w +0.01s
s -0.01s
q 退出

delay_time: 0.09
delay_time: 0.08
delay_time: 0.07
delay_time: 0.06
delay_time: 0.05
delay_time: 0.04
delay_time: 0.03
delay_time: 0.02
delay_time: 0.01

终端2

ros2 topic hz /hz_int
average rate: 12.608
min: 0.020s max: 0.101s std dev: 0.03208s window: 103
average rate: 20.830
min: 0.010s max: 0.101s std dev: 0.04129s window: 191
average rate: 28.096
min: 0.010s max: 0.101s std dev: 0.03806s window: 286
average rate: 34.061
min: 0.010s max: 0.101s std dev: 0.03470s window: 381
average rate: 39.041
min: 0.010s max: 0.101s std dev: 0.03194s window: 476
average rate: 43.257
min: 0.010s max: 0.101s std dev: 0.02969s window: 571

终端3

./3_subscribe_hz_订阅统计_模板版.py
/hz_int_array hz:63 rate:63.42 min:0.010 max:0.031 accum_dev:6.675 std dev:0.006
/hz_float hz:63 rate:63.43 min:0.010 max:0.031 accum_dev:18.912 std dev:0.006
/hz_float_array hz:63 rate:63.44 min:0.010 max:0.031 accum_dev:6.674 std dev:0.006
/hz_string hz:93 rate:93.82 min:0.010 max:0.011 accum_dev:3.909 std dev:0.000
/hz_int hz:93 rate:93.85 min:0.010 max:0.011 accum_dev:3.885 std dev:0.000
/hz_int_array hz:93 rate:93.86 min:0.009 max:0.011 accum_dev:41.827 std dev:0.000
/hz_float hz:93 rate:93.88 min:0.009 max:0.011 accum_dev:3.843 std dev:0.000
/hz_float_array hz:93 rate:93.89 min:0.009 max:0.012 accum_dev:41.870 std dev:0.000
/hz_string hz:94 rate:94.29 min:0.010 max:0.011 accum_dev:3.749 std dev:0.000
/hz_int hz:94 rate:94.31 min:0.010 max:0.011 accum_dev:3.720 std dev:0.000

结果如图
在这里插入图片描述

4.总结

  1. 后续尝试向ros2 github 提交PR, 添加:
    1. feat: 新增统计实时真实帧率选项
    2. feat: 新增统计结果保存为csv格式(或sql,其它格式), 用作性能统计分析,绘图
  2. 当别人问你为什么 ros2 topic hz 有一个缓慢的波动是, 可以解释:
    ros2 topic hz代码设计如此, 统计上是曲线变动, 实际上已经变化到另一个值
  3. 如图在nvidia Jetson Orix – ubuntu20.04上, 统计部分话题, 默认50Hz频率, 在高负载下, 使用我的统计程序, 频率波动很大, 故代码 和 系统性能 都需要优化
    在这里插入图片描述

相关文章:

  • 宇树科技开启“人形机器人格斗盛宴”
  • 深入探讨Facebook隐私政策的演变
  • idea写spark程序
  • ASP.NET MVC后端控制器用模型 接收前端ajax数据为空
  • 基于C++的IOT网关和平台2:github项目ctGateway技术说明书
  • 虚幻商城 Quixel 免费资产自动化入库(2025年版)
  • php+mysql活动报名学生选课产品预定旅游报名系统网站源码
  • 2025年“深圳杯”数学建模挑战赛D题-法医物证多人身份鉴定问题
  • Spring Boot 中集成 Kafka 并实现延迟消息队列
  • 2025年天梯题解(L1-8 + L2)
  • Redis热key大key详解
  • 将uni-app前端项目发布到微信小程序体验版
  • 拥抱健康生活,开启科学养生之旅
  • ROS:发布相机、IMU等设备消息主题
  • VINS-FUSION:配置参数说明与配置自己的参数
  • 在VTK中使用VTKCamera
  • 相机的基础架构
  • [Android]任务列表中有两个相机图标
  • 【网络原理】从零开始深入理解HTTP的报文格式(二)
  • EMI(电磁干扰)和EMC(电磁兼容)整改
  • 全文丨中华人民共和国传染病防治法
  • 新片|《我仍在此》定档5月,《新·驯龙高手》同步北美上映
  • 最高法强化涉新就业形态民事案件审判指导:推动出台司法解释
  • 陈文清:推进扫黑除恶常态化走深走实,有力回应人民群众对安居乐业的新期待
  • 东风着陆场做好各项搜救准备,迎接神舟十九号航天员天外归来
  • 一季度我国服务进出口总额19741.8亿元,同比增长8.7%