-
Notifications
You must be signed in to change notification settings - Fork 12
Architecture
当前架构把平台适配、控制框架、动作实现和模型资产分层。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()
-> 首帧建立完整 Robot Layout
-> RobotControlFramework 内的 RemoteEventAdapter / RobotStateMachine
-> RobotControlState 输出自己的 29/31/N 自然 MotorFrame
-> JointCommandResolver 补齐完整 Robot Layout
-> Transition 在完整布局上插值
-> 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/
framework/ # 与 ELF3 部署代码分离的可移植运控框架
inference/ # 后端、历史帧、策略契约和推理运行时
joints/ # 具名布局、默认目标、解析器、映射与标定
platform/ # 机器人接入协议、关节 I/O 和控制 Runtime
mod_api/ # 面向 Mod 作者的公共 API
runtime/ # 状态机、加载器、调度器和控制内核
transitions/ # 通用 Transition
policies/ # ELF3 内置推理策略
joints.py # 模型关节契约与策略内部顺序
normal.py
amp.py
beyondmimic.py
depth.py
bxi_example_demo.py # ELF3 ROS 适配层及平台默认目标
bxi_example_mjlab.py # 原 MJLab 示例入口
| 对象 | 责任 |
|---|---|
RobotControlRuntime |
持有控制调度器、Framework、维护线程和平台适配边界 |
RobotControlFramework |
接收 RobotObservation/events,推进状态机并返回 MotorFrame
|
ModRuntime |
保存合成配置、状态工厂、资源管理器、已加载 Mod 和动态模块 |
ResourceManager |
注册、按 eager/lazy 策略创建、缓存和关闭资源 |
StateBuildContext |
为状态工厂提供名称、稳定 state id 和强类型参数读取 |
RobotStateMachine |
处理事件、延迟、过渡、状态生命周期和图导出 |
RemoteEventAdapter |
把 MotionCommands 槽位变化转成 Mod 事件 |
JointCommandResolver |
将状态自然输出按名称解析成完整 Robot Layout;映射仅编译一次 |
Robot Layout 不再由固定的 29 关节常量传给 Runtime。具名消息的首个合法完整快照决定当前
机器人是 29、31 还是 N 个关节;策略类自己的 PolicyJointContract 仍固定模型输入输出,
二者互不改写。旧模型缺失的新增关节由平台 JointCommandDefaults 显式提供目标。
Mod 只能依赖 bxi_example_py_elf3.framework.mod_api;BxiExample 通过
framework.platform.RobotControlRuntime 使用运控内核,不再自己组装调度器、loader、
状态和状态机。项目不保留旧路径的兼容转发模块,错误依赖会在开发阶段直接暴露。
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: wave、to: wave 和 event: activate 会自动限定。跨 Mod 引用必须写完整名称,并通过 requires 声明依赖。
新增动作:
- 新建或扩展一个 Mod。
- 在
mod.yaml声明状态、事件、路由和 action。 - 简单状态用
factory: module:Class;需要资源和扩展注册时再由plugin.py返回工厂。 - 模型放进该 Mod 的
assets/并注册资源。 - 在遥控器 YAML 中输出清单所使用的
btn_N=value。
新增过渡:
- 框架通用过渡放入
framework/transitions/。 - 业务专用过渡放在对应 Mod 中,并由
ModDefinition.transition_plugins显式注册。 - profile 可放系统 YAML;Mod 私有 profile 放
mod.yaml,会自动加命名空间。
新增输入协议:
- 先判断是否仅靠遥控器 YAML 能完成。
- 必须读新设备时再实现
InputDriverBase和工厂。 - Driver 只产生 raw signal,不直接写状态名。
公开发布:
- 在要整体移除的 Mod 清单中设置
visibility: protected。 -
tools/sanitize_release.py删除整个目录并验证保留 Mod 的依赖闭包。