赛场联调诊断与排错复盘

2061 字
10 分钟
赛场联调诊断与排错复盘

赛场上车出了问题,最怕的不是问题本身,是不知道问题出在哪。上位机说是电控的事,电控说是雷达的事,雷达说是上位机的算法有问题——互相甩锅半小时,时间全浪费了。这一章给一套快速定位的方法,出了问题先搞清楚是谁的责任,再想办法修。

症状→根因映射表#

车在赛场上出问题了,先看症状,对着表查可能的原因。

蛇形走位 / 直线画龙#

车走直线的时候左右小幅摆动,幅度越来越大或者一直抖。

最可能的原因:定位数据有高频噪声。

激光 SLAM 或里程计的输出每一帧都有几厘米的抖动,控制算法每帧都在修正这个抖动,越修越抖,形成正反馈。

排查步骤:

  1. 打开 RViz(或者自己写个可视化),看定位轨迹是不是锯齿状
  2. 如果是锯齿 → 定位噪声太大,加低通滤波
  3. 如果轨迹平滑但车还是抖 → 控制器增益太大,降低 P 项

另一个可能:EKF 没收敛。 如果用了 EKF 融合多传感器,刚启动时 EKF 需要几秒钟收敛,这段时间定位是不准的。等几秒再启动任务。

走对数曲线 / 过弯过冲#

车走弯道的时候不走圆弧,走出一条越来越弯的线,像对数函数图像。或者到了弯道该转弯了,转不过来,冲出赛道。

最可能的原因:定位数据有高延时。

你拿到的位姿是 100ms 前的,但控制算法用这个”旧”位姿算出来的角速度是针对 100ms 前的位置的。速度越快,100ms 的位移越大,过弯时就切弯或者冲出去。

排查步骤:

  1. 在代码里打印定位数据的时间戳和当前系统时间,算差值
  2. 如果延时 > 50ms → 定位处理太慢,降分辨率或者换更快的算法
  3. 如果延时正常但还是过冲 → 运动学参数不对(轮距、最大角速度),或者前瞻距离太小

另一个可能:运动学参数错误。 代码里写的轮距和实际轮距不一样,算出来的左右轮速比例是错的,车就会走出奇怪的弧线。

坐标瞬移 / 90° 甩尾#

车走着走着突然跳了一截,或者朝向突然转了 90°。Pure Pursuit 看到位置突然变了,猛打方向,车直接甩尾。

但是还有一个因素会导致各种奇奇怪怪的bug,就是你们的雷达过热,需要散热。就比如我们26赛季用的Odin1,因为雷达过热出现了原点偏移,导致比赛途中出现重大事故

最可能的原因:重定位跟丢了。

激光 SLAM 的 ICP/NDT 匹配失败,重新匹配成功后位置跳了一大截。在环境退化(长走廊、空旷区域、相似结构)时容易发生。

排查步骤:

  1. 看定位轨迹有没有突然的跳变
  2. 如果有 → SLAM 匹配失败,检查地图质量、检查雷达有没有被遮挡
  3. 如果没有跳变但车还是甩 → 检查是不是里程计编码器松了,轮子打滑导致里程计突变

缓解措施:

  • 对定位输出做异常值检测,跳变超过阈值就丢弃
  • 用轮式里程计做降级,定位跳变时切回里程计
  • 控制器加输出限幅,角速度不能超过某个值

无中生有急停 / 空气墙#

车走着走着突然停了,面前什么都没有。或者明明前面是空的,车就是不过去。

最可能的原因:雷达点云有噪点。

灰尘、阳光直射、反光表面都会在雷达点云里产生噪点。如果没做 ROI 裁剪,这些噪点会被当成障碍物,触发避障或者急停。

排查步骤:

  1. 打开 RViz 看点云,找有没有离群点
  2. 如果有 → 加 ROI 裁剪,只保留赛场范围内的点
  3. 加点云滤波(统计滤波、半径滤波)去掉离群点

另一个可能:雷达脏了或者被遮挡。 比赛前检查一下雷达镜片有没有灰尘,线有没有松。


抓包与数据比对#

出了问题不要猜,看数据。

ROS2 Topic 日志#

