Project AirSim简介(1):无人机避障算法解析
该配置文件中通过 "robot-config": "robot_quadrotor_classic.jsonc" 指定了机器人配置,从而进一步导入 robot_quadrotor_classic.jsonc 中的详细参数设置。相机传感器(sensors)中第一个键(key)的获取,是根据前文提到的 robot_quadrotor_classic.jsonc 文件中的 id 进行匹配得到的。部分配置
一、为什么选择 Project AirSim
近年来,微软开源的AirSim 项目成为了无人机与自动驾驶研究中的重要仿真平台,但AirSim有个限制:同一仿真中无法同时使用车辆(Car)和无人机(Multirotor)。在 AirSim 中,我们需要通过修改 SimMode(SimMode=Multirotor 或 SimMode=Car)来切换模式,这意味着两种载具无法在一个世界中同时存在。
Project AirSim在原版 AirSim 的基础上进行了大量改进和重构,可以在同一场景中同时渲染无人机与地面车辆。(Issue #61 - Can ProjectAirSim support both cars and UAVs simulation?)
二、无人机避障算法解析
项目中自带了多个示例脚本,其中一个典型案例是:
ProjectAirSim/client/python/airsimv1_scripts_migrated/multirotor/navigate.py
它展示了如何让无人机基于深度图(Depth Image)实现一个简单的前向避障算法。下面我将结合源代码来详细分析其执行逻辑。
2.1 初始化与连接
首先,脚本通过 ProjectAirSimClient() 连接到仿真服务器,并加载场景与无人机对象:
client = ProjectAirSimClient()
client.connect()
world = World(client, "scene_drone_classic.jsonc", delay_after_load_sec=2)
drone = Drone(client, world, "Drone1")
其中,ProjectAirSimClient 模块负责与后端进行通信。World 会加载与 navigate.py 位于同一目录下的 sim_config 文件夹中的 scene_drone_classic.jsonc 配置文件。该配置文件中通过 "robot-config": "robot_quadrotor_classic.jsonc" 指定了机器人配置,从而进一步导入 robot_quadrotor_classic.jsonc 中的详细参数设置。
2.2 图像订阅与显示
前面,脚本使用ImageDisplay()创建显示窗口,并分别订阅追踪相机(ChaseCam)和前向深度相机(front_center depth)。
image_display = ImageDisplay()
chase_cam_window = "ChaseCam"
image_display.add_chase_cam(chase_cam_window)
client.subscribe(
drone.sensors["Chase"]["scene_camera"],
lambda _, chase: image_display.receive(chase, chase_cam_window),
)
depth_name = "Depth-Image"
image_display.add_image(depth_name, subwin_idx=0)
client.subscribe(
drone.sensors["front_center"]["depth_planar_camera"],
lambda _, depth: image_display.receive(depth, depth_name),
)
这一步的目的是在本地实时显示仿真画面,便于调试。相机传感器(sensors)中第一个键(key)的获取,是根据前文提到的 robot_quadrotor_classic.jsonc 文件中的 id 进行匹配得到的。部分配置内容如下所示。
"sensors": [
{
"id": "Chase",
"type": "camera",
"enabled": true,
"parent-link": "Frame",
"capture-interval": 0.03,
"capture-settings": [
2.3 起飞与准备工作
image_display.start()
drone.enable_api_control()
drone.arm()
await drone.takeoff_async()
无人机起飞后,将进入主循环。
2.4 深度图避障逻辑核心
主循环中,算法每一帧执行如下步骤:
2.4.1 获取前置深度图
result = drone.get_images("front_center", [ImageType.DEPTH_PLANAR])
depth_image = unpack_image(result[ImageType.DEPTH_PLANAR])
这里的 depth_image 是一个 NumPy 数组,表示视场内每个像素的深度信息。值越小表示越近。
2.4.2 取图像上半部分
top = np.vsplit(depth_image, 2)[0]
算法只分析上半部分(前方视野),忽略地面区域。
2.4.3 横向分割为五个区域
bands = np.hsplit(top, [50,100,150,200])
mins = [np.min(x) for x in bands]
将画面从左到右分为 5 个区域,并计算每个区域的最小深度值(代表最近的障碍距离)。
例如:索引 0 → 最左侧,索引 2 → 正前方,索引 4 → 最右侧。
2.4.4 判断最近障碍与最开阔方向
max = np.argmax(mins)
distance = mins[max] current = mins[2]
mins[max] 最大的区域表示“最开阔的方向”; current 是当前正前方的障碍距离。
2.4.5 悬停操作避免碰撞
if (current < 20):
await drone.hover_async()
projectairsim_log().info("whoops - we are about to crash, so stopping!")
input()
若正前方障碍过近(阈值为 20),无人机悬停并等待人工干预。
2.4.6 动态调整航向(yaw)
if (distance > current + 300):
if (max == 0):
change = -2*pi/10
elif (max == 1):
change = -pi/10
elif (max == 2):
change = 0
elif (max == 3):
change = pi/10
else: change = 2*pi/10
yaw += change
vx = math.cos(yaw)
vy = math.sin(yaw)
算法把 90° 视场分为 5 段,每段约 18°。当检测到某侧更“开阔”时,无人机偏航一定角度(±18° 或 ±36°),并重新计算速度向量。
2.4.7 以固定高度和速度前进
await drone.move_by_velocity_z_async( vx, vy, -6, 1, YawControlMode.ForwardOnly, yaw=0, yaw_is_rate=False )
move_by_velocity_z_async 是 Project AirSim 提供的用于控制无人机飞行的 API 接口。该函数使无人机在 高度 z = -6(由于 Project AirSim 采用 NED 坐标系,即 North–East–Down)时,以指定的 水平速度 vx、vy 飞行 1 秒。飞行结束后,系统会重新采样图像,并进入下一次循环。
值得注意的是,YawControlMode.ForwardOnly (= 1)(在drone.py中定义) 表示偏航角(Yaw)被限制为与运动方向保持一致,即无人机的机头始终朝向其当前的运动方向。 这也解释了在 2.4.6 节中,vx 和 vy 是根据偏航角的正弦与余弦计算得到的原因。除此之外,在drone.py文件中还定义一个MaxDegreeOfFreedom = 0,表示偏航与速度向量相互独立,即可以让无人机头朝向和移动方向不一致。
2.5 循环退出与资源释放
按下 Esc / q / x 键退出,程序会停止显示并断开连接:
image_display.stop()
client.disconnect()
3 相关连接
AirSim:https://github.com/microsoft/AirSim.git
Project AirSim:https://github.com/iamaisim/ProjectAirSim.git
为了方便使用,我在 Project AirSim 基础上略作修改:
https://github.com/QinCheng0928/UAV_UGV_Navigation_ProjectAirSim.git
本文仅为个人学习与理解笔记,水平有限,如有错误或理解偏差,欢迎评论区指正,轻喷。
希望这篇文章能帮到正在研究 Project AirSim 的同学!
更多推荐


所有评论(0)