4. 倒立摆模型简化
任务目标
将双足机器人简化为线性倒立摆模型(Linear Inverted Pendulum Model, LIPM),建立质心(CoM)水平运动与零力矩点(ZMP)之间的线性关系,为后续步态规划提供简化动力学基础。
模型简化假设
- 机器人总质量集中于质心,质心高度保持恒定(
z = z_c); - 支撑腿视为无质量伸缩杆,仅传递地面反力;
- 忽略踝关节力矩,ZMP位于支撑脚范围内;
- 水平方向运动与垂直方向解耦,仅研究水平面内动力学。
核心方程
在LIPM中,质心水平加速度与ZMP位置满足线性关系:
ddot{x} = (g / z_c) * (x - p_x)
其中 x 为质心水平位置,p_x 为ZMP位置,g 为重力加速度,z_c 为恒定质心高度。该方程为线性时不变二阶系统,可解析求解,是步态规划中轨迹生成的基础。
关键完整代码(Python + NumPy)
import numpy as np
class LIPM:
"""线性倒立摆模型:恒定质心高度,水平运动与ZMP线性关系"""
def __init__(self, z_c=0.8, g=9.81):
self.z_c = z_c # 质心高度 [m]
self.g = g # 重力加速度 [m/s^2]
self.w = np.sqrt(g / z_c) # 倒立摆自然频率 [rad/s]
def compute_zmp_from_com(self, x, ddot_x):
"""由质心位置和加速度反算ZMP位置"""
return x - (self.z_c / self.g) * ddot_x
def compute_com_trajectory(self, x0, v0, p_x, t, dt=0.001):
"""
给定恒定ZMP位置p_x,解析求解质心轨迹
返回: (t_array, x_array, v_array)
"""
# 双曲函数解析解
cosh_wt = np.cosh(self.w * t)
sinh_wt = np.sinh(self.w * t)
# 质心位置: x(t) = (x0 - p_x)*cosh(wt) + (v0/w)*sinh(wt) + p_x
x_t = (x0 - p_x) * cosh_wt + (v0 / self.w) * sinh_wt + p_x
# 质心速度: v(t) = (x0 - p_x)*w*sinh(wt) + v0*cosh(wt)
v_t = (x0 - p_x) * self.w * sinh_wt + v0 * cosh_wt
# 质心加速度: a(t) = w^2 * (x_t - p_x)
a_t = self.w**2 * (x_t - p_x)
# 由质心状态反算ZMP(应恒等于p_x,用于验证)
zmp_calc = self.compute_zmp_from_com(x_t, a_t)
t_array = np.full_like(x_t, t) if np.isscalar(t) else t
return t_array, x_t, v_t, zmp_calc
def simulate(self, x0, v0, p_x, duration=1.0, dt=0.001):
"""仿真接口:返回时间序列"""
t = np.arange(0, duration + dt, dt)
_, x_t, v_t, zmp_calc = self.compute_com_trajectory(x0, v0, p_x, t)
return t, x_t, v_t, zmp_calc
# ========== 最小验证闭环 ==========
if __name__ == "__main__":
# 参数设置
model = LIPM(z_c=0.8, g=9.81)
x0 = 0.0 # 初始质心位置 [m]
v0 = 0.5 # 初始质心速度 [m/s]
p_x = 0.1 # 恒定ZMP位置 [m]
duration = 2.0 # 仿真时长 [s]
# 运行仿真
t, x, v, zmp = model.simulate(x0, v0, p_x, duration)
# 验证1: ZMP反算误差(应接近0)
zmp_error = np.max(np.abs(zmp - p_x))
print(f"ZMP反算最大误差: {zmp_error:.2e} m")
# 验证2: 动力学方程残差 (ddot{x} - w^2*(x-p_x) ≈ 0)
# 由解析解计算加速度
a_analytic = model.w**2 * (x - p_x)
# 数值微分验证
a_numeric = np.gradient(v, t)
dyn_error = np.max(np.abs(a_numeric - a_analytic))
print(f"动力学方程最大残差: {dyn_error:.2e} m/s^2")
# 验证3: 输出关键时间点状态
idx = np.array([0, len(t)//4, len(t)//2, 3*len(t)//4, -1])
print("\n时间点状态采样:")
print(f"{'t(s)':>8} {'x(m)':>10} {'v(m/s)':>10} {'ZMP(m)':>10}")
for i in idx:
print(f"{t[i]:8.3f} {x[i]:10.4f} {v[i]:10.4f} {zmp[i]:10.4f}")
# 验证4: 断言检查
assert zmp_error < 1e-8, "ZMP反算误差过大"
assert dyn_error < 1e-6, "动力学残差过大"
print("\n所有验证通过:模型实现正确")
运行方式
python lipm_model.py
需要安装 numpy:pip install numpy
验证方法与判定标准
- ZMP反算一致性:由质心轨迹反算的ZMP应与设定值一致,最大误差
< 1e-8 m,证明正逆动力学关系自洽; - 动力学方程残差:数值微分得到的加速度与解析加速度最大残差
< 1e-6 m/s²,证明轨迹满足LIPM微分方程; - 状态输出:终端打印的采样点显示质心位置随时间呈双曲增长趋势(因
v0 > 0且p_x < x时不稳定),符合LIPM开环特性; - 程序末尾断言通过且无异常退出,即判定实现正确。
模型用途说明
该LIPM实现可直接用于:给定ZMP轨迹反推质心运动(步态规划正问题),或给定期望质心轨迹计算所需ZMP(稳定性判据)。实际双足行走中,ZMP必须保持在支撑多边形内,本模型为这一约束提供了线性化分析工具。若要扩展至三维,只需在 y 方向独立应用相同方程即可。