3.3 约束与关节


3.3 约束与关节

本节摘要:关节是引擎里"用约束方程把两个刚体绑起来"的机制,接触本质也是约束(不许穿透)。约束求解是数值近似最集中的环节,产生抖动、穿透、漂移、爆炸四大典型症状。本节给出关节类型对照、SDF 配置实例与症状-病因-处方对照表。

关节:受约束的自由度

真实铰链靠机械结构限位,仿真里靠数学:一个 revolute 关节 = 一个方程"两刚体绕该轴的相对转角自由,其余五个自由度锁死"。引擎每步在解一个带约束的力学问题——约束力是拉格朗日乘子,求解器在摩擦、限位、电机力矩多边条件下迭代出满足所有约束的力。近似就藏在这些迭代里。

SDF 的关节类型速查:

类型 自由度 典型用途 关键参数
revolute / hinge 绕轴转 1 关节臂、舵机关节 <axis><limit>、damping、friction
prismatic 沿轴滑 1 导轨、升降机构 行程限位、阻尼
ball 球面 3 肩关节 通常配阻尼防漂
fixed 0 刚性连接 慎用(见下)
revolute2 串联双转 车辆转向轮 两轴参数
<!-- 一个带物理性格的 revolute 关节 --> <joint name="elbow" type="revolute"> <parent>upper_arm</parent> <child>forearm</child> <axis> <xyz>0 1 0</xyz> <limit> <lower>-2.2</lower> <upper>2.2</upper> <effort>60</effort> <!-- 力矩上限, 超过即打滑式失效 --> <velocity>3.0</velocity> </limit> <dynamics> <damping>0.5</damping> <!-- 粘性阻尼: 抑制振荡 --> <friction>0.1</friction> <!-- 库仑摩擦: 消耗启停能量 --> <spring_reference>0</spring_reference> <spring_stiffness>0</spring_stiffness> </dynamics> </axis> </joint>

注意 <limit> 里藏着两本容易被忽略的账:effortvelocity 是控制器的能力上限。设成 1e16(很多人图省事这么干),等于告诉引擎"电机无限强"——仿真里什么都能推动,上真机全还回来。

⚠️ 常见坑:fixed 关节不是免费的。有些引擎把 fixed 关节处理为真实约束(每步迭代),大量 fixed 关节链会明显拖慢仿真并引入数值误差。建模时尽量在 CAD/Mesh 阶段合并固定件,而不是用几十个 fixed 关节拼机器人。

接触也是约束

地面不许穿透车轮——这也是一个约束方程,加上摩擦不等式后,求解器每步要解一个线性互补问题(LCP):接触力要么为零(分离),要么满足不穿透与摩擦锥(接触),两者互补。这就是 2.1 节 <kp>/<kd> 的岗位:把"硬约束"软化成"很硬的弹簧",让迭代求解更容易收敛。代价是软——太软会穿透,太硬会抖,这是调接触参数的永恒权衡。

四大症状的病因表

症状 高概率病因 处方
抖动(静止物体高频颤动) 接触刚度/阻尼不匹配;步长偏大;多接触点冲突 降 kp、加 kd;减小步长;简化碰撞几何
穿透(物体陷入地面) 步长太大或碰撞体太薄 减小步长;给薄板加厚度;开启 CCD(若引擎支持)
漂移(约束缓慢松开,关节"漏"角度) 迭代次数不足;约束冲突(冗余约束) 提高求解器迭代数;删冗余 fixed/ball 关节
爆炸(速度发散飞出场景) 惯性张量量级错误;NaN 传染(effort 无限 + 硬限位冲突) 核对惯性;给 effort/velocity 合理上限

调参的顺序感

口诀:先核惯性,再动步长,然后接触,最后几何。顺序反了(上来就乱调 kp),参数会互相掩盖,调出一个"碰巧能跑"但物理意义不明的配置。

💡 关键直觉:网格碰撞体是性能与稳定性的双料杀手。视觉网格可以百万面,碰撞体永远用基本几何体(盒、球、圆柱、凸包)近似——"视觉好看、碰撞简单"是物理仿真的基本修养。

处方验证:一次 effort 上限的定量对账

"effort 设成 1e16 等于电机无限强"这句话值得跑一遍数字。给 3.2 节那条机械臂肘关节配置两组对照——effort=60(真实舵机规格)与 effort=1e16(图省事写法),末端挂 5 公斤负载做抬臂动作,记录关节实际力矩峰值:

# 打开关节状态话题里的力矩字段(Wrench/位姿带力矩需插件记录) gz topic -e -t /model/arm/joint_state | grep -E "effort|position" > arm_torque.log # 分别在 effort=60 与 effort=1e16 两个世界文件下各跑 20 秒仿真
# 对账:真实上限下抬得动吗?无限上限下用掉了多少"假力矩"? import re def peak(path): effs = [float(m) for m in re.findall(r"effort: ([0-9.]+)", open(path).read())] return max(effs) if effs else 0.0 p_real, p_inf = peak("arm_torque.log"), peak("arm_torque_inf.log") print(f"真实上限组力矩峰值 {p_real:.1f} Nm(被 effort=60 钳住)") print(f"无限上限组力矩峰值 {p_inf:.1f} Nm —— 是真机的 {p_inf/60:.1f} 倍需求")

典型结果:无限上限组为克服启动瞬态可能调用 200 Nm 以上,是真实舵机的三倍还多——这条轨迹直接搬到真机必然堵转。对账结论应写回控制器:把轨迹规划的加速度限制压到 effort=60 可承受的范围内重跑仿真,直到力矩峰值留出 20% 裕度。这类"把能力上限当真"的实验,是把仿真从演示工具变成验证工具的分水岭。

本节要点回顾

  • 关节 = 约束方程,接触 = 带摩擦的 LCP 约束,误差集中在迭代求解环节。
  • effort/velocity 别设无限:那是"电机无限强"的账,真机会全额讨还。
  • fixed 关节有成本:固定结构在建模阶段合并,别用关节拼装。
  • 调参顺序:惯性 → 步长 → 接触(kp/kd)→ 碰撞几何简化;症状表按图索骥。

物理这本账记完。下一章转向机器人脚下与身边的世界——SDF 如何把地形、建筑、模型资源写成机器可校验的语义契约。


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