跳转至

调试指南:常见问题排查

本指南汇总 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 可视化技巧

# 启动 RViz2
rviz2

# 通过 launch 文件加载预设配置
ros2 launch armor_detector detector.launch.py rviz:=true

常用显示类型配置:

话题 显示类型 用途
/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

```bash tab="macOS"
# 安装
brew install --cask plotjuggler

# 启动
ros2 run plotjuggler plotjuggler

推荐监控的变量:

  • /tracker/armors 中的位置 x/y/z — 检查跟踪轨迹是否平滑
  • /detector/armors 中的数量 — 检查检测稳定性
  • 各节点的发布频率 — 检查是否丢帧
  • EKF 的状态协方差 — 检查滤波器是否收敛

使用步骤:

  1. 启动 PlotJuggler,选择 ROS2 Topic Streaming
  2. 勾选要监控的话题
  3. 将字段拖拽到绘图区域
  4. 使用时间轴缩放和平移查看细节
  5. 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

如果原始图像为全黑或全白,说明相机参数有问题,跳到「相机参数调整」。

第二步:检查二值化结果

# 查看二值化图像
ros2 run rqt_image_view rqt_image_view
# 选择 /detector/binary_img
  • 如果灯条在二值化图像中完全看不到 → 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 参数

# 确认目标颜色设置
ros2 param get /armor_detector 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 debug_mode true
# 查看 result_img 中灯条配对线是否正确

解决方案

调整分类器阈值:

# config/detector.yaml
classifier_threshold: 0.7  # 默认 0.7,适当降低可减少漏检但可能增加误检
# 运行时测试不同阈值
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 中可视化

# 添加 MarkerArray 显示
# Display Type: MarkerArray
# Topic: /tracker/marker

正常状态:

  • 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:

  1. 订阅 /tracker/debug 话题(如果可用)
  2. 绘制 NIS 值随时间变化
  3. 如果 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),注意区分

第二步:静态校准测试

  1. 将机器人固定,枪口对准一个已知目标
  2. 让视觉系统识别目标并计算角度
  3. 对比输出角度与实际需要的角度
# 记录输出
ros2 topic echo /solver/fire_command
# 对比 yaw/pitch 值与实际瞄准偏差

第三步:检查手眼标定

# 查看手眼标定结果文件
cat config/hand_eye_calibration.yaml

# 确认变换矩阵合理
# 旋转矩阵应接近单位矩阵(偏差通常 < 10 度)
# 平移向量单位应为米

第四步:检查子弹速度

# 查看子弹速度参数
ros2 param get /solver bullet_speed

# 用测速仪实测子弹速度
# 17mm 弹丸通常在 25-30 m/s
# 42mm 弹丸通常在 10-15 m/s

第五步:检查时间戳同步

# 查看当前 timestamp_offset
ros2 param get /serial timestamp_offset

# 时间戳偏差会导致运动补偿方向错误
# 特别是目标高速运动时影响显著

解决方案

修正偏移量:

# 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))

常见陷阱

  • ttyACM0ttyUSB0 是不同类型的设备,确认使用正确的设备路径
  • 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>
# 验证 URDF 语法
check_urdf robot.urdf

# 可视化 URDF
urdf_to_graphiz robot.urdf
# 生成的 PDF 展示关节树结构

修复 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_linkBase_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 占用

# 查看各进程 CPU 占用
top -p $(pgrep -d',' component_container)

# 或使用 htop(更友好)
htop

```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 配置

# 查看话题的 QoS 设置
ros2 topic info /camera/image_raw --verbose
# 关注 Reliability 和 Durability 策略

解决方案

使用 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, &param);

# 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 信息