4. 步态周期中单支撑与双支撑阶段的切换控制

任务目标

在双足机器人步态周期中,单支撑(SSP)与双支撑(DSP)阶段的切换是影响行走稳定性的关键。本案例实现一个相位切换控制器,基于归一化步态相位 φ∈[0,1) 计算各关节的目标角度与角速度,并在切换边界处采用五次多项式插值(quintic blend)保证关节位置和速度的连续过渡,避免冲击。

核心实现

import numpy as np

# 步态参数
T_ssp = 0.4   # 单支撑时长(s)
T_dsp = 0.2   # 双支撑时长(s)
T = T_ssp + T_dsp  # 完整周期

# 关节定义:髋关节、膝关节、踝关节(左右各3)
joint_names = ['L_hip', 'L_knee', 'L_ankle', 'R_hip', 'R_knee', 'R_ankle']

# 各阶段目标角度(弧度),行序:SSP起始、SSP结束、DSP结束
targets = {
    'L_hip':   [0.3, -0.2, 0.1],
    'L_knee':  [0.5, 0.8, 0.4],
    'L_ankle': [-0.2, -0.1, -0.15],
    'R_hip':   [-0.2, 0.3, 0.1],
    'R_knee':  [0.8, 0.5, 0.4],
    'R_ankle': [-0.1, -0.2, -0.15]
}

def phase_to_stage(phi):
    """返回 (阶段, 阶段内归一化时间t∈[0,1))"""
    if phi < T_ssp / T:
        return 'SSP', phi * T / T_ssp
    else:
        return 'DSP', (phi - T_ssp / T) * T / T_dsp

def quintic_blend(y0, y1, t):
    """五次多项式插值,保证位置和速度连续"""
    t2 = t * t
    t3 = t2 * t
    t4 = t3 * t
    t5 = t4 * t
    h = 6*t5 - 15*t4 + 10*t3
    dh = 30*t4 - 60*t3 + 30*t2
    return y0 + (y1 - y0) * h, (y1 - y0) * dh / 1.0  # 归一化时间导数

def get_joint_command(phi):
    """根据相位返回各关节目标角度与角速度"""
    stage, t = phase_to_stage(phi)
    cmd = {}
    for j in joint_names:
        if stage == 'SSP':
            # 从SSP起始插值到SSP结束
            theta, dtheta = quintic_blend(targets[j][0], targets[j][1], t)
        else:
            # 从SSP结束插值到DSP结束
            theta, dtheta = quintic_blend(targets[j][1], targets[j][2], t)
        cmd[j] = (theta, dtheta / (T_ssp if stage == 'SSP' else T_dsp))
    return cmd

# 验证:检查切换点连续性
def check_continuity():
    eps = 1e-6
    # SSP结束时刻(φ = T_ssp/T - eps)与DSP开始时刻(φ = T_ssp/T + eps)
    phi_boundary = T_ssp / T
    cmd_before = get_joint_command(phi_boundary - eps)
    cmd_after = get_joint_command(phi_boundary + eps)
    max_pos_err = 0.0
    max_vel_err = 0.0
    for j in joint_names:
        pos_err = abs(cmd_before[j][0] - cmd_after[j][0])
        vel_err = abs(cmd_before[j][1] - cmd_after[j][1])
        max_pos_err = max(max_pos_err, pos_err)
        max_vel_err = max(max_vel_err, vel_err)
    print(f"切换点最大位置误差: {max_pos_err:.2e} rad")
    print(f"切换点最大速度误差: {max_vel_err:.2e} rad/s")
    assert max_pos_err < 1e-4 and max_vel_err < 1e-4, "切换不连续!"
    print("连续性检查通过")

if __name__ == "__main__":
    check_continuity()
    # 示例输出:φ=0.3(SSP中段)和φ=0.7(DSP中段)的指令
    for phi in [0.3, 0.7]:
        cmd = get_joint_command(phi)
        print(f"\nφ={phi}: 阶段={phase_to_stage(phi)[0]}")
        for j in ['L_hip', 'R_knee']:
            print(f"  {j}: θ={cmd[j][0]:.3f} rad, ω={cmd[j][1]:.3f} rad/s")

运行与验证

依赖:仅需 Python 3 + NumPy。

运行:

python phase_switch_control.py

通过条件:程序输出切换点最大位置误差与速度误差均小于 1e-4(理论值为0),并打印“连续性检查通过”。示例输出展示不同相位下的关节指令,用于人工观察插值效果。

关键说明

  • 五次插值保证在阶段边界处位置和速度均连续,因为 h(0)=0, h(1)=1, dh(0)=dh(1)=0。
  • 角速度计算中,先对归一化时间求导,再除以实际阶段时长,得到物理角速度(rad/s)。
  • 实际机器人应用中,将 get_joint_command(phi) 输出的角度与角速度作为底层PD控制器的前馈指令即可。