Skip to content

State Machine Config

konodoki edited this page Jul 23, 2026 · 14 revisions

状态机 YAML 配置

状态机配置文件:

src/bxi_example_py_elf3/config/elf3_state_machine.yaml

它负责声明状态、事件、状态间的边、过渡插件配置、速度配置,以及状态图检查和导出。

1. 顶层结构

initial_state: zero_torque
default_transition: instant

graph:
  validate: true
  export:
    dot: /tmp/elf3_state_machine.dot
    mermaid: /tmp/elf3_state_machine.mmd

remote_events: {}
transition_profiles: {}
speed_profiles: {}
states: {}

default_transition 必须引用 transition_profiles 中已经声明的 profile。状态机核心不内置任何具体过渡名称;当前配置把普通的 instant profile 选作默认值。

2. initial_state

initial_state: zero_torque

启动时进入的状态,必须存在于 states。不写时使用 states 中第一个状态,但建议总是显式声明。

3. graph

graph:
  validate: true
  export:
    dot: /tmp/elf3_state_machine.dot
    mermaid: /tmp/elf3_state_machine.mmd
  • validate:启动时检查状态图,默认开启。
  • export.dot:可选,导出 Graphviz dot 文件。
  • export.mermaid:可选,导出 Mermaid 文件。

图检查会发现:

  • 目标状态不存在。
  • profile 或插件类型不存在。
  • 过渡所需的状态能力没有实现。
  • event 未在 remote_events 声明。
  • 状态从初始状态不可达。
  • 状态没有任何输出边。
  • after 自动边形成循环。

错误会阻止启动;warning 用于提示可能的配置问题。

4. remote_events

remote_eventsMotionCommands 字段转换成命名事件:

remote_events:
  normal_event:
    slot: btn_1
    value: 1
  • map key 是状态机事件名。
  • slotMotionCommands 字段名。
  • value 是触发值。
  • 如果值相比该事件上次观察到的值没有变化,不会重复触发。

也可以用字符串简写,表示 slot 任意变化时触发:

remote_events:
  any_btn_1_change: btn_1

5. transition_profiles

每个 profile 都是某个过渡插件的一份可复用配置,必须用 type 指定插件:

default_transition: instant

transition_profiles:
  instant:
    type: instant

  soft_switch:
    type: hold
    duration: 0.02

  first_frame_switch:
    type: sequence
    steps:
      - type: hold
        duration: 0.02
      - type: entry_gain_ramp
        duration: 1.0
        kp_from: zero
        kd_from: target

  dual_running_blend:
    type: running_blend
    duration: 0.3
    curve: smoothstep
    sample_from: true
    sample_to: true
    advance_from: false
    advance_to: false

profile 名只是配置引用名;插件由 type 决定。未知字段会在加载时直接报错,避免拼写错误被静默忽略。

5.1 instant

type: instant

零时长切换。它仍是普通插件,只是被当前 YAML 选为了默认 profile。

5.2 hold

type: hold
duration: 0.02

保持过渡开始前最后一帧电机目标。

5.3 entry_gain_ramp

type: entry_gain_ramp
duration: 1.0
kp_from: zero
kd_from: target

固定使用目标状态的进入帧位置,并插值 kp/kd。目标状态必须实现 EntryFrameProvider

kp_fromkd_from 支持:

  • current:当前实际输出增益。
  • zero:全零增益。
  • target:目标进入帧增益。

5.4 running_blend

type: running_blend
duration: 0.3
curve: smoothstep
sample_from: true
sample_to: true
advance_from: false
advance_to: false
  • curvelinearsmoothstepsmootherstep
  • sample_from:是否向源状态请求运行帧。
  • sample_to:是否向目标状态请求运行帧。
  • advance_from:采样源状态时是否推进其内部时间。
  • advance_to:采样目标状态时是否推进其内部时间。

启用采样的一侧必须实现 RunningFrameProvider。目标状态始终必须实现 EntryFrameProvider,它也是目标侧采样返回 None 时的稳定后备帧。源状态采样返回 None 时使用过渡开始前的最后电机帧。

