-
Notifications
You must be signed in to change notification settings - Fork 12
Architecture
konodoki edited this page Jul 23, 2026
·
21 revisions
这套代码的核心目标是把遥控器、状态机和机器人动作解耦。新增动作时,业务层只关心“当前状态该执行什么”;状态之间怎么切、由哪个按键触发、切换时怎么过渡,都交给配置和状态机。
手柄 / 键盘 / 自定义遥控器
-> InputDeviceManager(可用性、优先级、切换保护)
-> 唯一活动的 InputDriver
-> raw source
-> sources
-> controls
-> outputs
-> MotionCommands
-> remote_events
-> RobotStateMachine
-> RobotControlState 子类
-> ctx.set_motor_target(qpos, kp, kd)
-> ActuatorCmds
每一层的含义:
-
InputDeviceManager:按 YAML 优先级选择唯一活动设备,处理探测、抢占、断连、冷却和安全切换。 -
InputDriver:读取具体设备或协议,把输入归一化成 raw source;每个 driver 自己定义可用性和就绪状态。 -
raw source:最底层输入名,例如js.axis.3、js.button.0、crsf.ch1。 -
sources:把 raw source 命名成业务可读 source,例如gamepad.left_y。 -
controls:把多个设备的输入混合成统一控制量,例如move.vx、button.south。 -
outputs:把 controls 写入MotionCommands字段,或触发system.*命令。 -
remote_events:把MotionCommands.btn_N/value转成状态机事件名。 -
RobotStateMachine:管理当前状态、事件触发、延迟触发、自动触发、过渡态。 -
RobotControlState:具体状态类,真正执行当前状态的机器人控制逻辑。
遥控器相关:
src/remote_controller/config/xbox_default.yaml
src/remote_controller/include/remote_controller/config.hpp
src/remote_controller/include/remote_controller/input_device_manager.hpp
src/remote_controller/include/remote_controller/drivers/input_driver.hpp
src/remote_controller/include/remote_controller/drivers/driver_registry.hpp
src/remote_controller/include/remote_controller/input_mapper.hpp
src/remote_controller/include/remote_controller/motion_commands_adapter.hpp
src/remote_controller/src/config.cpp
src/remote_controller/src/input_device_manager.cpp
src/remote_controller/src/drivers/driver_registry.cpp
src/remote_controller/src/drivers/input_driver_base.cpp
src/remote_controller/src/drivers/joystick_input_driver.cpp
src/remote_controller/src/drivers/keyboard_input_driver.cpp
src/remote_controller/src/input_mapper.cpp
src/remote_controller/src/main.cpp
src/remote_controller/src/motion_commands_adapter.cpp
状态机和机器人状态相关:
src/bxi_example_py_elf3/config/elf3_state_machine.yaml
src/bxi_example_py_elf3/bxi_example_py_elf3/utils/state_machine.py
src/bxi_example_py_elf3/bxi_example_py_elf3/utils/robot_state_base.py
src/bxi_example_py_elf3/bxi_example_py_elf3/utils/robot_state_builder.py
src/bxi_example_py_elf3/bxi_example_py_elf3/utils/transition_core.py
src/bxi_example_py_elf3/bxi_example_py_elf3/utils/hot_reload.py
src/bxi_example_py_elf3/bxi_example_py_elf3/transitions/*.py
src/bxi_example_py_elf3/bxi_example_py_elf3/robot_states.py
src/bxi_example_py_elf3/bxi_example_py_elf3/bxi_example_demo.py
发布保护相关:
src/bxi_example_py_elf3/config/release_protection.yaml
tools/sanitize_release.py
tools/README.md
.github/workflows/sync_public_main.yml
| 名称 | 所在层 | 示例 | 作用 |
|---|---|---|---|
| raw source | driver 输出 | js.axis.3 |
物理输入的标准化名字 |
| semantic source | sources |
gamepad.left_y |
给 raw source 起业务可读名 |
| control | controls |
move.vx |
多输入混合后的统一控制量 |
| output | outputs |
btn_10=5 |
写入 MotionCommands 或触发系统命令 |
| remote event | remote_events |
sin_wave |
状态机事件名 |
| state | states |
normal |
状态机当前业务状态 |
| behavior | Python 类 | NormalState |
状态对应执行代码 |
| transition profile | transition_profiles |
first_frame_switch |
状态切换过渡方式 |
| speed profile | speed_profiles |
normal_run |
状态通过 get_cmd_vel() 使用的速度缩放 |
| action | state 或全局 handler | toggle_dance_pause |
不切状态,只执行动作 |
communication/msg/MotionCommands 是底层兼容消息。它适合保持稳定,不适合为每个业务动作新增字段。
新增动作推荐流程:
遥控器 YAML 输出 btn_N=value
-> 状态机 YAML remote_events 声明 event
-> states.*.transitions 监听 event
-> Python State 类执行动作
这样以后遥控器、键盘、CRSF、SBUS 都可以复用同一套状态机事件。
新增状态:
- 在已加载的
robot_states.py中添加一个状态类。 - 改
elf3_state_machine.yaml。 - 改
xbox_default.yaml绑定按键。 - 状态需要自己订阅话题时,实现
on_bind(ctx),不要把 ROS 订阅放进__init__()。 - 状态需要速度输入时,在状态类里调用
self.get_cmd_vel(ctx),不要直接读遥控器消息。
新增过渡行为:
- 在
bxi_example_py_elf3/transitions/添加一个SingleClassTransition子类文件。 - 通过唯一
type_name自动发现,无需修改注册表。 - 多插件共享的能力协议放
utils/transition_core.py。 - 单插件专属能力协议和插件放在同一文件,只让相关状态实现。
- 不要把插件专用字段加入状态机核心或状态基类。
框架辅助代码:
- 状态自动发现和实例化在
utils/robot_state_builder.py。 - 热重载实现放在
utils/hot_reload.py,bxi_example_demo.py里只保留模型声明和业务流程。
新增遥控器:
- 先尝试只改
xbox_default.yaml。 - 如果必须读取新设备或新协议,再在
src/remote_controller/src/drivers/新增一个InputDriverBase子类。 - 新 driver 实现非阻塞
is_available()和“初始状态安全可用”的is_ready(),并在driver_registry注册工厂。 - 新 driver 只写 raw source,不写业务动作名;设备优先级、超时和路径写在 YAML 的
sources.<name>。
底层消息结构变化:
- 优先改
motion_commands_adapter.hpp/cpp。 - 避免在业务代码里直接散落字段路径适配逻辑。
- 配遥控器输入:看 遥控器 YAML 配置。
- 配状态机:看 状态机 YAML 配置。
- 写新状态:看 手把手添加自定义状态。
- 接新遥控器:看 手把手添加自定义遥控器驱动。