基于三次样条插值的双足机器人多步态平滑切换仿真

项目概述

本教程在 ROS 2 Humble 中搭建一个平面双足机器人:躯干 + 双腿,每条腿 3 个关节(髋、膝、踝),共 6 个主动关节。 机器人依次经历 站立 → 行走 → 快步 → 跑步 → 行走 → 站立 六段步态,每段之间用三次 Hermite 样条完成平滑切换。

重点不是单一步态的步态生成,而是多步态切换的连续性:切换瞬间如果直接跳变关节目标,关节角速度/角加速度会出现尖峰; 三次样条同时匹配切换起点与终点的位置和速度,使关节运动在 C1 意义下连续。项目还运行一组“直接切换”对照实验,用实测数据量化平滑效果。

系统结构

controller_node (200 Hz)
   │  /joint_cmd (期望角度 + 角速度)
   ▼
sim_node (500 Hz, 子步进 PD 伺服)
   │  /joint_states (实际角度)
   │  /biped_metrics (质心、ZMP、裕度、双脚位置/接触)
   ▼
logger_node (100 Hz 固定网格) → trajectory.csv
  • 控制器只使用自身规划,不读取任何外部定位;
  • 仿真节点用带速度前馈的 PD 伺服跟踪期望角,关节限位做饱和保护;
  • 记录节点以自身单调时钟按 100 Hz 固定网格打时间戳(time = 起始时刻 + 序号/rate),CSV 相邻行严格等间隔,不再使用控制器消息中四舍五入的 elapsed;
  • 接触状态由控制器按规划相位给出,仿真节点用期望关节角 qdes 的 FK 构造支撑多边形;ZMP 由期望质心轨迹的平滑二阶差分计算,实际质心与跟踪误差单独统计。

步态定义

步态 周期 (s) 支撑相占比 步长 (m) 抬脚高度 (m) 髋高 (m) 前倾 (rad)
stand 1.00 0.50 0.00 0.00 0.84 0.00
walk 1.20 0.62 0.22 0.10 0.82 0.06
fast_walk 0.90 0.58 0.30 0.13 0.80 0.10
run 0.60 0.38 0.42 0.18 0.78 0.16

单腿相位 p 在 [0, 1) 内循环,左右腿相差 0.5。支撑相占比大于 0.5 时存在双支撑(行走/快步),小于 0.5 时存在腾空(跑步)。

摆动脚相对髋部的位置:

支撑相:x_rel = A - 2A·p/s        (A = s·step)
摆动相:u = (p - s)/(1 - s)
        x_rel = -A + 2A·(3u² - 2u³)
        z_rel = clearance·16u²(1-u)²

摆动相的水平与竖直曲线在两端速度均为 0,减少落足冲击。

三次 Hermite 样条切换

设切换时刻为 t0,过渡时长 T = 0.6 s。记录当前 6 个关节角 q0 与角速度 dq0, 并预测目标步态在 t1 = t0 + T 时的角度 q1 与角速度 dq1。过渡期内:

u  = (t - t0) / T
h00 = 2u³ - 3u² + 1      h10 = u³ - 2u² + u
h01 = -2u³ + 3u²        h11 = u³ - u²
q(t) = h00·q0 + h10·T·dq0 + h01·q1 + h11·T·dq1

该式为标准三次 Hermite 插值:端点位置精确,端点速度精确,因而位置与速度连续(C1)。 控制器同时使用该式的解析导数作为 /joint_cmd 的速度前馈,切换首拍不会把速度发布成 0。 切换期间前进速度也从旧步态速度平滑过渡到新步态速度(smoothstep),避免基座速度突变。

本教程中的“三次样条”指分段三次 Hermite 插值;自然三次样条(C2 连续、端点二阶导为零)并未在主流程中使用。

运行方法

mkdir -p ~/biped_ws/src
ln -s /path/to/biped_cubic_spline_gait_switch ~/biped_ws/src/
cd ~/biped_ws
colcon build --packages-select biped_cubic_spline_gait_switch --symlink-install
source install/setup.bash
cd src/humanoid/biped_cubic_spline_gait_switch
python3 main.py

main.py 会依次运行 spline 与 direct 两组 34 s 实验,并调用 tools/analyze.py 生成指标、图表与 GIF。

实验结果

34 s 调度(站立 3 s → 行走 6 s → 快步 6 s → 跑步 6 s → 行走 6 s → 站立 7 s),100 Hz 记录,共 3401 条严格等间隔采样。对照组在相同参数下把切换方式改为直接跳变。