5.5 sequence

type: sequence
steps:
  - type: hold
    duration: 0.02
  - type: entry_gain_ramp
    duration: 1.0
    kp_from: zero
    kd_from: target

顺序执行多个过渡。steps 不能为空,每一步都是完整的内联过渡配置,也可以继续嵌套 sequence。单周期跨越步骤边界时,剩余 dt 会继续交给下一步。

6. inline transition

边可以直接写插件配置:

transition:
  type: running_blend
  duration: 1.0
  curve: smootherstep
  sample_from: true
  sample_to: true
  advance_from: false
  advance_to: false

也可以从已有 profile 复制配置并覆盖字段:

transition:
  profile: dual_running_blend
  duration: 1.0
  curve: linear

只支持 profile 作为 profile 引用字段。合并后仍由对应插件严格验证字段。

代码中使用相同结构:

ctx.request_state(
    "normal",
    trigger="motion_finished",
    transition={
        "profile": "dual_running_blend",
        "duration": 0.5,
        "sample_from": False,
    },
)

不传 transition 时使用 default_transition

7. speed_profiles

speed_profiles:
  normal_run:
    vx_scale: 2.0
    vx_min: -1.0
    vx_max: 2.0
    vy_scale: 0.5
    yaw_scale: 1.0

支持字段:

  • vx_scalevy_scaleyaw_scale
  • vx_minvx_max
  • vy_minvy_max
  • yaw_minyaw_max

状态通过 speed_profile 选择配置,并在代码中调用 self.get_cmd_vel(ctx) 才会应用:

states:
  normal_run:
    behavior: NormalRunState
    speed_profile: normal_run

没有配置 profile 或引用不存在的 profile 时返回零速度。状态可以重写 process_cmd_vel() 做进一步过滤。

8. states

states:
  sin_wave:
    id: 20
    manifest:
      label: 正弦测试
      index: 20
      group: Debug
      icon: waves
      confirm: false
      confirm_message: ""
    behavior: SinWaveState
    params:
      joint: 22
      amplitude: 0.4
      frequency: 1.0
    speed_profile: normal
    transitions:
      on_event: {}
      after: []
  • behaviorRobotControlState 子类名,必须填写。
  • id:可选,未填写时自动分配且检查重复。
  • params:作为关键字参数传给状态构造函数。
  • speed_profile:可选速度配置名。
  • manifest:只用于展示,不参与切换决策。
  • transitions.on_event:事件边。
  • transitions.after:定时边。

新增状态行为不需要修改构建器注册表;把类添加到 robot_states.py 后,构建器会自动发现它。

9. on_event

使用默认过渡的简写:

zero_torque_event: zero_torque

完整写法:

recover_event:
  to: recover
  delay: 0.2
  transition: first_frame_switch

只执行 action:

toggle_pause_event:
  action: toggle_pause

同时执行 action 和切换:

start_event:
  action: record_start
  to: running
  transition: soft_switch
  • to:目标状态。
  • delay:开始过渡前的非负延迟秒数。
  • transition:profile 名或内联配置;不写时使用默认 profile。
  • action:全局 handler 或当前状态的 on_action()

活动过渡期间仍会处理源状态的 event,因此安全事件可以中断当前过渡。中断会调用已准备目标状态的 on_prepare_cancel()

10. after

transitions:
  after:
    - seconds: 1.0
      action: halfway
    - seconds: 3.0
      to: normal
      transition: soft_switch
  • seconds:进入当前状态后的非负秒数。
  • afterseconds 的等价字段。
  • 其余字段与完整 event 边一致。

状态机只会对当前进入周期触发每条 after 一次,并会报告纯自动边构成的循环。

11. 状态切换职责

适合写在 YAML:

  • 遥控器 event 边。
  • 固定时间自动边。
  • 可复用过渡配置。
  • 速度缩放。

适合写在状态代码:

  • 姿态安全判断。
  • 动作播放完成判断。
  • 模型输出或传感器条件。

主动请求:

ctx.request_state("zero_torque", trigger="safety")

12. 下一步

Clone this wiki locally