-
Notifications
You must be signed in to change notification settings - Fork 12
Hands On Dual Running Blend
konodoki edited this page Jul 29, 2026
·
8 revisions
Transition 描述从状态机收到切换请求到目标状态正式进入之间,电机帧应该怎样生成。如果两边都是持续运行的模型,直接切换可能让 qpos/kp/kd 突变;只向一个固定进入姿态缓慢靠近,又会丢失两边的动态输出。
running_blend 正是为这种情况准备的:它在过渡期间采样源状态和目标状态的运行帧,再混合两侧 qpos/kp/kd。
class SinWaveState(RobotControlState, EntryFrameProvider, RunningFrameProvider):
def get_entry_frame(self, ctx):
last = ctx.last_motor_frame
return self._motor_frame(ctx, last.qpos, last.kp, last.kd)
def sample_running_frame(self, ctx, dt, *, advance):
next_elapsed = self.elapsed + dt if advance else self.elapsed
qpos = self._calculate_qpos(ctx, next_elapsed)
if advance:
self.elapsed = next_elapsed
last = ctx.last_motor_frame
return self._motor_frame(ctx, qpos, last.kp, last.kd)
def on_update(self, ctx, dt):
self._apply_frame(
ctx, self.sample_running_frame(ctx, dt, advance=True)
)advance=False 时不得推进状态内部时间。
transition_profiles:
dual_running_blend:
type: running_blend
duration: 0.3
curve: smoothstep
sample_from: true
sample_to: true
advance_from: true
advance_to: false此共享 profile 位于系统 elf3_state_machine.yaml。
推荐保持这组推进设置:来源状态在交接期间继续推进时间、动作历史和步态相位,目标状态则停在入口时间点。这样机器人不会在过渡期间冻结,目标也不会在正式进入前提前消费时间轴。过渡完成后,目标执行 on_enter(),随后才由正常控制循环开始推进。
routes:
- from: com.bxi.basic_actions/normal
event: activate
to: sin_wave
transition: dual_running_blend
- from: sin_wave
event: com.bxi.basic_actions/normal
to: com.bxi.basic_actions/normal
transition:
profile: dual_running_blend
duration: 1.0代码主动返回:
ctx.request_state(
"com.bxi.basic_actions/normal",
trigger="motion_finished",
transition={
"profile": "dual_running_blend",
"duration": 0.5,
"sample_from": False,
},
)from_frame = 源运行帧,或过渡开始前最后电机帧
to_frame = 目标运行帧,或目标进入帧
alpha = curve(progress)
output = from + (to - from) * alpha
内置实现会先把两侧自然布局解析到完整 Robot Layout,再执行上述公式。因此旧 29 关节状态 和新 31 关节状态可以互相混合;新增关节会平滑过渡到平台声明的默认目标。
目标先执行 on_prepare(),Session 再取进入帧。过渡完成才调用源 on_exit() 和目标 on_enter();被中断时调用目标 on_prepare_cancel()。
同一个控制周期内会依次采样来源和目标。这里不要求两个模型并行运行;只要两次推理总耗时小于控制周期预算,串行采样具有更简单、确定性更强的状态语义。
- 开启
sample_from时源必须实现RunningFrameProvider。 - 开启
sample_to时目标必须实现RunningFrameProvider。 - 目标始终需要
EntryFrameProvider。 - 默认使用
advance_from: true、advance_to: false。双方都为false会冻结两端动态输出;目标设为true则可能在正式进入前推进历史,并在on_enter()重置时产生跳变。 - 仅当来源动作已经结束、无法继续生成有效帧时,才使用
sample_from: false,让过渡从开始前最后一个电机帧混合。 - 突跳时检查进入帧和目标进入后的首帧是否一致。