指标 三次 Hermite 切换 直接切换
前进距离 / 平均速度(全程) 16.800 m / 0.494 m/s 同调度
平均速度(行进段) 0.686 m/s 同调度
关节跟踪 RMS 0.0097 rad —
切换时刻 qddes 左右极限差(主结论) 0.530 rad/s(100 Hz 采样表观值;连续极限为 0) 157.375 rad/s
切换窗口最大相邻采样命令速度差(qddes) 0.550 rad/s(21.126 s) 149.811 rad/s(21.011 s)
切换窗口最大相邻采样速度差(qdes) 1.658 rad/s 30.622 rad/s
切换窗口最大 jerk(100 Hz 差分,分辨率敏感) 14140.4 rad/s³ 161009.7 rad/s³
切换窗口最大角加速度(100 Hz 差分,分辨率敏感) 107.91 rad/s² 1553.87 rad/s²
ZMP 最小裕度(规划几何量) -0.2002 m —
腾空比例 / 步数(规划相位) 0.045 / 50 —
步态 采样数 ZMP 最小裕度 (m) 跟踪 RMS (rad)
stand 1001 0.1477 0.0004
walk 1200 -0.1484 0.0075
fast_walk 600 -0.1442 0.0113
run 600 -0.2002 0.0168

切换发生在 3 / 9 / 15 / 21 / 27 s。pytest 对 5 次切换逐次断言首拍速度与上一拍相同(使用规划器解析导数);CSV 中 0.530 rad/s 的最大表观左右差出现在 21.006 s(跑步→行走),是因为 100 Hz 记录点在切换后 6 ms、过渡已开始演化,并非真实跳变。最大相邻采样 qddes 差 0.550 rad/s 出现在 21.126 s,属于 21.0 s 的切换窗口(跑步→行走);直接切换同窗口为 149.811 rad/s。

jerk/角加速度是差分指标,会随分析网格变化:Hermite 只保证 C1,过渡起止点的加速度仍有跳变,因此 jerk 同样不收敛。下表把同一份 100 Hz 记录插值到更细网格,仅用于说明分辨率敏感性;主结论采用切换时刻 qddes 左右极限差。

分析网格 (Hz) Hermite jerk 直接 jerk Hermite 角加速度 直接角加速度
100 14140.4 161009.7 107.91 1553.87
200 78371.0 604825.0 526.54 3062.16
400 210616.0 2434512.0 970.32 6086.28

接触状态按规划相位统计,walk / fast_walk 腾空为 0、run 段为 0.255(理论 0.24)、整体 0.045;步数 50(排除切换边界);ZMP 裕度由 qdes 的 FK 支撑多边形得到,为规划几何量;行走/跑步阶段为负是因为本仿真为开环轨迹跟踪、未加入平衡控制器。

关节轨迹

关节轨迹

上图为 6 个关节的期望角(实线)与实际角(虚线),橙色区间为 0.6 s 切换过渡。切换期间角度、角速度均连续。

质心与 ZMP

质心与 ZMP

切换平滑性对比

切换对比

三次样条切换与直接切换在同一调度、同一 PD 参数下对比:切换时刻命令速度左右极限差与相邻采样差均显著下降;jerk 与角加速度作为同网格参考,并附分辨率敏感性表。

加加速度

jerk

行走动画

行走动画

局限性

  • 采用平面(矢状面)运动学,未建模侧向平衡、脚掌打滑与接触力;
  • 浮动基座位置由步态规划给定,不是完整浮动基动力学积分;
  • ZMP 由期望质心轨迹计算,支撑多边形由期望关节角 qdes 的 FK 与规划接触相位得到;二者均为规划几何量,不代表真实接触力;
  • PD 伺服参数为等效惯量模型,不等同于真实电机/减速器参数。

复现说明

results/run_spline 与 results/run_direct 由 main.py 在本机实际运行产生,均包含 100 Hz、3401 条等间隔采样的 trajectory.csv;run_spline 还包含分析脚本生成的 metrics.json、metrics.md、图表与 GIF。运行输出已通过 .gitignore 排除、不入库,文档所需图表保存在 docs/img/。测试通过 python3 -m pytest -q test 验证三次 Hermite 插值与解析导数、运动学,以及完整 34 s 调度下全部 5 次切换的逐窗口速度连续性。