步态循环(Gait Cycle)

步态循环及其在外骨骼中的应用

一、什么是步态循环(Gait Cycle)

定义:
步态循环是同一只脚从一次触地(Heel Strike)到下一次触地的完整运动周期,通常用 百分比(0%–100%) 表示。

在这里插入图片描述
上述图片来自:https://musculoskeletalkey.com/assessment-of-gait/

二、步态周期的两大阶段

阶段百分比简介
支撑期 Stance Phase0%–60%足部与地面接触,用于支撑身体重量
摆动期 Swing Phase60%–100%足部腾空前摆,为下一次接触做准备

支撑期细分(约 60%):

  1. Initial Contact(初始接触)
  • 时间:0%

  • 关键事件:Heel Strike(脚跟触地)

  • 关节行为:

    • 髋关节屈曲(~30°)

    • 膝关节接近伸直

    • 踝关节中立或轻微背屈

  • 肌肉:胫前肌、股四头肌开始活跃

  • 外骨骼助力提示:通常不助力,可用于步态事件的触发(FSM状态重置)

  1. Loading Response(负重反应)
  • 时间:0%–10%

  • 描述:身体重量转移到脚上

  • 关键动作:膝关节屈曲(减震)

  • 关节行为:

    • 膝关节轻屈(~15°)

    • 髋继续屈曲,踝快速跖屈

  • 肌肉:大腿肌群协同控制膝盖屈曲,胫前肌控制脚掌着地

  • 外骨骼助力提示:缓冲期,外骨骼若助力,需精细调控阻尼,否则会阻碍自然缓冲

  1. Mid Stance(中期支撑)
  • 时间:10%–30%

  • 描述:身体重心正好位于脚的正上方

  • 关键事件:另一脚离地,单腿支撑开始

  • 关节行为:

    • 髋由屈曲转为伸展

    • 膝逐渐伸直

    • 踝背屈达到高点

  • 肌肉:臀大肌、股四头肌活跃维持姿态

  • 外骨骼助力提示:可提供轻微支撑力矩,协助髋膝抗重力

  1. Terminal Stance(末端支撑)
  • 时间:30%–50%

  • 描述:身体重心向前移动,脚跟抬起

  • 关键事件:Heel Off(脚跟离地)

  • 关节行为:

    • 髋继续伸展

    • 踝快速跖屈

  • 肌肉:小腿三头肌(比目鱼、腓肠肌)发力产生推进力

  • 外骨骼助力提示:可提供推进助力,尤其是踝关节(软体外骨骼常在此施力)

  1. Pre-Swing(预摆期)
  • 时间:50%–60%

  • 描述:准备抬腿,脚趾最后接触地面

  • 关键事件:Toe Off(脚趾离地)

  • 关节行为:

    • 膝开始屈曲

    • 髋屈曲

    • 踝达到最大跖屈

  • 肌肉:腘绳肌开始活动准备抬腿

  • 外骨骼助力提示:助力触发时机,开始进入摆动控制状态

摆动期细分(Swing Phase,约 40%):

  1. Initial Swing(初始摆动)
  • 时间:60%–73%

  • 描述:脚离地后抬起腿

  • 关节行为:

    • 膝关节快速屈曲(最高 ~60°)

    • 髋开始屈曲

    • 踝背屈以避地

  • 肌肉:髂腰肌、腘绳肌

  • 外骨骼助力提示:助力抬腿动作,髋膝柔性引导

  1. Mid Swing(中期摆动)
  • 时间:73%–87%

  • 描述:小腿继续前摆,准备伸展

  • 关节行为:

    • 髋持续屈曲

    • 膝开始伸展

    • 踝背屈维持

  • 肌肉:伸膝肌开始控制腿部伸展

  • 外骨骼助力提示:可维持轨迹引导,使穿戴者动作更流畅

  1. Terminal Swing(末端摆动)
  • 时间:87%–100%

  • 描述:脚准备再次接触地面

  • 关键事件:Heel Strike(重新开始循环)

  • 关节行为:

    • 膝接近伸直

    • 髋仍略微屈曲

  • 肌肉:腘绳肌收缩控制膝伸速度

  • 外骨骼助力提示:控制终点位置,避免脚掌“拍地”或晃动

