使用 Jupyter 分析 ROS 消息时间间隔抖动数据

ROS 是一个分布式机器人操作系统软件框架,节点之间通过松耦合的方式进行组合,包括使用 Topic、RPC 服务和参数服务器等方式进行通信。其中,Topic 是最常见的一种通信方式,例如一个雷达传感器节点实时采集三维点云数据,通过 Topic 发布到 ROS 系统,而 ROS 系统中的其他节点(如 Rviz)可以订阅这个 Topic,接收来自雷达的点云数据,将其显示出来。

案例背景

在使用 Rviz 显示雷达点云数据的过程中,我们发现 Rviz2 的三维视窗周期性地出现卡顿。数据由雷达驱动节点发布,Rviz2 节点订阅,我们想要知道卡顿的具体情况,进一步分析卡顿是由于发布端慢了还是订阅端慢了导致的,因此需要对数据进行分析。

每一个 ROS 消息都带有时间戳信息(字段名为 stamp),在 ROS2 中,可以通过 ros2 topic echo 命令打印指定 Topic 的信息。假设雷达的 Topic 为 /lidar_topic,通过下面命令即可过滤出每一条消息的时间戳信息。

bash 复制代码
ros2 topic echo /lidar_topic | grep -w -A 2 "stamp"

打印内容如下所示,ROS 消息的时间戳包括秒和纳秒两部分。

bash 复制代码
  stamp:
    sec: 1702388539
    nanosec: 988327026
--
  stamp:
    sec: 1702388540
    nanosec: 107672930
--
  stamp:
    sec: 1702388540
    nanosec: 226908922
--
  stamp:
    sec: 1702388540
    nanosec: 346390963
--

为了采集足够多的数据,我们将输出的内容写入到文件中,以便后续处理。

bash 复制代码
ros2 topic echo /lidar_topic | grep -w -A 2 "stamp" > ts-data.txt

作为对比,我们关闭 Rviz2,只启动雷达驱动节点,再采集一组数据。

bash 复制代码
ros2 topic echo /lidar_topic | grep -w -A 2 "stamp" > ts-data-quiet.txt

分析数据

新建一个终端,执行 jupyter-notebook 命令,打开 Jupyter Notebook 浏览器界面。然后点击 "新建",选择 Python3,开始编写 Python 代码。

程序的流程大致如下:

  1. 读取文件内容,并将其中的 sec 和 nanosec 字段信息重新组合成一个完整的 timestamp 时间戳,保存到列表 timestamps 中(这里保存 800 组数据)。
  2. 将时间戳两两相减,得到时间间隔信息,保存到列表 time_intervals 中。
  3. 从 time_intervals 列表计算时间间隔的均值、中值、最大值、最小值等指标,可用于衡量抖动情况。
  4. 以时间间隔大小为纵轴,绘制图表,可直观看出抖动情况。

下面是完整代码,这里使用 matplotlib 库绘制图表,因此首先需要引入相关 Python 库。

python 复制代码
import matplotlib.pyplot as plt
from datetime import datetime
from matplotlib.font_manager import FontProperties

# 设置中文显示
font = FontProperties(fname='/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc')

file_path = 'ts-data.txt'
timestamps = []

with open(file_path, 'r') as file:
    lines = file.readlines()
    for i in range(len(lines) - 1):  # 避免越界
        if 'sec' in lines[i] and 'nanosec' in lines[i + 1]:
            sec = int(lines[i].split(':')[-1].strip())
            nanosec = int(lines[i + 1].split(':')[-1].strip())
            timestamp = sec + nanosec * 1e-9
            timestamps.append(timestamp)
            if (len(timestamps) > 800):
                break

time_intervals = [timestamps[i + 1] - timestamps[i] for i in range(len(timestamps) - 1)]

mean_interval = sum(time_intervals) / len(time_intervals)
median_interval = sorted(time_intervals)[len(time_intervals) // 2]
max_interval = max(time_intervals)
min_interval = min(time_intervals)

print(f"均值: {mean_interval} 秒")
print(f"中值: {median_interval} 秒")
print(f"最大值: {max_interval} 秒")
print(f"最小值: {min_interval} 秒")

# 绘制时间间隔的图表
plt.figure(figsize=(10, 6))
plt.plot(time_intervals, marker='o', linestyle='-', color='b')
plt.title('ROS Message Time Intervals (with Rviz)')
plt.xlabel('index')
plt.ylabel('interval (s)')
plt.grid(True)
plt.show()

提示:代码和数据可在 GitHub 仓库下载,你也可以参考该示例程序分析其他类似的数据。

输出结果

在 Jupyter Notebook 中点击 Run 执行代码,可以看到如下输入:

bash 复制代码
均值: 0.1342798188328743 秒
中值: 0.11950397491455078 秒
最大值: 0.7162301540374756 秒
最小值: 0.11851811408996582 秒

时间间隔分布情况如下:

将上述 ROS-Message-Time-Intervals.py 程序中的第8行修改为 ts-data-quiet.txt,第37行修改为 plt.title('ROS Message Time Intervals (no Rviz)'),再次点击 Run 重新执行程序。可以看到如下输出:

bash 复制代码
均值: 0.12153411984443664 秒
中值: 0.1189870834350586 秒
最大值: 0.8321161270141602 秒
最小值: 0.11800003051757812 秒

时间间隔分布情况如下:

可以看到,在不启动 Rviz2 的情况下,时间间隔抖动情况有明显改善。

相关推荐
努力的家伙是不讨厌的32 分钟前
解析json导出csv或者直接入库
开发语言·python·json
云空1 小时前
《Python 与 SQLite:强大的数据库组合》
数据库·python·sqlite
凤枭香2 小时前
Python OpenCV 傅里叶变换
开发语言·图像处理·python·opencv
测试杂货铺2 小时前
外包干了2年,快要废了。。
自动化测试·软件测试·python·功能测试·测试工具·面试·职场和发展
艾派森2 小时前
大数据分析案例-基于随机森林算法的智能手机价格预测模型
人工智能·python·随机森林·机器学习·数据挖掘
小码的头发丝、2 小时前
Django中ListView 和 DetailView类的区别
数据库·python·django
小黄人软件2 小时前
android浏览器源码 可输入地址或关键词搜索 android studio 2024 可开发可改地址
android·ide·android studio
Chef_Chen3 小时前
从0开始机器学习--Day17--神经网络反向传播作业
python·神经网络·机器学习
千澜空3 小时前
celery在django项目中实现并发任务和定时任务
python·django·celery·定时任务·异步任务