一、学学知识
① UE4 是什么?
② AirSim 是什么?
- AirSim 是微软开源的一个跨平台的建立在虚幻引擎(Unreal Engine)上的无人机以及其它自主移动设备的模拟器。它支持硬件在循环与流行的飞行控制器的物理和视觉逼真模拟。它被开发为一个虚幻的插件,可以简单地放到任何你想要的虚幻环境中。
- 该模拟器创造了一个高还原的逼真虚拟环境,模拟了阴影、反射等其它现实世界中容易干扰的环境,让无人机不用经历真实世界的风险就能进行训练。
- AirSim 的目标是作为 AI 研究的平台,以测试深度学习、计算机视觉和自主车辆的增强学习算法。为此,AirSim 还公开了 API ,以平台独立的方式检索数据和控制车辆。
③ UE4 和 AirSim 的关系
- AirSim 是基于虚幻引擎开发的仿真平台,是作为虚幻引擎的插件而存在的。
二、开始配置
① 硬件要求
- 来自 Unreal Engine 官网:为了最大程度发挥 Nanite 、虚拟阴影贴图和 Lumen 的潜力,我们目前推荐 NVIDIA GTX 1080 或 AMD VEGA 64 显卡及同类或更高端的产品。要配合 Lunmen 使用硬件光线追踪,我们推荐 NVIDIA RTX 20 系列或 AMD RX 6000 系列显卡,或更高端产品。我们还推荐将您的显卡驱动更新到最新版本。
- 虽然 AirSim 支持 Linux,但是如果使用 Linux系统,则会造成很多麻烦。比如目前还没有 Linux 版本的 Epic Games 启动程序,如果想要新建仿真场景,则需要先在 Windows 电脑上创建场景工程文件,然后将其拷贝到 Linux 电脑上。
② 安装虚幻引擎
③ 下载 AirSim 源码
- 先进入到预备放置的文件夹中(不建议C盘)。输入指令:
git clone https://github.com/Microsoft/AirSim.git下载 AirSim 源码。
CD AirSim 进入 “AirSim” 文件夹,输入build.cmd,开始编译AirSim。编译好之后会在 “AirSim\Unreal” 文件夹中生成 “Plugins” 文件夹,将它复制到虚幻引擎的工程中就可以使用 AirSim 插件了。
④ Block 环境测试
- 打开 “Developer Command Prompt for VS 2019”,
CD Airsim\Unreal\Environments\Blocks进入 “Airsim\Unreal\Environments\Blocks” 文件夹,输入 update_from_git.bat生成 “Blocks.sln” 工程文件,双击打开此工程文件,会自动运行 Visual Studio。
- 在 Visual Studio 中,将 “Block工程” 设为启动项目,编译选项设为 “DebugGame_Editor” 和 “Win64”,然后点击 “调试” -> “开始调试”,这时就会打开Unreal Engine。
- 点击“运行”,此时会跳出一个对话框,点击 “No”,就会出现一个四旋翼无人机。
三、尝试让无人机在场景中飞行
① 下载并配置 Landscape Mountains

- 在安装的地址中找到
LandscpeMountains.uproject,双击打开。

- 为了能够使用 Visual Studio 编译
.sln文件,我们需要创建自己的类。点击左上角的文件,选择新建C++类,父类选择无,所以直接点击下一步;命名和路径都是默认就好了,直接点击创建类。这时Unreal会自动编译C++代码,然后会自动打开Visual Studio。到此 Landscape Mountain环境就下载安装好了。

② 添加 AirSim 插件
- 找到
AirSim\Unreal\Plugins文件夹,并将其复制到LandscapeMountains文件夹中。

- 右键
LandscapeMountains.uproject打开,并用英文输入法将内容改为如下所示。

- 然后右键点击
LandscapeMountains.uproject选择Generate Visual Studio project files。

③ 跑起来!
- 双击打开
LandscapeMountains.sln,会自动打开 Visual Studio,选择编译选项为 DebugGame Editor 和 Win64,同时确保LandscapeMountais为启动项目。

- 用 pyCharm 打开预先写好的控制代码,右键跑起来!

"""
airsim 四旋翼飞圆形
"""
import airsim
import numpy as np
import math
import time
client = airsim.MultirotorClient()
client.enableApiControl(True)
client.armDisarm(True)
client.takeoffAsync().join()
client.moveToZAsync(-3, 1).join()
center = np.array([[0], [5]])
speed = 2
radius = 5
clock_wise = True
pos_reserve = np.array([[0.], [0.], [-3.]])
for i in range(2000):
state = client.simGetGroundTruthKinematics()
pos = np.array([[state.position.x_val], [state.position.y_val], [state.position.z_val]])
dp = pos[0:2] - center
if np.linalg.norm(dp) - radius > 0.1:
vel_dir_1 = -dp
elif np.linalg.norm(dp) - radius < 0.1:
vel_dir_1 = dp
theta = math.atan2(dp[1, 0], dp[0, 0])
if clock_wise:
theta += math.pi / 2
else:
theta -= math.pi / 2
v_dir_2 = np.array([[math.cos(theta)], [math.sin(theta)]])
v_dir = 0.08 * vel_dir_1 + v_dir_2
v_cmd = speed * v_dir / np.linalg.norm(v_dir)
client.moveByVelocityZAsync(v_cmd[0, 0], v_cmd[1, 0], -3, 1)
point_reserve = [airsim.Vector3r(pos_reserve[0, 0], pos_reserve[1, 0], pos_reserve[2, 0])]
point = [airsim.Vector3r(pos[0, 0], pos[1, 0], pos[2, 0])]
point_end = pos + np.vstack((v_cmd, np.array([[0]])))
point_end = [airsim.Vector3r(point_end[0, 0], point_end[1, 0], point_end[2, 0])]
client.simPlotArrows(point, point_end, arrow_size=8.0, color_rgba=[0.0, 0.0, 1.0, 1.0])
client.simPlotLineList(point_reserve + point, color_rgba=[1.0, 0.0, 0.0, 1.0], is_persistent=True)
pos_reserve = pos
time.sleep(0.02)