最终结果
完整任务链跑通
夹蛋起飞、沿线飞行、中途降高动作与终点放蛋均已完成
巡航高度
0.6 m
由 0.8 m 多次实飞后收敛出的最佳稳定点
飞行时长
约 1 分 30 秒
通过多次实飞调参,由约 2 分钟压缩而来
红色识别参数
C=0.6 / T=40 / E=0
在实时性与抗误检之间取得最好平衡
篮筐减重
54.9 g → 3 g
最终版本兼顾强度、重心和载荷约束
落台容差
±32.5 mm / 27.8°
通过地面基础设施放宽精确着陆要求
项目概览
这个项目要解决的不是单点功能,而是一整条真实的无人机任务链路:让一架 Parrot Mambo 在机载计算能力、有效载荷和飞行稳定性都很有限的前提下,依靠下视摄像头识别红色路径与圆形标记,自主完成夹蛋起飞、沿线飞行、中途圆点处降高、终点放蛋,以及最后的受控降落。
系统难点主要集中在子系统耦合。视觉需要在有限算力下稳定输出可用信号,飞控需要把离散视觉标志位组织成连续动作,机械结构则不能显著破坏重心与气动表现。任何一环不稳定,整机都会退化成若干彼此割裂的单点功能。
实现层面上,整套系统基于 MATLAB / Simulink 搭建。视觉处理、控制器、混合器和保护逻辑主要以方块图形式组织,任务阶段切换则通过 Stateflow 状态机实现,并结合 Parrot Mambo 的支持包部署到无人机上运行。因此,后续开发和调试基本都围绕模型结构、参数切换和机载联调展开。
任务本身是一条完整的空间链路,而不是单次起降演示。无人机先从起点夹取鹌鹑蛋,沿地面红色路径飞行,在中途圆形标记上方执行一次降高和回升,再继续沿后半段轨迹飞到终点释放载荷,最后完成受控降落。把路线展开来看,视觉、飞控和机械设计的耦合关系就很直接了:前半段主要解决跟线和拐角,圆点位置主要用于触发阶段切换,后半段则同时考验半圆轨迹、载荷平衡和落台容差。
开发顺序采用了尽早联调的方式。静态图像先用于确定红色检测和网格阈值,随后通过“看到红色就驱动电机”的台架测试检查实时性,再进入不带载荷的实飞,最后逐步加入抓手、蛋、篮筐和落台。这样可以更早暴露载荷、气流、重心和照明变化带来的真实问题。
为了让链路尽量清晰,视觉端并没有直接输出连续位置估计,而是输出 7 个可以直接被飞控状态机消费的标志位:
redDetect:画面中存在可用红色路径straight:当前应继续前进turnLeft:应执行左转turnRight:应执行右转shiftLeft:机体在路径右侧,需要平移回左shiftRight:机体在路径左侧,需要平移回右circleDetect:已进入圆形标记区域,可触发悬停、降高或着陆相关逻辑
设计目标与约束
这套系统从一开始就被几个很硬的约束绑住了:
- 视觉算法必须运行在无人机已有的机载图像链路上,不能依赖重型检测模型。
- 额外载荷非常敏感。虽然测得的理论最大载荷可达
31.1 g和47.1 g,但实飞时连10 g左右的附加质量都会明显改变飞行表现。 - 抓手和载荷会把重心前移,导致起飞和悬停调参不能沿用空载状态。
- 路径跟踪速度必须低于
3 km/h,对应飞控里的横向速度上限0.83 m/s。 - 系统不仅要沿线飞,还要在不同圆点触发不同动作,因此视觉、计数器、状态机和着陆逻辑必须协同。
也正因为这些限制,项目最后采用的是非常工程化的路线:视觉上尽量用简单但鲁棒的阈值和区域逻辑,控制上用显式状态机组织动作,机械上则尽量把困难转移到轻量化结构和地面基础设施上,而不是把复杂度全部堆到机体本身。
机器视觉流水线
红色检测
视觉链路的第一步是先把红色路径和红色圆点从背景里干净地抠出来。初版模型直接在 RGB 空间上做差分判断,核心逻辑非常简单:
red if R - C*G - C*B > T
初始参数对应的是 C=0.5、T=40,也就是最早的 R - 0.5G - 0.5B > 40。满足条件的像素被置成白色,其余为黑色,整幅图像被二值化成一个后续模块可直接处理的矩阵。
为了验证这一步是否够稳,先从无人机摄像头在 0.8 m 高度下截取了 5 类测试图:红色圆点、直线、弯道、多彩地毯和橙色书本。前 3 类用来确认路径像素能否被保留,后 2 类则是用来专门制造误检。
- Test 1,
C=0.5 / T=40 / E=0:圆点、直线和弯道都能被清楚分离出来,但多彩地毯仍出现9个误检像素,橙色书本则直接产生2.81e4个误检像素。 - Test 2,
C=0.5 / T=66 / E=0:地毯和橙色书本的误检被压到0,但路径有效像素明显减少,直线像素从1.13e4掉到8.03e3。 - Test 3,
C=0.5 / T=66 / E=0.1:加入imlocalbrighten()做 10% 增亮后,图像上边缘的路径像素被追回来一些,但橙色书本又重新冒出了3.39e3个误检像素。
从静态图调参走到机载可用之前,还专门做了一步“先不飞,只验证反应链”的台架测试。思路很直接:把红色检测模型直接部署到无人机上,只要 redDetect 对应的红色像素数超过阈值,前右电机就动作;同时把前左电机固定在一个常数输出上,只用来证明飞控主链路本身在正常运行。这样一来,系统到底是“识别错了”还是“识别对了但动作太慢”,可以很快分开看。
静态图片测试结束后,又做了一个更接近实飞的实时性测试:把模型部署到无人机上,当红色像素数大于 1000 时,令前右电机输出 200;同时把前左电机固定在 200,作为“模型正在正常工作”的参考。这个测试直接暴露出一个关键问题:只要保留 imagePreprocessing 预处理块,无人机被移动到红线之上后,前右电机平均要延迟 5.56 s 才会动作,实时性完全不可接受。
因此后续不是继续在“有预处理”的前提下修补,而是回到无预处理结构重新找参数。最终选定的版本是:
C=0.6 / T=40 / E=0- 圆点像素约
3.65e4 - 直线路径像素约
1.04e4 - 弯道路径像素约
1.04e4 - 多彩地毯和橙色书本误检都为
0
这一版在低照度和高照度下都表现稳定,同时把实时延迟压回到可以忽略的程度,成为后续网格检测和飞控整合的基础。
网格检测与指令生成
路径识别并没有走常见的边缘检测或梯度方向路线,而是选择了一个更适合机载实时实现的网格化方案:把二值图像切成若干个固定区域,只统计每个区域里的红色像素数,再用组合逻辑生成离散动作指令。
初版网格模型先把机载 160×120 图像左右各裁掉 20 px,得到一个 120×120 的工作区域,再划分为 8 个感兴趣区域(ROI):
Top Left:45×45Middle Left:45×30Top Middle Top:30×22Top Middle Bottom:30×23Middle:30×30Top Right:45×45Middle Right:45×30Circle Detect:60×75
除此以外,底部 120×45 的大部分区域被直接丢弃,因为它对“下一步该怎么飞”几乎没有帮助,只会增加计算量。每个区域都通过 Submatrix + Sum 统计红色像素,之后交给门限和组合逻辑生成动作。这个结构的好处很明确:它并不试图做精确几何重建,而是把视觉问题压缩成“当前应该前进、转向、平移还是已经进圈”的离散控制问题。
第一次阈值设定是依据 6 张测试图逐区测得的红色像素数来定的。核心逻辑如下:
初版阈值
circleDetect: M>750, CD>2000, RD>2500
straight: TMT>0, TMB>100, M>100
turnLeft: TL>100, ML>100, TMT==0, TMB<50
turnRight: TR>100, MR>100, TMT==0, TMB<50
shiftLeft: TL>150, ML>150, TMT<20, TMB<20, M<20
shiftRight: TR>150, MR>150, TMT<20, TMB<20, M<20
这里 CD 对应圆形区域 Circle Detect 的红色像素数,RD 对应整幅工作图像里的红色总像素数。turnLeft / turnRight 之所以同时检查 Top Middle Top 和 Top Middle Bottom,就是为了把转弯起点和终点压到更合适的时刻,补偿无人机在真实飞行中的响应延迟。
在仿真里,这套组合逻辑是成立的:处在直线区域时,只有 redDetect=1 与 straight=1;处在右转区域时,只有 redDetect=1 与 turnRight=1。但一旦接到真实飞控上,问题就出现了。无人机在 yaw 过程中会向外漂,因此“看见角点再转”已经太晚,必须更早触发。于是第一次集成测试后,网格阈值被整体前移,变成了:
最终阈值
circleDetect: M>900, CD>2250, RD>2750
straight: TMT>20, TMB>100, M>100
turnLeft: TL>100, ML>100, TMT<20, TMB<150
turnRight: TR>100, MR>100, TMT<20, TMB<150
shiftLeft: TL>150, ML>150, TMB<20, M<20
shiftRight: TR>150, MR>150, TMB<20, M<20
同时还做了几项很关键的结构性调整:
- 中间列加宽
10 px,左右列各缩窄5 px,提高沿线容差。 shiftLeft/shiftRight不再受Top Middle Top限制,避免靠近拐角时无法横移纠偏。circleDetect的Middle、Circle Detect和总红色像素门限一起上调,让无人机更接近圆心后再进入降高或着陆逻辑。- 后续又重新整理了区域划分结构,把
Top Middle Bottom与Middle的职责进一步收拢,中间区域做得更宽,并与左右区域部分重叠,以提高轻微偏航或偏移时的容错性。
圆形检测与精确悬停
圆形检测的目标不是单纯“看出一个圆”,而是给飞控提供足够稳定的圆心信息,让无人机能够在圆点上方悬停,并为精确着陆做准备。
最先尝试的是 imfindcircles()。这个方案在孤立圆形目标上并不差,但实际测试很快发现一个结构性问题:圆点并不是单独存在的,它通常和路径线连在一起,圆的左右两侧同时有红线进入视野。这会让 imfindcircles() 对真实圆形反而不敏感,把一些并不存在或者边界不完整的结构当成更“可信”的圆输出。
因此后面改成了一个更朴素但更稳定的方法:在 Circle Detect 区域里统计水平和竖直方向上的连续白色像素,用连续段的中点去估计圆心。这个方法的绝对精度不如标准圆检测高,但一致性更好,也更容易塞进 MATLAB Function 块里直接机载运行。
后续还预留了一套“圆心是否落在图像内部 5% 区域”的判断逻辑,原本是准备用来在下降过程中持续把无人机压回圆心附近。但这一部分没有完全接入最终实飞流程,因此面向精确着陆的闭环入口已经搭好,完整验证则留到了后续。
飞控与任务状态机
视觉只负责说“现在应该往哪走”,真正把这些离散信号变成可执行飞行动作的,是飞控里的路径规划、状态机、控制器和保护逻辑。
飞控部分并未从空白模型开始重写,而是以已有的 Parrot minidrone 控制框架作为基底,保留状态估计、位置控制和电机混合链路,再针对 Mambo 机体、抓手载荷、延迟起飞和机载视觉输入调整参数与逻辑。这样可以把改动集中在任务相关模块,而不是重复实现底层控制框架。
具体到实飞前,还做了一轮 IMU 偏置标定。因为飞控后面的横向纠偏、yaw 保持和高度估计都非常依赖估计器输出,所以无人机在水平静止状态下先被用来记录传感器偏置,后面再把这些偏置从输入信号中扣掉。这类改动在图上不如状态机那么显眼,但如果不先做,后面的横向纠偏、高度估计和姿态保持就会一起在集成测试里漂掉。
状态机被拆成两个部分:前半段主要处理起飞、直线、直角转向和第一次圆点动作;后半段则针对半圆轨迹与最终着陆。这样做不是为了图上更好看,而是因为后半段的轨迹曲率和动作节奏与前半段确实不同,参数必须单独调。
这套状态机里最关键的动作链路如下:
CloseGrabber / Hold:先闭合抓手,并通过Hold确保四个电机保持静止。TakeOff:延迟3 s后起飞,把高度目标设为0.6 m,同时令YawOut = yaw_es保持朝向;在这套控制模型的符号约定里,向上对应负号,因此实现上写成zout = -0.6。TakeOffFlag:在起飞的前0.35 s置为1,让位置控制器切到更激进的起飞增益;之后清零,回到巡航增益。Hovering:起飞5 s后进入悬停。为了对冲机体天然的右偏旋转,YawOut会持续减去0.00015。FlyForward:前半程的位移增量大约是xout += cos(yaw_es) * 0.00065、yout += sin(yaw_es) * 0.00065;后半段半圆轨迹则改成更小的前进增量,以避免绕圈时持续过冲。YawLeft / YawRight:除了改 yaw,本身还会在xout/yout上叠加一个与sin(yaw_es ± π/2)相关的小平移修正,用来补偿真实飞行中转弯时的向外漂移。ShiftLeft / ShiftRight:当视觉判断机体偏离路径时,不必重新大幅转向,而是直接执行侧向纠偏,再回到FlyForward。Lower / Rise:当circleCount == 1时,先以0.001 m/s下降到0.5 m,完成圈点动作后再以0.001 m/s回升到0.6 m。Land:当circleCount == 2时,开始向0.25 m附近下降,下降速率为0.0008 m/s;落地后3 s打开抓手。
除了显式状态机本身,飞控还有几块决定系统能否稳定工作的关键模块:
延迟起飞是控制链路里的一个关键问题。系统要求先闭合抓手,再延迟 3 s 起飞,但这 3 秒里无人机虽然静止,估计器仍在继续积分,导致 z estimate 在静止状态下会漂到超过 7.8 cm。因此在起飞前 3 秒对 z 和 dz 强制归零,避免离地瞬间控制器接收到错误高度状态。
另外几条保护逻辑也直接写进了控制模型里:
Speed Limiter:根据v = sqrt(dx^2 + dy^2)计算横向速度,并与0.83 m/s比较,限制飞行速度不超过3 km/h。Time Limit:起飞后开始计数,到36,000触发超时保护,避免在电池状态不确定时无限飞行。NoRed:只有连续50个采样都检测不到红色,才认为确实丢线并进入着陆/停止逻辑,避免单帧异常把任务直接打断。Sensor Offset Correction:先在水平静止条件下录日志,提取 IMU 偏置,再把这组偏置从所有后续传感器输入中减掉。
最后,着陆也不是简单“到高度就断电”。原始做法是直接把电机增益切成 0,但这会导致触地动作很硬。后面改成了一个 0.5 s 的递减增益块:计数器启动后,输出值平方再乘增益,从而把电机命令从 1 平滑压到 0,着陆表现明显更可控。
另外几个辅助模块也直接影响实飞表现。TakeOffFlag 将起飞和巡航切分为两组 PI 参数,前者用于控制带载起飞阶段的冲击,后者用于恢复巡航阶段的响应速度。NoRed 则要求连续 50 次采样都没有红色信号后才判定为丢线,用于抑制单帧噪声带来的误触发。
机械设计与落台基础设施
机械部分的关键判断并不是“重新设计一个更复杂的抓具”,而是先看现有抓手到底能不能被保留。如果现有抓手本身不会把蛋夹碎,且拆装方便、重量低,那么更合理的方向是围绕它设计承载结构和地面基础设施,而不是把机体做得越来越复杂。
首先做的是强度和载荷边界测试。
最终得到的几个关键数字是:
- 抓手平均夹持力约
0.99735 N - 12 个蛋样本的平均极限抗力约
7.2 N - 最脆的样本也有
3.6 N - 最大 3D 打印蛋样本尺寸约
35.6 mm × 26.1 mm - 理论最大载荷测得
31.1 g和47.1 g - 但实飞时,附加质量接近
10 g就已经会明显影响稳定性
这组数据说明现有抓手不会轻易夹碎蛋,但在湍流和落地冲击条件下也不足以长期稳定固定载荷。因此后续设计重点转向了篮筐和落台,用结构手段补足整条任务链中的承载与定位问题。
几种重新设计抓具的方案经过评估后被排除。勺形和蟹爪结构需要把蜗杆传动改成另一种方向,制造复杂度和重量都太高;挂钩方案虽然做得出来,但依赖摩擦保持,遇到湍流就有滑落风险。
后续机械迭代主要集中在篮筐。它既要保护蛋,又要能被抓手可靠提起,同时还要尽量轻,并且与落台的对准关系一起设计。材料层面一共评估了几条路线:
- 竹编篮:轻且硬,但会在飞行中摆动,甚至有扫到桨叶的风险。
- A4 纸篮:保护性不错,摆动也小,但太轻,容易被桨流吹走。
- 铝线结构:容易弯折,刚度不够。
PLA:是唯一一个兼顾强度、形状稳定和可制造性的方案。
这几类样本对应了后续材料路线的筛选过程。组织材料虽然试制速度快、成本低,但一致性不足;完全封闭的实体篮筐虽然保护性更强,却会放大质量和前移重心问题。最终采用的开网化 PLA 篮筐是在保护性、抓手接入空间、气流通过能力和可打印性之间取得平衡后的结果。
篮筐最终经历了非常明显的减重过程:
- 初版质量
54.9 g,完全不可飞 - 中期挖孔减重版本降到
5.79 g - 最终版本压到
3 g
与此同时,结构细节也逐步收敛下来:
- 绝大多数薄壁宽度控制在
2-3 mm - 厚度定为
1.5 mm - 所有转角至少做
1.5 mm圆角,改善 3D 打印薄壁结合质量 - 句柄位置围绕整机重心重新布置,最终重心偏差约为俯视
5.193 mm、侧视2.03 mm
即便如此,机体还是对载荷非常敏感,因此系统没有把“让无人机直接抓起一个重篮筐飞完全程”当成最终方向,而是把地面基础设施一起设计进去,通过结构容差去换控制难度。
落台就是这一思路的核心。与其给机体加腿、加复杂机构、再要求视觉去识别一个小小的蛋,不如直接把蛋固定在地面基础设施里,让无人机只需要在一个有导向和容差的结构上完成取放。
落台的关键设计点包括:
- 采用地面基础设施而不是机体附加支腿,避免增加飞行载荷和视觉复杂度。
- 3D 打印尺寸受限于打印机构建体积
250×220×270 mm。 - 填充率只用
5%,在保证自重足够压住平台的前提下尽量省料。 - 导向槽做成漏斗形,并和机脚外形匹配,让误差在接触过程中被被动修正。
- 第一版实测后,把导向槽外径加大到与桨盘扫掠直径一致的
70 mm,改善气流分布。 - 绿色定位点从结构阴影里挪到立柱顶部,直径从
10 mm提到20 mm,提升视觉识别。 - 平台主体用白色
rPLA打印后再喷成红色,不是为了外观,而是为了降低表面摩擦。 - 抓手前方多余材料被挖掉,避免机体落下时发生结构干涉。
最终这套落台给出了相当可观的几何容差:
x / y方向最大容差±32.5 mm- 偏航最大容差
27.8°
这意味着精确着陆问题被重新组织成了“先进入一个相对宽松的几何捕获区,再由结构把机体导正”。这比直接要求飞控在小载荷、低算力和地效干扰下完成高精度定点着陆现实得多。
地效和气流问题也没有被忽略。为了确认平台中心区域不会在起降时形成明显压力堆积,还额外做了 CFD 检查,边界条件使用 10 m/s 顶部速度入口、底面壁面和四周大气压出口,重点不是算出精确压力值,而是确认最终几何不会把气流困在平台内部。
制造和成本也被当成真实约束来算过:
- 线性串行制造总时长
23.75 h - 并行安排后可降到
22.65 h - 如果打印机数量更多,可进一步降到
17.65 h - 其中 3D 打印本身约占
19.2 h,也就是总制造时间的85% - 平台、定位点和篮筐的材料成本约
£22.12 - 计入喷漆和底漆损耗后,总成本约
£24.28
制造策略本身也在服务迭代效率。落台本体和绿色定位点都按“尽量无需支撑”的方向布置,篮筐则改用 organic supports,减少材料浪费,也降低后处理难度。这样做不是单纯为了省一点耗材,而是为了让后面的试错节奏足够快,打印失败或尺寸不合适时可以更低成本地马上回到下一轮。
集成测试与结果
视觉、控制和结构测试分别验证了各自模块,系统级表现则主要通过两轮集成测试来确认。
-
第一次集成测试先将视觉系统和飞控接在一起,在不带抓手和蛋的条件下验证沿线飞行能力。测试一开始只跑前半段路径,确认直线和拐角动作后才扩到整条轨迹。这一轮带来了几项关键修改:巡航高度从
0.8 m调到0.6 m;状态机前半段新增[straight == 0]返回Hovering的回路,避免失去直行信号后继续前冲;视觉网格中间列加宽10 px、左右列各缩窄5 px;转弯阈值前移;YawLeft/YawRight中加入向后的小平移补偿;ShiftLeft/ShiftRight从仿真备用功能变成实飞必需功能;圆点计数器加入20 s延时,避免把起飞圆点误计入任务流程。完成这些调整后,系统已能在空载条件下完成起飞、沿线飞行、圆点识别和中途降高动作。 -
第二次集成测试把抓手、蛋、篮筐和落台都纳入系统,开始处理真实载荷和气动干扰。飞控中先将有效质量参数增加
0.03,再通过TakeOffFlag切换两套 PID 参数,一套对应起飞,一套对应巡航;同时在控制混合器中加入 pitch 修正,用于抵消抓手和蛋带来的前移重心。着陆阶段把“到高度就停桨”替换成0.5 s递减增益,着陆触发高度也从0.3 m下调到0.25 m。前进和转向增量经过再次调节后,总任务时间从约2 min压缩到约1 min 30 s。这一轮同时验证了延迟起飞期间z/dz锁零逻辑的必要性。最终,系统在带抓手和蛋的真实条件下完成了从夹蛋起飞、沿线飞行、中途圆点处降高到终点放蛋的完整任务;而作为飞行载荷的篮筐对稳定性要求过高,因此最终方案优先保留了“抓手直接执行 + 落台提供定位与承载基础设施”的链路。
项目最终形成的是一条完整的开发闭环:
- 视觉端已经能够稳定区分路径、拐角和圆点
- 飞控端已经能把 7 个离散标志位组织成实际任务流程
- 机械端已经把抓取、保护、承载与落台公差收敛成可制造结构
- 集成测试已经把关键失效模式逐个暴露出来并回写到系统设计里
局限与下一步
这套系统已经能完成任务,但它的边界也非常清楚:
- 巡航高度基本被锁在
0.6 m,再高就会因为视觉分辨率和区域划分敏感度不足而掉线。 - 载荷能力依然紧张,任何离重心稍远的质量都会显著改变控制表现。
- 当前状态机仍然是针对特定路径形态调过的,泛化能力有限。
- 一旦完全丢线,系统更偏向“安全结束任务”,而不是主动重新搜索路径。
- 绿色定位点与落台导向已经为精确着陆打好了基础,但真正的闭环精确着陆还没有完成实飞验证。
如果继续往下做,最值得优先推进的方向会是:
- 做自适应区域划分或更多层级的网格划分,让视觉对高度变化不那么敏感。
- 把圆心 5% 约束真正接入下降过程,补完基于定位圆点的精确着陆闭环。
- 继续优化载荷布局和控制补偿,降低对手工调参的依赖。
- 把状态机从“针对当前赛道调参”推进到“对更多轨迹形态都能工作”的版本。
总结
这个项目完成的是一套面向特定任务链的无人机系统实现。页面中涉及的红色检测、网格逻辑、圆点计数、起飞锁零、双增益 PID、轻量化篮筐和容差落台,分别对应视觉感知、状态切换、控制稳定性、载荷适配和地面基础设施几个关键环节。
在当前版本中,系统已经具备完成夹蛋起飞、沿线飞行、中途降高、终点放蛋和受控降落的能力。后续工作可以继续围绕精确着陆闭环、任务切换鲁棒性和载荷适应性展开。