调试指南:常见问题排查¶
本指南汇总 RoboMaster 视觉系统中最常见的故障场景,按照「症状 → 可能原因 → 排查步骤 → 解决方案」的结构组织。遇到问题时,先定位症状,再逐一排查原因。
调试工具速查¶
在进入具体场景前,先熟悉核心调试工具。
ROS2 命令行工具¶
# 查看当前所有活跃话题
ros2 topic list
# 实时查看话题数据(Ctrl+C 退出)
ros2 topic echo /detector/armors
# 查看话题发布频率
ros2 topic hz /camera/image_raw
# 查看话题详情(类型、发布者、订阅者)
ros2 topic info /detector/armors --verbose
# 查看节点信息
ros2 node info /armor_detector
# 查看节点参数
ros2 param list /armor_detector
ros2 param get /armor_detector binary_thres
# 动态修改参数(运行时热更新)
ros2 param set /armor_detector binary_thres 160
# 查看系统所有节点
ros2 node list
# 查看日志
ros2 run rclcpp_components component_container --ros-args --log-level debug
RViz2 可视化技巧¶
常用显示类型配置:
| 话题 | 显示类型 | 用途 |
|---|---|---|
/camera/image_raw |
Image | 查看原始相机画面 |
/detector/binary_img |
Image | 查看二值化结果 |
/detector/number_img |
Image | 查看数字识别输入 |
/detector/result_img |
Image | 查看检测叠加结果 |
/tracker/marker |
MarkerArray | 可视化跟踪状态 |
/tf |
TF | 查看坐标变换树 |
RViz2 实用技巧:
- 在 Image 面板中切换不同话题,快速对比处理前后效果
- 使用
Panels > Selection面板点击 Marker 查看详细信息 - 按
F键聚焦到选中的物体 - 保存配置:
File > Save Config As,下次启动直接加载
PlotJuggler 数据绘图¶
```bash tab="Linux"
安装¶
sudo apt install ros-humble-plotjuggler-ros
启动¶
ros2 run plotjuggler plotjuggler
推荐监控的变量:
/tracker/armors中的位置 x/y/z — 检查跟踪轨迹是否平滑/detector/armors中的数量 — 检查检测稳定性- 各节点的发布频率 — 检查是否丢帧
- EKF 的状态协方差 — 检查滤波器是否收敛
使用步骤:
- 启动 PlotJuggler,选择
ROS2 Topic Streaming - 勾选要监控的话题
- 将字段拖拽到绘图区域
- 使用时间轴缩放和平移查看细节
- 用
Measure工具测量时间差和数值差
rosbag2 录制与回放¶
# 录制所有话题(慎用,数据量大)
ros2 bag record -a -o debug_session
# 只录制关键话题
ros2 bag record \
/camera/image_raw \
/detector/armors \
/detector/binary_img \
/tracker/target \
/serial/receive \
-o debug_session
# 带压缩录制
ros2 bag record \
--compression-mode file \
--compression-format zstd \
/camera/image_raw \
-o debug_compressed
# 回放
ros2 bag play debug_session
# 按倍速回放
ros2 bag play debug_session --rate 0.5
# 循环回放(用于长时间调试)
ros2 bag play debug_session --loop
# 查看 bag 信息
ros2 bag info debug_session
# 只回放特定话题
ros2 bag play debug_session --topics /detector/armors
录制调试数据的最佳实践:
- 问题复现时立即开始录制,保留足够上下文
- 同时录制图像和检测结果,便于离线对比
- 在文件名中注明场景和问题,例如
red_base_shaking_20260715 - 录制前确认磁盘空间充足(原始图像流约 100MB/s)
场景一:灯条检测不到¶
症状¶
/detector/armors话题无数据或数据为空- 结果图像上没有绘制任何装甲板
- 自瞄完全不工作,不发送目标信息
可能原因¶
| 原因 | 可能性 | 快速验证 |
|---|---|---|
binary_thres 设置不当 |
高 | 查看二值化图像 |
| 曝光/增益参数不合适 | 高 | 查看原始图像亮度 |
detect_color 参数错误 |
中 | 检查参数配置 |
| 相机未正常工作 | 中 | 查看原始图像话题 |
| 灯条面积过滤过于严格 | 低 | 查看日志输出 |
排查步骤¶
第一步:确认相机正常
# 检查相机话题是否有数据
ros2 topic hz /camera/image_raw
# 查看原始图像
ros2 run rqt_image_view rqt_image_view
# 在下拉菜单中选择 /camera/image_raw
如果原始图像为全黑或全白,说明相机参数有问题,跳到「相机参数调整」。
第二步:检查二值化结果
- 如果灯条在二值化图像中完全看不到 →
binary_thres太高,降低它 - 如果图像中充满噪点 →
binary_thres太低,提高它 - 如果灯条断断续续 → 曝光不足或阈值处于临界值
第三步:检查参数配置
# 查看当前参数
ros2 param get /armor_detector binary_thres
ros2 param get /armor_detector detect_color
ros2 param get /armor_detector light_min_area
ros2 param get /armor_detector light_max_ratio
# 动态调整参数测试
ros2 param set /armor_detector binary_thres 120
ros2 param set /armor_detector binary_thres 160
ros2 param set /armor_detector binary_thres 200
第四步:检查 detect_color 参数
detect_color 值为 0 表示检测红色,1 表示检测蓝色。如果己方是红方但参数设为 1,系统会检测蓝色灯条,自然找不到目标。
解决方案¶
调参流程:
# 在 config/detector.yaml 中调整
binary_thres: 130 # 从低到高逐步调整,找到灯条清晰且噪点少的值
detect_color: "RED" # 确认与己方颜色匹配
light_min_area: 50 # 降低此值可检测更小的灯条
light_max_ratio: 1.0 # 灯条最大长宽比
light_min_ratio: 3.0 # 灯条最小长宽比(正常灯条约为 5:1)
相机曝光调整:
```bash tab="Linux"
使用 v4l2 工具调整相机参数¶
v4l2-ctl -d /dev/video0 --set-ctrl=exposure_time_absolute=3000 v4l2-ctl -d /dev/video0 --set-ctrl=gain=50
或在相机驱动的参数文件中设置¶
exposure: 3000 # 曝光时间(微秒)¶
gain: 50 # 增益¶
!!! note "macOS 说明"
macOS 没有 v4l2-ctl。工业相机使用厂商 macOS SDK 调整参数。USB 相机可用 `imagesnap`(`brew install imagesnap`)
**调整原则:**
- 曝光时间短 → 灯条更亮更小,适合高速运动
- 曝光时间长 → 灯条更大更连续,但可能运动模糊
- 增益过高 → 噪点增加,二值化困难
### 常见陷阱
- 红色灯条在 OpenCV HSV 空间中跨越 H=0/180 边界,需要特殊处理
- 仓库代码默认的 `detect_color` 可能与当前比赛颜色不同
- 切勿在强光环境下测试,环境光会干扰检测
---
## 场景二:数字识别错误
### 症状
- 装甲板被检测到,但识别出的数字编号错误
- `/detector/armors` 中 `number` 字段值与实际不符
- 自瞄频繁切换目标或跟踪错误目标
### 可能原因
| 原因 | 可能性 | 快速验证 |
|------|--------|---------|
| `classifier_threshold` 过低 | 高 | 查看置信度 |
| 透视变换结果质量差 | 高 | 查看 number_img |
| 模型文件未正确加载 | 中 | 查看启动日志 |
| 灯条配对错误 | 中 | 查看灯条检测结果 |
### 排查步骤
**第一步:查看数字识别输入**
```bash
# 查看透视变换后的数字图像
ros2 run rqt_image_view rqt_image_view
# 选择 /detector/number_img
正常的输入应该是:
- 一个正向的矩形图像,包含清晰的数字
- 数字居中,无明显畸变
- 背景与数字对比度高
如果图像扭曲或包含多余内容,说明透视变换有问题。
第二步:检查置信度
# 查看检测结果中的置信度
ros2 topic echo /detector/armors --field armor.number
ros2 topic echo /detector/armors --field armor.confidence
如果置信度普遍偏低(< 0.7),说明分类器难以判断,可能需要降低 classifier_threshold。
第三步:检查模型加载
# 查看启动日志中是否包含模型加载信息
ros2 launch armor_detector detector.launch.py --ros-args --log-level info 2>&1 | grep -i model
# 检查模型文件是否存在
ls -la /path/to/model/mlp.onnx # 或对应模型路径
第四步:检查灯条配对
解决方案¶
调整分类器阈值:
# 运行时测试不同阈值
ros2 param set /armor_detector classifier_threshold 0.5
ros2 param set /armor_detector classifier_threshold 0.8
确认模型文件:
# 检查模型路径配置
ros2 param get /armor_detector classifier_model
# 确认模型文件完整性
md5sum /path/to/model/mlp.onnx
# 与仓库中记录的 MD5 值对比
重新训练或更换模型:
如果当前场景光照条件与训练数据差异较大,可能需要重新采集数据训练分类器。参考模型训练文档进行。
常见陷阱¶
- 不同版本的模型文件格式可能不同(ONNX/TorchScript),确认驱动加载的是正确格式
debug_mode开启后会显著影响性能,调试完成后记得关闭- 数字 1 和数字 bias 的区分容易出错,注意检查特殊字体
场景三:EKF 发散¶
症状¶
- 跟踪的目标位置在 RViz 中剧烈抖动或飞向远处
/tracker/target中的装甲板位置数值异常大- 弹道计算输出完全不合理
可能原因¶
| 原因 | 可能性 | 快速验证 |
|---|---|---|
sigma2_q_* 过大 |
高 | 查看协方差 |
| 半径约束不匹配 | 高 | 检查参数 |
| 检测噪声突然增大 | 中 | 查看检测轨迹 |
| 时间戳不同步 | 中 | 检查时间戳 |
排查步骤¶
第一步:检查滤波器状态
# 查看跟踪目标
ros2 topic echo /tracker/target
# 重点观察:
# - position.x/y/z 是否在合理范围内(通常 < 10m)
# - velocity 是否合理(通常 < 5m/s)
# - armor_id 是否稳定
第二步:在 RViz 中可视化
正常状态:
- Marker 位置平滑移动
- 协方差椭球大小稳定
- 没有突然跳变
发散状态:
- Marker 飞出视野
- 协方差椭球急剧增大
- 位置在帧间大幅跳变
第三步:检查过程噪声参数
# 查看当前参数
ros2 param get /armor_tracker sigma2_q_x
ros2 param get /armor_tracker sigma2_q_y
ros2 param get /armor_tracker sigma2_q_z
ros2 param get /armor_tracker sigma2_q_yaw
第四步:检查 NIS/NEES 统计
归一化估计误差平方(NEES)是判断滤波器是否一致的关键指标:
# NEES 计算公式(离线分析时使用)
# NEES = (x_true - x_est)^T * P^{-1} * (x_true - x_est)
# 对于一致的滤波器,NEES 的期望值等于状态维度
在 PlotJuggler 中绘制 NIS/NEES:
- 订阅
/tracker/debug话题(如果可用) - 绘制 NIS 值随时间变化
- 如果 NIS 持续大于阈值(自由度的 2-3 倍),说明滤波器不一致
解决方案¶
调整过程噪声:
# config/tracker.yaml
# 过程噪声越大,滤波器越信任观测值(响应快但不稳定)
# 过程噪声越小,滤波器越信任预测值(平滑但响应慢)
# 推荐初始值
sigma2_q_x: 20.0 # 位置 x 方向过程噪声
sigma2_q_y: 20.0 # 位置 y 方向过程噪声
sigma2_q_z: 20.0 # 位置 z 方向过程噪声
sigma2_q_yaw: 100.0 # 偏航角过程噪声(自旋时需要增大)
设置合理的半径约束:
# config/tracker.yaml
# 四灯装甲板外接圆半径约束
min_armor_distance: 0.05 # 最小距离(米)
max_armor_distance: 0.5 # 最大距离(米)
如果目标距离约束范围过远,检查:
- 单位是否为米(不是毫米或像素)
- 是否与实际机器人尺寸匹配
- 不同类型装甲板尺寸不同,约束可能需要放宽
重置滤波器:
# 如果滤波器已经发散,最直接的方式是重启
ros2 lifecycle set /armor_tracker shutdown
ros2 lifecycle set /armor_tracker configure
ros2 lifecycle set /armor_tracker activate
# 或直接重启整个节点
ros2 run armor_tracker tracker_node --ros-args --params-file config/tracker.yaml
常见陷阱¶
- 自旋(小陀螺)时需要大幅增大
sigma2_q_yaw,否则跟踪会滞后 - 如果检测噪声参数(
sigma2_p_*)设置过小,滤波器会过度信任观测值 - EKF 初始化阶段的前几帧可能有较大误差,这是正常的
场景四:弹道偏了¶
症状¶
- 发弹时子弹偏左/偏右/偏上/偏下
- 固定偏差(每次偏移方向和距离一致)
- 随距离增大偏差增大
可能原因¶
| 原因 | 可能性 | 快速验证 |
|---|---|---|
yaw_offset / pitch_offset 错误 |
高 | 检查配置文件 |
| 手眼标定结果不准确 | 高 | 复查标定 |
| 子弹速度参数错误 | 中 | 测量实际初速 |
timestamp_offset 未校准 |
中 | 检查时间同步 |
| 弹道模型不匹配 | 低 | 检查空气阻力参数 |
排查步骤¶
第一步:检查偏移参数
# 查看当前偏移参数
ros2 param get /solver yaw_offset
ros2 param get /solver pitch_offset
# 这两个参数补偿枪管与相机之间的安装偏差
# 单位通常为度(degree)或弧度(radian),注意区分
第二步:静态校准测试
- 将机器人固定,枪口对准一个已知目标
- 让视觉系统识别目标并计算角度
- 对比输出角度与实际需要的角度
第三步:检查手眼标定
第四步:检查子弹速度
# 查看子弹速度参数
ros2 param get /solver bullet_speed
# 用测速仪实测子弹速度
# 17mm 弹丸通常在 25-30 m/s
# 42mm 弹丸通常在 10-15 m/s
第五步:检查时间戳同步
解决方案¶
修正偏移量:
# config/solver.yaml
# 修正流程:固定偏差用 offset 补偿,非固定偏差检查标定
yaw_offset: 0.0 # 正值:弹道右移;负值:弹道左移(根据实际定义)
pitch_offset: 0.0 # 正值:弹道上移;负值:弹道下移
手眼标定流程:
# 1. 拍摄多组标定图像(不同角度、不同距离)
# 2. 运行标定程序
ros2 run calibration hand_eye_calibrator \
--images /path/to/calibration/images \
--output config/hand_eye_calibration.yaml
# 3. 验证标定结果
# 在 RViz 中查看相机坐标系和枪管坐标系是否对齐
校准子弹速度:
# 记录不同距离的实际射击偏差
# 距离 2m:偏差 x1 cm
# 距离 4m:偏差 x2 cm
# 距离 6m:偏差 x3 cm
# 如果偏差随距离线性增大 → 偏移角问题
# 如果偏差随距离非线性增大 → 子弹速度或弹道模型问题
校准时间戳偏移:
# 使用高速相机或示波器测量系统总延迟
# 将延迟值设置到 timestamp_offset
# 运行时微调
ros2 param set /serial timestamp_offset 0.015 # 15ms 延迟示例
常见陷阱¶
- 弧度和度数搞混:
1 度 = 0.01745 弧度,差一个数量级 - 手眼标定需要在实际安装状态下进行,不能拆下标定再装回
- 温度变化会影响枪管形变,需要在比赛场地重新校准
场景五:串口通信失败¶
症状¶
- 主控板收不到视觉数据
/serial/receive话题无数据- 电控端反馈未收到自瞄信息
可能原因¶
| 原因 | 可能性 | 快速验证 |
|---|---|---|
/dev/ttyACM0 权限不足 |
高 | ls -l 检查权限 |
| 波特率不匹配 | 高 | 检查配置 |
| 串口设备路径错误 | 中 | 检查设备文件 |
| CRC 校验失败 | 中 | 抓包分析 |
| USB 线缆松动 | 低 | 物理检查 |
排查步骤¶
第一步:检查串口设备
# 列出可用串口设备
ls -la /dev/ttyACM*
ls -la /dev/ttyUSB*
# 检查设备权限
ls -l /dev/ttyACM0
# 应该有 crw-rw---- 权限,所属组为 dialout
# 查看串口设备信息
udevadm info /dev/ttyACM0
# macOS 替代:system_profiler SPUSBDataType 或 ioreg -p IOUSB -l
# 查看 USB 设备列表
lsusb
# macOS 替代:system_profiler SPUSBDataType
第二步:检查权限
# 检查当前用户是否在 dialout 组中
groups $USER
# 如果不在,添加到组
sudo usermod -aG dialout $USER
# 需要重新登录才能生效
# 临时方案(不推荐用于生产环境)
sudo chmod 666 /dev/ttyACM0
第三步:检查串口配置
# 查看串口当前配置
stty -F /dev/ttyACM0 -a
# macOS 使用 stty -f 而非 -F
# 检查波特率是否匹配
ros2 param get /serial_device port_name
ros2 param get /serial_device baud_rate
# 常见波特率:9600, 115200, 921600
# 确认与电控端一致
第四步:用 minicom 手动测试
```bash tab="Linux"
安装 minicom¶
sudo apt install minicom
打开串口(Ctrl+A 然后 Z 查看帮助,Ctrl+A 然后 X 退出)¶
minicom -D /dev/ttyACM0 -b 115200
发送测试数据,观察是否有回复¶
```bash tab="macOS"
# 安装 minicom
brew install minicom
# 打开串口(Ctrl+A 然后 Z 查看帮助,Ctrl+A 然后 X 退出)
minicom -D /dev/cu.usbmodem* -b 115200
# 或使用 screen:screen /dev/cu.usbmodem* 115200
第五步:检查 CRC 校验
# 在串口节点中开启调试日志
ros2 param set /serial_device debug true
# 查看日志中的 CRC 错误
ros2 run serial_driver serial_node --ros-args --log-level debug 2>&1 | grep -i crc
# 如果频繁出现 CRC 错误:
# 1. 降低波特率测试
# 2. 更换 USB 线缆
# 3. 检查信号线是否有干扰
解决方案¶
创建 udev 规则(推荐):
仅适用于工控机 Linux
macOS 无 udev 机制,设备权限由系统自动管理。
# 创建规则文件
sudo nano /etc/udev/rules.d/99-serial.rules
# 添加内容(替换为实际的 VID:PID)
SUBSYSTEM=="tty", ATTRS{idVendor}=="1234", ATTRS{idProduct}=="5678", MODE="0666", GROUP="dialout"
# 重新加载规则
sudo udevadm control --reload-rules
sudo udevadm trigger
串口参数配置:
# config/serial.yaml
port_name: "/dev/ttyACM0"
baud_rate: 115200 # 确认与电控端一致
flow_control: false
parity: false
stop_bits: 1
CRC 校验排查脚本:
#!/usr/bin/env python3
"""串口数据包解析和 CRC 校验工具"""
import struct
import binascii
def verify_crc(data: bytes) -> bool:
"""验证数据包 CRC16 校验"""
if len(data) < 4:
return False
payload = data[:-2]
received_crc = struct.unpack('<H', data[-2:])[0]
calculated_crc = binascii.crc_hqx(payload, 0xFFFF)
return received_crc == calculated_crc
# 使用方式:将抓取的原始数据粘贴到这里验证
# sample = bytes.fromhex("AA 55 ...")
# print(verify_crc(sample))
常见陷阱¶
ttyACM0和ttyUSB0是不同类型的设备,确认使用正确的设备路径- USB Hub 可能引入额外延迟,尽量直连主板 USB 口
- 拔插 USB 后设备号可能变化(ACM0 → ACM1),建议用 udev 规则固定
场景六:TF2 变换失败¶
症状¶
- RViz 中坐标系显示警告(红色)
- 日志中出现
Lookup would require extrapolation into the past/future - 目标位置在不同坐标系间转换时出错
- 弹道计算使用了错误的参考坐标系
可能原因¶
| 原因 | 可能性 | 快速验证 |
|---|---|---|
timestamp_offset 不正确 |
高 | 查看 TF 时间差 |
| URDF 未正确加载 | 高 | 查看 TF 树 |
| TF 发布频率过低 | 中 | 检查频率 |
| 坐标系名称不匹配 | 中 | 对比配置 |
排查步骤¶
第一步:查看 TF 树
# 生成 TF 树可视化
ros2 run tf2_tools view_frames
# 输出 frames.pdf,用浏览器或 PDF 阅读器打开
# 检查:
# 1. 所有预期的坐标系是否出现
# 2. 父子关系是否正确
# 3. 是否有孤立的坐标系
第二步:检查特定变换
# 查询两个坐标系之间的变换
ros2 run tf2_ros tf2_echo base_link gimbal_link
# 输出示例:
# Translation: [0.0, 0.0, 0.15]
# Rotation: [0.0, 0.0, 0.0, 1.0]
# 检查数值是否合理
第三步:检查时间戳问题
# 查看 TF 数据的时间戳
ros2 topic echo /tf --once
# 比较 TF 时间戳与相机图像时间戳
ros2 topic echo /camera/image_raw --once --field header.stamp
# 时间差过大说明 timestamp_offset 需要调整
第四步:检查 URDF
# 查看机器人描述是否正确加载
ros2 param get /robot_state_publisher robot_description
# 在 RViz 中添加 RobotModel 显示
# Display Type: RobotModel
# Description Topic: /robot_description
# 如果模型不显示,说明 URDF 加载失败
解决方案¶
修正 timestamp_offset:
# config/serial.yaml 或 config/tracker.yaml
# timestamp_offset 补偿不同设备之间的时间偏差
# 正值表示将时间戳向后推移
timestamp_offset: 0.0 # 单位:秒
URDF 加载检查清单:
<!-- 确认 URDF 中的坐标系名称与代码中一致 -->
<joint name="gimbal_joint" type="revolute">
<parent link="base_link"/>
<child link="gimbal_link"/>
<origin xyz="0 0 0.15" rpy="0 0 0"/>
</joint>
修复 TF 超时:
# 如果使用 lookupTransform,增加超时时间
transform = tf_buffer.lookup_transform(
'base_link',
'gimbal_link',
rclpy.time.Time(),
timeout=rclpy.duration.Duration(seconds=1.0) # 增加超时
)
常见陷阱¶
rclpy.time.Time()表示最新可用时间,不是当前时间- 静态变换用
static_transform_publisher,不要用动态 TF 代替 - 坐标系名称大小写敏感,
base_link和Base_Link是不同的
场景七:性能优化¶
症状¶
- 检测频率低于预期(< 100Hz)
- 处理延迟过大(> 20ms)
- CPU 占用率过高
- 图像帧丢失
可能原因¶
| 原因 | 可能性 | 快速验证 |
|---|---|---|
| 使用独立进程而非 Component | 高 | 查看进程列表 |
| QoS 设置不匹配 | 中 | 检查 QoS 配置 |
| 图像格式转换开销 | 中 | 查看编码格式 |
| 调试模式开启 | 中 | 检查 debug 参数 |
| CPU 调度策略 | 低 | 查看进程优先级 |
排查步骤¶
第一步:测量各节点延迟
# 查看话题发布频率
ros2 topic hz /camera/image_raw
ros2 topic hz /detector/armors
ros2 topic hz /tracker/target
# 查看消息时间戳差值
ros2 topic delay /detector/armors
# 输出各帧的延迟统计
第二步:检查进程组成
# 查看是否使用 Component Container(推荐)
ps aux | grep component_container
# 如果每个节点都是独立进程,会有多个进程
ps aux | grep armor
第三步:检查 CPU 占用
```bash tab="Linux"
使用 perf 分析热点函数¶
perf top -p $(pgrep component_container)
```bash tab="macOS"
# macOS 使用 Xcode Instruments
xctrace record --template 'Time Profiler' --attach-pid $(pgrep component_container)
第四步:检查 QoS 配置
解决方案¶
使用 Component Container(关键优化):
# 不推荐:多个独立进程
ros2 run armor_detector detector_node
ros2 run armor_tracker tracker_node
ros2 run serial_driver serial_node
# 每个进程独立运行,进程间通信开销大
# 推荐:单进程 Component Container
ros2 launch bringup bringup.launch.py
# 所有组件在同一进程内,使用进程内通信,延迟降低 50%+
launch 文件配置示例:
# launch/bringup.launch.py
from launch import LaunchDescription
from launch_ros.actions import ComposableNodeContainer
from launch_ros.descriptions import ComposableNode
def generate_launch_description():
container = ComposableNodeContainer(
name='vision_container',
namespace='',
package='rclcpp_components',
executable='component_container',
composable_node_descriptions=[
ComposableNode(
package='armor_detector',
plugin='rm_vision::DetectorNode',
name='armor_detector',
parameters=['config/detector.yaml'],
),
ComposableNode(
package='armor_tracker',
plugin='rm_vision::TrackerNode',
name='armor_tracker',
parameters=['config/tracker.yaml'],
),
ComposableNode(
package='serial_driver',
plugin='rm_vision::SerialNode',
name='serial_device',
parameters=['config/serial.yaml'],
),
],
output='screen',
)
return LaunchDescription([container])
QoS 优化:
# 对于实时性要求高的传感器数据
sensor_qos:
reliability: BEST_EFFORT # 不重传,减少延迟
durability: VOLATILE # 不缓存历史消息
depth: 1 # 队列深度最小
deadline: 10ms # 超时警告阈值
# 对于关键控制指令
control_qos:
reliability: RELIABLE # 确保送达
durability: VOLATILE
depth: 10
图像处理优化:
# 使用硬件加速的图像编码
# 避免不必要的格式转换
# 原始图像使用 mono8/bgr8,避免 jpeg/png 编解码
# 如果使用 USB 相机,考虑 MJPEG 格式减少 USB 带宽
v4l2-ctl -d /dev/video0 --set-fmt-video=pixformat=MJPEG,width=640,height=480
CPU 调度优化:
# 给视觉进程设置实时调度策略(需要 root)
sudo chrt -f 50 ros2 run component_container
# macOS 不支持实时调度。可用 sudo renice -20 -p PID 调整优先级
# 或在代码中设置
# struct sched_param param;
# param.sched_priority = 50;
# sched_setscheduler(0, SCHED_FIFO, ¶m);
# CPU 亲和性绑定(绑定到大核)
taskset -c 4-7 ros2 run component_container
# macOS 无 taskset。CPU 亲和性控制有限。
性能基准参考¶
| 指标 | 目标值 | 可接受值 | 需优化 |
|---|---|---|---|
| 检测频率 | > 200 Hz | 100-200 Hz | < 100 Hz |
| 端到端延迟 | < 10 ms | 10-20 ms | > 20 ms |
| CPU 占用率 | < 50% | 50-70% | > 70% |
| 丢帧率 | 0% | < 1% | > 1% |
快速排查清单¶
遇到问题时,按以下顺序排查效率最高:
# 1. 检查系统状态
ros2 node list # 所有节点是否在运行
ros2 topic list # 所有话题是否在发布
# 2. 检查核心话题
ros2 topic hz /camera/image_raw # 相机是否正常出图
ros2 topic echo /detector/armors --once # 检测器是否输出
ros2 topic echo /tracker/target --once # 跟踪器是否输出
# 3. 检查关键参数
ros2 param dump /armor_detector # 导出检测器全部参数
ros2 param dump /armor_tracker # 导出跟踪器全部参数
# 4. 检查日志
ros2 log list # 查看日志文件位置
# 或在终端输出中查看 ERROR/WARNING 级别日志
调试工作流模板¶
测试新参数¶
# 1. 记录当前参数
ros2 param dump /armor_detector > backup_detector_params.yaml
# 2. 录制测试数据
ros2 bag record /camera/image_raw /detector/armors /detector/binary_img -o test_before
# 3. 修改参数
ros2 param set /armor_detector binary_thres 150
# 4. 录制修改后数据
ros2 bag record /camera/image_raw /detector/armors /detector/binary_img -o test_after
# 5. 对比分析
ros2 bag play test_before &
ros2 run rqt_image_view rqt_image_view # 对比 /detector/binary_img
远程调试(SSH)¶
# 在机器人端启动
export ROS_DOMAIN_ID=0
ros2 launch bringup bringup.launch.py
# 在远程电脑上连接
export ROS_DOMAIN_ID=0
# 现在可以使用所有 ros2 命令远程监控
ros2 topic list
ros2 node list
ros2 topic echo /detector/armors
# 图像传输占用带宽较大,建议:
# 1. 使用有线网络(千兆网口)
# 2. 只在需要时 echo 图像话题
# 3. 或者使用 rqt_image_view 的低带宽模式
复现比赛问题¶
# 比赛中遇到问题时,立即录制
ros2 bag record -a -o match_issue_$(date +%Y%m%d_%H%M%S)
# 回到调试环境后回放
ros2 bag play match_issue_20260715_143022
# 结合 RViz 和 PlotJuggler 分析问题根因
日志分析技巧¶
日志级别设置¶
# 命令行设置
ros2 run armor_detector detector_node --ros-args --log-level debug
# launch 文件中设置
# Node(
# ...,
# arguments=['--ros-args', '--log-level', 'debug'],
# )
# 运行时动态修改(需要节点支持)
ros2 service call /armor_detector/set_logger_level rcl_interfaces/srv/SetLoggerLevels \
"{levels: [{name: 'rm_vision', level: 'DEBUG'}]}"
日志级别说明¶
| 级别 | 用途 | 生产环境 |
|---|---|---|
FATAL |
不可恢复的错误 | 保留 |
ERROR |
功能异常但可继续 | 保留 |
WARN |
潜在问题警告 | 保留 |
INFO |
关键状态信息 | 保留 |
DEBUG |
调试详细信息 | 关闭 |
TRACE |
最细粒度追踪 | 关闭 |
关键日志关键词¶
# 监控错误
ros2 run armor_detector detector_node 2>&1 | grep -E "ERROR|WARN|exception|failed"
# 监控检测统计
ros2 run armor_detector detector_node 2>&1 | grep -i "detected\|lost\|track"
# 监控串口通信
ros2 run serial_driver serial_node 2>&1 | grep -i "send\|receive\|crc\|timeout"
硬件检查清单¶
当软件排查无果时,检查硬件:
- USB 线缆连接是否牢固
- 相机镜头是否清洁(是否有灰尘、指纹)
- 灯条是否正常亮起
- 电源电压是否稳定(USB 供电不足会导致相机丢帧)
- 散热是否良好(过热会导致 CPU 降频,影响实时性)
- 网线连接(远程调试时)
附录:常用调试命令速查表¶
# === 节点管理 ===
ros2 node list # 列出所有节点
ros2 node info /armor_detector # 查看节点详细信息
ros2 lifecycle nodes # 查看生命周期节点状态
# === 话题调试 ===
ros2 topic list # 列出所有话题
ros2 topic list -t # 列出话题及其类型
ros2 topic echo /detector/armors # 打印话题消息
ros2 topic hz /camera/image_raw # 测量发布频率
ros2 topic delay /detector/armors # 测量消息延迟
ros2 topic info /detector/armors --verbose # 查看话题详情
# === 参数操作 ===
ros2 param list /armor_detector # 列出节点参数
ros2 param get /armor_detector binary_thres # 获取参数值
ros2 param set /armor_detector binary_thres 150 # 设置参数值
ros2 param dump /armor_detector # 导出全部参数
# === TF 调试 ===
ros2 run tf2_tools view_frames # 生成 TF 树 PDF
ros2 run tf2_ros tf2_echo base_link gimbal_link # 查看特定变换
ros2 run tf2_ros tf2_monitor # 监控 TF 更新频率
# === 性能分析 ===
ros2 topic bw /camera/image_raw # 测量话题带宽
ros2 doctor # 系统健康检查
top -p $(pgrep component_container) # CPU 占用
# === 日志查看 ===
ros2 log list # 列出日志文件
cat /root/.ros/log/latest/*.log # 查看最新日志
# macOS 日志路径:~/.ros/log/latest/(不在 /root/ 下)
# === Bag 操作 ===
ros2 bag record -o session /topic1 /topic2 # 录制指定话题
ros2 bag play session # 回放
ros2 bag info session # 查看 bag 信息