简介:这份 Word 文档是北京汉库科技 HGR-3HV-C 双足机器人步伐源代码手册的整理稿,面向从事嵌入式机器人开发、步态控制研究的工程师与学生,帮助其读懂厂商源代码、理解运动控制机制并据此调参优化。文档以步伐函数为主线,逐段拆解初始站立、双腿下蹲、起立及侧身等动作的第 1、2 族变速子程序,涉及关节角度、电机速度与重心变化的协同控制,为定制行走模式、提升动态性能与能源效率提供依据。压缩包内共 1 个 doc 文件,约 9.07MB,页面含目录与逐页页码标注,便于按章节定位查阅;其中也涉及姿态检测、传感器融合、动力学模型与控制算法等配套组件。目前已有 478 人学习,适合具备一定嵌入式基础、希望从源码层面理解双足机器人步态实现的读者研读。
1. 双足机器人设计不是画腿:一份设计文档该有的骨架
很多人接到「双足机器人设计.doc」这个题目,第一反应是打开三维软件画两条腿,画完才发现关节装不下、电机选大了、整机站上去三秒就趴下。双足机器人设计的难点从来不在建模,而在于把自由度构型、连杆尺寸、关节选型、步态时序、稳定性判据这五件事写进同一份文档,并且让它们互相对得上。这份文档要能回答三个问题:腿多长、关节多大、走路时质心往哪挪。它适合做机器人方向课程设计的学生、做具身智能原型的小团队,以及把玩具级双足改到能连续走十步的开发者。下面按一份真实可落地的设计文档顺序往下拆,参数都给到能直接抄的程度。
2. 自由度与构型先定死:12 自由度方案怎么落到图纸上
构型一旦定错,后面所有参数都是白算。这一章只解决一件事:把「几条腿、每条腿几个关节、每个关节转哪个方向」写成一张谁看都一样的表。
2.1 关节拓扑与自由度分配的取舍
小型双足最常见的起点是单腿 6 自由度、整机 12 自由度:髋关节 3 个(pitch 前后摆、roll 侧摆、yaw 转向)、膝关节 1 个(pitch)、踝关节 2 个(pitch、roll)。这个分配不是凑数,髋 roll 负责把摆动腿甩到侧向落点,踝 roll 负责把支撑脚的 ZMP 推向内侧,两者一配合才有侧向稳定裕度。
砍到 5 自由度(踝只留 pitch)的腿能省一个电机和一套减速器,代价是侧向稳定完全靠髋 roll 加大步宽来兜,步宽一加,髋 roll 的力矩需求翻倍,横滚方向的振荡也更难压。原地转向同样做不了,因为缺少髋 yaw,只能靠双脚交替蹭。反过来说,加到 7 自由度(踝加 yaw 或膝加 roll)对 3~5 kg 的小机器几乎没有收益,多出来的关节反而增加零位标定和线束布置的麻烦。
| 构型 | 单腿自由度 | 优点 | 代价 | 适用场景 |
|---|---|---|---|---|
| 平面双足 | 4(髋 pitch、膝 pitch、踝 pitch + 髋 roll) | 电机少、控制简单 | 只能前后走,侧向靠步宽硬撑 | 教学演示、步态算法验证 |
| 标准 12 自由度 | 6 | 前后侧向都能调,可原地转向 | 关节多,标定和线束复杂 | 大多数小型双足原型 |
| 加腰 13 自由度 | 6 + 腰 yaw | 转向时上身可反向补偿 | 腰部刚度要求高,多一级标定 | 需要灵巧转向的场景 |
对刚起步的方案,我一般建议先锁 12 自由度,把腰部留成刚性连接但预留安装孔,等步态跑稳了再决定要不要加腰。
2.2 从构型到连杆参数表:一张能复现的尺寸表
连杆尺寸不能凭感觉。以腿长 L(髋关节轴线到脚底)为基准归一化,大腿长和小腿长通常取接近 1:1,大腿略长 0~10%,这样膝关节在站立相接近伸直但不完全锁死,避免奇异位形导致逆解跳变。脚长按 0.3L 左右取,太长会增加踝关节峰值力矩,太短则支撑多边形面积不够,ZMP 裕度被压到 1 cm 以内。
下表是一台腿长 0.40 m、整机 3.5 kg 的小型双足的实际取值,直接照抄后按比例缩放即可。
| 参数 | 符号 | 取值 | 与腿长 L 的关系 | 影响 |
|---|---|---|---|---|
| 大腿长 | L1 | 0.200 m | 0.50L | 与 L2 接近时膝关节力矩最小 |
| 小腿长 | L2 | 0.200 m | 0.50L | 决定踝关节到膝的力臂 |
| 踝关节高度 | h_a | 0.050 m | 0.125L | 越低越稳,但脚掌空间受限 |
| 脚长 | l_f | 0.130 m | 0.325L | 支撑多边形前后长度 |
| 脚宽 | w_f | 0.070 m | 0.175L | 支撑多边形左右宽度 |
| 髋宽(两髋轴线间距) | d_h | 0.160 m | 0.40L | 决定步宽下限 |
| 整机质量 | m | 3.5 kg | — | 关节扭矩计算的输入 |
| 站立质心高度 | h | 0.280 m | 0.70L | 决定倒立摆时间常数 |
质心高度这一行最容易被忽略。线倒立摆的时间常数是 √(h/g),h = 0.28 m 时约 0.169 s,意思是质心一旦偏离 ZMP 参考点,偏差按指数发散,特征时间不到 0.2 s。这就是为什么双足的平衡环必须跑到 200 Hz 以上,低于这个频率,控制器还没反应过来,机器已经倒了。
2.3 关节选型:扭矩、转速、减速比三件套怎么算
关节选型分三步,顺序不能反。
第一步算静态保持扭矩。支撑相单腿承受整机重量,膝关节的力臂取踝关节到膝关节轴线的最大水平距离。整机 3.5 kg 即 34.3 N 的重力,力臂 0.08 m,静态扭矩约 2.7 N·m。第二步乘峰值系数,双足在落地冲击和快速摆动时扭矩会冲到静态值的 2.5~3 倍,取 2.8,得到 7.6 N·m,向上取整到 8 N·m。第三步算转速:步态周期 0.8 s、摆动相 0.32 s、摆腿角度行程约 60°(1.05 rad),平均角速度约 3.3 rad/s,即 31 rpm;峰值按 2 倍留,取 60 rpm 输出端。
减速比按 i = 电机额定转速 / 关节需求峰值转速 反推。以额定 3000 rpm 的电机配 60 rpm 输出端,i ≈ 50。这里有个取舍:减速比越大扭矩越够,但反驱能力越差。踝关节需要吸收落地冲击,反驱能力不能太低,我一般把踝的减速比压到 20~30,剩下靠电机本身的峰值扭矩补。
| 关节 | 峰值扭矩 | 输出峰值转速 | 减速比 | 备注 |
|---|---|---|---|---|
| 髋 pitch | 8 N·m | 60 rpm | 50 | 摆动腿 + 躯干质量 |
| 髋 roll | 6 N·m | 50 rpm | 50 | 侧向甩腿 |
| 髋 yaw | 3 N·m | 40 rpm | 80 | 转向时阻力大 |
| 膝 pitch | 8 N·m | 60 rpm | 50 | 支撑相主力 |
| 踝 pitch | 5 N·m | 50 rpm | 30 | 需保留反驱 |
| 踝 roll | 3 N·m | 40 rpm | 30 | 需保留反驱 |
编码器分辨率按「关节角分辨率优于 0.05°」倒推。关节端 0.05° 对应输出端一圈 7200 分度,如果编码器装在电机端,乘减速比 50 后等效分辨率会被放大 50 倍,14 位(16384 线)绝对编码器就够用,但前提是减速器背隙要小,背隙超过 0.5° 时编码器再准也没意义,因为机械端已经丢了。
3. 逆运动学与步态时序:把「走路」拆成可算的轨迹
构型和尺寸定完,接下来要把「抬脚、迈步、落地」翻译成每一时刻的六个关节角。这一章给的是能直接跑通的最小实现。
3.1 单腿逆运动学:髋-膝-踝的解析解与代码
矢状面内,髋、膝、踝三个 pitch 关节构成一个两连杆机构(踝 pitch 只影响脚掌姿态,不参与腿长解算)。给定踝相对髋的位置,用余弦定理直接解,不需要迭代。
import math def leg_ik_sagittal(x, z, L1, L2): """矢状面两连杆逆解。 x: 踝相对髋的前向距离 (m),向前为正 z: 踝相对髋的垂直距离 (m),向下为正 L1: 大腿长, L2: 小腿长 返回 (hip_pitch, knee_pitch),单位 rad,屈膝为负 """ d = math.hypot(x, z) # 限幅:目标点超出可达范围时,收敛到最大伸展的 99.9% d = min(d, (L1 + L2) * 0.999) d = max(d, abs(L1 - L2) * 1.001) # 余弦定理求膝角 cos_knee = (L1 * L1 + L2 * L2 - d * d) / (2 * L1 * L2) cos_knee = max(-1.0, min(1.0, cos_knee)) # 防 acos 定义域越界 knee = -math.acos(cos_knee) # 屈膝取负,与关节方向约定一致 # 髋角 = 目标方向角 + 大腿与目标连线的夹角 alpha = math.atan2(x, z) cos_beta = (L1 * L1 + d * d - L2 * L2) / (2 * L1 * d) cos_beta = max(-1.0, min(1.0, cos_beta)) beta = math.acos(cos_beta) hip = alpha + beta return hip, knee代码里有三处限幅,每一处都对应一次实际翻车。d的上限防的是站立相膝关节被指令到完全伸直,此时cos_knee恰好等于 -1,再小一点就进入acos定义域外,返回 NaN,电机收到 NaN 会直接失控。d的下限防的是抬脚过高时踝关节贴到髋部,腿长退化为 |L1−L2|。cos_knee和cos_beta的钳位是浮点误差的最后一道保险,math.acos(1.0000000002)同样会抛异常。
踝 pitch 角由脚掌姿态决定:ankle = -(hip + knee) + pitch_desired,其中pitch_desired是希望脚掌相对地面的俯仰角,支撑相取 0 保持脚掌贴地,摆动相按落脚角度给一点前倾。这一行看起来简单,但符号搞反是新手最常见的错误,表现为机器一迈步脚掌就朝天。
3.2 步态时序表:一个周期里每条腿在干什么
步态参数决定走起来是「稳」还是「僵」。下面这组参数在 3.5 kg 小机器上跑得比较顺,可以直接作为初值。
| 参数 | 取值 | 说明 |
|---|---|---|
| 步态周期 T | 0.8 s | 越小越快,但摆动相时间被压缩 |
| 单腿支撑相占比 | 0.60 | 双支撑相合计 0.20 |
| 双支撑相占比 | 0.10(每段) | 小于 0.05 时容易在换脚瞬间失稳 |
| 步长 | 0.10 m | 约 0.25L,超过 0.35L 后 ZMP 裕度急剧下降 |
| 抬脚高度 | 0.04 m | 够越过地面不平即可,越高摆动时间越紧 |
| 步宽 | 0.14 m | 比髋宽略窄,靠踝 roll 把 ZMP 推向内侧 |
| 质心高度(行走) | 0.26 m | 比站立低 2 cm,换取稳定裕度 |
时序上,一个周期分成四段:左腿支撑 + 右腿摆动、双支撑、右腿支撑 + 左腿摆动、双支撑。双支撑段虽然只占 0.08 s,却是整个步态里最容易出事的位置,因为两条腿同时接地时,支撑多边形从单脚变成两脚,ZMP 可以在这片区域里自由移动,一旦规划器没把质心按时推到新支撑脚上方,换脚瞬间就会侧倾。
3.3 足端轨迹:摆线比样条更好调
摆动腿的足端轨迹我一般用摆线,不用三次样条。摆线的好处是起止点速度严格为零、加速度连续,落地冲击小;样条虽然可以任意指定中间点,但边界条件一改就要重新解方程,调参时很麻烦。
摆线的水平与垂直分量:
- 水平:
x(t) = x0 + (x1 - x0) * (t/Ts - sin(2π t/Ts)/(2π)) - 垂直:
z(t) = z0 + H * (1 - cos(2π t/Ts)) / 2
其中 Ts 是摆动相时长,H 是抬脚高度,t 从 0 到 Ts。垂直分量在 t = Ts/2 处达到最高点,此时水平速度最大,正好对应腿从后往前甩的中段。这个「速度最大」的时刻是踝关节反驱能力最吃紧的时刻,如果踝减速比选得太大,腿甩到中段会有明显顿挫。
摆动相结束前的 20% 时间里,我会把足端轨迹从摆线平滑切到一条朝向落点的直线,速度按落地速度(约 0.15 m/s)给,避免足端在触地瞬间还带着水平速度蹭地。这个细节不做,脚掌橡胶垫会很快磨出斜面。
3.4 从关节角到电机指令:位置环加力矩前馈
关节角算出来只是目标值,真正下发到电机还要过一层。位置环用 PD,但纯位置环在支撑相会有一个问题:腿部承重时关节被压下去一点,位置误差始终存在,PD 会持续输出一个偏大的力矩,表现为站立时机身轻微下沉后再弹起。
解决办法是加重力补偿前馈。按当前关节角算出各连杆质心位置,用雅可比矩阵把重力矩映射回关节空间,作为前馈项直接叠加到 PD 输出上。位置环只负责修正模型误差,增益可以调低,超调明显减小。这套做法在仿真里看不出差别,实机上站着不动时的机身晃动会小一半。
控制频率上,逆解和轨迹生成跑 200 Hz 就够,但电流环和重力补偿要跑到 1 kHz,两个频率分开放在不同任务里。把逆解塞进 1 kHz 循环是常见的资源浪费,一次逆解连同三角函数大概几十微秒,看似不多,但挤占了电流环的时间片,反而拖累响应。
4. 稳定性判据:ZMP、支撑多边形与线性倒立摆
步态轨迹能走,不代表走得稳。判断「稳不稳」需要一个可量化的指标,双足领域最通用的就是零力矩点。
4.1 线性倒立摆:把整机压成一个质心
整机十几个连杆,直接做动力学分析方程会爆炸。工程上先做一个简化:把所有质量等效成一个位于质心、长度等于质心高度的倒立摆,质心以上部分视为刚体,忽略腿的摆动惯量。这个近似在步频不高、腿质量占比小于 30% 时误差可以接受。
线性倒立摆的运动方程是ẍ = (g/h)(x - p),其中 x 是质心水平位置,p 是 ZMP 位置,h 是质心高度。这个方程是线性的,意味着给定 ZMP 轨迹,质心轨迹可以解析求出;反过来给定质心轨迹,也能反解出需要的 ZMP。步态规划就是在两者之间来回倒腾。
4.2 ZMP 计算与稳定裕度
实机上 ZMP 靠足底力传感器或者踝关节力矩反算。用六维力传感器时,公式很直接:
def zmp_from_foot(F, T, origin_xy, fz_threshold=20.0): """由足底六维力传感器计算 ZMP。 F: (Fx, Fy, Fz),合力,单位 N T: (Tx, Ty, Tz),以传感器原点为参考的合力矩,单位 N·m origin_xy: 传感器原点在世界系下的 (x, y),单位 m fz_threshold: 判定腾空的垂直力阈值,单位 N 返回世界系下的 (x, y),腾空时返回 None """ Fx, Fy, Fz = F Tx, Ty, Tz = T if abs(Fz) < fz_threshold: return None # 腾空相 ZMP 无定义 x = origin_xy[0] - Ty / Fz # 符号约定:绕 y 轴力矩对应前后 y = origin_xy[1] + Tx / Fz # 绕 x 轴力矩对应左右 return x, y符号约定必须跟传感器安装方向对齐,装反了 ZMP 会在屏幕上正常跳动,但方向和实际相反,排查时极其费劲。建议第一次装好后用手在脚掌前部按压,ZMP 应该往按压点方向移动,不符合就调符号。
ZMP 算出来要和支撑多边形比对。稳定裕度定义为 ZMP 到支撑多边形边界的最短距离,工程上取 15~25 mm 比较合适。低于 10 mm 时,传感器噪声和地面不平就能把 ZMP 推出多边形,表现为机身突然抽一下;高于 30 mm 时,机器会显得「蹲着走」,质心大幅左右摆,能耗和关节磨损都上去了。
| 稳定裕度 | 行走表现 | 适用阶段 |
|---|---|---|
| < 10 mm | 频繁抽搐,地面稍不平就倒 | 不可用 |
| 15~25 mm | 平稳,允许小幅地面起伏 | 推荐区间 |
| > 30 mm | 左右大幅摆胯,能耗高 | 仅调试初期用 |
4.3 踝策略与质心调整
ZMP 偏离参考点时,第一道防线是踝关节。支撑脚踝 pitch 和 roll 各转一个小角度,把压力中心往需要的方向推。踝策略的带宽高、延迟小,适合处理高频扰动,但角度行程有限,踝 roll 一般只能给 ±8°,超出就要靠髋关节把质心挪回来。
第二道防线是髋策略,也就是调整质心位置。质心跟踪的参考轨迹由线性倒立摆反解得到,实际执行时用 PD 控制,增益不能太高,否则质心追得太急,ZMP 反而被甩到多边形外。髋策略的响应慢但幅度大,负责处理持续性的偏差,比如一只脚踩在小台阶上。
第三道是迈步策略,也就是「要倒了就多走一步」。这一步实现起来最复杂,需要落脚点规划器根据当前质心速度预测下一步落点。小型双足如果不追求抗扰,可以先不做,把前两道调好,能应付大部分平地场景。
4.4 参数整定顺序:别一上来就调步态
整定顺序错了,会陷入「调 A 崩 B」的死循环。我一般的顺序是:
- 先调单腿悬空的位置环增益,让空载跟踪误差小于 0.5°,超调小于 5%。
- 再加整机站立的重力补偿,让静止时机身晃动幅度小于 1 mm。
- 然后调踝策略增益,用手轻推机身,看 ZMP 回到参考点的时间,控制在 0.3 s 以内。
- 接着调质心跟踪增益,原地踏步时 ZMP 不越界。
- 最后才开步态行走,从步长 0.05 m、周期 1.2 s 开始,逐步加快。
每一步没达标就不要进下一步。跳步省下来的时间,后面会在实机上一次一次还回来。
5. 联调避坑:双足机器人最容易翻车的五件事
前面几章的参数在仿真里都对得上,实机上照样会出问题。这一章记的是现场最常遇到的五条,按「现象 → 原因 → 解决」写。
5.1 一上电就高频抖动,频率在 30~60 Hz
现象:机器站直后整条腿出现细密抖动,手摸能明显感觉到,但姿态没倒。
原因:位置环增益过高,叠加减速器背隙形成极限环。电机端编码器看到的角度和关节实际角度差一个背隙量,控制器不断修正,机械端每次过零都撞一下背隙边界。另一个常见原因是电流环带宽不够,位置环给的速度指令电流环跟不上。
解决:先把位置环 P 降到原来的一半,看抖动是否消失;如果只是变慢没消失,就是背隙加增益的问题,需要降低位置环增益并加入速度前馈。电流环带宽至少要跑到位置环的 10 倍以上,1 kHz 电流环配 200 Hz 位置环是安全比例。
5.2 走三步后向一侧偏,越走越歪
现象:步态本身没报错,但机器人整体轨迹持续向同一侧漂移。
原因:左右腿零位标定不对称。机械零位和编码器零位存在 1~2° 的偏差,单腿看没问题,整机走起来每条腿的着地点都会偏几毫米,累积几步就明显。另一种可能是脚掌安装面不平行,一侧脚底橡胶垫厚了 0.5 mm。
解决:把机器吊起来,手动把两条腿摆到同一姿态(用直尺量膝关节到基准面的距离),读两边的编码器值,差值写进零位偏置表。脚掌用平板平台加塞尺检查,两侧高度差控制在 0.2 mm 以内。
5.3 落地瞬间脚掌打滑,机身横向甩
现象:每次摆动腿触地,支撑脚会往内侧滑一下,ZMP 曲线出现尖峰。
原因:落地瞬间足端还带有水平速度,加上触地时刻的冲击让踝关节反向弹了一下。步长越大、抬脚越低,这个现象越明显。
解决:在摆动相最后 20% 把足端水平速度降到 0.15 m/s 以下,落地后给踝关节 20 ms 的位置保持锁定。另外检查脚底材料,硬质橡胶在光滑地面上的摩擦系数可能只有 0.4,换成软一些的材料能到 0.7,打滑明显减少。
5.4 仿真走得好,实机走两步就趴
现象:同一套参数,仿真跑一分钟不倒也,实机撑不过三秒。
原因:最大的差异是关节延迟和柔性。仿真里关节指令是瞬时到位的,实机上有 5~15 ms 的通信加驱动延迟,还有减速器的扭转柔性。延迟在闭环里等同于相位滞后,稳定裕度被吃掉一大截。其次是仿真里地面是理想刚性平面,实机地面有微小起伏。
解决:在仿真模型里加一段纯延迟(10 ms 起步)和一阶关节柔性环节,重新调增益;同时把仿真里的地面加入 ±2 mm 的随机起伏。改完之后仿真里能稳定走,实机成功率会高很多。这条我踩过不止一次,现在默认仿真比实机乐观 30%。
5.5 站立时缓慢下沉,一分钟下降 5 mm 以上
现象:静止站立时机身高度单调下降,不抖不震,就是在沉。
原因:重力补偿只补偿了模型里的连杆质量,没有覆盖线束、螺丝、传感器这些「没算进去的重量」。整机 3.5 kg,漏算 200 g 就是 5% 的力矩缺口,位置环靠积分项慢慢补,表现就是缓慢下沉。
解决:把整机放在秤上称,跟模型里的质量对比,差值分摊到各连杆。也可以用实测关节电流反推实际重力矩,在几个固定姿态下采点,做一张补偿表,比纯模型补偿准得多。
6. 仿真到实机:三段验证和一个必须养成的习惯
参数调完不等于能用,从上电到连续行走中间要过三道关,每一道都设明确的通过判据,不达标就不往下走。
| 阶段 | 做法 | 通过判据 | 常见拦截项 |
|---|---|---|---|
| 单腿吊装 | 整机吊起,只跑摆动腿轨迹 | 关节跟踪误差 < 1°,无异常噪音 | 零位偏、线束干涉 |
| 原地踏步 | 双支撑架护住,跑完整步态但不前进 | ZMP 全程在支撑多边形内,裕度 > 15 mm | 踝策略增益过大 |
| 限幅行走 | 步长 0.05 m、周期 1.2 s,逐步提速 | 连续 20 步不触发保护 | 落脚点规划滞后 |
三段验证里最值钱的是第二段原地踏步。很多问题在吊装阶段看不出来,因为腿没承重;一承重,重力补偿的误差、踝 roll 的耦合、足底传感器的零点漂移全冒出来了。原地踏步跑够 5 分钟不触发保护,再放开走,成功率会高得多。
最后说一个习惯:黑匣子日志。每个控制周期把关节指令、关节反馈、IMU 姿态、足底力、ZMP、当前步态相位写进一块环形缓冲区,容量按 30 秒设计,触发保护或者跌倒时自动落盘。双足摔倒往往就在 200 ms 内,事后凭记忆复现根本不可能,没有日志就只能靠猜,而猜测的代价是重新跑一遍所有参数。我现在的习惯是日志字段只增不减,加一个新参数就加一列,宁可文件大一点,也不要某次翻车时发现缺了关键那一列。
这套流程走下来,从零到能连续走二十步,一个人大概要两到三周,其中一半时间花在标定和整定上,写代码反而是最快的部分。急着一上来就跑步态的,基本都会在第五步摔跟头。希望帮到你。
本文还有配套的精品资源,点击获取