ROS2 自带命令行工具,可以实时查看每个 Topic 的数据:

Terminal window
# 查看某个 Topic 的最新消息
ros2 topic echo /decision
# 查看 Topic 的发布频率
ros2 topic hz /odom
# 列出所有活跃的 Topic
ros2 topic list

车走蛇形的时候,先 ros2 topic hz /odom 看定位频率正不正常。频率正常说明定位没问题,是控制的问题;频率不对说明定位有延迟或者丢帧。

录包回放#

ROS2 可以把所有 Topic 的数据录下来,事后回放分析:

Terminal window
# 录包(所有 Topic)
ros2 bag record -a
# 录指定 Topic
ros2 bag record /odom /decision /command
# 回放
ros2 bag play <bag文件路径>

录包的好处是:赛场上出了问题,把包录下来,回实验室慢慢分析。不用在赛场上现调。

分离责任的思路#

出了问题,先搞清楚是哪一层的:

车走蛇形?
→ 看 /odom 的轨迹
→ 轨迹是锯齿 → 定位层的问题(噪声太大)
→ 轨迹平滑 → 控制层的问题(增益太大)
车不到目标点?
→ 看 /command 里的坐标
→ 坐标不对 → 决策层的问题(路径点标错了)
→ 坐标对了但车没到 → 控制层或感知层的问题
机械臂不动作?
→ 看 /command 里的 block/stair 字段
→ 字段值不对 → 决策层的问题
→ 字段值对了但没动 → 电控的问题(串口通信或硬件)

每一层只看它的输入和输出。输入对了输出不对,是这一层的问题。输入就不对,是上一层的问题。从上往下查,5 分钟内定位到问题出在哪。


技术资产沉淀#

赛季结束了,代码和文档要留给下一届。

写文档,不写注释#

代码里的注释是给写代码的人看的,文档是给接手的人看的。下一届的人不会逐行读你的代码,他们需要的是:

  • 系统架构图: 整个上位机有哪些模块,模块之间怎么通信
  • 模块 API 文档: 每个模块对外暴露什么接口,输入输出是什么
  • 配置说明: YAML 里每个参数是什么意思,改了会怎样
  • 赛场排错指南: 就是上面那张症状→根因映射表
# R2 上位机架构文档
## 模块列表
- serial_node (C++): 串口驱动,负责和电控通信
- decision_node (Python): 决策状态机,负责任务调度
- control_node (C++): 运动控制,负责 Pure Pursuit
## 通信接口
- /command (robot_serial/msg/Command): 决策 → 串口驱动
- /decision (robot_serial/msg/Ack): 串口驱动 → 决策
- /odom (nav_msgs/msg/Odometry): 定位 → 控制
## 配置参数
见 config/params.yaml 注释

仓库结构#

r2_upper/
├── README.md # 项目说明、怎么跑起来
├── docs/
│ ├── architecture.md # 架构文档
│ ├── troubleshooting.md # 排错指南
│ └── protocol.md # 串口协议文档
├── config/
│ └── params.yaml # 所有可调参数
├── src/
│ ├── r2_serial/ # 串口驱动
│ ├── r2_decision_py/ # 决策(Python)
│ └── r2_control/ # 运动控制
└── launch/
└── r2_system.launch.py

README 里要写清楚三件事:怎么把环境搭起来、怎么把代码跑起来、改了配置怎么生效。下一届的人拿到仓库,30 分钟内能跑起来,你的文档就合格了。


小结#

赛场上出了问题,先看症状对着映射表查可能的原因,再用 Topic 日志和录包定位是哪一层的问题。不要猜,看数据。

赛季结束后把架构、接口、参数、排错经验写成文档留给下一届。代码会过时,但文档里的排错经验不会——蛇形走位是定位噪声、过弯过冲是延时太大、坐标跳变是重定位发散,这些因果关系十年后还是这样。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

赛场联调诊断与排错复盘
https://firefly-7a0.pages.dev/posts/rc/10troubleshooting/
作者
lumivers
发布于
2026-07-26
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
lumivers
Hello, I'm lumivers.
公告
欢迎来到我的博客!
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
170
分类
13
标签
528
总字数
350,523
运行时长
0
最后活动
0 天前

目录