拓冰建站拓冰建站
首页 / 资讯中心 / 正文

基于AirSim的二维无人机避障算法仿真与Python实现解析

简介基于AirSim仿真平台的二维无人机避障算法研究Python实现源码包面向无人机避障算法初学者、机器人方向学生及毕业设计开发者适合作为课程设计、毕设课题或算法对比实验的基础工程。项目聚焦二维平面内的自主避障任务提供了两种算法的Python实现一种利用距离传感器返回的测距信息进行避障判断另一种利用摄像头采集的深度图像完成环境感知两类方案均可在AirSim构建的虚拟场景中运行并配有测试场景图片便于直观理解运行环境与算法效果。压缩包共6个文件包括2个Python源码文件、3张场景示意图和1个说明文档整体大小约5.12MB结构精简既便于初学入门也方便二次调试。该资源已有638人学习说明其在同类避障研究或毕业设计场景中具有一定参考价值。通过阅读源码读者能掌握AirSim中传感器和图像数据的读取接口学习距离式避障与视觉式避障在判断逻辑、阈值设定及场景适应性上的差异同时现有工程结构为修改仿真场景、调整检测参数、切换传感器输入或后续扩展三维避障研究提供了可复用的起点。 先聊几句闲话。无人机避障这个方向我个人这几年看下来最劝退新手的反而不是算法本身而是“真机试错成本”。桨叶、电机、机架哪一样摔了都肉疼更别提飞控参数没调好、姿态解算出问题很多时候还没跑到避障那一步飞机已经在草丛里躺着了。所以当我看到这个标题——基于AirSim仿真平台的二维无人机避障算法研究、Python实现源码——我第一反应是这个切入点选得挺聪明。AirSim加上二维场景等于把“环境感知”和“决策控制”的难度都拉到了适合入门研究的位置既能把避障逻辑跑通又不会被传感器噪声、动态建模这些深坑拖死。这篇博文我就围绕这个项目把这个仿真方案的前前后后掰开揉碎讲一遍包括为什么选AirSim、二维避障通常怎么做、Python端怎么跟仿真器对接、算法核心怎么写以及我实测中踩过的一些坑。内容主要是基于常见实践做的补充梳理适合准备做无人机仿真课题、或者想低成本入门无人机算法的朋友参考。1. 项目整体设计与技术选型思路1.1 为什么偏偏是AirSim而不是Gazebo或其它平台这两年无人机仿真的选择其实不少Gazebo配PX4、AirSim、甚至Webots都能干这事。但这个项目既然把AirSim放在标题里肯定有它的道理。我个人的体验是AirSim在“视觉感知”和“Python友好度”这两点上优势非常明显。AirSim是微软开源的一套基于虚幻引擎的仿真平台它渲染出来的场景真实度比Gazebo那种基于OGRE的渲染高出不少。对于避障算法来说如果你打算用视觉方案比如深度图或者单目图像去做障碍物检测那么场景渲染的真实程度会直接影响算法迁移到真机的效果。AirSim在这一点上几乎是无缝衔接它底层用虚幻引擎的物理和渲染同时又提供了一套非常干净的Python API可以直接拿到图像、深度、位置、姿态、激光雷达点云等数据不需要你自己去写中间件。再一个就是坐标和运动模型。AirSim内置了多旋翼的动力学模型你给它一个速度或者位置指令它会通过内置的PID控制器去执行不会出现“你发一个设定值它瞬间瞬移过去”这种脱离物理的假象。对于研究避障算法的人来说这一点很重要因为避障不仅要“算出路径”还要考虑飞行器能不能跟上这条路径。相比之下Gazebo的优势在于跟ROS、PX4的生态整合更强如果你后续要接真正的PX4飞控、跑完整的软硬件在环Gazebo那条链路会更接近工程落地。但如果你现阶段的目标就是把避障算法本身跑通、把论文图表做出来、快速验证想法AirSim的Python API会让你少走很多弯路。1.2 二维避障的定位为什么说它是个“刚刚好”的研究粒度标题里明确写了“二维无人机避障”有些朋友可能觉得二维是不是太简单了。我倒觉得二维场景是研究避障绕不开的第一步而且它并不是“降维打击”到没有意义。你想想看无人机在定高飞行模式下高度方向由飞控锁定这时候避障问题本质上就退化成二维平面内的路径规划问题。二维场景下你可以集中精力去处理“传感器数据怎么来—障碍物怎么表示—路径怎么生成—控制指令怎么下发”这条完整链路而不用一上来就面对三维空间里OBB碰撞体、四元数姿态插值、空间搜索策略爆炸这些复杂问题。这个项目的二维设定还有个实际好处——可视化和调试非常直观。你可以用Matplotlib把无人机位置、障碍物、规划路径一次性画在一张图上算法哪里有毛病一眼就能看出来。三维的话调试起来真的会头疼你得不停旋转视角找盲区。所以这个项目其实是在“够用”的复杂度下把整个仿真闭环打通了后续如果要做三维扩展底层的AirSim接口和Python控制框架完全可以复用只是把障碍物检测和路径搜索从二维改成三维的问题。2. AirSim环境搭建与Python接口对接2.1 环境准备与API模式选择AirSim在使用上有一个前置概念必须搞清楚仿真器有两种模式。一个是AP模式Area Park也就是只运行AirSim自己的模拟不接外部飞控另一个是CP模式Complete Park全栈仿真需要外接PX4等飞控。这个项目标题既然提到Python实现而且核心是避障算法那大概率用的是AP模式也就是你不需要折腾PX4、QGroundControl那些外部依赖直接让AirSim自带的动力学模型跑起来就行。这个选择很务实。我自己在Ubuntu和Windows上都搭过AirSim如果一开始就上CP模式配PX4光是版本匹配和环境变量就够折腾几天的。而AP模式下你只要下载编译好的AirSim二进制包或者从源码编译启动模拟环境后Python那边通过airsim这个pip包就能直接连上。安装Python客户端很简单pip install airsim连接方式更简单import airsim client airsim.MultirotorClient() client.confirmConnection() client.enableApiControl(True) client.armDisarm(True)这几行意味着你已经有了一台在仿真世界里待命的无人机随时可以下指令。2.2 数据获取拿什么“眼睛”去看障碍物二维避障的前提是知道障碍物在哪里。在AirSim里最常用的传感器有三种激光雷达、深度相机、以及简单的光线投射检测。因为它们都通过Python API直接提供不需要在虚幻引擎编辑器里做额外配置不过需要在settings.json里启用了对应传感器。先说深度相机方案。AirSim可以返回相机的深度图用client.getDepthImageData()或者直接拿ImageRequest请求DepthPerspective类型的数据。拿到深度图之后你可以把图像中心区域的平均深度当成“前方障碍物距离”来用。这个方案最简单但要注意深度图有视场角限制旁边飞过来的障碍物可能完全感知不到。再说激光雷达方案。AirSim里启用Lidar后可以用client.getLidarData()拿到点云。对于二维场景你可以只取无人机的水平扫描面也就是让激光雷达发出的射线保持在同一个平面内然后把这些水平射线打到障碍物上的距离值组成一个“距离数组”。这个数组就相当于扫地机器人上面那种2D雷达扫描结果后面接什么避障算法都方便。我的建议是如果只是做算法验证优先用AirSim自带的激光雷达或光线投射方案因为数据格式清晰、没有深度图那种“尺度模糊”问题。如果后续想往视觉避障方向发论文、或者复现别人的视觉方案再切换到深度图输入。2.3 动作控制MoveToPosition还是MoveByVelocity拿到障碍物信息之后怎么控制无人机运动又是一个选择点。AirSim的Python API里主要两类控制接口moveToPositionAsync(x, y, z, velocity)给目标点内部PID帮你飞过去moveByVelocityAsync(vx, vy, vz, duration)给速度矢量飞指定时长。做避障的时候我强烈建议用moveByVelocityAsync。原因是避障算法本质上是在每个控制周期根据环境信息决定“下一步往哪个方向飞多快”这是一个连续决策过程跟速度控制天然的匹配。而moveToPositionAsync更适合“已知全局路径、点到点飞行”的场景。举个例子当你检测到前方3米有障碍物时你可能想“减速并向右绕行”这用速度控制就是client.moveByVelocityAsync(2.0, -1.5, 0, 1).join()表示接下来1秒内以2m/s的前飞速度、1.5m/s的向右速度飞行。如果换成位置控制你得先算出绕行目标点飞行过程中一旦感知到新的障碍物还得重新规划目标点实时性反而差了。3. 二维避障算法的Python实现解析3.1 算法选型为什么不用A*或RRT既然标题里写的是“避障算法”很多人第一反应可能是A*、Dijkstra、RRT这种路径规划算法。但在做仿真验证的时候我建议先想清楚你的场景是“已知地图的静态路径规划”还是“未知环境的在线避障”。AirSim里的无人机其实是不知道完整地图的——你虽然可以在代码里手动设置障碍物坐标但在真实飞行中障碍物位置是通过传感器实时探测的。所以这个项目更适合用“反应式避障”或者“局部规划”的思路。比如经典的人工势场法、动态窗口法DWA、或者更简单的“候选速度空间法”。我在类似项目里最常用的是一种基础但有效的方案——候选方向评估法。思路不复杂把无人机当前朝向的左右各60度范围内均匀取样N个候选方向对每个候选方向利用激光雷达距离数组判断“这个方向上是否安全”即该方向上的最小障碍物距离是否大于安全阈值在安全的方向里选择“与目标方向夹角最小”的那个方向如果是全向障碍物包围就悬停或者原地旋转。这个算法在二维场景下表现非常稳健计算量小而且完全符合“在线感知—实时决策”的避障定义。3.2 核心代码结构与避障函数实现伪代码级别的核心逻辑可以这么写import airsim import numpy as np import math client airsim.MultirotorClient() client.confirmConnection() client.enableApiControl(True) client.armDisarm(True) client.takeoffAsync().join() # 假设已经在settings.json里启用了lidar def get_obstacle_distances(): lidar_data client.getLidarData() points np.array(lidar_data.point_cloud, dtypenp.float32).reshape(-1, 3) if len(points) 0: return [] # 计算每个点到无人机的水平距离和角度 distances [] for p in points: x, y, _ p dist math.hypot(x, y) angle math.degrees(math.atan2(y, x)) distances.append((dist, angle)) return distances def decide_new_velocity(target_heading_deg, obstacle_distances, max_speed3.0): safe_angle_range 30 # 安全半角 candidates np.arange(-60, 61, 5) best_candidate None best_score -float(inf) for cand in candidates: # 检查该方向附近是否有障碍物 collision False for dist, angle in obstacle_distances: if abs(angle - cand) safe_angle_range and dist 2.0: collision True break if collision: continue # 倾向选更接近目标方向且偏航角变化小的方向 score -abs(cand - target_heading_deg) - 0.1 * abs(cand) if score best_score: best_score score best_candidate cand if best_candidate is None: return 0, 0, True # 悬停 # 转成机身坐标系下的速度分量 rad math.radians(best_candidate) vx max_speed * math.cos(rad) vy max_speed * math.sin(rad) return vx, vy, False # 主循环 while True: dists get_obstacle_distances() vx, vy, should_hover decide_new_velocity(0, dists) if should_hover: client.moveByVelocityAsync(0, 0, 0, 0.5).join() else: client.moveByVelocityAsync(vx, vy, 0, 0.5).join()代码逻辑清晰理解成本低。但有几个细节必须注意第一getLidarData()返回的点云是世界坐标系还是机体坐标系取决于AirSim设置。如果没做坐标变换可能会导致左右判断颠倒。我的经验是先把点云打印出来对比无人机实际朝向确认坐标系再写算法逻辑。第二safe_angle_range和dist 2.0这两个阈值是整个算法的灵魂。阈值设太大无人机会绕远路甚至转圈设太小容易擦着障碍物飞过。我建议先在地图上设置几个稀疏障碍物用绘图把探测到的距离数组画出来再调阈值。第三moveByVelocityAsync带join()会阻塞当前线程直到指令执行完。在实时避障循环里抖动控制和决策频率要匹配好我一般把单次控制指令时长定在0.3到0.5秒太短飞控来不及响应太长则避障不及时。3.3 人工势场法的另一个参考实现跟候选方向法相比人工势场法是另一种经典路线。它的思路是把目标点看成“引力源”把障碍物看成“斥力源”无人机受到的合力方向就是运动方向。def potential_field_control(target_pos, obstacle_list, current_pos, k_att1.0, k_rep2.0, d02.0): # 引力方向 to_target np.array(target_pos) - np.array(current_pos) dist_to_target np.linalg.norm(to_target) att_force k_att * to_target / dist_to_target if dist_to_target 0 else np.zeros(2) # 斥力方向 rep_force np.zeros(2) for obs in obstacle_list: obs_pos np.array(obs[:2]) dist_to_obs np.linalg.norm(obs_pos - np.array(current_pos)) if dist_to_obs d0: rep_force k_rep * (1.0 / dist_to_obs - 1.0 / d0) * (1.0 / dist_to_obs**2) * (np.array(current_pos) - obs_pos) / dist_to_obs total_force att_force rep_force return total_force / (np.linalg.norm(total_force) 1e-6)人工势场法实现简单但经典版有两个著名缺陷局部极小值问题和目标不可达问题。无人机可能在某两个障碍物中间来回震荡或者目标点刚好在障碍物附近时产生抖振。如果项目是为了做对比实验你可以把候选方向法和人工势场法都跑了用轨迹图直观展示两种算法的优劣这在论文里是很有说服力的一组对比图。4. 仿真场景搭建与实验流程4.1 在AirSim里布置障碍物场景AirSim默认有几张地图可以玩比如Blocks环境和LandscapeMountains。对于二维避障研究Blocks环境是最理想的里面有很多规则的立方体建筑你可以把它们当作障碍物。如果你需要自定义障碍物布局有两种做法。一种是在虚幻引擎编辑器中手动摆放物体这种方式效果最真实但你需要安装虚幻引擎、编译AirSim插件流程较重。另一种是用AirSim的设置文件配合代码动态生成障碍物常见做法是用settings.json里定义多个simmode或者直接加载不同地图。我个人的建议是第一版实验不需要在虚幻编辑器里折腾直接用Blocks地图里面天然的墙面、柱子就可以当成障碍物使用。你只需要设定无人机的起点和目标点让它在街区里飞一段看避障算法能否让它绕开墙体到达目标点。场景设定好之后你的实验流程大概是设置无人机初始位置和朝向启动主循环无人机进入避障模式记录每0.1秒的无人机位置、速度、和目标点距离最终判断无人机是否在限定时间内到达目标点附近比如距离0.5m途中是否发生碰撞AirSim的碰撞状态可以通过getCollisionInfo().has_collided读取。4.2 实验指标怎么设不只“有没有撞”很多新手做避障实验只关注一个指标有没有撞上。但如果你准备写论文或者做完整项目总结光一个碰撞率是远远不够的。我建议至少记录下面几项航线偏移量无人机偏离理想直线路径的距离反映避障的“代价”到达时间从起点到终点的总耗时反映算法效率平滑度相邻时刻航向角变化量反映无人机飞行是否平稳最小安全距离飞行全程与障碍物的最近距离反映算法保守程度。把这些指标记录下来之后你还可以调整算法参数比如安全距离阈值、候选方向间隔画出一条“参数—指标”的变化曲线。这组实验不仅让项目内容更扎实而且对理解算法本质非常有帮助。比如我做过一个简单测试安全距离阈值从1.5米调到3.0米碰撞率确实降到了零但到达时间增加了差不多一倍路线偏移也变大了。这说明避障算法本质上是“风险”和“效率”的博弈没有绝对最优只有针对场景的调参。这些数据放在你的项目总结里含金量比单纯贴一段能跑的代码高得多。5. 常见问题与排查技巧实录5.1 AirSim连接失败或API超时这类问题几乎每个新手都会遇到。现象是Python端报错RuntimeError: Cannot connect to AirSim或者长时间卡在confirmConnection()。排查思路分两步。第一确认仿真器是不是真的启动好了——AirSim的窗口弹出来后还需要等左下角出现“Press Play”或场景完全加载完成连接指令才不会超时。第二检查你是不是在启动AirSim之前就先运行了Python脚本。AirSim的RPC服务是在场景启动后才开始监听的先跑客户端大概率连接失败。正确顺序永远是先开仿真器再跑Python端。另外如果开启了多个AirSim进程或者之前有异常退出RPC端口可能会被占用。把仿真器和Python进程全部退出等几秒再重试很多时候就能解决。5.2 无人机起飞后原地打转或匀速往外飞这个问题十有八九是坐标系搞错了。AirSim的getLidarData()返回的点云默认是“机体坐标系”还是“世界坐标系”取决于你读取数据时是否做了变换。如果点云原点在无人机当前位置而你用世界坐标系的期望航向去算相对角度无人机就会朝错误方向避障表现出来就是乱转。我的排查办法是先写一段测试脚本把无人机水平旋转90度然后打印激光雷达点云中某个已知障碍物的坐标变化。如果障碍物的坐标跟着无人机旋转了说明点云是机体坐标系如果不变就是世界坐标系。相当于先确认“我的眼睛装在哪个位置”再去写避障逻辑。5.3 避障过程卡在局部震荡哪怕你用的是候选方向法如果候选方向取样间隔太粗或者安全角度阈值太大也可能出现无人机在两个候选方向之间反复横跳的局面。比如前方左45度和右45度都是可通行方向算法可能这帧选左下帧选右机身来回摆动。改善方法有三个方向一是加“航向惯性”——让候选方向打分函数里包含“与当前机头朝向的偏差”惩罚项无人机不会突然大角度转向二是提高决策频率让方向切换更平滑三是加一个简单的“记忆”逻辑规定某方向一旦选中至少保持0.5秒不变。这些都实现起来不难但对飞行质量的改善非常明显。5.4 Python版本和依赖库的坑项目说“Python实现源码”但Python版本不同AirSim客户端兼容性也会有差异。我实测下来Python 3.8到3.10问题都不大但装的时候尽量用干净环境装airsim包避免跟已有的numpy版本冲突。airsim对numpy有依赖如果你先装了一个特别新的numpy版本有时反而会报_ARRAY_API not found这类错误这时把numpy降级到1.23左右基本就能解决。另外建议用Anaconda或venv建一个独立环境AirSim不像ROS那样有完整的依赖管理但隔离环境能让你在出问题时快速重建不用动系统级的Python环境。6. 从仿真到实机的扩展心得仿真做完之后很多人会问这东西能直接搬到真机上吗我泼一盆冷水不能但仿真阶段积累的“感知—决策—控制”框架是有迁移价值的。AirSim仿真和真机的主要差异体现在三个方面。一是传感器噪声模型AirSim的激光雷达点云过于干净真机上有抖动、有温度漂移、有测量误差算法阈值必须重新标定。二是执行延迟仿真环境里moveByVelocityAsync几乎即时执行但真机上从飞控接收到速度指令到电机实际响应中间有几十毫秒的延迟这会直接限制避障算法的最大飞行速度。三是场景动态性仿真里障碍物是静止的真机上可能有移动的行人、车辆避障算法要考虑时间维度的变化。所以从仿真到实机正确的做法是先在仿真里加入高斯噪声、随机动态障碍物把算法“搞难受”再上真机。同时要确保控制频率和决策频率匹配飞行速度先设置在1m/s以内逐步增加。从我个人的角度来说这个项目的价值不仅仅是“写了一段避障代码”而是把整个仿真闭环——环境感知、算法设计、控制接口、实验验证——完整地串了起来。你在调试过程中得到的那些阈值调整经验、坐标系排查方法、震荡解决方案才是真正能沉淀下来的东西。如果你正在做类似研究我建议先别急着加新功能多花点时间把基础避障场景的稳定性打磨好再去扩展三维空间、动态障碍物、或者是接ROS2做更完整的机载规划链路。这样一步一步走后面的路会顺很多。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门