3.2 刚体动力学核心概念


3.2 刚体动力学核心概念

本节摘要:物理引擎每一步在做的事,是对每个刚体解"牛顿-欧拉方程"的数值积分——质量与惯性张量决定它抗拒运动的方式,步长决定积分的精度与稳定性。工程上最重要的两件事:核对惯性张量量级(sim-to-real 失败案例头名)、按"步长小于最快周期十分之一"选步长。

每一步到底在算什么

把一个刚体的运动方程摊开,就是两句话:合外力决定质心加速度,合外力矩决定角加速度。引擎每个步长做的事:

  1. 收集这个刚体受到的所有外力:重力、关节约束力、接触力、你插件施加的力;
  2. 用质量与惯性张量把力换算成加速度(平动用质量 m,转动用惯性张量 I);
  3. 数值积分得到下一步的速度与位姿。

听起来平凡,但每一项都是一本账。重力的账最简单;关节与接触的账最糊涂(3.3 展开);而惯性张量这本账,是新手错得最多的地方

惯性张量:错一个零的世界

<!-- 一个 10 kg、尺寸 0.3×0.3×0.1 m 的扁平箱体 --> <inertial> <mass>10.0</mass> <inertia> <ixx>0.0833</ixx> <iyy>0.0833</iyy> <izz>0.1500</izz> <ixy>0</ixy> <ixz>0</ixz> <iyz>0</iyz> </inertia> </inertial>

量级自检的粗算方法:均匀箱体绕质心的惯量量级 ≈ m×L²/12。本例 izz ≈ 10×0.3²/6 ≈ 0.15,与所写一致。如果 URDF 导出时单位错了(把 g 当 kg),惯量差三个量级,症状非常戏剧化:机器人落地像纸片一样乱飘、或者像灌铅一样纹丝不动。核对动作:对每个 link 算一遍 m×L²/12 与所填值比对数量级,三十秒一个模型。

⚠️ 常见坑:URDF 里 <origin> 的惯性参考系与碰撞几何参考系不重合,导出工具有时填错。症状是静止悬浮的物体缓慢旋转(本应只受重力的物体出现自转)——遇到"幽灵自转",先查惯性张量的对角项与非对角项。

一步求解的全景

一步求解的全景

步长:精度与成本的旋钮

数值积分用离散步进近似连续时间。步长 dt 越小越准、越慢。经验准则:

  • dt ≤ 系统最快动态周期的 1/10。机械臂关节动力学几十到几百 Hz,dt=1ms 通常够;研究接触瞬态或高频振荡才需要更小。
  • dt 太大的症状:能量凭空增加(方块越弹越高)、关节角度发散(机器人"爆炸"飞出场景)、约束求解震荡(抖动)。
# 用命令行验证 SDF 并检查物理配置 gz sdf -p model.sdf | head -40

一个能量守恒小实验

拿导读的落体世界,分别用 dt=1ms、10ms、50ms 跑同一高度落体,记录第一次触地时刻:1ms 接近理论值 0.452s;10ms 开始漂移;50ms 可能穿过地面(连续碰撞检测未开时)。穿透是"步长大于几何尺度变化"的直接后果——一步之内物体跨过了整个薄板。这就是 3.3 症状表里"穿透"的头号病因。

三类量的记账规则速查

真实世界 仿真账本 核对动作
质量 称重 <mass> 一行数 与 BOM 表对照
惯性张量 CAD 软件算 <inertia> 六个数 量级 ≈ mL²/12 比对
重力 9.81 依赖纬度 <gravity> 可改 做山地/月球实验前记得改回来

最后一行不是玩笑:把重力改成月球值(1.62)做过实验的世界文件,忘了改回来就投入下一轮测试——这类"环境污染"在团队协作里真实发生过,值得在世界文件版本化时用 CI 检查兜底。

💡 关键直觉:物理参数错误的反馈是即时的、症状是夸张的。这其实是好事——学会读症状(飘、沉、抖、爆),比背参数表有用得多。

把三十秒自检固化成 CI:惯性量级批量核对

手工逐个 link 算 mL²/12 在小模型上可行,上百个 link 的机器人底盘就需要脚本兜底。思路:解析 SDF 里每个 <inertial>,用质量与所在碰撞盒尺寸的粗算值比对所填惯量,偏差超过一个数量级即报警:

# inertia_lint.py:对目录下所有 SDF 做惯性量级核对 import re, glob, sys XML = re.compile(r"<ixx>([0-9.e+-]+)</ixx>.*?<izz>([0-9.e+-]+)</izz>", re.S) MASS = re.compile(r"<mass>([0-9.e+-]+)</mass>") BOX = re.compile(r"<size>([0-9.]+) ([0-9.]+) ([0-9.]+)</size>") bad = 0 for f in glob.glob(sys.argv[1] + "/**/*.sdf", recursive=True): text = open(f, encoding="utf-8").read() for i, (m_grp, inert) in enumerate(zip(MASS.findall(text), XML.findall(text))): mass = float(m_grp) boxes = BOX.findall(text) if not boxes: continue x, y, z = map(float, boxes[min(i, len(boxes)-1)]) rough = mass * max(x, y, z)**2 / 12 # 量级粗算 for label, val in zip(("ixx", "izz"), inert): ratio = float(val) / rough if rough else 0 if ratio < 0.05 or ratio > 20: bad += 1 print(f"{f} link#{i}: {label} 与 mL^2/12 粗算差 " f"{ratio:.3f} 倍,疑似单位或来源错误") print(f"核对完成:{bad} 处可疑")

脚本故意只查量级不查精确值——CAD 导出的精确惯量允许与均匀箱体粗算差数倍(材料分布不均匀),但差十倍以上几乎必然是单位错(克当千克)或参考系错(非对角项挪窝)。把它挂进 CI,配一条"可疑数为零"的门禁,惯性类 sim-to-real 事故就挡在了合入之前。这份脚本与正文的手工口诀共用一条根:精确值可以交给工具,量级感觉必须长在工程师自己身上。

本节要点回顾

  • 每步求解 = 外力求和 → 惯性换算 → 数值积分,惯性张量决定转动的"抗拒程度"。
  • 惯性量级核对:mL²/12 粗算比对,三十秒防住 sim-to-real 最大杀手。
  • 步长准则:≤ 最快周期 1/10;穿透与能量暴涨先怀疑步长。
  • 幽灵自转查惯性参考系,越弹越高查步长,纹丝不动/轻飘飘查质量单位。

单个刚体的账清楚了。机器人是刚体加关节的组合——下一节看误差最集中的地方:约束求解。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U