2、物理引擎基础:Carla使用的物理引擎介绍、Unreal Engine物理系统、PhysX与Carla的关系

好,咱们正式开始聊物理引擎。说实话,很多做自动驾驶仿真的朋友,一开始都容易忽略这一块。大家总觉得,我只要把传感器模型调好,把场景搭漂亮,车能跑起来就行。但我要告诉你,物理引擎才是决定你的车「像不像真车」的关键。

我自己刚接触Carla那会儿,就踩过一个坑。当时调了一整天车辆动力学参数,转向、悬挂都设好了,结果车一开起来就像在冰面上滑行。后来才发现,问题出在物理引擎的配置上,而不是动力学模型本身。嗯,从那以后,我再也不敢小看物理引擎了。

2.1 Carla到底用了什么物理引擎?

先说结论:Carla使用的是 Unreal Engine 4(UE4)的物理系统,而UE4的物理系统底层,其实是 NVIDIA PhysX

说白了,Carla的物理计算链条是这样的:

Carla 车辆动力学模型
    ↓
UE4 物理系统(刚体碰撞、约束、摩擦力等)
    ↓
PhysX 引擎(底层物理求解器)

你想想看,Carla本身并不直接调用PhysX的API。它通过UE4的物理接口来驱动车辆。而UE4的物理模块,就是基于PhysX 3.x版本开发的。所以,我们平时调的那些物理参数,最终都会落到PhysX的求解器里去计算。

核心要点:Carla的物理模拟 = UE4物理框架 + PhysX底层求解器 + Carla自定义动力学扩展。

2.2 Unreal Engine的物理系统长什么样?

UE4的物理系统,我个人觉得设计得挺巧妙的。它把物理模拟分成了几个层次:

  • 碰撞检测层:负责检测两个物体是否接触。UE4用的是基于包围盒的粗检测 + 基于网格的细检测。我在项目中遇到过一个问题,就是车辆底盘太低时,碰撞检测会漏掉一些小凸起,导致车辆直接穿模。后来我把碰撞体的形状改成了更精细的凸包网格,问题就解决了。
  • 约束求解层:负责处理关节、弹簧、悬挂这些连接关系。Carla的车辆动力学,说白了就是一堆约束的组合。车轮和车身之间是悬挂约束,车轮和地面之间是接触约束。PhysX的求解器会迭代计算这些约束力,直到满足所有条件。
  • 动力学求解层:根据力和力矩,更新物体的位置和速度。这一步就是牛顿第二定律的数值积分。UE4默认用的是半隐式欧拉法,精度一般,但胜在稳定。

这里我要提醒你一点:UE4的物理系统默认是 单线程 的。如果你的场景里车辆很多(比如超过50辆),物理计算就会成为瓶颈。我曾经在一个大场景里同时跑了100辆车,结果物理帧率直接掉到了15 FPS。后来我不得不把物理子步数调低,才勉强跑起来。

注意:UE4物理系统的默认子步数是2。如果你发现车辆在高速行驶时抖动或者穿透地面,可以尝试把子步数提高到4或6。但代价是CPU开销会翻倍。

2.3 PhysX与Carla的关系,到底有多深?

很多人以为Carla直接用了PhysX的车辆动力学模块。其实不是。PhysX本身确实带了一个 PhysXVehicle 模块,但Carla并没有直接用。为什么?

原因很简单:PhysXVehicle是为游戏设计的。它追求的是「看起来爽」,而不是「物理上准」。它的轮胎模型用的是简化的刷子模型,悬挂也是线性弹簧。对于自动驾驶仿真来说,精度远远不够。

所以Carla的做法是:

  • 用PhysX处理 刚体碰撞基础约束(比如车轮的旋转轴)。
  • 自己实现了一套 车辆动力学模型,包括轮胎的Pacejka魔术公式、悬挂的非线性刚度、转向系统的阿克曼几何等。
  • 把动力学模型计算出来的力,通过UE4的物理接口施加到刚体上。

我举个例子你就明白了。当你的车转弯时:

  1. Carla的动力学模块根据方向盘转角,计算出每个车轮的侧向力和纵向力。
  2. 这些力被传递给UE4的物理系统。
  3. UE4调用PhysX的求解器,把这些力应用到车辆的刚体上,同时处理与地面的碰撞。
  4. PhysX计算出新的位置和速度,更新渲染。

你看,PhysX在这里扮演的是「执行者」的角色,而不是「决策者」。决策者是Carla自己的动力学模型。

小技巧:如果你想调试物理引擎的行为,可以在Carla的配置文件里打开 PhysicsSubsteppingEnableVehiclePhysics 这两个参数。前者控制物理子步,后者控制是否启用Carla的自定义动力学。关掉后者,车就会用UE4默认的物理行为,你会发现车变得特别「游戏化」——转向过度、刹车打滑,完全不像真车。

2.4 三个引擎的分工,一张表说清楚

为了方便你理解,我整理了一张表格:

层级 负责内容 典型参数 我的经验
Carla动力学模型 轮胎力、悬挂力、转向几何 轮胎刚度、悬挂K值、阿克曼百分比 这里调参最敏感,我一般先调轮胎
UE4物理系统 刚体运动、碰撞响应、约束求解 子步数、碰撞精度、摩擦力系数 子步数别超过6,否则CPU扛不住
PhysX引擎 底层数学求解、接触点计算 求解器迭代次数、穿透恢复速度 默认值够用,别乱改

2.5 避坑指南:我曾经踩过的三个坑

最后,分享几个我亲身经历过的坑,希望能帮你省点时间。

坑一:物理引擎版本不匹配。 Carla早期版本用的是UE4.24,对应的PhysX是3.4。后来升级到UE4.26,PhysX也升级到了3.5。如果你自己编译Carla,一定要确保UE4和PhysX的版本对应。我曾经因为用了旧版的PhysX库,导致车辆碰撞后直接飞出去,排查了两天才发现是版本问题。

坑二:摩擦力参数不是线性关系。 很多人以为把轮胎的摩擦力系数从0.8调到1.6,抓地力就会翻倍。其实不是。PhysX的摩擦力模型用的是库仑摩擦定律,但实际计算时还涉及接触法向力和相对速度。我建议你调参时,每次只改10%,然后跑一次直线加速和紧急制动,看看效果。

坑三:不要忽略地面材质。 Carla里的路面是有材质属性的。沥青、水泥、草地,它们的摩擦系数和滚动阻力都不一样。如果你发现车在某个路段突然失控,先检查一下路面的材质是不是设成了「冰面」。我遇到过最离谱的一次,是场景设计师把整条路都设成了「抛光大理石」……

好了,物理引擎的基础就聊到这里。下一章我们会深入Carla的车辆动力学模型,看看那些参数到底是怎么影响车辆行为的。到时候我会手把手带你调一个能漂移的车辆模型,嗯,想想就刺激。