-
Notifications
You must be signed in to change notification settings - Fork 12
Hands On Custom State
konodoki edited this page Jul 23, 2026
·
26 revisions
本课创建 com.example.sin_wave,从基础走路状态进入正弦摆动,再按正常模式键返回。
src/bxi_example_py_elf3/mods/com.example.sin_wave/
mod.yaml
plugin.py
state.py
state.py:
from __future__ import annotations
import math
from typing import TYPE_CHECKING
from bxi_example_py_elf3.utils.robot_state_base import RobotControlState
from bxi_example_py_elf3.utils.transition_core import (
EntryFrameProvider,
MotorFrame,
RunningFrameProvider,
)
if TYPE_CHECKING:
from bxi_example_py_elf3.bxi_example_demo import BxiExample
class SinWaveState(RobotControlState, EntryFrameProvider, RunningFrameProvider):
def __init__(self, name, state_id, *, amplitude, frequency):
super().__init__(name, state_id)
self.amplitude = amplitude
self.frequency = frequency
self.elapsed = 0.0
def on_enter(self, ctx: BxiExample) -> None:
self.elapsed = 0.0
def _frame(self, ctx: BxiExample, elapsed: float) -> MotorFrame:
qpos = ctx.joint_nominal_pos.copy()
qpos[15] += self.amplitude * math.sin(
2.0 * math.pi * self.frequency * elapsed
)
return self._motor_frame(qpos, ctx.joint_kp, ctx.joint_kd)
def get_entry_frame(self, ctx: BxiExample) -> MotorFrame:
return self._frame(ctx, 0.0)
def sample_running_frame(self, ctx, dt, *, advance):
elapsed = self.elapsed + dt if advance else self.elapsed
frame = self._frame(ctx, elapsed)
if advance:
self.elapsed = elapsed
return frame
def on_update(self, ctx: BxiExample, dt: float) -> None:
self._apply_frame(
ctx, self.sample_running_frame(ctx, dt, advance=True)
)plugin.py:
from bxi_example_py_elf3.utils.mod_system import ModDefinition, ModLoadContext
from .state import SinWaveState
def create_mod(context: ModLoadContext) -> ModDefinition:
return ModDefinition(
state_factories={
"sin_wave": lambda state: SinWaveState(
state.name,
state.state_id,
amplitude=state.float_param("amplitude", 0.25),
frequency=state.float_param("frequency", 0.5),
)
}
)mod.yaml:
schema: 1
id: com.example.sin_wave
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}
states:
sin_wave:
manifest:
label: 正弦摆动
index: 20
group: Customer
icon: waves
params:
amplitude: 0.25
frequency: 0.5
routes:
- from: com.bxi.basic_actions/normal
event: activate
to: sin_wave
transition: first_frame_switch
- from: sin_wave
event: com.bxi.basic_actions/normal
to: com.bxi.basic_actions/normal
transition: dual_running_blendcolcon build --packages-select bxi_example_py_elf3 \
--symlink-install --merge-install
source install/setup.bash启动日志应包含:
Mod com.example.sin_wave@1.0.0
状态完整名是 com.example.sin_wave/sin_wave。此时还没有遥控器输出 btn_10=8,可先用测试发布或继续第 3 课完成绑定。
- 清单状态名与 factory 键完全一致。
- 跨 Mod 引用有完整名称和
requires。 - 参数全部通过
StateBuildContext消费。 -
advance=False不推进 elapsed。 - index 与现有状态错开;若冲突会自动调整并告警。
下一课:模型动作状态。