1. 先弄明白一件事:避障系统要解决的到底是什么问题
几年前我第一次接触无人机避障时,跟大多数人想法一样:这事得上机载视觉、上Linux板卡、上深度相机,最好再来个GPU推理。后来做完了才发现,这是典型的“武器升级”思维,而不是“解决问题”思维。室内小型四轴上最硬的需求其实就三条:别撞墙、别撞人、能绕过去。换句话说,你做的是一个可以在室内飞、能自动躲开障碍物的验证系统,而不是一台全自主配送无人机。
我给自己的定位很明确:用一块STM32F407VET6,加上低成本传感器组合(超声波+单线激光雷达+光流模块),实现一套能在标准房间环境里自主起飞、路径规划、动态避障、降落的完整闭环。做完之后,这套系统在60cm宽的通道中反复飞行测试,避障成功率稳定在九成以上。这不算是多高端的成果,但它很能说明一个问题:STM32这个级别的MCU,再配上合理的算法与传感器选型,完全能做出一套可用的智能避障系统。
先拆解一下这个系统到底要解决哪些子问题。一套完整的避障与路径规划系统,在我看来就是三个模块的接力赛:感知层负责回答“哪里有障碍物”,规划层负责回答“去哪个点、走哪条路”,控制层负责回答“用多大速度、朝哪个方向飞行”。三者的关系类似于人做决策的过程:眼睛看到前面有桌子(感知),大脑规划绕过去的路线(规划),腿脚执行转弯迈步(控制)。三层缺一不可,很多做避障项目的人容易陷入一个误区:花了大量时间堆传感器,却忽略了路径规划算法本身的落地,结果传感器数据一大堆,飞控却不知道拿这些数据干什么;反过来,也有人成天调A*算法,传感器数据质量却差到让路径规划变成纸上谈兵。
从这个角度出发,我给系统定义了几个可量化的指标,它们贯穿了整个设计过程:
- 避障反应时间:从传感器扫到障碍物到控制指令生效的延迟,目标小于100ms。
- 规划频率:全局路径规划单次计算耗时,目标小于50ms,局部路径重规划小于10ms。
- 通道通过率:在60cm宽的测试通道中往返飞行20次的成功概率,目标大于85%。
这些指标决定了你做技术选型时的方向。比如规划频率要求50ms以内,你要是想着在STM32上跑RRT*,那基本不用玩了;同样,反应时间要求100ms以内,传感器的数据更新频率就得至少在20Hz以上。做项目最忌讳的是一上来就写代码,先把指标立起来,后边所有方案取舍都有了依据。
这个系统适合谁来参考?我建议三类人重点看看:一是正在做基于STM32毕业设计的学生,这个题目方向目前依然非常热门,而且可以分层拆解、模块化验收;二是想从纯代码转向“算法落地”的嵌入式工程师,这里边有大量实际调试经验是课本里不会写的;三是对无人机飞控原理感兴趣的业余玩家,你会看到姿态控制、导航控制、路径规划三者之间如何协作。下面我尽量把从硬件选型到算法落地的完整链路都说清楚。
2. STM32在这个项目里够不够用?核心器件选型实录
先回答这个项目里最容易被问到的第一个问题:STM32到底选哪一颗?网上搜“stm32无人机”能搜出一堆基于F103或者F407的方案,两者我都试过,直接说结论:如果做避障与路径规划,强烈建议F407起步,不要用F103。
| 对比项 | STM32F103VET6 | STM32F407VET6(本系统使用) |
|---|---|---|
| 主频 | 72MHz | 168MHz |
| 硬件FPU | 无 | 有(单精度) |
| Flash/RAM | 512KB/64KB | 512KB/128KB+64KB CCM |
| 浮点运算能力 | 软件模拟,慢 | 硬件指令,快数倍 |
| UART/SPI/I2C数量 | 5/2/2 | 6/3/3 |
| 定时器资源 | 4个通用 | 12个(含2个高级定时器) |
为什么F103跑不动?关键在于路径规划算法里有大量浮点运算。A算法的代价计算、坐标转换、PID控制量的结算,如果全靠软件浮点库去模拟,168MHz的F407都要花不少周期,72MHz的F103就更吃力了。实测在F103上跑同样的A算法(41x41栅格地图),单次规划耗时大约120ms;换到F407之后直接降到15ms以内。一个是“勉强能动”,一个是“顺畅响应”,体验差距非常大。
再说传感器组合。我这套系统用了三种感知器件,分工不同:
- 单线激光雷达(YDLIDAR X2/X3):负责水平360度扫描,测量距离范围0.1~8米,扫描频率5~10Hz。这是路径规划的主力数据来源,相当于无人机在水平面上的一圈“眼睛”,用来构建栅格地图。
- 超声波模块(US-100):负责正前方近距离探测,测距范围2cm~450cm,频率约20Hz。雷达在30cm以内存在盲区,超声波的责任就是把这个近场盲区补上,避免无人机在快贴上障碍物时毫无感知。
- 光流模块(XD2410P)+ 激光定高模组(VL53L0X或TFmini):负责速度与高度的感知。室内没有GPS,无人机需要知道自己飞了多远、以及当前离地多高,光流就是低成本替代GPS的速度感知方案。
选择这三类传感器,每一样都有明确理由。激光雷达贵一些,但它是所有方案里数据质量最稳定、算法处理最简单的;如果预算实在有限,也可以先用三个超声波替代,但覆盖范围和实时性会明显变差。我见过有人用一两个超声波做避障,避障效果受限很大,核心原因是超声波波束角宽、单点信息太少,只能探测正前方有没有物体,无法感知障碍物在左边还是右边、路径是否够宽。
动力系统方面,室内小型验证机建议用空心杯电机配减速组或者小型无刷电机(如2204、2212)配DShot电调。空心杯的优点是便宜、替换成本低、调试期炸机不心疼;缺点是寿命短、负载能力弱。我的方案是用四只8520空心杯电机加30mm桨叶,总拉力大约450g,整机重量控制在300g以内,飞行余量就在1.4:1左右,悬停没问题、动作太猛会掉高度——这倒是意外地约束了测试时的飞行包线,降低了炸机风险。如果想飞得更稳、能挂载额外传感器,直接换无刷方案就好,F407的PWM资源完全够用。
硬件连接上有一个必须提醒的细节:IMU(惯性测量单元)的安装位置和减震方式。我用的MPU6500,安装在飞控板的中心位置,底下用了一小块泡棉胶做减震,再通过铜柱固定在机架中心板上方。第一次试飞时没装减震泡棉,飞起来姿态数据噪声大到陀螺仪积分快速漂移,无人机在原地打转。后来加了一层泡棉再测试,陀螺仪噪声方差下降了将近一个数量级。这一类问题其实是最容易在选型阶段忽略、到调试阶段花掉大把时间的坑。
3. 传感层数据质量:避障系统真正的“隐形天花板”
配置好硬件之后,编码第一步不是写路径规划,而是先處理数据。传感器数据质量的优先级,永远高于算法本身。数据是脏的,算法再漂亮也是给垃圾桶做分拣。我在这个项目里花在传感数据预处理上的时间,几乎占了整体开发时间的一半,现在回头看是非常值得的。
3.1 激光雷达数据怎么转成机载地图
我使用的是单线激光雷达,它输出的是“角度+距离”格式的数据。以机体正前方为0度,按逆时针方向每度输出一个距离值。要做路径规划,需要先把这360个点投影到以机体为中心的栅格地图上。
栅格地图的分辨率我选的是5cm/格,共41x41格,也就是覆盖机体前方2m、后方2m、左右各2m的空间范围。这个尺寸不是随手定的:室内无人机速度一般在0.5m/s左右,2米的可规划范围意味着在刹停距离(约0.3m)之外还有充足的反应余量。栅格大小选5cm,是因为雷达的角分辨率约1度,在2米处相邻光点之间的间距大约3.5cm,选5cm刚好能让每个栅格稳定地被光点覆盖;如果地图分辨率太高,会出现大量空白栅格,反而影响路径规划的连续性。
投影时有一个细节:触发边沿对齐。因为雷达转一圈需要约0.2秒,在这一圈内无人机自身也在移动,直接使用极坐标原始数据会导致地图边缘出现位置偏差。解决方法是让飞控每收到一帧雷达数据,就读取一次当前姿态和位置(来自惯性推算或光流),把这帧数据整体做一次坐标变换,投影到机体坐标系里。这一步在F407上计算量完全可接受,函数本身只有几十行三角函数代码。
3.2 超声波与雷达的“近场互补”
单线雷达有两个短板:一是在30cm以内几乎成盲区(出来的距离值会跳变不稳定),二是对于低矮障碍物(比如地面三脚架)容易扫描不到。超声波模块在这种场景是救命的。
融合逻辑上,不是简单取平均,而是采用安全优先选近原则:在正前方60度扇区内,如果超声波距离小于雷达距离的80%,就采用超声波数据覆盖雷达数据。这样做的理由是避障场景的安全逻辑:感知到更近的障碍物时,宁可信其有,不可信其无。实测下来,在45cm距离处放置纸箱,雷达的读数在40~55cm之间跳动,超声波稳定在46cm左右,融合后地图上障碍物栅格的位置精度提升到了±5cm以内。
3.3 光流定位与高度融合
没有GPS的室内环境,无人机的水平位移只能靠光流模块估算。原理其实就是地面纹理移动的速度计算,类似于电脑鼠标的光学传感器,只不过装在无人机底部朝下,它通过对比连续两帧图像的纹理位移推算出机体水平速度,再积分得到位置。
光流模块的优缺点我直接摆出来:优点是便宜、实现简单,尤其适合1.5米以下的低空飞行;缺点是对地面纹理和光线极度敏感。在纯色地板或有强反光的地砖上,光流数据会大幅跳变。我的处理办法是给光流速度加一个限幅滤波器,单帧位置变化超过0.15m就视为无效数据,同时用加速度计短时积分做填空。高度方面用VL53L0X激光测距模组,测距范围4cm~2m,输出频率50Hz,这比单纯用超声波定高稳定太多——超声波的波束角宽,在低空很容易被自身螺旋桨气流干扰,数据跳变能把高度控制器折磨得来回震荡。
3.4 数据预处理的顺序
把几种传感器数据进来之后的处理流水线总结一下,对后面做类似项目的人会有参考价值:
- 中值滤波:雷达每组扫描数据按扇区做3点中值滤波,剔除孤立毛刺点。
- 时间戳对齐:拿到光流速度时,要记录它对应的积分时间窗口,不能直接在任意时刻读取。
- 滑动平均速度输出:光流速度做5帧滑动平均,抑制高频抖动。
- 安全距离覆盖:按上边说的近场覆盖逻辑融合超声波。
- 栅格占据标记:最后把融合后的测距结果投影到地图,并对每个栅格执行“一旦标记过障碍物,就在N帧内保持占据”的滞留机制,避免偶发误判导致路径规划剧烈抖动。
这一套处理完成之后,地图数据才真正具备喂给路径规划算法的资格。很多人卡在这里,觉得程序写了、传感器也工作了,但路径规划效果差,其实根子就在数据质量不达标。
4. 路径规划在Cortex-M4上的落地:从A*到可用的全套流程
路径规划是整个系统的“大脑”。传统嵌入式开发涉及路径规划时,第一反应是“这个在单片机上跑不动”。实际做完这个项目我的结论是:只要选对算法、做好地图分辨率取舍、用静态内存代替动态分配,STM32F407完全能流畅跑实时路径规划。
4.1 为什么先选A*而不是RRT或Dijkstra
Dijkstra是A无启发式的特殊情况,它会把所有栅格都扩展一遍再找最短路径,效率太低;RRT系列算法在状态空间大、甚至高维空间里优势明显,但在二维栅格地图这种结构化空间里,它生成的路径带有随机性,不是最优,且耗时不够稳定。A结合了启发式搜索的效率与最优性,同时实现简单——它只需要维护两个链表(open list和close list),在二维栅格里不需要复杂的数据结构和空间搜索。基于这些理由,在STM32上第一选择就是优化后的A*。
A的核心公式就一句话:f(n) = g(n) + h(n)。g(n)是从起点到当前节点n的实际代价,h(n)是从当前节点n到终点的估计代价。只要h(n)不大于实际代价,A一定能找到最短路径。实际代码里,关键是h(n)的选择。我用的欧几里得距离(直线距离)作为启发函数,替代曼哈顿距离,这样在允许八方向移动时得到的路径更自然、转折更少。
4.2 静态内存设计:嵌入式A*的关键
A*在PC上写很简单,用new动态分配节点就行;但MCU上动态分配容易产生内存碎片,而且时间不可控。我的方案是预分配固定数组。41x41=1681个栅格,每个节点的数据规模是:
- 栅格坐标:int8_t,2字节
- f/g/h值:float,各4字节
- 父节点索引:uint16_t,2字节
- 在open/close列表中的状态标志:uint8_t,1字节
总共约21字节,所以节点池总共1681×21≈35KB。F407的128KB RAM完全够用。open list我用一个静态数组按f值插入排序,每次取表头就是最小f值的节点。虽然插入排序时间复杂度是O(n),但栅格总数有限,实测在41×41地图上A*单次规划最多约20ms,满足设计指标。
4.3 A*路径后处理:消除冗余转折点
如果直接把A*栅格路径给飞控执行,飞机会走出“折线+停顿”的效果——每个栅格之间都做一个直角转弯,不但效率低,还会加剧姿态震荡。标准的后处理方法是路径压缩:从起点开始,检查当前路径段能否直接跳过中间多个节点抵达更远节点(即检查这条直线上所有的栅格是否都不是障碍物),如果能就直接连过去。这个操作本质上是“拉直”路径。
压缩之后再做一次平滑。我没有用复杂的B样条或贝塞尔曲线,只做了简单三次样条插值,把路径点之间插出三个中间点,让轨迹过渡更柔顺。你可以这样理解:路径压缩告诉你大致方向,平滑插值把动作从“柴油机”变成“电动车”的体验。
4.4 局部重规划:应对动态障碍物
静态路径规划完成后,无人机起飞沿路径飞行。但障碍物可能是人、宠物或者被移动的家具,这就需要局部重规划。
我的策略是:每个控制周期(50ms)检查一次前向60度扇区内的最近障碍物距离,当前方距离小于触发阈值(默认0.5m)时,将当前机体位置重新设为起点,以当前目标点(或原路径上未经过的最近航点)为终点,立刻重跑一次A*。因为A*单次耗时小于25ms,局部重规划完全跟得上节奏。同时,为了让重规划后的路径与原来路径尽量一致(避免绕远路),我在代价函数里加了一个小的“惯性偏移量”,让新路径优先朝原路径方向扩展。
这里有一个细节值得说:重规划不是越频繁越好。如果每次都从起点直接寻路,路径可能会在两个相近的规划结果之间来回切换,导致无人机“犹豫不前”。所以我在连续两次重规划之间设置了一个冷却时间:如果第一次重规划的路径还没走完30cm,就优先沿用之前的结果;真的撞到新障碍物上再触发新一轮规划。这个经验排除了很多奇怪的抖动问题。
5. 避障动作的决策逻辑:什么时候转弯、什么时候绕行、什么时候放弃
路径规划算出一条路线,但路线是“空间上的打算”,具体怎么飞还得靠控制决策。很多做路径规划的人容易忽略这一点:无人机不是一台只能执行死板的轨迹的数控机床,它在飞行中会遇到规划层没算到的新情况,决策层必须应对。
5.1 控制架构:内外双环
我的控制架构采用经典的双闭环PID结构,也就是姿态内环+速度/位置外环。
- 内环(姿态环):频率400Hz,控制无人机的roll/pitch角速度和角度,输出油门和角度指令,这部分相当于无人机的“平衡感”——人小脑那种作用。
- 外环(导航环):频率50Hz,根据路径规划输出的期望位置/速度,反向解算出期望姿态角,给内环发指令。
姿态环我手写了一个标准PID,参数通过串级PID试凑法结合模型仿真确定,然后在小范围实测微调。如果你用的是匿名、雷迅等开源飞控的Pixhawk版本做基础,那可以直接在ArduPilot或PX4的基础上做上层控制,但要注意:STM32F407的资源要跑自己的避障代码,通常还是建议从姿态环开始自己写,或者用精简版移植方案。我的做法是“底层从零写,上层自己定义”,这样整个系统每个环节都可解释、可复现,调试时找不到问题可以一层层排查。
5.2 区域划分与动作决策
避障决策本质上就是把连续的几何空间离散成几个带阈值的区域。我的划分方式是:
| 区域 | 判定条件 | 执行动作 |
|---|---|---|
| 安全区 | 前方距离 > 1.5m | 沿原路径正常飞行 |
| 注意区 | 前方距离 0.8m~1.5m | 减速到0.3m/s,同时根据左右雷达数据预判绕行方向 |
| 危险区 | 前方距离 < 0.8m | 立即悬停,启动局部重规划,重新计算绕行路径 |
| 紧急区 | 任意方向距离 < 0.35m | 直接反向减速并爬升到安全高度,重新规划路径 |
为什么把0.8m作为重规划触发距离?因为室内飞行速度0.5m/s、机体急刹减速度大约1.5m/s²,刹停距离约0.28m。考虑到超声波近场探测距离至少0.3m,加上传感器更新延迟和控制延迟,0.8m就提供了大约0.5s的反应时间窗口,这个窗口足够A*完成一次局部重规划。0.35m的紧急区基本是底线,进了这个距离任何规划都不再有意义,只能是“先停下来再说”。
关于绕行方向的选择——这也是一个看似简单但值得认真处理的问题。我的逻辑是:当危险区触发后,比较左、右两侧雷达探测到最近障碍物的距离,选择更远、更开阔的一侧绕行;如果两侧差不多,就选与目标方向夹角更小的一侧,因为通常这意味着总绕行距离更短。这个策略简单有效,而且完全不需要增加传感器。
5.3 最容易被忽略的:绕行成功后的路径恢复
刚开始测试时我发现一个有趣的现象:无人机绕过障碍物之后,往往会“忘了”自己的原定目标,沿着绕行路径越飞越偏。原因很简单——局部重规划的终点(原路径的某个中间航点)被绕过了,但到达该航点之后,全局路径的剩余部分还是同一条线,如果不重新接入全局路径,导航就会一直跟着“过时的局部路径”走。
解决办法是在每个控制周期都检查:如果当前位置到原路径最近航点的垂直距离小于阈值(0.5m),就认为已经“回到正轨”,后续航点仍然从全局路径里取。这个“重回到原路径”的判断逻辑,是绕行成功、不跑偏的关键,值得每个做动态避障的开发者重点关注。
5.4 失败兜底:当避障无能为力时
再好的避障系统都有极限情况:比如障碍物群形成了一条狭窄的死胡同,通道宽度小于飞机自身尺寸;又比如传感器刚好在某个角度被干扰,长时间丢失有效数据。在这些场景下,最高性能的设计不是“硬穿”或“原地犹豫”,而是安全停机。
我的决策逻辑里设置了一个死胡同检测:如果两个规划周期内,A*返回“无可行路径”的次数大于3次,就启动兜底策略——先原地悬停2秒,然后自动下降降落,同时用蜂鸣器和LED闪烁提示操作员。后续可以远程手动接管。有时候,主动放弃是比强行完成任务更好的策略。
6. 室内实测与踩坑记录:从“能飞”到“能绕”
项目做到这个阶段,硬件、算法、决策逻辑都已就位,剩下最磨人的就是实测调试。下面把我在测试过程中遇到的几个关键问题和完整的排查链路写出来,这些问题你大概率也会碰到。
6.1 测试环境与流程设计
我的测试场地是一个约3m×4m的室内房间,地面铺普通防滑地垫。障碍物用标准尺寸纸箱(40cm×40cm×50cm)和办公椅模拟。测试流程:
- 在房间中央设定起飞点,目标点设定在房间对角位置。
- 在两点之间放置2~3个障碍物。
- 无人机自动起飞→路径规划→避障绕行→到达目标点→自动降落。
- 记录每次飞行的路径偏差和耗时,统计通道通过率。
6.2 踩坑1:超声波模块之间互相串扰
第一次使用两个超声波模块(一个朝前、一个朝下)时,发现朝前模块的测距值偶尔会跳到异常大的数值,和实际障碍物距离完全对不上。排查链路是这样的:
- 首先怀疑是电源干扰,检查并加大滤波电容后依旧复现。
- 然后用示波器同时抓取两个模块的触发和回波引脚,发现当前方超声波发出声波后,朝下模块的回波信号被前方模块误认为是自己的回波,导致测距值突然变为直射地面高度。
- 解决策略是分时触发:两个超声波模块错开20ms以上发射,当前方传感器等待回波期间,朝下模块的发射波已经衰减消失。
- 进一步优化是给每个模块加装了不同谐振频率的收发端(US-100有普通模式和专用模式),但分时触发已经足够解决问题,最终保留了这个方案。
6.3 踩坑2:激光雷达读到螺旋桨桨叶
我的机架上激光雷达安装在中心板上方,四个螺旋桨分布在四周。飞行时雷达偶尔会把旋翼桨叶识别成障碍物,导致前方明明是空却报出0.5m的假目标,触发急停,系统表现为“空中抽搐”。
排查过程:先看雷达数据,发现假目标的相对角度分布与桨叶位置高度吻合,再对比地面静止测试(没装桨)和空中测试,问题复现。解决策略是在雷达扫描数据中加了一个高度掩码逻辑:因为传感器知道当前的俯仰角,它可以根据角度解算当前扇区测得的距离点是否真的在地面高度附近。桨叶往往在雷达扫描平面下方,算出来的高度远低于地面,就直接剔除。更简单的办法是做“扇区窗口滤波”——在连续N次扫描中,如果某个角度区域频繁出现孤立近距值,就判定为固定干扰源,不再作为障碍物参与建图。
6.4 踩坑3:光流在强光地板砖上失灵
室内飞行到了一侧窗户附近,阳光直射地砖,光流模块突然输出很大的速度残差,无人机瞬间朝侧面飘出去。查了很久才意识到是光流模块的帧率跟不上高流动纹理(反光条纹),导致位移解算错误。
解决方法是给光流模块增加光照异常检测:如果连续3帧的匹配质量指标过低,就标记为“无效光流”,此时位置更新暂时切换到加速度计积分模式,同时降低飞行速度、增强位置环阻尼。等光流质量恢复后,再把位置估计权重切回来。这个检测逻辑用了一个非常简单的置信度评分,不稳定时Naive地给体面结果打折,效果却出奇得好。
6.5 踩坑4:绕行时无人机“点头”振荡
局部绕行动作执行时,无人机在转弯过程中出现明显的俯仰振荡,有点像“点头”。一开始怀疑是内环姿态参数问题,反复调PID后收效甚微。后来查看了飞行日志,发现振荡频率与路径重规划频率几乎一致——原来是因为转弯过程中,雷达扫描到自身倾斜导致地图短暂变换,局部路径的终点在几个相邻栅格之间跳动,飞控对着一个“不稳定目标”不断修正姿态。
解决策略是给路径终点加了终态锁定:一旦开始执行某条局部路径,就把终点栅格锁定,除非遇到新的紧急障碍物,否则在路径执行期间不重新规划。这跟之前提到的30cm冷却时间本质上是同一思路——路径规划系统要输出“稳定的决定”,而不是“每帧都换一个最新最优的决定”。
6.6 实测数据汇总
经过上面几轮迭代,系统的最终实测数据如下:
| 测试项目 | 结果 |
|---|---|
| 单次全局A*规划耗时(F407实测) | 12~20ms |
| 局部重规划耗时 | 3~8ms |
| 60cm通道通过率(20次往返) | 90%(18次成功) |
| 从触发避障到完成绕行的平均耗时 | 1.6s(障碍物为0.4m纸箱) |
| 单次飞行时长(室内悬停+绕行) | 约4分钟(450mAh电池) |
这个结果谈不上惊艳,但它证实了一条路线:在有限的MCU资源下,通过合理地让传感器、路径规划和飞控逻辑互相配合,是可以实现真正闭环的智能避障系统。同样的指标在Pixhawk+树莓派方案里可能做得更轻松,成本却翻了好几倍。
7. 做完这个系统之后,我建议你也考虑这几件事
如果你准备复刻这个项目,或者在此基础上做毕业设计/竞赛作品,下面几条建议是我踩了两次以上的坑换来的,希望你能跳过。
7.1 先做仿真,至少做一个“动力学+地图模拟”
很多同学一上来就搭硬件、写飞控,最后时间的八成花在机械调试和飞控稳不上上面。我的做法是先在PC端用Python写了路径规划与部分决策逻辑的仿真,用网格地图模拟障碍物与无人机运动,跑通逻辑后,再把C语言版本固件写到STM32上联调。这样能把算法问题与硬件问题分开排查,效率高很多。
具体的流程可以是:Step 1,在PC上验证A*路径的正确性;Step 2,加入动力学约束(最大速度、最大角速度),观察路径转角是否可执行;Step 3,移植到MCU后,先用串口把实时地图和规划结果发到PC端可视化;最后才装到飞机上试飞。每一步都有明确的验收标准,不会出现“炸机了不知道是控制问题还是规划问题”的窘境。
7.2 每个模块单独做测试台验证
飞控里最容易混淆的是“软件问题”和“硬件问题”。我建议在板上为每个传感器留串口打印接口(F407的UART资源非常充分),单独用测试固件验证传感器读数是否合理。超声波的数据用串口直接看,雷达的数据画成扫点图,光流速度用串口间隔50ms打印一次看是否为平缓值。这样做一遍,基本能提前排除大半“硬件看起来正常但实际数据不对”的问题。
7.3 想升级?视觉避障的方向
这套系统做完后,如果还想扩展,最自然的方向是视觉感知。网上有很多基于OpenMV或K210的视觉模块,可以识别特定类型障碍物(如“低慢小”目标、动态人体),再把视觉信息作为辅助信号叠加到现有雷达地图中。STM32F407通过串口或SPI与视觉模块通信,数据量不大,实时性完全可行。路径规划算法不变,只是输入的地图多了一层“动态目标”信息,这会显著提高系统对移动障碍物的避让能力。
另外如果对全覆盖路径规划感兴趣(比如做巡检类应用),可以把A*换成覆盖算法,这一类在热搜里也有不少人搜“全覆盖路径规划matlab”,思路是相似的:在地图基础上生成覆盖轨迹而不是单条路径。
7.4 最后说点我这个过来人的真心话
做了这个项目之后,我最大的体会是:嵌入式智能系统最难的往往不是算法本身,而是把算法放到有限的资源里让它稳定地、实时地跑起来。A*的原理三个小时就能学会,但让它在一个会震动、有干扰、还会飞的平台上稳定工作,靠的是对传感器特性的理解、对数据质量的打磨、以及对系统每一层职责边界的清晰划分。这条路会有无数个“为什么明明程序没错飞起来就是不对”的夜晚,但当你看到无人机第一次顺畅地绕过纸箱、稳稳落到目标点的时候,那种成就感是模拟器里永远得不到的。
如果你正在做类似的方向,希望这篇文章能帮你少走几步弯路。项目代码和硬件清单我已经整理过了,后续有机会再展开聊聊姿态控制环的PID整定方法,以及激光雷达点云在STM32上的处理优化技巧。有问题随时留言交流。