Skip to content

Debugging

konodoki edited this page Jul 23, 2026 · 26 revisions

调试、验证与常见问题

本页按症状排查遥控器、状态机、过渡、driver 和发布保护问题。

1. 编译

常用编译:

colcon build --packages-select remote_controller bxi_example_py_elf3

加载环境:

source install/setup.bash

如果只改 wiki,不需要编译。

如果正在调试热重载,不建议使用 --symlink-install。普通 build 会在代码修改完成后更新 install/ 目录并触发一次热重载;--symlink-install 可能因为编辑器自动保存而频繁触发热重载。

2. 单独看遥控器输出

手柄:

ros2 launch remote_controller remote_controller.launch.py

键盘:

ros2 launch remote_controller remote_controller_keyboard.launch.py

观察:

ros2 topic echo /motion_commands

publish_on_change: true 时,只有 payload 变化才会发布。调试时可以临时改:

outputs:
  publish_on_change: false

3. 看状态机信息

ros2 topic echo /simulation/state_machine_info

会看到:

  • 当前状态名和 id。
  • 是否正在 transition。
  • transition 的 from / to / progress。
  • pending transition。
  • 本周期收到的 events。
  • 当前速度命令。
  • 状态图快照。

如果用了不同 topic_prefix,话题是:

<topic_prefix>state_machine_info

4. 看状态图

默认配置会导出:

/tmp/elf3_state_machine.dot
/tmp/elf3_state_machine.mmd

Mermaid 文件可以贴到支持 Mermaid 的 Markdown 查看器。

5. 按键没反应

按顺序查:

  1. sources.*.signals 是否声明 source。
  2. controls 是否引用这个 source。
  3. outputs.edge / outputs.levelwhen 是否引用 control 名。
  4. /motion_commands 中对应 btn_N 是否变化。
  5. elf3_state_machine.yamlremote_events 是否匹配 slot/value
  6. 当前状态的 transitions.on_event 是否监听该 event。
  7. /simulation/state_machine_infoevents 是否出现目标 event。

6. 状态类找不到

检查:

  • 类是否继承 RobotControlState
  • 类是否直接写在 robot_states.py 里,或者已被 robot_states.py 导入。
  • YAML 里的 behavior 是否和类名完全一致。

7. 状态切换了但动作没执行

检查:

  • on_update() 是否调用 ctx.set_motor_target()
  • timer_callback() 中是否有 motor_target
  • 状态是否处于 transition 中。活动过渡期间不调用当前状态 on_update();过渡输出由 TransitionSession 负责。
  • 是否刚进入状态就被安全逻辑切到其他状态。

8. 切换时机器人突然软掉

检查:

  • transition profile 的 type 是否正确。
  • entry_gain_ramp 的目标状态是否实现 EntryFrameProvider.get_entry_frame()
  • kp_from / kd_from 是否是预期的 currentzerotarget
  • kp/kd 数组 shape 是否和 dof 数一致。

9. running_blend 没有运行混合效果

检查:

  • sample_from / sample_to 配置,相关状态是否实现 RunningFrameProvider
  • 目标状态是否实现 EntryFrameProvider
  • sample_running_frame() 是否返回 MotorFrame,且没有直接调用 ctx.set_motor_target()
  • advance_from / advance_to 是否符合预期。
  • 源侧返回 None 时会保持开始前最后电机帧;目标侧返回 None 时会使用目标进入帧。

10. publish_on_change 下机器人突然停

正常设计里,publish_on_change: true 只是减少重复发布,不应该导致机器人因为输入没变而停下。

排查:

  • BxiExample 是否保持上一次收到的原始速度到 raw_cmd_vel / current_raw_cmd_vel
  • 当前状态是否调用了 self.get_cmd_vel(ctx);基类会把处理后的速度写入 current_cmd_vel
  • 当前状态是否配置了 speed_profile;没有 profile 时默认返回零速度。
  • driver 的 is_available() 是否错误返回 false,导致设备切换。
  • 当前活动设备是否还在 ready_timeout_ms 内等待 is_ready()
  • 流式协议的字段 timeout_ms 是否过小。

11. 摇杆静止或流式字段超时