三、关键关节的行为(Hip、Knee、Ankle)

髋关节 Hip:

  • 支撑期:从屈曲 (~30°) 到接近伸展 (~0°)

  • 摆动期:再屈曲至 ~30°,为脚前摆提供动力

膝关节 Knee:

  • 支撑期初:微屈防震(15–20°)

  • 中后期:接近伸直

  • 摆动期初:屈曲至 ~60°

  • 终摆动期:伸展至接触准备

踝关节 Ankle:

  • Initial Contact:背屈(~0°)

  • Mid Stance:慢慢跖屈(负重推进)

  • Toe-Off:最大跖屈 (~15°)

  • 摆动期:背屈以避免拖地

四、常见生物力学指标(助力控制必备)

指标含义应用
关节角度(Joint Angle)髋/膝/踝在步态中的变化曲线控制器目标轨迹
角速度(Angular Velocity)角度的时间导数事件检测、估计意图
关节力矩(Joint Torque)肌肉产生的力矩估算阻抗控制、力控制参考
地面反作用力(GRF)脚接触地面产生的力步态识别、助力触发
步长(Step Length)一只脚到另一脚的距离步态节律评估
步频(Cadence)步数 / 每分钟调整控制参数节奏
双支撑期时长双脚同时接触地面的时间跟踪平衡与步态稳定性

应用于外骨骼的场景

