最近在做人形机器人的双足行走动力学仿真,工具选来选去最后还是回到了OpenSim上。之前陆续用过ADAMS、Gazebo、Webots,也写过一版自己的Python动力学求解器,但凡是涉及“步态像不像人、关节力矩够不够、能耗高不高”这类问题,OpenSim是现阶段把生物力学模型和数值仿真串得最顺的开源工具,而且它对股骨等骨性结构、肌肉路径和关节自由度的定义方式,和我们在机器人工程里做机构建模的习惯很不一样,转换思路这个过程中踩了不少坑。
这篇文章围绕“人形机器人双足行走动力学”这个项目展开,重点讲三件事:为什么双足行走必须算动力学而不是只靠运动学规划;在OpenSim里如何从头建一个可靠的股骨模型(以及连带的下肢骨骼与关节);然后完整跑一遍从步态数据到关节力矩、再到机器人电机力矩映射的流程。最后把常见问题和排查思路整理成一张速查表。内容适合人形机器人方向的研究生、刚接触OpenSim的开发者,以及想用仿真结果反哺机构设计和电机选型的工程师。下面的内容都是我实际跑过项目之后沉淀下来的,该给的参数会给,该避的坑也会说清楚。
1. 双足行走的动力学家底:为什么选OpenSim
1.1 双足行走的本质是动力学问题
先从根上说。双足机器人的难点不在于“能走”,而在于“动态稳定地走”。轮式机器人只要地面摩擦够,运动学规划基本就能覆盖绝大多数问题;四足机器人因为有四条腿、支撑多边形大,静态稳定裕度相对充足。但人形机器人重心高、脚掌小、支撑面窄,一步迈出去之后,身体其实一直在“向前跌倒”和“稳住重心”之间切换。这个过程中,地面反作用力、关节力矩、质心运动、脚底接触状态是强耦合的,单纯给关节画一条平滑角度轨迹根本不够用。
这就是为什么必须做动力学分析。核心要算的无非几件事:当前姿态下维持加速度需要多大的关节力矩、地面反作用力落在什么位置、关节功率是否超出电机或驱动器能力。这些量无法从运动学数据里直接读出来,必须通过牛顿-欧拉方程或拉格朗日方法去求。OpenSim提供的就是一条“测量数据——人体骨骼肌肉模型——动力学量”的成熟链路,它可以输入运动捕捉数据和地面反作用力数据,计算出每个关节的净力矩、肌肉激活程度和各个肌肉的贡献,这对人形机器人设计有很强的参考意义。
我在实际项目里最常用到的是逆运动学(IK)、残差缩减(RRA)和计算肌肉控制(CMC)这三个工具。IK解决“关节角度是多少”,RRA解决“动力学方程残差太大怎么压下去”,CMC解决“肌肉怎么协同发力才能跟踪上这个步态”。如果目标是快速估算机器人关节力矩,IK加逆动力学就够了;但如果想把人的步态“翻译”成机器人能用的肌肉—关节映射关系,RRA和CMC基本绕不开。
1.2 OpenSim、Webots、Gazebo和自研求解器的对比
人形机器人圈子常用的仿真工具有不少,但每个工具的出发点不一样,选之前最好先搞清楚自己的目标是“机器人实时控制”还是“生物力学尺度上的步态分析”。
Webots和Gazebo底层用的是ODE、Bullet这类物理引擎,它们擅长模拟轮式、四足、机械臂的刚体碰撞、摩擦、PID控制闭环,计算速度快、传感器模型丰富。但它们没有人体肌肉模型,也不适合做“人体步态中关节力矩和肌肉激活”的细粒度分析。你要是拿Gazebo去算一块股骨对步态能耗的影响,基本等于用游戏引擎做有限元,方向不对。
ADAMS是传统多体动力学软件,精度高,建模灵活,适合航天、汽车、机器人领域的刚柔耦合分析。但它的学习曲线陡,肌肉骨骼模型需要自己搭或者买额外模块,而且和运动捕捉数据、公开步态数据集的对接不如OpenSim直接。OpenSim之所以在这类项目里更好用,是因为它本身就是从生物力学领域长出来的,内置了Thelen2003Muscle、Millard2012EquilibriumMuscle这些肌肉模型,自带多个经过验证的全身/下肢模型,还提供缩放、IK、RRA、CMC、静态优化、正向仿真等一整个工具箱。开源、免费、有Python API,这三个条件对高校实验室和初创团队非常友好。
我之前还试过用Python写多刚体动力学求解器来处理步态数据。对于简化倒立摆模型或者五连杆模型,自己推导完全可行;一旦模型复杂到髋关节三自由度、膝关节单自由度、踝关节两自由度,加上几十条肌肉路径、肌肉力—长度—速度关系,自研求解器的开发成本就变得非常夸张。所以合适的策略是:把OpenSim当成“高保真参考实现”,用来算关节力矩、功率、能量、肌肉激活这些物理量;把自研的简化模型用于实时控制或蒙特卡洛参数扫描。
2. 股骨模型与建模:从CT到OpenSim的Body组件
2.1 股骨在人体动力学链里的角色
很多人第一次接触OpenSim会把注意力全放在“肌肉怎么调参数”上,但在我看来,骨骼模型才是整个动力学仿真的地基,尤其是股骨。股骨是人体最长、最粗壮的长骨,上端接髋关节,下端接膝关节,中间承担了从躯干传递到小腿和地面的力流。它的长度和方位直接影响质心高度、髋膝关节轴的位置,而这些又决定了步态中的ZMP零力矩点位置和关节载荷。
摆动腿的运动学与股骨惯性参数关系更大。大腿在摆动相里要快速前摆,股骨质量如果设置过大,髋关节需要提供的加速力矩会明显上升;股骨质心位置如果偏得太多,膝关节的屈伸力矩曲线也会跟着变。另一个容易被忽略的点是肌肉附着路径。股骨上附着着臀大肌、髂腰肌、股四头肌、腘绳肌等多条重要肌肉,这些肌肉不是简单地从一个bone point连到另一个bone point,而是会绕过骨骼表面、通过via-point或wrap surface改变力线方向。股骨的几何形状如果简化得太离谱,肌肉力臂就算不准,最后输出的肌肉激活度会失真。
在OpenSim里,股骨被定义为一个Body对象。每个Body需要完整声明质量(mass)、质心位置(mass_center)和惯性张量(inertia),并且要和关节、肌肉附着点形成正确的父子拓扑关系。也就是说,股骨模型不只是“一根骨头模型”,它同时还是质量属性、关节轴坐标和肌肉路径的挂载点。
2.2 股骨建模的三步操作
既然股骨这么关键,那就具体拆一下怎么建模。下面这套流程我在项目里实际跑过,结论是可复现的,但参数一定需要根据你自己的模型来源和机器人尺寸重新标定。
第一步,获取骨骼几何。股骨的几何数据来源主要有三个:一是从CT或MRI影像里分割重建,精度高但门槛高;二是使用公开解剖数据集,比如一些开源的骨骼STL文件;三是从已有的OpenSim模型(比如gait2392模型里有基于真实人体测量的骨骼几何)里提取股骨几何,然后改参数。对于做人形机器人而不是做临床骨科研究的场景,我个人最推荐第三种方式起步,先把一个已验证模型里的股骨几何拿过来,再根据自己机器人腿部的尺寸去缩放,这样能少踩很多“几何形状不合理”的坑。
拿到STL/OBJ网格之后,需要做简化处理。OpenSim对骨骼几何的精度要求不是“医学影像级”,重点是关节窝的位置、长轴方向、肌肉附着点大致形状。三角面片数量太大的话,模型加载和wrap surface计算都会变慢。一般我会把网格简化到几千到一万面片左右,只要能清晰表达股骨头、股骨颈、大转子、股骨髁这些关键结构就够了。
第二步,计算质量属性。股骨的真实质量约为人体总质量的2%左右,一个70kg成年人的单根股骨大约1.2kg到1.5kg。但并不是所有仿真都要用真实股骨质量,如果你的目标是给机器人做等效计算,就需要按机器人的腿部质量重新分配。计算方法很简单:在建模软件里读取网格体积,乘以骨的等效密度。皮质骨密度大概1900 kg/m³,松质骨密度低一些,整体股骨用1500到1800 kg/m³做估算比较稳妥。体积乘密度得到质量,然后让建模软件自动计算质心和惯性张量。这里要特别注意惯性张量的单位,OpenSim内部单位是kg·m²,而很多CAD软件默认输出的是kg·mm²,换算关系是1 kg·mm² = 1×10⁻⁶ kg·m²,记错的话仿真结果直接差六个数量级。
第三步,在OpenSim里定义股骨Body。最简单的方式是直接用OpenSim GUI创建一个Body,然后在XML编辑器里把质量属性填进去。一个简化的示例如下:
<Body name="femur_r"> <mass>6.8</mass> <mass_center>0 -0.21 0</mass_center> <inertia>0.11 0.03 0.11 0 0 0</inertia> </Body>上面的数值只是一个示意:股骨质量6.8kg在这个场景里意味着这条“大腿”包含了部分肌肉和软组织,所以远重于纯骨骼重量。mass_center写在局部坐标系里,表示质心在髋关节原点下方0.21米处。inertia六个分量依次是Ixx、Iyy、Izz、Ixy、Ixz、Iyz,单位是kg·m²。如果把股骨近似看成竖直圆柱,Ixx和Izz(绕水平轴的转动惯量)会明显大于Iyy(绕长轴的转动惯量),这符合直觉。
定义完Body之后,还要定义它和其他Body之间的关节关系。股骨上端通过髋关节连到骨盆,通常用BallJoint或自定义3自由度关节;下端通过膝关节连到胫骨,通常用PinJoint模拟主要屈伸自由度。关节轴的位置直接决定力臂,所以这一步绝对不能草率。
2.3 建模时容易翻车的三个细节
第一个容易翻车的地方是坐标系方向。OpenSim的全局坐标系是Y轴向上,股骨长轴一般沿Y方向。很多从CAD软件导出的模型默认Z轴向上,导入之后整个腿是横着躺在地上的,关节轴方向全乱。解决方法是进入模型文件后先检查每个Body的<location>和<orientation>,或者直接把网格重新摆放成Y-up。
第二个翻车点是我前面提到的单位换算。不止惯性张量,长度单位也很容易踩雷。CAD里习惯用毫米,OpenSim用米,差了1000倍会导致质心位置完全错误。我见过一个案例,把0.5m写成了500,模型直接飞到天上去,IK误差爆炸,一开始还以为是数据问题,后来发现是单位问题。
第三个翻车点是肌肉路径穿骨。股骨建模时如果只做一根光杆骨骼,没有合适的肌纤维路径,肌肉的力线就会从骨骼中间穿过去。OpenSim里处理这个问题通常用via-point(路径点)和wrap surface(包络面)。通俗地说,via-point是人为规定肌肉必须经过的点,wrap surface是给肌肉一个“绕过圆柱表面”的物理约束。这个在建模初期可以简化,但到了CMC阶段,肌肉路径不对会导致激活度忽高忽低,甚至出现肌肉力方向完全错误的结果。
3. 双足行走动力学仿真全流程:从数据采集到结果分析
3.1 一套可用的步态数据怎么来
OpenSim不是无中生有给你算出一个步态,它需要真实的运动学和动力学输入。最理想的数据来源是实验室里的光学动作捕捉系统加测力台。Vicon、OptiTrack这类系统用多台红外相机捕捉贴在皮肤表面的反光标记点,以100Hz左右的采样率记录每个点的三维坐标;测力台以1000Hz采样记录地面反作用力和压力中心。两条数据必须做时间同步和坐标系统一,否则后面RRA阶段会非常痛苦。
如果实验室没有这套设备,也可以使用公开步态数据集。比较常见的是CMU Graphics Lab Motion Capture Database、HuMoD、以及一些生物力学论文中公开的步态数据。用公开数据的好处是省事,缺点是标记点定义和模型不匹配,经常需要自己写脚本做标记点重命名和坐标转换。
拿到数据之后有几个预处理细节:一是标记点轨迹必须滤波,推荐用截止频率6Hz左右的低通滤波器;二是要注意标记点缺失问题,步态数据里经常出现短暂遮挡,需要做插值,但千万别在支撑相和摆动相交界处做大幅插值;三是地面反作用力数据需要去除零点偏移,并且判断力台触发时刻。如果力和运动数据差了几十毫秒,最后逆动力学算出来的关节力矩在支撑相起点会明显失真。
3.2 从缩放模型到逆运动学
模型和数据的尺寸不可能天生一致。OpenSim里的标准模型(比如gait2392)是某个参考人体的尺寸,而你的受试者或机器人腿部尺寸可能完全不一样,所以第一步是缩放。
Scale Tool做的事情有两件:根据标记点之间的距离,把每根骨骼的长度缩放到测量值;再按缩放比例调整每个Body的质量和惯性张量。这里有一个工程诀窍:缩放因子不要只靠全局缩放,尽量手动检查每个Body的缩放结果。尤其是股骨和胫骨的长度比,如果机器人腿型和人体比例差别很大,全局缩放会把比例扭曲,这时候需要单独指定每个Body的缩放因子。
缩放完成之后进入逆运动学IK。IK的目标是找到一组关节角度,使模型上的虚拟标记点和实验测得的标记点位置误差最小,这是一个加权最小二乘问题。实际操作里,IK误差一般控制在2厘米以内算正常,5厘米以上就是危险信号。误差过大时,首先检查标记点是否放错了位置、骨盆的六个自由度是否被过度约束,其次检查模型缩放是否合理。
3.3 RRA和CMC:从逆动力学到肌肉坐标
直接对IK得到的运动学数据做逆动力学,经常会发现计算出的关节扭矩和地面反作用力之间存在很大残差。这个残差的来源很多:标记点软组织伪影、人体模型质量分布偏离真实受试者、数据滤波阶数不合适等等。所以OpenSim提供了残差缩减算法RRA(Residual Reduction Algorithm)。RRA允许在合理范围内调整模型的质量分布、质心位置,甚至微调躯干角度,让残差力降到可以接受的范围。经验上,RRA后的残差力最好控制在10N以内,残差力矩控制在50N·m以内。如果残差还是很大,不要硬调RRA参数,该回头检查数据同步和缩放。
RRA之后的数据就可以交给CMC(Computed Muscle Control)了。CMC做的事情是在每一个仿真时间步里,用肌肉激活度作为控制量,通过比例-积分控制器跟踪目标关节角度,同时在满足肌肉力—速度—长度关系、激活度0到1边界等约束的前提下,最小化肌肉激活的平方和。本质上这就是一个动态优化问题。输出结果包括肌肉激活曲线、肌肉力曲线、关节力矩曲线等。对机器人工程师来说,CMC最大的价值就是让你看到“一个动作到底要哪几块肌肉发多少力”,转换到机器人上就是“哪几个关节电机在什么时刻出多少力”。
3.4 结果里的关节力矩怎么映射到人形机器人电机
OpenSim输出的是人体关节净力矩,直接拿去给机器人电机用显然不对。人体和机器人的质量、惯量、腿长完全不同,至少要做一次相似性缩放。最粗粒度的估算是先定两个无纲量缩放因子:质量缩放系数 km = m_robot_lowerlimb / m_human_lowerlimb,长度缩放系数 kl = l_robot_leg / l_human_leg。假设动力学的惯性力主导,关节力矩近似按 km × kl 的倍数缩放。
举个例子,如果人体下肢等效质量20kg、腿部长度0.9m,机器人下肢等效质量8kg、腿部长度0.75m,那么km = 0.4,kl ≈ 0.833,折算系数约0.333。OpenSim算出的髋关节峰值力矩如果是100N·m,那机器人对应关节的峰值力矩估算为33N·m左右。当然这只是量级估算,精确选型还是应该把机器人的质量和惯量参数代入多刚体动力学模型重新算一遍,OpenSim给出的曲线可以作为验证基准。
还要强调的是,人的“关节力矩”包含了拮抗肌共同收缩造成的非保守力矩,而机器人电机不会像肌肉那样主动产生反向力,所以直接从OpenSim的肌肉合力矩映射到电机,往往会偏保守。这在初期选型阶段反而是好事,能给扭矩余量留出空间。
4. 常见问题与排查技巧实录
4.1 IK误差爆炸
IK是整条链路里最容易报错的一环。我遇到的典型情况是模型缩放之后,虚拟标记点和实验标记点位置差了十万八千里。排查步骤是这样:先看标记点名称是否一一对应,OpenSim对不上名字会直接报错;再看单位,如果实验数据单位是毫米而OpenSim里模型单位是米,所有标记点坐标都该除以1000;最后看模型缩放,重点查骨盆宽度、大腿长度、小腿长度这些大尺寸是否合理。
如果以上都对,但IK误差还是很大,可以尝试给不同标记点设置不同的权重。比如骨盆和股骨上的标记点因为软组织相对少,可以给高权重;大腿中部有些标记点软组织伪影严重,权重给低一些。这不是作弊,而是提高估计精度的常规做法。
4.2 RRA残差降不下来
RRA残差大的原因通常不在RRA本身。很多人在RRA里反复调残差权重,效果都不好,其实问题往往出在力台数据和运动学数据的同步偏差上。时间差哪怕只有20到30毫秒,足底压力中心的位置就会和脚掌实际位置对不上,RRA再怎么调,残差也无法真正收敛。这时应该回头检查数据同步,用已知的碰撞事件(比如脚跟着地瞬间力台信号突变)作为时间对齐基准。
另一个常见原因是模型缩放不准,尤其是下肢质量分布和真实差异太大。RRA允许调整质量分布,但调整范围是有限度的,超出范围就说明缩放环节有硬伤。
4.3 肌肉路径穿模、激活度超限
肌肉激活度超过1,一般不是算法问题,而是模型参数问题。常见原因是肌肉最大等长力Fmax设置比实际值小太多,为了产生足够的关节力矩,优化算法只能把激活度往上顶。另一种原因是肌肉路径走错了方向,导致肌肉力臂过小,需要很大的力才能产生目标力矩。解决思路是:先用逆动力学算一遍关节净力矩,大概知道力矩范围,然后对照肌肉的力臂和最大等长力估算理论最大关节力矩,再看肌肉路径是否需要增加via-point。
穿模问题更直白,就是骨骼几何和肌肉路径碰撞检测没做好。给关键肌肉添加合适的wrap surface,或者在肌肉经过骨骼转角的地方加via-point,是最常见的处理办法。
4.4 OpenSim Python API崩溃
OpenSim 4.x提供了Python绑定,但版本兼容性是个大坑。经常遇到的问题包括:conda环境和系统Python里安装了多个OpenSim版本,模块加载冲突;OpenSim 4.3和4.4的API有细微变化,代码在某个版本能跑另一个版本直接崩溃。我的建议是先固定一个虚拟环境,用官方推荐的pip或conda命令安装固定版本,不要轻易升级。遇到崩溃时,把model文件路径改成绝对路径、把osim模型所在目录加入环境变量,也能解决不少莫名其妙的报错。
4.5 快速排查表
| 问题现象 | 可能原因 | 排查与解决建议 |
|---|---|---|
| IK误差大于5cm | 标记点命名/位置错误、单位错误、模型缩放错误 | 检查标记点对应关系、单位换算、缩放因子 |
| RRA残差大于10N/50N·m | 力台与运动数据不同步、缩放不准 | 用脚跟着地事件对齐数据,重新缩放模型 |
| 肌肉激活度超过1 | 最大等长力不足、肌肉路径力臂错误 | 检查Fmax参数,增加via-point,检查路径几何 |
| 肌肉穿模 | 缺少wrap surface或via-point | 给肌肉添加包络面或路径点 |
| Python API崩溃 | 版本不兼容、环境冲突 | 固定虚拟环境,统一OpenSim版本 |
| 正向仿真发散 | 积分器步长过大、初始状态不满足约束 | 减小积分步长,对模型做预平衡 |
5. 从股骨模型到数学建模:一个可以落地的延伸方向
5.1 把OpenSim问题翻译成最优控制问题
当OpenSim的流程跑通之后,很多人会想把人体步态规律直接用到机器人上。这时候你会发现,OpenSim的CMC本质上是在求解一个带约束的最优控制问题:状态变量是关节角度和角速度,控制量是肌肉激活度,目标函数是最小化激活度平方和或能量消耗,约束条件包括肌肉动力学方程、关节运动方程、激活度上下限,以及地面反作用力与运动状态的相容性。
如果参加数学建模类竞赛,或者要做更细的机器人步态优化,完全可以用更轻量的方式复现这个思路。比如把双腿简化成一个五连杆模型,把关节力矩作为控制变量,目标是最小化总能量或最大稳定裕度,约束条件包含ZMP落在支撑多边形内、关节力矩限幅、关节角度限位。然后用二次规划或非线性规划求解。OpenSim里跑出来的关节力矩曲线可以作为简化模型的参考值,用来校验你的目标函数和约束设置是否合理。
我自己会这样搭建一个简化版:先用OpenSim的模型文件和步态数据,把每个关节在一个步态周期内的角度、角速度、角加速度曲线导出来,再用Python的CasADi或者MATLAB的fmincon求解一个最优控制问题,目标函数是关节力矩平方和或机械能耗,约束是腿部连杆运动学、ZMP稳定条件、电机峰值力矩。把OpenSim的CMC结果作为基准对比,能直观看到简化模型在哪个相位上偏差最大,然后针对性调整约束函数。
5.2 从仿真到原型:最后的实操建议
做完整个项目之后,我最大的体会是:OpenSim里的股骨模型和人体骨骼模型,应该被当作“数据增强器”而不是“黑盒子”。股骨模型不能只盯着质心和转动惯量,更要看关节轴位置和肌肉附着点。如果这两点错了,后面算出来的所有关节力矩和肌肉激活都不可信。
这里再分享一个对做机器人特别有用的细节:选电机时别只盯着峰值力矩。人体步态中不少关节的峰值力矩出现在脚跟着地和脚尖离地附近,持续很短,但电机的热效应更多由整个步态周期里的RMS力矩决定。所以我在导出OpenSim结果时,会习惯额外计算每个关节在一个完整步态周期内的RMS力矩和功率积分。很多电机瞬时峰值能满足要求,但连续运行几分钟后因为RMS过载发热严重,这一步提前算清楚,能省掉很多后期原型测试的返工。
这个流程目前还在持续迭代,下一步我打算把OpenSim输出的肌肉激活模式作为先验,放到机器人步态生成网络里做模仿学习。从实验效果看,用人体肌肉力矩曲线做约束生成出来的步态,会比纯靠强化学习乱逛的步态更平滑,也更接近人类自然摆腿的节奏。项目相关的模型文件、Python脚本和步态数据,我整理好之后会再单独写一篇分享。