简介:针对中国飞行器设计创新大赛多旋翼无人机任务飞行场景,这份资源以代码工程为主,面向具备一定机器人操作系统与嵌入式基础、希望快速上手无人机自主导航与飞行控制开发的参赛者和开发者。包内共两千个文件,压缩包约九百二十二兆,涵盖C/C++与Python源码及头文件,并有大量launch/yaml启动配置、消息定义与说明文档,同时涉及Jetson Orin Nano 8G平台与V1-550机架适配,便于按模块研究系统结构。目前已有二百三十九人学习浏览。资源围绕竞赛任务整合机架设计、嵌入式软件、自主飞行算法与工具插件等模块,从底层驱动到上层感知均有源代码可读,内容预览中也能看到目标检测、卷积网络等感知相关实现;整体可作为拆解赛题方案、梳理数据流与控制链路的完整素材,并在理解开发环境后按需进行二次适配。
1. 任务飞行不只是飞起来:软件/插件配置决定你能不能在限定时间内拿分
多旋翼无人机任务飞行比单纯飞航线复杂得多——同样的机型,同样的飞控,一天前还能稳定完成定点投放,隔天换了风速和光照,航线全部跑偏,任务直接拿零分。这类任务通常由起飞、航线穿越、定点投放、识别与抓取、安全返航组成,大多数队伍把精力压在机械结构和电机调试上,真正卡住进度的往往是软件/插件配置。这篇笔记适合正在准备类似竞赛任务、想尽快跑通全流程并减少真机浪费的开发者,内容以软件工具链为主线,从选型拆到参数层,最后给出可复现的验证流程。
2. 软件/插件选型与工具链:先确定你是在“飞任务”还是在“开发任务”
2.1 地面站与飞控固件怎么搭配
任务飞行最常用的地面站是 QGroundControl(QGC)和 Mission Planner(MP),两者都能规划航线、上传任务、查看遥测和下载日志,但侧重点差别明显。QGC 对开源飞控固件的适配更规整,插件接口和视觉传感器配置入口集中,跨平台体验一致;MP 在 ArduPilot 生态里更成熟,日志分析和航线微调的工具链更完整。我一般默认选 QGC + 开源飞控固件组合,理由是比赛任务要频繁改动作参数、挂视觉插件,QGC 的“任务编辑器”和参数树结构更容易定位问题。
选型还要注意版本匹配。有一次某同学上传任务项一直失败,折腾半天发现是地面站版本和飞控固件小版本不兼容,任务协议字段对不上。这类问题在真机上很隐蔽,因为飞行、解锁、手动起降都正常,只有写 Mission 的时候才报错。建议固定一版组合并记录在队伍文档里,不要随手升级。
| 对比维度 | QGC | Mission Planner |
|---|---|---|
| 主要适配固件 | 开源飞控固件 | ArduPilot 生态 |
| 任务编辑 | 图形化、动作类型覆盖全 | 表格化、适合批量调整 |
| 日志分析 | 曲线查看、字段过滤 | 深度分析插件多 |
| 视觉/传感器配置 | 入口集中 | 散落在参数页 |
| 跨平台 | Windows/macOS/Linux | 以 Windows 为主 |
2.2 仿真环境:先搭 SITL 再碰硬件
任务飞行必须先在仿真里跑通整条航线,否则真机调试的机时成本太高。常见做法是使用开源飞控的 SITL(软件在环仿真)配合 Gazebo 或 AirSim,地面站里看到的执行逻辑和真机几乎一致。启动 SITL 后,飞控固件跑在电脑上,仿真器提供机体模型和传感器数据,QGC 通过 UDP 通信连接。
# 启动 SITL 并加载仿真器模型 make px4_sitl gazebo说明:这条命令把开源飞控固件以 SITL 方式跑起来,并启动 Gazebo 仿真环境。默认监听 14550 端口,QGC 里添加 UDP 连接即可看到飞行器。参数层面,仿真默认内置了 GPS 噪声和少量风场模型,但模型参数和真机差别很大,尤其是电池内阻、推力曲线和传感器刷新率,这些需要在真机上重新辨识。
另一个关键点是日志对比。仿真里跑出来的 PID 参数直接搬到真机经常翻车,因为真机的机架刚性和电机响应延迟不一样。我一般把仿真当作“验证任务逻辑”的工具,把真机当作“验证参数”的工具,两者职责分开。
2.3 MAVLink 协议与任务插件扩展
任务飞行中所有航线数据、动作指令、遥测信息都走 MAVLink 消息。理解这一点很重要,因为 QGC 只是图形化外壳,真正能灵活定制的是协议层。常见做法是使用 MAVSDK 或 pymavlink 写脚本,在普通电脑上遥控完成航线上传、任务启动和状态监控,甚至可以做成一键执行的状态机。
from pymavlink import mavutil # 连接 SITL 或真机,地址按实际端口改 master = mavutil.mavlink_connection('udp:127.0.0.1:14550') master.wait_heartbeat() print("已连接到飞行器") # 发送起飞指令 master.mav.command_long_send( master.target_system, master.target_component, mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM, 0, 1, 0, 0, 0, 0, 0, 0 )说明:wait_heartbeat()确保链路建立;command_long_send是通用命令通道,参数 2 置 1 表示解锁。注意这里是直接解锁,真机使用前必须确保桨叶附近无人。这个脚本的价值在于把起飞动作抽成函数,方便任务流程自动化。插件扩展方面,可以在 QGC 上挂自定义分析插件,也可以把脚本挂在旁边做状态监控,比赛实用路线是后者,因为不侵入飞控逻辑,出问题时可以快速回退。
3. 航线规划与任务动作联动:航点、投弹与时间节奏
3.1 航点参数怎么设不跑偏
比赛任务里的航点不是随便点几个坐标就完事,航线高度、飞行速度、转弯半径三者互相耦合。航点设置太低会被障碍物遮挡 GPS 信号,太高又浪费任务时间;速度太高时转弯半径不够,飞行器会冲出航线段。常见的做法是把直线段速度设为 8-12m/s,转弯段降到 4-6m/s,让飞控有足够的路径跟踪余量。
| 参数 | 推荐起始值 | 调整方向 |
|---|---|---|
| 航线高度 | 8-15m | 障碍物高则抬高,同时注意任务限高 |
| 直线段速度 | 8-12m/s | 越快越省时间,但投放精度下降 |
| 转弯半径 | 5-8m | 半径越大路径越平滑,但可能越过评分区 |
| 航点容差 | 0.5-1.5m | 容差大容易判定过点,容差小容易来回修正 |
航点容差是个容易被忽略的参数。容差设得太小,飞行器会为了“精确经过”航点反复修正,反而浪费时间;容差太大,评分系统可能认为你没经过目标点。我习惯按照任务评分圆的半径倒推,让航点容差略小于评分半径的一半。
3.2 定点投放的提前量计算
定点投放是任务飞行里最典型的“看着简单、做起来翻车”的环节。核心原因在于飞行器不是静止的,从触发投放到物体落地需要时间,这个时间段里飞行器还在往前飞。如果按飞行器当前位置直接投放,落点总会偏后。需要计算提前量:
投放提前距离 = 飞行器地速 × (物体下落时间 + 舵机/机构响应延迟) + 风速补偿项不同高度和速度下提前量不同,不能只测一个点。常见做法是提前测出机构响应延迟,比如舵机从信号发出到释放完成需要 0.2-0.3s,这一段在高速飞行时对应 1 米以上的误差。
import math # 投放点提前量计算 height = 10.0 # 当前高度 forward_speed = 10.0 # 地速 gravity = 9.8 drop_delay = 0.25 # 舵机响应延迟 # 物体下落时间(忽略空气阻力,够用) fall_time = math.sqrt(2 * height / gravity) # 提前距离 lead_distance = forward_speed * (fall_time + drop_delay) print(f"应在目标点前 {lead_distance:.2f} 米触发投放")说明:这是简化模型,真实场景建议加入风力影响。在有风天气,地速和空速不一致,要把地速代入计算;如果投放物是随风漂移的小型物体,还要测一下侧风偏移量。比赛现场通常风速不大,但侧风仍会造成横向偏差,我一般会在航线侧面多飞一轮测偏差。
3.3 任务脚本化:把评分项拆成状态链
任务飞行的时间是有限的,执行航线、投放、识别、返航每一步都影响总分。把任务拆成脚本状态链,每完成一个评分项就推进到下一状态,比让飞手全程手动操作稳健得多。
mission = [ {"action": "takeoff", "altitude": 10}, {"action": "goto", "lat": 31.2318, "lon": 121.4721, "speed": 10}, {"action": "drop", "lead_distance": 6.5}, {"action": "hover", "duration": 3}, {"action": "rtl"} ] for step in mission: print("执行任务环节:", step["action"]) # 实际开发中这里调用 MAVSDK 或 pymavlink 执行对应动作说明:这里的列表结构只体现状态划分思路,实际代码里每个动作要对应到具体的协议指令。脚本化的好处是每步之间的延时可控,复现性好。比赛前我会反复跑这个状态链,确保真机和仿真里的时序一致。
4. 避障与视觉识别:传感器数据质量比模型精度更先决
4.1 避障传感器选哪些
多旋翼任务飞行的避障分为两类:一类是航线级的绕障,提前规划路径躲开已知障碍;另一类是意外障碍检测,靠传感器反馈实时规避。比赛中后者更常见,比如突然闯入视场的风筝线、树枝、其他飞行器。传感器选配要综合考虑重量、刷新率和探测距离。
| 传感器 | 探测距离 | 刷新率 | 适用场景 |
|---|---|---|---|
| ToF 单点测距 | 2-4m | 30-50Hz | 近距离防撞、地形跟随 |
| 双目视觉 | 5-20m | 10-30Hz | 中距离障碍识别 |
| 激光雷达 | 10-40m | 5-20Hz | 全向避障、地图构建 |
| 超声波 | 0.2-5m | 20Hz | 近距离与地面避障 |
任务飞行机上重量受限,我一般建议带一个 ToF 朝下做地形跟随,再加一个双目视觉朝前做障碍探测。避障不是传感器越多越好,多传感器意味着参数冗余和调试时间翻倍,比赛周期内根本调不完。
4.2 视觉识别插件和曝光参数
识别任务的目标通常是颜色标靶或特定图形,OpenCV 在插件生态里最方便。常见实现是颜色阈值分割 + 轮廓查找 + 中心偏移计算,然后把偏移量通过 MAVLink 回传给飞控。这个链路不复杂,容易翻车的是相机曝光和帧率参数。
import cv2 import numpy as np cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() if not ret: continue # 转 HSV 便于颜色提取 hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # 识别红色标靶,比赛用色通常饱和度较高 mask = cv2.inRange(hsv, (0, 100, 100), (10, 255, 255)) contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: area = cv2.contourArea(cnt) if area > 300: x, y, w, h = cv2.boundingRect(cnt) target_cx = x + w / 2 frame_cx = frame.shape[1] / 2 offset = target_cx - frame_cx print("横向偏移像素:", offset)说明:inRange的 HSV 阈值是第一个坑,不同光照环境下同一个颜色的阈值变化很大。比赛当天如果是阴天,红色标靶的 V 通道会明显不同。关键参数是相机的自动曝光,务必要关掉,改成固定曝光时间和固定增益,否则检测面积时好时坏。帧率方面 30fps 够用,重点是处理延迟要稳定,不要出现单帧卡顿。
4.3 传感器数据异常与优先级
传感器数据不能直接信,要加有效性判断。比如 ToF 在草地或反光材料上会跳变,视觉在逆光下会丢帧,两者同时报出冲突位置时,避障逻辑要定义优先级。我通常把超声波作为最后一道保护,把视觉作为主导,ToF 作为地形跟随,三层之间做简单的投票机制,优先级低的自动忽略。
需要注意“悬崖效应”:朝下的测距传感器在越过高处边界时,数值会瞬间跳变,如果避障逻辑把这个跳变理解成地面突然升高,飞机会猛拉高度。解决方案是加入变化率限幅,单次数据变化超过一定阈值时不更新。
5. 真机与仿真避坑:五种翻车场景的排查与复位
5.1 起飞后往一侧漂移
现象:解锁起飞后飞行器朝某个方向持续漂移,回中后仍然漂。
原因:磁罗盘校准未覆盖当前磁场环境,常见于场地存在钢筋结构或充电设备干扰。还有一种情况是机架上有金属物质改变了磁传感器读数。
解决:重新做磁罗盘校准,校准时机体要在无金属区域缓慢旋转,俯仰和横滚都要转满。如果校准后仍然漂移,检查电机座螺丝是否有退磁现象,替换非磁化螺丝。
5.2 定点投放每次都偏后
现象:投放点明明计算好了,但落点总是在目标后方一段距离。
原因:提前量公式里的地速用的是飞行速度设定值,而不是实际地速。顺风飞行时地速大于设定值,逆风时小于设定值,偏差在高速段尤其明显。
解决:从遥测日志里取实际地速反馈,或者用视觉定位辅助。投放时读取最新地速再计算提前量,不要用任务里填写的速度值。
5.3 视觉识别时好时坏
现象:同一条航线上午识别正常,下午识别不到标靶,或者检测框乱跳。
原因:光照变化导致自动曝光不断调整,HSV 阈值随之失效;另一种可能是任务期间电池电压下降,相机供电不稳导致帧率波动。
解决:把相机曝光模式改为手动,固定曝光时间和增益;给相机加独立稳压模块,排查电池低电量时的压降。比赛现场建议在起飞前拍一张当次光照下的标靶图,动态调整 HSV 范围。
5.4 仿真能过、真机过不了
现象:仿真里航线、投放、返航全部正常,真机上首飞就偏离航线或者姿态振荡。
原因:仿真环境的传感器噪声模型过于理想,GPS 定位精度、气压计漂移、电机响应延迟都和真机差距大;另外机架振动的频率特性没有进入仿真模型。
解决:把真机日志的震动频谱和加速度数据回放到仿真模型里,做一次模型校准。更稳妥的方案是在真机上先做小幅悬停参数辨识,再把辨识结果替换仿真参数,最后跑完整航线。
5.5 RTL 返航撞障碍物
现象:任务结束后返航,飞行器在途中撞到树冠或楼顶边缘。
原因:返航模式的高度参数设置为固定值,而返航路径上的障碍物高于该值;或者周界设置错误,飞行器从远处执行 RTL 时沿直线返回,路径和去程不一致。
解决:把返航高度设成任务航线最高点再加 5 米以上,并检查 RTL 行为模式的路径规划方式。如果任务场地环境复杂,干脆把返航点设在场地上空宽阔区域,不要直接设起飞点。
6. 从仿真到真机的验证流程:一个我改过的关键参数
6.1 一小时飞行前验证清单
真机飞行前的时间比飞行本身值钱。我的习惯是列一张验证清单,每项检查不超过 10 分钟,全部走完才允许解锁起飞。这张表解决了大多数“到现场才手忙脚乱”的问题。
| 检查项 | 方法 | 通过标准 |
|---|---|---|
| 磁罗盘校准 | 场地中央旋转机体 | 校准完成无异常 |
| GPS 定位 | 观察卫星数和水平精度 | 卫星数大于 10,水平精度小于 1m |
| 航线上传比对 | 地面站重读任务项 | 航点数、动作类型与脚本一致 |
| 曝光参数锁定 | 手动曝光在阴面测试 | 检测识别稳定,偏移量波动小 |
| 遥测链路 | 拉距测试到任务最远端 | 心跳不间断,RSSI 有余量 |
| 电量与返航点 | 记录电池电压和返航点位置 | 返航点正确,电压满足续航 |
6.2 一个关键参数:返航时的风速补偿阈值
这里说一个我印象深刻的调整。某次模拟项目里,飞行器在 6m/s 侧风中执行任务,航线段偏航纠偏正常,但 RTL 返航路径始终偏右,最后落在安全区外。排查日志发现飞控的返航控制里风速补偿阈值默认偏低,飞行器实际偏移量已经积累到很大才触发修正。后来我把风速补偿阈值从默认值调到更敏感的范围,同时给航线加了一版基于风向的侧偏预补偿。从那以后我每次飞行前都强制走一遍完整的磁罗盘校准和风速补偿检查,再不敢拿仿真参数直接上真机,毕竟一套流程十几分钟,换来的是不炸机、不丢分。希望帮到你。
本文还有配套的精品资源,点击获取