2、物理引擎基础:Carla使用的物理引擎介绍、Unreal Engine物理子系统、时间步长与子步长设置

好,咱们直接进入正题。这一章聊的是物理引擎,说白了就是让车「动起来」并且「动得真实」的那套底层机制。很多刚接触Carla的朋友,上来就调轮胎摩擦系数、改悬挂刚度,结果车要么像抹了油,要么像开坦克。为什么?因为没搞懂物理引擎在背后怎么算的。

我个人习惯,在调任何动力学参数之前,先花半小时把物理引擎的底牌摸清楚。这半小时,能省下后面几天的调试时间。

2.1 Carla使用的物理引擎

Carla用的是Unreal Engine自带的物理引擎——Chaos Physics。从Carla 0.9.11版本开始,官方全面切换到了Chaos。之前的老版本用的是PhysX,如果你还在用老版本,我建议你尽快升级。Chaos在车辆动力学模拟上,精度和稳定性都上了一个台阶。

Chaos是UE4.25之后引入的物理系统,它最大的特点是支持多线程并行计算。你想想看,仿真场景里同时跑十几辆车,每辆车有四个轮子、悬挂、转向、刹车,再加上行人、传感器、天气系统……如果物理计算是单线程的,CPU早就冒烟了。

核心要点:Carla的车辆动力学完全依赖Chaos Physics。你调的所有参数,最终都是喂给Chaos去算的。

我在项目中遇到过一个问题:同样的参数,在Carla 0.9.10和0.9.12上跑出来的车辆响应完全不同。查了半天,发现就是物理引擎从PhysX换成了Chaos。所以,如果你在参考网上一些老教程,记得先确认一下版本。

2.2 Unreal Engine物理子系统

Chaos在UE里不是孤立的,它由几个子系统协同工作。我画个简单的逻辑图给你看:

  • 碰撞检测子系统:负责检测车辆和地面、墙壁、其他车辆的碰撞。这是最基础的,但也是最容易出问题的。我曾经遇到过车辆「穿透」地面的情况,后来发现是碰撞检测的阈值设得太宽松了。
  • 约束求解子系统:处理悬挂、铰链、关节这些连接关系。车辆的悬挂系统就是靠这个子系统来模拟的。你调悬挂刚度,实际上就是在调约束求解器的参数。
  • 动力学求解子系统:计算力、力矩、加速度、速度、位置。这是核心中的核心。轮胎的摩擦力、空气阻力、发动机扭矩,最终都汇总到这里。
  • 并行调度子系统:把上面的计算任务分配到不同的CPU核心上。嗯,这里要注意,如果你的CPU核心数不够,或者调度策略不对,仿真帧率会直接崩掉。

说白了,这四个子系统就像一条流水线。碰撞检测先判断「有没有接触」,约束求解再算「接触后怎么约束」,动力学求解算「约束后怎么运动」,并行调度保证这一切跑得快。

小提示:如果你发现车辆在低速时抖动,或者高速时飘忽不定,多半是约束求解子系统的迭代次数不够。这个我们后面会讲到怎么调。

2.3 时间步长与子步长设置

好,这部分是重点中的重点。很多动力学问题,根源都在时间步长设置上。

时间步长(Time Step),就是物理引擎每次更新状态的时间间隔。比如你设成0.01秒,那物理引擎每10毫秒算一次。步长越小,精度越高,但计算量也越大。

子步长(Sub Step),是把一个时间步长再拆成更小的步长。比如时间步长是0.01秒,子步长设成2,那物理引擎会先算两个0.005秒的步长,再更新画面。

为什么要拆子步长?因为有些物理现象,比如轮胎和地面的高速摩擦,在0.01秒内可能发生好几次变化。如果不拆,就会漏掉这些变化,导致仿真失真。

我个人的经验是:

场景 时间步长(秒) 子步长 说明
低速城市工况(< 30 km/h) 0.02 1 精度要求不高,省资源
高速巡航(> 80 km/h) 0.01 2 保证高速下的稳定性
极限操控(漂移、紧急避让) 0.005 4 需要捕捉瞬态响应
多车协同仿真(> 10辆车) 0.02 1 优先保证帧率,牺牲一点精度

你看,没有一套参数能通吃所有场景。我刚开始做仿真时,图省事,所有场景都用0.01秒步长、2个子步长。结果低速场景CPU占用高得离谱,高速场景又不够精确。后来学乖了,根据场景动态调整。

在Carla里,时间步长和子步长是通过Python API设置的:

import carla

# 获取世界对象
world = client.get_world()

# 设置时间步长
settings = world.get_settings()
settings.fixed_delta_seconds = 0.01  # 时间步长
settings.substepping = True          # 启用子步长
settings.max_substep_delta_time = 0.005  # 子步长最大时间
settings.max_substeps = 4            # 最大子步长数

# 应用设置
world.apply_settings(settings)

警告:不要随意把子步长设得太大。我曾经为了追求精度,把子步长设成8,结果仿真直接卡死。因为每个时间步长要算8次物理更新,CPU根本扛不住。一般来说,子步长不要超过4。

还有一个坑:固定时间步长 vs 可变时间步长。Carla默认是可变时间步长,也就是物理引擎根据实际渲染帧率来调整步长。这会导致一个问题:帧率波动时,车辆动力学表现不一致。比如你跑30帧和跑60帧,同一辆车的操控响应完全不同。

我建议,做动力学调优时,一定要用固定时间步长。这样才能保证每次仿真结果可复现。你想想看,如果连仿真条件都不一致,你怎么判断参数调得好不好?

设置固定时间步长后,还有一个好处:你可以精确控制仿真速度。比如设成0.01秒步长,那1秒仿真时间对应100步物理更新。如果你想做慢动作分析,可以把步长设小一点,比如0.005秒,这样物理更新更密集,但仿真时间会变慢。

嗯,这里要注意:固定时间步长下,如果物理计算跟不上,帧率会下降。所以你需要找到一个平衡点。我个人习惯是:先设0.01秒步长、2个子步长,跑一下看看CPU占用。如果占用超过70%,就降低子步长;如果低于30%,就增加子步长或减小步长。

最后,分享一个我曾经踩过的坑:

有一次,我在仿真高速场景时,发现车辆在120 km/h时突然失控。检查了轮胎参数、悬挂参数,都没问题。后来无意中看了一眼物理设置,发现时间步长是0.02秒,子步长是1。也就是说,每0.02秒才更新一次物理状态。在120 km/h下,0.02秒车辆已经跑了0.67米。这么长的间隔,轮胎和地面的交互信息大量丢失,不失控才怪。

把时间步长改成0.005秒,子步长设成2,问题立刻解决。所以,高速场景下,时间步长一定要足够小。这是铁律。

总结一下这一章的核心:

  • Carla用Chaos Physics,不是PhysX
  • 物理引擎由四个子系统协同工作
  • 时间步长和子步长是调优的基石
  • 根据场景动态调整,不要一套参数打天下
  • 固定时间步长是动力学调优的前提

下一章,我们会深入轮胎模型。轮胎是车辆和地面唯一的接触点,它的参数直接影响车辆的操控极限。到时候我会分享一些我在轮胎摩擦系数调优上的实战经验。