Linux joystick 默认不配置 timeout_ms;摇杆静止没有事件是正常的,不应被判定为断连。

如果 UDP/TCP 的某个字段被写成 failsafe,检查该字段是否确实需要独立过期保护:

字段可能独立停止更新
  -> 可以配置 timeout_ms / failsafe

设备或协议整体断连
  -> 由 driver is_available() + loss_timeout_ms 处理

CRSF 应按最近一次 CRC 正确完整帧判断 is_available(),而不是靠每通道 timeout_ms

12. Ctrl+C 无法退出遥控器节点

driver 不能永久阻塞在 read()

检查:

  • fd 是否非阻塞。
  • 是否用 select() / poll() 带超时等待。
  • 循环里是否定期检查 stop_flag_
  • stop() 是否能关闭 fd 或打断阻塞。

13. 多个输出写同一个 btn

检查:

outputs:
  conflict_policy: first_wins

可选值:

  • first_wins:先匹配的生效。
  • last_wins:后匹配的生效。
  • error:冲突时报错。

调试阶段可以用 error 尽早发现配置冲突。

14. release 脚本删多了或没删干净

检查:

  • release_protection.yamlprotected_states.<state> 是否和状态名一致。
  • behavior 是否包含所有需要删除的类。
  • 要删除的模型文件是否都显式写在 files 中。
  • model_keys 是否和 self.<model_key> 一致。
  • files 相对路径是否按 manifest 所在目录解析。

运行:

python3 tools/sanitize_release.py \
  --manifest src/bxi_example_py_elf3/config/release_protection.yaml \
  --out dist/public_release \
  --self-check

手动扫残留:

rg "BackFlipState|ForwardFlipState|back_flip|forward_flip" dist/public_release

15. 热重载没有生效或有明显延迟

先确认热重载是否开启:

  • 仿真 example_demo.launch.py 默认 "/hot_reload": True
  • 硬件 example_demo_hw.launch.py 支持热重载,但默认 "/hot_reload": False
  • 真机上临时开启前先在仿真验证,并确认机器人处于安全姿态。

检查改动位置:

  • 换模型路径:改 bxi_example_demo.pyload_models()
  • 覆盖模型文件:确认 .onnx / .npz 是当前 load_models() 正在引用的文件。
  • 改状态类:改 robot_states.py
  • 改状态机结构:改 elf3_state_machine.yaml
  • 改遥控器映射:改 remote_controller/config/xbox_default.yaml
  • 改 launch 参数:需要重启 launch,不能靠热重载。

推荐触发方式:

  • 不使用 --symlink-install
  • 修改 src/ 下代码或模型。
  • 修改完成后执行对应 package 的 colcon build --packages-select ...
  • build 更新 install/ 目录后,运行中的 demo 节点或 remote_controller 会看到文件变化并触发热重载。

如果使用了 --symlink-install

  • 编辑器自动保存可能导致还没改完就触发热重载。
  • 保存多次会触发多次重载。
  • 真机上尤其不建议这样调试。

如果看到 actuator delay:

  • 模型加载已放到后台线程,正常情况下控制循环只做最终替换。
  • robot_states.pyelf3_state_machine.yaml 的结构热重载仍是同步提交,真机上不要在高风险动作中修改。
  • 新模型很大时可能仍有 CPU/内存带宽竞争,先在仿真观察日志和控制周期。

更多说明看 热重载

16. 最小验证 checklist

新增状态后:

1. colcon build 通过。
2. /motion_commands 能看到目标 btn_N/value。
3. /simulation/state_machine_info 的 events 出现目标 event。
4. current.name 切到新状态。
5. transition 信息符合预期。
6. 新状态 on_update 输出电机目标。

新增 driver 后:

1. driver factory 已在 InputDeviceManager 创建前注册。
2. 候选设备可用、启动、ready、断连和切换都有明确日志。
3. Ctrl+C 能退出。
4. 高优先级设备稳定后会抢占;切换前会发布一次零运动命令。
5. 设备断联会在 loss_timeout_ms 后安全回退。
6. 切换后 edge 命令必须释放再按,不会误触发。
7. /motion_commands 输出符合 YAML 配置。

Clone this wiki locally