Skip to content

Architecture

konodoki edited this page Jul 28, 2026 · 21 revisions

架构总览

当前架构把平台适配、控制框架、动作实现和模型资产分层。BxiExample 只处理 ROS 和硬件边界;RobotControlFramework 拥有 Mod、状态、Transition、Context 和状态机。状态侧的部署单元是 Mod,不再依赖中央状态类文件。

当前 bxi_example_demo.py 是 ELF3 的一个平台适配实现,不是框架本体。需要接入其他 机器人消息、SDK 或硬件总线时,请按机器人平台适配指南 实现新的 ControlPlatformAdapter,不要把硬件差异写进状态机或策略公共运行时。

总数据流

手柄 / 键盘 / CRSF / 自定义设备
  -> InputDeviceManager
  -> InputDriver
  -> sources -> controls -> outputs
  -> communication/msg/MotionCommands
  -> BxiExample 的 ROS subscription
  -> BxiExample 采集 RobotObservation 并排队 raw events
  -> RobotControlRuntime 的独立控制线程
       -> BxiExample.snapshot_control_inputs()
       -> RobotControlFramework 内的 RemoteEventAdapter / RobotStateMachine
       -> Transition / RobotControlState
       -> MotorFrame
       -> BxiExample.publish_motor_frame()
  -> BxiExample 将 MotorFrame 转换为 ActuatorCmds
  -> 机器人硬件

这条边界的核心约定很简单:平台每周期给框架一份完整观测和事件,框架返回最终电机帧。框架不创建硬件消息,不发布电机话题,也不负责机器人 reset。因此更换消息类型、总线或硬件平台时,状态图和 Mod 不需要跟着改。

当 route 要求切换状态时,RobotStateMachine 会在源状态和目标状态之间执行 Transition。它负责切换期间的电机帧,避免两边 qpos/kp/kd 不连续时直接换帧产生突跳;完成后目标 RobotControlState 才接管正常更新。

配置和代码的加载流:

elf3_state_machine.yaml(系统配置)
  + 内置 mods/
  + mod_paths 中的客户 Mod
  -> 发现 mod.yaml
  -> 校验依赖并排序
  -> 加载 entrypoint
  -> 注册 eager/lazy 资源、状态工厂和 Python 节点
  -> 合成 states/events/routes/actions/nodes/profiles
  -> 构建 RobotStateMachine
  -> 按 Mod/State 生命周期管理节点

文件分层

src/remote_controller/
  config/xbox_default.yaml
  include/remote_controller/
  src/

src/bxi_example_py_elf3/
  config/elf3_state_machine.yaml       # 系统级配置
  mods/
    com.bxi.basic_actions/
      mod.yaml                         # 状态图贡献
      plugin.py                        # 工厂和资源注册
      *_state.py                       # 状态实现
      assets/                          # 该 Mod 私有资产
    com.bxi.back_flip/
    com.bxi.forward_flip/
    com.bxi.ballet/
  bxi_example_py_elf3/
    bxi_example_demo.py               # ROS/硬件适配层
    mod_api/                          # 面向 Mod 作者的稳定公共 API
      context.py
      frame.py
      state.py
      states.py
      resource.py
      mod.py
      transition.py
      geometry.py
    _runtime/
      control_runtime.py             # 平台接口、调度和运行时生命周期
      controller.py                  # Mod、状态机和每周期控制计算
      ...                            # 加载、合成、状态机和注册表
    inference/                         # 后端无关的策略、模型运行时与性能工具
    transitions/                       # 内置过渡类型

运行时对象

对象 责任
RobotControlRuntime 持有控制调度器、Framework、维护线程和平台适配边界
RobotControlFramework 接收 RobotObservation/events,推进状态机并返回 MotorFrame
ModRuntime 保存合成配置、状态工厂、资源管理器、已加载 Mod 和动态模块
ResourceManager 注册、按 eager/lazy 策略创建、缓存和关闭资源
StateBuildContext 为状态工厂提供名称、稳定 state id 和强类型参数读取
RobotStateMachine 处理事件、延迟、过渡、状态生命周期和图导出
RemoteEventAdapter MotionCommands 槽位变化转成 Mod 事件

Mod 只能依赖 mod_apiBxiExample 通过一个 RobotControlRuntime 使用 _runtime, 不再自己组装调度器、loader、状态和状态机。项目不再提供旧 utils 扩展入口,错误的 依赖会在开发阶段直接暴露。

命名空间

Mod 清单中的本地名称会自动限定:

Mod id:       com.example.wave
state:        wave
event:        activate
resource:     com.example.wave/policy

运行时状态:  com.example.wave/wave
运行时事件:  com.example.wave/activate

同一 Mod 内的 from: waveto: waveevent: activate 会自动限定。跨 Mod 引用必须写完整名称,并通过 requires 声明依赖。

修改边界

新增动作:

  • 新建或扩展一个 Mod。
  • mod.yaml 声明状态、事件、路由和 action。
  • 简单状态用 factory: module:Class;需要资源和扩展注册时再由 plugin.py 返回工厂。
  • 模型放进该 Mod 的 assets/ 并注册资源。
  • 在遥控器 YAML 中输出清单所使用的 btn_N=value

新增过渡:

  • 框架通用过渡放入包内 transitions/
  • 业务专用过渡放在对应 Mod 中,并由 ModDefinition.transition_plugins 显式注册。
  • profile 可放系统 YAML;Mod 私有 profile 放 mod.yaml,会自动加命名空间。

新增输入协议:

  • 先判断是否仅靠遥控器 YAML 能完成。
  • 必须读新设备时再实现 InputDriverBase 和工厂。
  • Driver 只产生 raw signal,不直接写状态名。

公开发布:

  • 在要整体移除的 Mod 清单中设置 visibility: protected
  • tools/sanitize_release.py 删除整个目录并验证保留 Mod 的依赖闭包。

下一步

Clone this wiki locally