步态阶段助力控制常见策略
Heel Strike检测触发控制状态机重置
Mid Stance提供关节支撑力(如膝关节助力)
Toe Off助力推进,输出力矩/目标角度
Swing Phase控制关节随动轨迹,避免脚拖地
Terminal Swing精准位置控制,准备接地
阶段控制策略建议
支撑早期最小干预,避免破坏自然缓冲
Mid-Stance提供髋/膝支撑助力
Terminal Stance适当推进力(尤其是踝)
Pre-Swing – Initial Swing施加髋屈曲力矩,抬腿助力
Terminal Swing控制终点稳定性,准备落地
#include <iostream> #include <vector> #include <algorithm> #include <cmath> #include <iomanip> #include <stdexcept> // 定义步态事件结构体 struct GaitEvent { double time_offset; // 相对于起始时间的时间偏移 std::vector<std::string> legs; // 站立腿列表 // 添加构造函数以便调试 GaitEvent(double t, std::vector<std::string> l) : time_offset(t), legs(std::move(l)) {} // 添加辅助方法用于打印 void print() const { std::cout << "T+" << std::fixed << std::setprecision(3) << time_offset << ": "; for (size_t i = 0; i < legs.size(); ++i) { if (i > 0) std::cout << ", "; std::cout << legs[i]; } std::cout << "\n"; } }; class EndEffectorPlanner { private: // 基础事件序列(一个完整周期) std::vector<GaitEvent> base_events; // 精度控制常量 static constexpr double GAIT_PERIOD = 1.0; static constexpr double TIME_EPSILON = 1e-9; // 时间比较精度 public: EndEffectorPlanner() { // 初始化基础事件序列 base_events = { {0.0, {"LH", "RF", "RH"}}, {0.4, {"LF", "LH", "RH"}}, {0.8, {"LF", "RF", "RH"}}, {1.2, {"LF", "LH", "RF"}}, {1.6, {"LH", "RF", "RH"}} }; } // 获取从给定起始时间点开始的一个完整周期内的步态时序 std::vector<GaitEvent> get_gait_sequence(double start_time) { // 1. 安全计算相位偏移(处理负数和浮点精度) double phase_offset = safe_fmod(start_time, GAIT_PERIOD); // 2. 构建结果序列 std::vector<GaitEvent> sequence; sequence.reserve(base_events.size() + 1); // 预留空间提高性能 // 3. 添加当前周期后半部分事件 for (const auto& event : base_events) { double adjusted_time = event.time_offset - phase_offset; // 使用epsilon进行安全比较 if (adjusted_time >= -TIME_EPSILON && adjusted_time <= GAIT_PERIOD + TIME_EPSILON) { // 处理负时间(下一个周期) if (adjusted_time < 0) { adjusted_time += GAIT_PERIOD; } // 避免重复添加0.0事件 if (!(adjusted_time < TIME_EPSILON && sequence.size() > 0 && sequence[0].time_offset < TIME_EPSILON)) { sequence.push_back({adjusted_time, event.legs}); } } } // 4. 添加下一个周期前半部分事件(仅添加小于1.0的部分) for (const auto& event : base_events) { // 跳过0.0事件(已包含在当前周期末尾) if (event.time_offset < TIME_EPSILON) continue; double next_cycle_time = (GAIT_PERIOD - phase_offset) + event.time_offset; // 确保时间在周期内 if (next_cycle_time < GAIT_PERIOD - TIME_EPSILON) { sequence.push_back({next_cycle_time, event.legs}); } } // 5. 处理特殊情况:起始点不是事件点 if (sequence.empty() || !is_time_equal(sequence[0].time_offset, 0.0)) { // 找到相位偏移前最近的事件 auto nearest_event = find_nearest_event(phase_offset); sequence.insert(sequence.begin(), {0.0, nearest_event.legs}); } // 6. 按时间偏移排序 std::sort(sequence.begin(), sequence.end(), [](const GaitEvent& a, const GaitEvent& b) { return a.time_offset < b.time_offset; }); // 7. 确保周期完整性(添加结束点) if (!is_time_equal(sequence.back().time_offset, GAIT_PERIOD)) { // 使用base_events中1.0事件的腿部状态 sequence.push_back({GAIT_PERIOD, base_events[0].legs}); } // 8. 规范化时间(确保在0.0到1.0之间) for (auto& event : sequence) { event.time_offset = std::fmod(event.time_offset, GAIT_PERIOD); if (event.time_offset < 0) event.time_offset += GAIT_PERIOD; } return sequence; } // 打印步态序列 void print_sequence(const std::vector<GaitEvent>& sequence) { std::cout << "\nGait Sequence:\n"; for (const auto& event : sequence) { event.print(); } } private: // 安全的浮点数取模函数 double safe_fmod(double value, double period) { // 处理无穷大和NaN if (std::isinf(value) || std::isnan(value)) { return 0.0; // 默认起始点 } double offset = std::fmod(value, period); // 处理负值 if (offset < 0) { offset += period; } // 处理浮点精度问题 if (offset >= period - TIME_EPSILON) { offset = 0.0; } return offset; } // 浮点数安全比较 bool is_time_equal(double a, double b) const { return std::abs(a - b) < TIME_EPSILON; } // 查找相位偏移前最近的事件 GaitEvent find_nearest_event(double phase_offset) { GaitEvent nearest_event = base_events[0]; // 默认使用第一个事件 double min_distance = GAIT_PERIOD; // 寻找最接近但不超过phase_offset的事件 for (const auto& event : base_events) { // 计算事件与相位偏移的距离(考虑周期闭环) double distance = (event.time_offset <= phase_offset) ? (phase_offset - event.time_offset) : (GAIT_PERIOD - event.time_offset + phase_offset); if (distance < min_distance) { min_distance = distance; nearest_event = event; } } return nearest_event; } }; // 测试函数 void test_gait_sequence() { EndEffectorPlanner planner; std::cout << "===== Test Cases ====="; // 测试用例1:起始时间正好在事件点上 std::cout << "\n\nTest 1: Start at 0.0"; auto seq1 = planner.get_gait_sequence(0.0); planner.print_sequence(seq1); // 测试用例2:起始时间在两个事件点之间 std::cout << "\n\nTest 2: Start at 0.22"; auto seq2 = planner.get_gait_sequence(0.22); planner.print_sequence(seq2); // 测试用例3:起始时间接近周期结束 std::cout << "\n\nTest 3: Start at 0.95"; auto seq3 = planner.get_gait_sequence(0.95); planner.print_sequence(seq3); // 测试用例4:负起始时间 std::cout << "\n\nTest 4: Start at -0.3"; auto seq4 = planner.get_gait_sequence(-0.3); planner.print_sequence(seq4); // 测试用例5:超大起始时间 std::cout << "\n\nTest 5: Start at 100.22"; auto seq5 = planner.get_gait_sequence(100.22); planner.print_sequence(seq5); } int main() { test_gait_sequence(); return 0; } 运行
09-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值