简介这份PDF文档是Marc H. Raibert所著《Legged Robots that Balance》的中文译介围绕足式机器人动态平衡与奔跑控制展开面向机器人学、控制算法与人工智能方向的学习者和研究者。文档从20世纪70年代MIT的步行运动探索讲起回顾弹性腿、弹跳杆机器人到Leg实验室的研发脉络并系统讨论主动平衡、运动控制分解、动力学建模、传感器融合与反馈闭环等关键技术兼顾理论框架与机器实验记录。压缩包内仅含1个PDF文件大小约7.13MB篇幅完整、便于检索与离线阅读。目前已有395人学习适合作为足式机器人平衡算法的入门导读与专题参考。读者可从中梳理该领域的发展线索理解单腿跳跃、三维运动与多腿奔跑的控制思路并借助书中的实验案例和目录结构为算法选型、课程学习或科研选题建立较完整的知识坐标。1. 主动平衡为什么跑得稳的机器人每一刻都在「倒」把一台四足机器人加速到小跑速度慢放它的质心轨迹会看到一个反直觉的画面大部分时间里质心并不在支撑足的正上方某些时刻甚至跑到了支撑多边形之外。按静态稳定的判据它每一刻都在摔可它偏偏没摔。这就是足式机器人平衡算法的核心结论——稳定不是靠「把质心按住不动」而是靠「承认它会倒然后每个周期用一次落足把倒的方向掰回来」。静态稳定的机器靠足够大的支撑域兜底主动平衡的机器靠倒下去的时间足够短、纠正来得足够快。这份关于足式机器人平衡的经典资料讲的就是这套思路最早的系统化推导从单腿弹跳台架到三维奔跑再到双足与四足的降维复用每一步都在回答同一个问题——动态系统里控制律能简化到什么程度还依然 work。搞懂它值得因为几乎所有后来的腿式机器人、平衡车、乃至人形机器人的行走控制都能在这里找到最初的那几个假设。2. 三段分解跳跃高度、前进速度和身体姿态凭什么能各算各的面对一个多关节、欠驱动、还带弹性的动态系统直觉做法是建一个大模型把所有状态塞进一个最优控制器里统一求解。这份资料走的是完全相反的路把奔跑拆成三个几乎互不干扰的子问题——跳多高、跑多快、身体保持什么姿态每个子问题配一个独立的、各自简单到可以在纸上一行写完的控制律。这个分解不是什么工程妥协它基于两条硬理由。第一条是时间尺度分离垂直方向的弹跳周期在几百毫秒量级前进速度的调节以「一次支撑相」为节拍而姿态误差必须在几十毫秒内压住三个环的带宽差了一个数量级耦合项在频域上被自然滤掉了。第二条是执行器分工高度靠腿的伸缩改变支撑力大小速度靠落足点的前后位置改变支撑力方向和作用时长姿态靠髋部力矩改变机体角动量。三个控制量对应三组不同的物理通道才可以分开算。2.1 弹跳循环里的状态机为什么用事件推进而不是定时器动态腿式系统的运动是周期性的但这个周期不是常数。腿压得深一点支撑相就长一点地面软一点飞行相就短一点。如果控制律按固定时间片去安排「现在是支撑相第 30 毫秒该做什么」那么第一次扰动就会让时钟和物理现实错位之后所有动作全部对不上相位。所以这类系统的骨架是一个事件驱动的状态机四个事件把循环切成四段触地、压缩到底垂直速度由负转正、离地、到达顶点垂直速度过零。每个事件只做一件事记录一个状态量或者切换一次控制模式。# 弹跳循环的状态机骨架状态只由物理事件推进没有定时器 FLIGHT, STANCE 0, 1 class HopFSM: def __init__(self): self.state FLIGHT self.z_apex None # 飞行相顶点高度用于评估上一跳的能量 self.z_bottom None # 支撑相最低点推力从这里开始施加 def step(self, z, zdot, contact): if self.state FLIGHT: # 飞行相不施加任何主动控制只观察 if self.z_apex is None and zdot 0: self.z_apex z # 顶点垂直速度换向 if contact: self.state STANCE # 触地事件 self.z_bottom None else: # 支撑相等压缩到底再发力避免落地瞬间硬顶造成冲击 if self.z_bottom is None and zdot 0: self.z_bottom z if not contact: self.state FLIGHT # 离地事件 self.z_apex None return self.state这段代码里最关键的两个参数不是数值而是时机。z_apex必须在垂直速度换向的那一刻采因为只有在这一刻全部机械能才等价于重力势能用高度就能反推能量。z_bottom必须等到压缩到底才允许推力介入否则落地冲击和主动推力叠加关节力矩会瞬间打满。判断contact的信号来源通常是足底接触开关或者腿长突变两者都有几毫秒抖动实际实现里要做去抖否则状态机会在触地瞬间反复横跳。2.2 高度控制把「跳多高」翻译成「注入多少能量」高度控制的难点在于支撑相极短。一条腿从触地到离地可能只有一百多毫秒想在这段时间里让质心跟踪一条平滑的 z(t) 参考轨迹需要很高的位置增益而高增益遇到落地冲击就是电流饱和加机械抖动血泪经验基本都是这么来的。替代方案是放弃轨迹跟踪改成能量记账。一个跳跃周期里系统的机械能在动能、重力势能、腿部弹性势能之间来回倒手下落时势能变动能触地时动能变弹性势能回弹时再变回动能和势能。控制目标其实是「让这一跳的总能量等于目标能量」至于中间怎么分配交给物理自己去完成。实现的写法很朴素在触地瞬间测一次垂直速度算出本次循环的入射能量与目标能量的差在压缩行程内用一次恒力补偿掉。def height_force(m, zdot_in, zdot_target, stroke, k_leg0.0): # 触地瞬间动能 ≈ 本周期可用于弹跳的总机械能顶点处全部为势能 e_in 0.5 * m * zdot_in ** 2 e_ref 0.5 * m * zdot_target ** 2 # 能量缺口在压缩行程内以恒力补偿stroke 越大单次推力越小、越平缓 dE e_ref - e_in return dE / max(stroke, 1e-3)stroke是预期的腿部压缩量它决定了同样的能量缺口需要多大的力也决定了推力对时间的分布是否平缓。zdot_target不是直接给定的通常由目标跳跃高度反推zdot_target sqrt(2*g*h_des)但如果腿上有弹簧弹簧在离地时仍储存一部分能量这个反推要做一次修正修正系数跟弹簧刚度和离地时的腿长有关。这一点在做实物时特别容易被忽略仿真里调好的高度一到台架上就偏低原因就在这里。能量法真正的价值在于它天然带反馈地面软、腿打滑、电池电压掉这些都会体现在触地速度上控制律自动把差额补回来不需要单独建模。这也是「复杂动态系统的简单控制」最典型的一次体现。2.3 速度控制不解微分方程只解一个落点水平方向的控制比垂直方向更微妙。垂直方向有弹簧和执行器直接作用水平方向没有——腿在支撑相内对质心施加的水平力方向和大小都取决于「脚相对质心在什么位置」。换句话说唯一能连续调节的输入量是落足点。于是速度控制退化成一个几何问题这一脚该落在哪儿答案不需要求解完整动力学方程只需要利用一个近似——支撑相内质心绕足端做倒立摆运动水平位移和水平速度的比值近似恒定。据此可以反推出一个落点使得支撑相结束时水平速度恰好不变这个点就是中性点。偏离中性点多少速度就改变多少。这段推导放在下一章展开因为它值得单独说清楚它把一个动力学控制问题压缩成了一个只含位置和速度的线性反馈式而且这个反馈式里的增益有明确的物理量纲可以直接照着量纲去调。3. 落足点算法为什么脚落在哪儿就等于写了一个速度控制器「控制速度」这件事在轮式系统里是给电机发一个转速指令在腿式系统里没有对应的物理量——没有哪个关节直接对应「前进速度」。这份资料的处理方式是把速度误差映射成落足点的偏移让物理过程自己去完成剩下的部分。3.1 中性点脚落在正下方为什么反而越跑越快先做一个思想实验。假设机器人以速度 v 前进脚恰好落在质心正下方。触地之后质心继续向前运动脚相对质心越来越靠后。支撑相前半段地面反力的水平分量向后质心减速支撑相后半段质心越过足端反力水平分量向前质心加速。这两段是否抵消不会完全抵消因为前半段质心离足端近、重力分量小后半段质心离足端远、重力分量大净效果是向前的冲量更多。结果就是每落一次脚速度涨一点越跑越快直到飞出去。中性点就是那个让净冲量为零的位置它在质心正前方距离约等于「速度乘以支撑相时长的一半」。这个结论只用到两个量当前速度、支撑相持续时间。不需要质量不需要惯量不需要关节力矩模型。3.2 一阶线性化把落足点写成一个反馈增益在中性点附近做一阶展开支撑相结束时的速度变化近似正比于落足点相对中性点的偏移。于是控制律只有一行def foot_placement(x, xdot, xdot_des, T_stance, k_ff1.0, k_v0.15): # 中性点支撑相内净水平冲量为零的落足位置正比于速度与支撑时长 x_neutral x k_ff * xdot * T_stance / 2.0 # 速度误差也折算成落点偏移k_v 的量纲是秒表示每 1 m/s 的误差挪多远 return x_neutral k_v * (xdot - xdot_des)k_ff是对理想模型的修正系数实物上永远不等于 1因为支撑相内腿不是刚性杆、质心高度在变、地面有形变实测一般落在 0.7 到 1.2 之间。k_v的量纲是时间这个细节很重要它不能随便调大物理上它的合理上限大约是半个支撑相时长超过这个值落足点会摆到中性点之外太远系统从一个速度环变成一个振荡器。很多调试记录里「速度在目标值附近持续摆动、越调增益越糟」都是因为把k_v当成无量纲增益在拧。这张表可以作为调参时的锚点参数物理含义量纲偏大时的现象偏小时的症状k_ff中性点前移量的修正系数无量纲低速时前倾、高速时刹不住每步加速速度单调爬升k_v速度误差到落点偏移的换算秒速度振荡落足点左右横跳速度收敛极慢抗扰差T_stance支撑相时长估计秒高速段落点过前抬腿打空落点偏后越跑越拖3.3 三维扩展俯仰和滚转为什么可以分开处理平面里的落足点只有一个自由度三维里机体还要处理俯仰前后倾和滚转左右倾。这两个方向的处理方式不对称原因在重力。俯仰方向重力和前进加速度同向倒立摆模型直接适用落足点的前后位置同时管速度和俯仰两者通过同一个输入耦合在一起。这时的常见做法是把俯仰目标设成一个与加速度相关的小角度让机身略微前倾来配合加速而不是硬把姿态锁在水平——锁死会强迫落足点做剧烈前后移动反而牺牲速度跟踪。滚转方向没有持续的外部加速度驱动横向的倒立摆是「不稳定但可控」的一旦横向速度建立起来靠落足点前后移动是修不回来的必须用髋部力矩主动施加横向力。所以三维系统的横向控制通常是两层落足点负责把脚放到质心投影线附近提供支撑髋部力矩负责在支撑相内把横向速度拉回零。这两层如果都用落足点来实现就会出现「脚越落越靠外、机身却越来越歪」的典型翻车现象。三维运动学里还有一个容易被忽略的细节当腿从髋部向外伸展时足端在水平面的投影位置会随腿长变化落足点的计算必须用实际足端位置而不是关节角度否则腿越长、误差越大跑圆形轨迹时会往外漂。这也是为什么这类系统的运动学解算部分通常要单独写一个模块而不是塞在控制律里边算边用。4. 虚拟腿两条腿、四条腿怎么被压缩成一条腿来算单腿的控制律写清楚之后双足和四足的问题并没有自动解决——四条腿同时着地时每条腿该出多少力如果给每条腿单独设计一套控制律参数会爆炸而且腿与腿之间会互相抢。这份资料给出的答案是虚拟腿把同时支撑的 n 条腿等效成一条从质心指向某个虚拟足端的腿先在这条虚拟腿上做控制再把力分配回真实关节。4.1 虚拟腿的定义把 n 条支撑腿折成一条指向质心的腿虚拟腿的两个自由度正好对应两个控制目标腿的长度对应高度或支撑力大小腿的方向对应姿态和速度。这一步降维之所以成立前提是所有支撑腿的触地相位一致、且各自的力可以按几何关系分配到同一条虚拟腿上。单腿系统天然满足这个前提。双足的对角支撑一条腿在前、一条腿在后同时触地也近似满足。四足的小跑步态里对角的两条腿同时触地、同时离地另外对角的两条腿相位差半个周期整机在任何时刻都恰好有两条腿构成一条虚拟腿。这就是为什么四足能直接套用单腿的控制器——它本质上就是一个「左右交替的单腿弹跳系统」只不过虚拟足端的落点由两条腿共同实现。步态同时触地腿数虚拟腿数量对单腿控制律的复用程度单腿弹跳11直接复用双足对角跑21复用落点需投影到两足中点四足小跑2对角1交替两根虚拟腿复用左右虚拟腿各一套相位四足慢走34不稳定不适用需退回静平衡判据4.2 力分配与雅可比转置末端力怎么落到关节力矩上虚拟腿算出的是一个期望的足端力不是关节力矩。两者之间的映射用雅可比转置完成这也是整个框架里唯一需要认真算矩阵的地方。import numpy as np def virtual_leg_torque(J_list, F_virtual, weights): J_list : 各支撑腿的足端雅可比3xNN 为该腿关节数 F_virtual : 虚拟腿期望足端力世界坐标系3x1 weights : 各支撑腿的分力权重和为 1按触地相位或腿长动态分配 tau [] for J, w in zip(J_list, weights): F_i w * F_virtual # 虚拟力按权重拆到每条真实腿 tau.append(J.T F_i) # 雅可比转置末端力 - 关节力矩 return tau权重weights的分配有讲究。最简单是平均分但两条支撑腿的腿长往往不同腿短的那条刚性更大、能承受更多力平均分会让它过载。常见做法是按腿长的倒数归一化或者按各腿的垂直刚度加权。另外雅可比必须在同一个坐标系下计算——通常统一到机体系力也变换到机体系再做乘法否则当机身有俯仰角时分配出来的力矩会有系统性偏差表现为机器人越跑越往前趴。雅可比转置的物理意义值得多说一句它保证虚拟力做的功与各关节力矩做的功相等也就是能量守恒。这个性质让「先算末端力、再映射到关节」这条路在动力学上是自洽的不需要额外补偿。代价是没有考虑腿本身的质量和惯量所以当腿比较重、摆动比较快时末端力和实际关节力矩之间会有偏差这也是后面避坑章节里会提到的一条。4.3 对角步态与相位为什么四足跑起来像两条腿对角步态的选择不是随意的。当对角的两条腿同时触地它们构成的支持多边形的中心最接近质心在水平面的投影。这意味着虚拟足端几乎就在质心正下方虚拟腿接近竖直此时的俯仰和滚转耦合最小姿态控制可以独立处理。如果改用同侧腿同时触地类似侧对步虚拟足端会偏到质心一侧虚拟腿有一个固定的倾角这个倾角会在支撑相内产生持续的滚转力矩姿态环必须实时对抗一个偏置控制难度陡增。这也是为什么大多数四足机器人默认小跑而不是侧对步——不是侧对步不能跑是它的虚拟腿模型不再是「一条从质心垂直向下的腿」前面所有的简化都失效了。相位管理上左右两条虚拟腿各有一套完整的高度和速度控制器它们的输出由同一个「相位协调器」错开半个周期。协调器只需要保证一件事前一条腿离地之后后一条腿才触地中间允许有短暂的飞行相。这个飞行相的长度直接决定了机器人的「弹跳感」飞行相越长越像奔跑越短越像快走。4.4 姿态控制为什么用髋部而不是踝虚拟腿模型把真实腿当成无质量的连杆力只能沿腿的方向传递。要产生一个绕机体质心的力矩最直接的办法是让虚拟腿的方向偏离质心——虚拟力不通过质心自然产生力矩。这个「偏离」是通过髋部关节实现的踝关节在这里帮不上忙因为它改变的是足端相对腿的方向不改变力的作用线。这带来一个设计上的取舍髋部做姿态意味着虚拟腿必然有一定的倾角倾角会分掉一部分垂直支撑力垂直分量是 F·cosθ。姿态修正越猛倾角越大可用于支撑高度的力就越少。实机上表现为「一加姿态修正跳跃高度就掉」——不是高度控制器坏了是姿态环把力借走了。常见的处理是给姿态环的输出加一个上限或者把姿态环的带宽设得比高度环高一个量级让它只在瞬态起作用稳态时倾角趋近于零。5. 调试排查动态平衡系统最容易翻车的五个地方理论上的解耦在实物上会打折扣下面这五条是按「现象—原因—解决」记录下来的高频问题顺序大致对应调试的先后先让高度环稳住再调速度环最后处理耦合。5.1 控制律层面的三个坑第一条上电后腿在支撑相里拼命追一条参考轨迹落地瞬间电流打满、整机弹飞。原因在于把位置跟踪的思路照搬到了动态系统——支撑相只有一两百毫秒参考轨迹的初值又和实际触地状态对不上误差一开始就很大高增益直接把控制量推到饱和。解决方式是把高度环从位置跟踪换成能量补偿触地瞬间测一次垂直速度算出能量缺口在压缩行程内用恒力补掉。控制量的峰值立刻降下来落地冲击也变得可预测。第二条速度在目标值附近持续振荡加大落足点增益只会让振荡更剧烈。原因有两个一是落足点用的是实时速度而实时速度的估计本身有十几毫秒延迟延迟加高增益就是振荡器二是增益k_v的量纲是时间随手拧到 0.5 秒以上就超过了半个支撑相物理上已经不允许。解决办法是改用触地时刻的速度做落足点决策整个支撑相内保持不变并且把k_v限制在半个支撑相以内。如果还是振荡先怀疑状态估计而不是控制律。第三条跳得越高高度反而越不受控最后发散。原因是模型里把腿当成了无质量的弹簧实际腿有质量飞行相收腿时质心位置会变用顶点高度反推能量的换算关系随跳跃高度漂移。跳跃高度越大收腿越深偏差越大。解决办法是把腿的折算质量并进能量模型或者干脆放弃顶点高度直接用触地瞬间的垂直速度做反馈量——后者更稳因为它绕过了对腿姿态的假设。5.2 状态估计与机械层面的两个坑第四条姿态环一开高度就跟着抖两个环互相抢。现象是俯仰角收敛了但跳跃高度出现周期性波动。原因在虚拟腿的力分配——姿态修正让虚拟腿倾斜垂直分力变小高度环看到高度不够就加大总力总力加大又让姿态修正的力矩变大形成正反馈。解决办法是带宽分离姿态环的响应频率设成高度环的三到五倍让它在高度环反应过来之前就把倾角拉回去同时给姿态输出加限幅保证倾角不超过十度左右垂直分力的损失控制在百分之一点五以内。第五条换了地面之后速度控制整体失效从橡胶垫换到光滑地面机器人开始原地打滑、速度估计漂移。原因是落足点算法默认支撑相内脚不打滑一旦打滑质心的实际位移与模型预期不符而速度估计又是从质心位移推出来的误差会累积。解决办法是引入触地时刻的速度校正每次触地时用机身惯性测量单元积分的速度做一次重置打滑检测则比较支撑相内足端相对机身的位移与模型预测值偏差超阈值就标记本次支撑相为「低置信」落足点控制退回中性点保守策略。这类打滑在仿真里几乎不会出现一到实物就是主要误差源摔几次之后就知道了。6. 对称性与表格控制一次关于「少算一点」的设计取舍把单腿的控制器复用到双足、四足之后还有一个隐藏的复杂度左右腿的参数是不是要各调一套严格来说是的因为机械加工有公差、电机有差异。但这份资料里有个很实用的观察——腿式运动的解在对称变换下是不变的把左腿的状态做一次镜像就得到右腿的等价状态同一套控制律可以直接吃两边。这个观察的价值不在数学优雅在于调试成本。如果左右腿各调一套参数那么任何一次改动都要在两个地方验证出问题时还要判断是参数问题还是耦合问题。用对称性把两套压成一套参数空间直接砍半而且镜像变换本身会曝露不对称的 bug——如果镜像之后行为不一致说明某处的符号或者坐标定义错了这比逐条对比日志高效得多。对称性之外还有一次取舍体现在「表格控制」这条支线上。理论上给定性能指标比如最小能量、最小峰值力矩可以离线把最优控制律算出来做成一张以状态为索引的表运行时只做插值和查表。这样做的好处是能把非线性、约束、甚至执行器饱和都提前算进去运行时算力几乎为零代价是表的维度随状态数指数增长而且一旦机械参数变了换电机、加配重整张表要重算。维度解析控制律表格控制运行时算力每周期几十次浮点运算几次查表加插值参数变化适应性改系数即可秒级需离线重算整表可解释性每项有物理含义只能看插值曲面非线性与约束需手动近似可完整编码调试难度参数少好定位表边界处易出现跳变我的判断是这两种方式不是替代关系。解析律适合做「骨架」保证在任何状态下都有一个合理的、不会发散的输出表格适合做「修正项」在解析律的基础上补掉那些模型没覆盖的偏差比如腿质量的惯性影响、地面刚度变化。纯表格的系统在训练工况内表现很好一旦越界就完全没有兜底这在实物上很危险。验证方法上我一般会做两步第一步是把解析律和表格在同一批状态点上对拍看两者的输出差异分布差异大的区域就是模型缺失的部分第二步是在实物上做「扰动-恢复」测试用固定能量侧向推一下机身看恢复过程的超调量和恢复时间这两个指标比轨迹跟踪误差更能反映动态平衡的真实品质。这套东西我在早期项目里吃过一次亏仿真里调好的小跑参数直接上实物机器人跑了三步就往前栽。事后复盘发现是落足点的前馈系数在仿真里恰好补偿掉了腿质量带来的偏差换了电机之后腿变重了系数不再匹配。从那以后我每次上线新的步态参数都强制先用单腿台架把完整弹跳循环跑满一百次确认高度、速度、姿态三个环各自的收敛曲线都干净才允许上四足。希望帮到你。本文还有配套的精品资源点击获取