AirSim自动驾驶仿真:Unreal Engine环境搭建与配置实战
1. 项目缘起与整体设计思路做自动驾驶仿真绕不开两个核心问题一是场景从哪来二是传感器数据怎么拿。AirSim 这个开源仿真器之所以在圈子里被反复提起就是因为它把这两个问题都接住了——它作为 Unreal Engine 的一个插件存在能直接调用 UE 的渲染管线输出逼真的相机图像同时还能模拟激光雷达、IMU、GPS 等传感器的数据流。但很多人第一次上手就卡在了第一步Unreal Engine 环境到底怎么搭工程怎么建AirSim 插件怎么挂进去。我自己前前后后搭过五六次环境从 UE4.26 到 UE5.3 都试过踩过的坑包括但不限于插件编译报错、工程打开后场景全黑、AirSim 模块加载失败、Python 端连不上仿真器。这些问题看起来零散其实根子都在环境配置这一环。所以这篇内容我打算把“创建并设置 Unreal Engine 环境”这件事从头到尾讲透不是照着官方文档念一遍而是把我实际操作的顺序、每个选择背后的理由、以及那些文档里不会写的细节都摊开来说。这篇文章适合谁看如果你已经决定用 AirSim 做自动驾驶相关的仿真验证不管是做感知算法的数据采集、控制算法的闭环测试还是单纯想跑通一个仿真 Demo那这篇内容就是为你准备的。我默认你对 Python 有基本了解对 Unreal Engine 完全没接触过也没关系我会把必要的操作都拆开讲。整个流程我会按照“先跑通再优化”的思路来组织不追求一步到位配到最优而是先让你能看到一辆车在场景里动起来再逐步调整参数和配置。在方案选型上我选择的是Unreal Engine AirSim 插件这条路线而不是直接用 AirSim 自带的预编译二进制包。原因很简单预编译包虽然开箱即用但场景是固定的你没法换地图、没法改车辆模型、没法调整传感器安装位置。做自动驾驶仿真场景的多样性是刚需你不可能只在一个街区里测算法。所以从源码编译虽然麻烦一点但后续的灵活性完全值得。另外我建议用UE4.27而不是 UE5原因后面会详细说简单讲就是 AirSim 对 UE5 的支持还不够稳定很多 API 有变动新手很容易卡在编译错误上。整个环境搭建的核心逻辑是这样的Unreal Engine 负责提供物理引擎和渲染环境AirSim 作为插件嵌入其中负责车辆动力学、传感器模拟和对外通信接口。Python 客户端通过 RPC 调用和 AirSim 插件通信发送控制指令、读取传感器数据。所以环境配置的本质就是让这三层——UE 引擎、AirSim 插件、Python 客户端——能够正确对话。任何一个环节的版本不匹配或者路径配置错误都会导致整个链路断掉。2. 核心细节解析与实操要点2.1 Unreal Engine 版本选择的门道版本选择这件事我一开始也觉得无所谓装个最新的不就行了。结果在 UE5.0 上折腾了两天AirSim 插件编译死活过不去报了一堆关于渲染 API 变更的错误。后来查了社区里的讨论才知道AirSim 的代码库对 UE5 的适配一直处于“能用但问题多”的状态尤其是 Nanite 和 Lumen 这两个新渲染特性开启后AirSim 的相机捕获会出问题。所以我的建议很明确用 UE4.27。这个版本是 UE4 的最后一个稳定版AirSim 官方文档里明确标注支持社区里绝大多数教程和问答也都是基于这个版本。你可能会想UE4 是不是太老了对于仿真来说稳定比新潮重要得多。UE4.27 的渲染质量做自动驾驶仿真完全够用物理引擎也足够成熟。具体操作上你需要去 Unreal Engine 的官网下载 Epic Games Launcher然后在 Launcher 里选择安装 UE4.27。这里有个细节安装的时候会问你要不要安装“Editor symbols for debugging”这个东西大概占 30 多 G 空间。如果你只是跑仿真不打算调试引擎源码可以不装能省不少磁盘。但如果你后续想深入看 AirSim 插件在引擎层面的调用逻辑建议装上不然调试的时候看不到调用栈。注意UE4.27 的安装路径不要有中文和空格不然后面编译 AirSim 插件的时候大概率会报路径错误。我一般直接装在D:\UE4.27这种纯英文短路径下。2.2 AirSim 插件的获取与放置AirSim 的源码在 GitHub 上开源你可以直接 clone 或者下载 zip 包。这里我建议用 git clone因为后续更新和切换分支方便。clone 下来之后你需要的核心目录是AirSim/Unreal/Plugins/AirSim这个文件夹这就是要放进 UE 工程里的插件本体。但这里有个很多人会搞混的地方AirSim 仓库里其实有两套东西一套是 Unreal 插件一套是 Python 客户端库。插件在Unreal/Plugins/AirSim目录下Python 库在PythonClient目录下。你搭环境的时候两个都要用到但放置的位置完全不同。插件要放到 UE 工程的Plugins目录下Python 库则是通过 pip 安装到你的 Python 环境里。我自己的习惯是先在磁盘上建一个总的工作目录比如D:\AirSim_Work然后把 AirSim 仓库 clone 到这个目录下。这样插件源码和后续创建的 UE 工程都在同一个父目录下管理起来清晰。clone 命令很简单cd D:\AirSim_Work git clone https://github.com/microsoft/AirSim.gitclone 完成后你会看到AirSim文件夹里面的Unreal\Plugins\AirSim就是我们要的插件。先别急着复制等 UE 工程创建好之后再放进去这样路径不容易搞错。2.3 工程目录结构的规划创建 UE 工程的时候UE 会自动生成一套目录结构。但 AirSim 插件需要放在特定的位置才能被识别。标准的做法是在 UE 工程的根目录下创建一个Plugins文件夹然后把AirSim插件文件夹整个复制进去。最终的结构看起来是这样的MyAirSimProject/ ├── Config/ ├── Content/ ├── Plugins/ │ └── AirSim/ │ ├── AirSim.uplugin │ ├── Source/ │ └── ... ├── Source/ └── MyAirSimProject.uproject这个结构看起来简单但有一个坑如果你在创建 UE 工程的时候选择了“Blank”模板UE 不会自动生成Plugins文件夹你需要手动创建。而且文件夹名字必须是Plugins大小写敏感写成plugins或者Plugin都不行。我第一次搭的时候就是因为写成了pluginUE 死活识别不到排查了半天。另外AirSim.uplugin这个文件是插件的描述文件UE 通过它来识别插件的名称、版本、依赖模块等信息。你可以用文本编辑器打开看看里面有个Modules字段列出了插件包含的模块。如果这个文件损坏或者格式不对UE 会直接忽略整个插件连报错都没有。所以复制插件的时候一定要确保文件完整最好用robocopy或者直接拖拽整个文件夹不要只复制部分文件。3. 实操过程与核心环节实现3.1 创建 Unreal Engine 工程打开 UE4.27 的 Epic Games Launcher点击“启动”按钮旁边的下拉箭头选择“新建项目”。在项目模板选择界面我建议选“Blank”模板不要选“Vehicle”或者“Racing”那些。原因有两个一是 Blank 模板最干净没有多余的蓝图和资源编译速度快二是 AirSim 插件会自己加载车辆模型和场景设置用其他模板反而可能冲突。项目设置里选择C而不是 Blueprint因为 AirSim 插件是 C 写的需要编译。项目名称用英文比如AirSimDemo路径选你刚才建的工作目录。创建完成后UE 会自动打开编辑器你会看到一个空荡荡的场景只有一个默认的 Floor 和 Sky。这时候先别急着关让编辑器把初始的着色器编译完大概需要几分钟。编译完成后关闭 UE 编辑器。然后在文件管理器里打开工程目录你应该能看到AirSimDemo.uproject文件。在这个文件旁边新建一个Plugins文件夹把之前 clone 下来的AirSim/Unreal/Plugins/AirSim整个文件夹复制进去。复制完成后目录结构应该和上面说的一样。3.2 生成工程文件与编译插件这一步是整个流程里最容易出问题的环节。UE 的 C 工程需要通过.uproject文件生成 Visual Studio 的解决方案文件.sln然后才能编译。生成的方式有两种一是右键点击.uproject文件选择“Generate Visual Studio project files”二是通过命令行调用 UE 的GenerateProjectFiles工具。我推荐用右键菜单的方式简单直接。但这里有个前提你的系统里必须装了 Visual Studio而且装了“使用 C 的游戏开发”工作负载。如果没装右键菜单里根本不会出现“Generate Visual Studio project files”这个选项。VS 的版本建议用 2019 或者 2022社区版就够用。安装的时候记得勾选“Windows 10 SDK”和“C 游戏开发工具”。生成.sln文件后双击打开在 VS 里把编译配置切换成“Development Editor”平台选“Win64”。然后右键点击工程名选择“生成”。编译过程大概需要 10 到 20 分钟取决于你的机器性能。编译成功后你会看到输出窗口显示“生成: 成功 1 个失败 0 个”。注意如果编译报错说找不到某个头文件大概率是因为 AirSim 插件依赖了一些第三方库比如 Eigen、rpclib 等。这些库在 AirSim 仓库里是作为子模块存在的如果你 clone 的时候没有加--recursive参数这些子模块就是空的。解决办法是进入 AirSim 目录执行git submodule update --init --recursive把子模块拉下来然后重新生成工程文件并编译。3.3 配置 AirSim 的 settings.json编译通过后先别急着运行。AirSim 的行为需要通过一个settings.json文件来配置这个文件决定了用哪个车辆模型、传感器怎么装、仿真模式是什么。这个文件需要放在C:\Users\你的用户名\Documents\AirSim目录下如果目录不存在就手动创建。一个最基础的settings.json长这样{ SettingsVersion: 1.2, SimMode: Car, Vehicles: { Car1: { VehicleType: PhysXCar, AutoCreate: true, Cameras: { front_center: { CaptureSettings: [ { ImageType: 0, Width: 640, Height: 480, FOV_Degrees: 90 } ], X: 1.0, Y: 0.0, Z: -0.5, Pitch: 0.0, Roll: 0.0, Yaw: 0.0 } } } } }这个配置的意思是仿真模式为 Car创建一辆 PhysXCar在车头位置装一个前视相机分辨率 640x480视场角 90 度。相机的安装位置用 X、Y、Z 坐标表示单位是米X 是前进方向Y 是右侧方向Z 是上方方向。注意 Z 是负数表示相机在车辆中心下方 0.5 米处。这个文件看起来简单但参数调整很有讲究。比如 FOV_Degrees 设成 90 度拍出来的图像会有明显的畸变如果你做视觉算法可能需要设成 60 度左右更接近真实车载相机。再比如相机的安装高度设得太低会被车头挡住视线设得太高又不像真实驾驶视角。我一般会把前视相机放在 X1.5, Z-0.3 的位置这个位置大概对应真实车辆的前挡风玻璃上方。3.4 启动仿真与验证配置好settings.json后回到 UE 编辑器点击播放按钮。如果一切正常你会看到场景里出现一辆车并且 AirSim 会在屏幕左上角显示一个绿色的“Connected”提示。这时候打开一个命令行窗口进入 AirSim 的 PythonClient 目录运行一个简单的测试脚本import airsim client airsim.CarClient() client.confirmConnection() print(Connected!) car_state client.getCarState() print(fSpeed: {car_state.speed})如果输出显示“Connected!”并且打印出了速度值说明整个链路已经通了。你可以进一步用client.moveByAngleThrottle或者client.setCarControls来控制车辆移动验证仿真是否正常响应。提示如果 Python 端报连接超时先检查 UE 编辑器里的仿真是否在运行状态。AirSim 的 RPC 服务只在仿真运行时才监听端口编辑器暂停或者停止状态下是连不上的。另外Windows 防火墙可能会拦截 RPC 端口第一次运行的时候会弹窗询问是否允许一定要点“允许访问”。4. 常见问题与排查技巧实录4.1 编译阶段的典型报错与解决编译 AirSim 插件的时候最常见的报错是“无法打开源文件”类的错误比如找不到Eigen/Dense或者rpc/server.h。前面说过这通常是子模块没拉全导致的。但还有一种情况是子模块拉下来了但路径不对。AirSim 的build.cmd脚本会自动处理这些依赖但如果你手动编译 VS 工程就需要确保AirSim/Unreal/Plugins/AirSim/Source下的AirLib目录里有完整的依赖库。另一个高频报错是“模块 AirSim 无法被加载”。这个错误通常发生在 UE 编辑器启动的时候原因是插件的.uplugin文件里声明的模块名和实际编译出来的模块名不一致。解决办法是打开AirSim.uplugin检查Modules数组里的Name字段确保和Source目录下的模块文件夹名字一致。如果还是不行可以尝试删除工程目录下的Binaries和Intermediate文件夹重新生成工程文件并编译。还有一种比较隐蔽的错误是“LNK2019 无法解析的外部符号”。这个错误说明链接阶段找不到某个函数的实现通常是因为 AirSim 的某些模块没有被正确编译进最终的 DLL。我遇到过一次是因为 VS 的编译配置选成了“Debug”而不是“Development Editor”Debug 模式下有些优化相关的宏定义不一样导致链接失败。所以编译配置一定要选对。4.2 运行阶段的常见异常仿真启动后最常见的问题是场景全黑或者只有天空。这个问题的原因通常是 UE 的默认地图没有加载或者 AirSim 插件没有正确初始化场景。解决办法是在 UE 编辑器的“Window”菜单里打开“World Settings”检查“GameMode”是否设置成了AirSimGameMode。如果没有手动选上。另外AirSim 需要一个有地面的场景如果默认地图里没有 Floor可以自己拖一个 Plane 进去。另一个常见问题是车辆掉出地图或者穿模。这通常是因为车辆的碰撞体设置不对或者地面的碰撞检测没开。在 UE 编辑器里选中地面模型在“Details”面板里找到“Collision”设置确保“Collision Presets”不是“NoCollision”。车辆的碰撞体在 AirSim 插件的蓝图里已经配好了一般不需要改但如果你的场景地面不平整可能需要调整车辆的初始高度。Python 端连接失败也是高频问题。除了前面说的仿真未运行和防火墙原因还有一个可能是 AirSim 的 RPC 端口被其他程序占用了。默认端口是 41451你可以用netstat -ano | findstr 41451检查一下。如果被占用了可以在settings.json里加一个ApiServerPort字段改成其他端口然后 Python 端连接的时候也要指定同样的端口。4.3 性能优化与参数调校仿真跑起来之后你可能会发现帧率很低尤其是开了多个相机的时候。UE 的渲染开销主要来自三个方面分辨率、后处理效果和场景复杂度。对于自动驾驶仿真来说后处理效果比如 Bloom、Motion Blur其实没什么用反而会干扰视觉算法。可以在 UE 编辑器的“Project Settings”里找到“Rendering”设置把“Default Post Processing”里的 Bloom 和 Motion Blur 关掉能省不少 GPU 资源。相机的分辨率也是性能大户。640x480 的分辨率对于大多数视觉算法来说够用了如果你非要上 1920x1080帧率可能会掉到个位数。我的建议是先用低分辨率跑通流程确认算法逻辑没问题之后再逐步提高分辨率看性能瓶颈在哪。另外AirSim 支持设置相机的捕获频率在settings.json里可以加一个CaptureInterval字段单位是毫秒设成 100 就表示每秒捕获 10 帧这样能大幅降低 CPU 和 GPU 的负载。还有一个容易被忽略的性能点是UE 编辑器的实时预览。在编辑器里点播放的时候UE 会同时渲染编辑视口和仿真视口相当于渲染了两遍。如果你不需要在编辑器里看仿真画面可以把编辑视口最小化或者直接用“Standalone Game”模式运行这样只渲染仿真视口帧率会明显提升。4.4 常见问题速查表问题现象可能原因排查方法解决措施编译报错找不到头文件子模块未拉取检查AirLib目录是否为空执行git submodule update --init --recursiveUE 启动时插件加载失败.uplugin文件模块名不匹配对比.uplugin和Source目录修正模块名或删除Binaries重新编译场景全黑无地面GameMode 未设置检查 World Settings设置 GameMode 为AirSimGameModePython 连接超时仿真未运行或端口被占检查仿真状态和端口占用启动仿真或修改ApiServerPort车辆掉出地图碰撞体未启用检查地面和车辆的 Collision 设置启用碰撞检测帧率过低分辨率过高或后处理过多查看 GPU 占用率降低分辨率、关闭后处理、降低捕获频率5. 环境搭建后的扩展思路环境跑通之后下一步通常是把仿真和你的算法 pipeline 对接起来。AirSim 的 Python API 提供了比较完整的接口包括获取图像、获取激光雷达点云、获取车辆状态、发送控制指令等。你可以用 OpenCV 直接处理client.simGetImage返回的字节流也可以用 NumPy 把点云转成数组做聚类或者分割。如果你做的是端到端的深度学习可能需要批量采集数据。AirSim 支持多相机同时捕获你可以在settings.json里配多个相机然后在 Python 端用client.simGetImages一次性获取所有相机的图像。采集的时候注意时间戳对齐AirSim 返回的图像数据里带了时间戳但不同相机的捕获时刻可能有微小差异对时间敏感的任务需要做插值对齐。另外AirSim 的场景是可以替换的。UE 的 Marketplace 里有很多免费的场景资源包你可以把 AirSim 插件放到一个更复杂的场景里比如城市街区、高速公路、乡村道路等。替换场景的时候需要注意场景的坐标系和尺度AirSim 默认使用 NED 坐标系北东地而 UE 使用的是左手坐标系插件内部会做转换但如果你自己往场景里加物体要注意坐标的对应关系。我个人在实际操作中的体会是环境搭建这件事看起来是体力活但其实每一步都有它的道理。版本选择、目录结构、参数配置这些细节决定了你后续能不能顺畅地做仿真实验。我见过不少人环境搭了一半就放弃了其实只要把编译和连接这两个环节打通后面就是水到渠成的事。最后再分享一个小技巧每次修改settings.json之后不需要重启 UE 编辑器只需要在仿真运行时按R键重置车辆位置AirSim 会重新读取配置文件。这个技巧能省不少来回启动的时间。