一、ACT系统性能基准测试:理解延迟、吞吐量、抖动等关键指标,搭建标准测试环境,执行首次基准测试并记录基线数据
各位同学,欢迎来到ACT具身智能性能调优的第一课。
说实话,很多团队做具身智能项目,上来就调模型、改算法,结果系统上线后才发现——机器人反应慢半拍,抓取动作抖得厉害。为什么?因为没有基线数据。你连系统现在跑多快、稳不稳都不知道,怎么优化?
我个人习惯,拿到任何ACT系统,第一件事就是做基准测试。这就像体检,先测心率、血压,再谈怎么锻炼。今天我们就来聊聊这件事。
1.1 三个核心指标:延迟、吞吐量、抖动
先搞清楚我们要测什么。ACT系统里,我重点关注三个指标。
延迟(Latency)
说白了,就是从发出指令到机器人执行动作的时间差。比如你让机械臂去抓杯子,从视觉传感器拍到杯子,到机械臂开始移动,这中间花了多少毫秒。
我在项目中遇到过,有个客户抱怨机器人抓取总是慢半拍。一测延迟,好家伙,平均200ms,峰值能到500ms。这种延迟在高速产线上根本没法用。
延迟通常分三段:感知延迟(摄像头采集+识别)、规划延迟(路径计算)、执行延迟(电机响应)。我们做基准测试时,要分别记录这三段。
吞吐量(Throughput)
单位时间内系统能处理多少任务。比如每分钟能完成多少次抓取动作,或者每秒能处理多少帧视觉数据。
吞吐量和延迟是冤家。你想想看,一味压延迟,可能牺牲吞吐量;反过来,拼命堆吞吐量,延迟可能飙升。怎么平衡?这就是调优的艺术。
抖动(Jitter)
这个指标很多人忽略,但恰恰最要命。抖动是延迟的波动程度。比如平均延迟50ms,但有时候突然跳到200ms,这种不稳定性会让机器人动作忽快忽慢,抓取成功率直线下降。
我曾经调试一个双臂协作系统,延迟平均值很漂亮,但抖动大得离谱。结果两个机械臂经常撞在一起。后来花了整整一周,才把抖动从±80ms压到±15ms以内。
核心要点:
- 延迟:端到端响应时间,关注P50、P95、P99分位值
- 吞吐量:单位时间任务完成数,关注峰值和持续值
- 抖动:延迟标准差,关注最大值和分布形态
1.2 搭建标准测试环境
环境不标准,数据就是废的。我见过太多团队,今天在A机器上测,明天在B机器上测,数据根本没法对比。
硬件环境标准化
至少固定以下几项:
- 控制主机:CPU型号、内存大小、硬盘类型(SSD还是HDD)
- 传感器:摄像头型号、分辨率、帧率、曝光参数
- 执行器:电机型号、驱动器参数、减速比
- 网络:有线还是无线,带宽限制,是否共享
我建议,把硬件配置写成一个配置文件,每次测试前检查一遍。别嫌麻烦,我吃过亏——有一次发现延迟异常,查了半天,原来是测试人员换了台笔记本。
软件环境标准化
- 操作系统版本、内核参数
- ROS2版本、DDS中间件配置
- 模型推理框架(TensorRT、ONNX Runtime等)版本
- 依赖库版本(OpenCV、Eigen、PyTorch等)
测试场景标准化
固定测试任务。比如:
- 视觉识别:固定10张测试图片,每张重复100次
- 路径规划:固定起点和终点,障碍物布局不变
- 抓取动作:固定目标物体位置、姿态、重量
嗯,这里要注意:测试场景要能代表真实工况。我见过有人用空载测延迟,结果上线后负载一上去,数据全变了。
1.3 执行首次基准测试
环境搭好了,开始跑测试。我一般按这个步骤来:
- 预热:先让系统跑5-10分钟,等温度稳定、缓存预热。冷启动的数据不要。
- 连续测试:跑至少1000次任务,或者持续10分钟以上。样本太少,统计没意义。
- 记录时间戳:在每个关键节点打时间戳——感知开始、感知结束、规划开始、规划结束、执行开始、执行结束。
- 保存原始数据:不要只记平均值,把每次的延迟、吞吐量、抖动都存下来。
下面是我常用的测试脚本框架:
# 基准测试脚本示例
import time
import csv
def run_benchmark(trials=1000):
results = []
for i in range(trials):
# 记录感知延迟
t0 = time.perf_counter_ns()
obs = sensor.capture()
t1 = time.perf_counter_ns()
action = policy.predict(obs)
t2 = time.perf_counter_ns()
robot.execute(action)
t3 = time.perf_counter_ns()
results.append({
'perception_latency': t1 - t0,
'planning_latency': t2 - t1,
'execution_latency': t3 - t2,
'total_latency': t3 - t0
})
# 保存到CSV
with open('baseline.csv', 'w') as f:
writer = csv.DictWriter(f, fieldnames=results[0].keys())
writer.writeheader()
writer.writerows(results)
return results
1.4 记录基线数据
跑完测试,数据怎么整理?我习惯用一张表来呈现:
| 指标 | 平均值 | P50 | P95 | P99 | 最大值 | 标准差 |
|---|---|---|---|---|---|---|
| 感知延迟 (ms) | 32.5 | 30.1 | 45.2 | 58.7 | 102.3 | 8.2 |
| 规划延迟 (ms) | 18.3 | 16.8 | 28.5 | 35.1 | 67.4 | 5.6 |
| 执行延迟 (ms) | 45.1 | 44.0 | 52.3 | 60.8 | 89.2 | 4.1 |
| 总延迟 (ms) | 95.9 | 90.9 | 126.0 | 154.6 | 258.9 | 17.9 |
| 吞吐量 (次/分钟) | 42 | 43 | 38 | 35 | 48 | 3.2 |
| 抖动 (ms) | 17.9 | — | — | — | — | — |
看到这个表,你能发现什么?总延迟P99是154.6ms,但最大值到了258.9ms。这说明系统偶尔会卡顿,抖动很大。这就是优化的突破口。
我的小技巧: 把基线数据保存到版本控制里。每次改完代码,重新跑一遍测试,对比数据。如果延迟变差了,说明改坏了,赶紧回滚。
避坑指南: 我曾经犯过一个错误——只记录了平均延迟,没看P99。结果优化后平均值降了20%,但P99反而涨了50%。系统在99%的情况下更差了,只是被平均值掩盖了。所以,一定要关注尾延迟。
1.5 知识体系总览
下面这张图,是我对本章知识结构的总结。你可以把它当作一个检查清单:
这张图把本章内容串起来了。左边是三个核心指标,中间是测试环境,右边是执行流程。你每次做基准测试,就按这个框架来,保证不会漏东西。
好了,第一课就到这里。记住:没有基线,就没有优化。先把这一步做扎实,后面调优才有方向。