Skip to content

Hands On Model State

konodoki edited this page Jul 25, 2026 · 22 revisions

手把手 2:把模型动作封装成 Mod

本课在独立 Mod 中放置 .npz.onnx,通过惰性资源交给状态使用。

1. 目录

mods/com.example.motion/
  mod.yaml
  plugin.py
  state.py
  assets/
    motion.npz
    motion.onnx

2. 状态

复用框架的 MotionReplayState

from bxi_example_py_elf3.inference.beyondmimic import (
    DanceMotionPolicyGravityIsaaclab,
)
from bxi_example_py_elf3.mod_api import ResourceHandle
from bxi_example_py_elf3.mod_api import MotionReplayState


class ExampleMotionState(
    MotionReplayState[DanceMotionPolicyGravityIsaaclab]
):
    def __init__(self, name, state_id, policy):
        super().__init__(
            name,
            state_id,
            policy,
            finish_trigger="example_motion_finished",
            end_frame_trim=20,
            end_transition={
                "profile": "dual_running_blend",
                "duration": 0.6,
                "sample_from": True,
            },
        )

基类负责重置 timestep、预热、进入帧、运行采样、播放结束返回基础 normal 和暂停 action。

3. 注册惰性资源

plugin.py

from bxi_example_py_elf3.inference.beyondmimic import (
    DanceMotionPolicyGravityIsaaclab,
)
from bxi_example_py_elf3.mod_api import (
    ModDefinition,
    ModLoadContext,
    ResourceKey,
    ResourceLoadContext,
)

from .state import ExampleMotionState

POLICY = ResourceKey[DanceMotionPolicyGravityIsaaclab](
    "com.example.motion/policy"
)


def _load(context: ResourceLoadContext):
    return DanceMotionPolicyGravityIsaaclab(
        str(context.asset("assets/motion.npz")),
        str(context.asset("assets/motion.onnx")),
        start_frame=0,
    )


def create_mod(context: ModLoadContext) -> ModDefinition:
    context.register_resource(POLICY, _load)
    policy = context.resource(POLICY)
    return ModDefinition(
        state_factories={
            "motion": lambda state: ExampleMotionState(
                state.name, state.state_id, policy
            )
        }
    )

加载 Mod 不会创建推理器;状态首次访问 handle 时才加载文件。

4. 清单

schema: 1
id: com.example.motion
version: 1.0.0
api: 1
entrypoint: plugin:create_mod
requires:
  - {id: com.bxi.basic_actions, version: ">=1,<2"}

events:
  activate: {slot: btn_10, value: 8}
  toggle_pause: {slot: btn_9, value: 1}

states:
  motion:
    manifest:
      label: 模型动作
      priority: 100
      group: Customer
      icon: animation
      confirm: true
      confirm_message: 请确保周围安全

routes:
  - {from: com.bxi.basic_actions/normal, event: activate, to: motion, transition: soft_switch}
  - {from: motion, event: com.bxi.basic_actions/normal, to: com.bxi.basic_actions/normal, transition: dual_running_blend}
  - {from: motion, event: toggle_pause, action: toggle_pause}
  - {from: motion, event: com.bxi.basic_actions/zero_torque, to: com.bxi.basic_actions/zero_torque}

Transition 是两个状态之间的临时控制过程:状态图已经决定要从哪里切到哪里,Transition 再决定切换期间怎样生成 qpos/kp/kd。模型第一帧和当前电机帧可能差异很大,因此通常需要保持、增益渐变或双状态混合,避免直接换帧造成突跳。上例进入前使用短暂保持,返回 normal 时混合动作模型与行走模型的运行帧。

5. 调试顺序

  1. 先离线加载 Mod,确认资源仍是未加载状态。
  2. 仿真进入动作,确认 on_prepare() 预热成功。
  3. 检查第一帧、结束帧和 end_frame_trim
  4. 检查安全退出与 normal 返回。
  5. 最后再进入真机低增益验证。

下一课:绑定按键

Clone this wiki locally