做一只微型迷宫鼠:用洪水填充求解迷宫的机器人
一台机器人:能自己探索墙式迷宫、为它建出地图,然后从起点到中心跑出最短路线,一个弯都不走错。
做的是什么
扔进没见过的迷宫、找中心、二刷能证明的最短路线回来的车。
后半程正是微型迷宫鼠和本站其它所有机器人的不同之处。循迹车会做出反应,避障车会做出反应,而微型迷宫鼠会记住——它一边开一边建图,然后在那些自己还没访问过的格子上做规划。这是最小的一个完整机器人问题:感知、运动、建图和规划,而且必须同时工作。
两趟策略
竞赛鼠好几趟,最快计时。策略没人计时也值得抄:
**第一趟——探索。**小心地开,记下每个格子有哪些墙,并抵达中心。速度无关紧要;地图才是产出。
**第二趟——利用。**成品图洪水填充,算最短路线,已知的不停感知直接开。
这个划分之所以重要,是因为这两趟跑需要的东西正好相反。探索需要缓慢、谨慎的动作和持续的传感;竞速跑需要果断下决心。想同时兼顾两者,只会得到一台两件事都做不好的机器人。
为什么算法不是难处
洪水填充确实简单:给目标格距离 0,给每个相邻格比它能到达的最低邻居多 1 的值,然后永远走向数字更小的格子。几十行代码,而且在栅格上可以证明它给出的是最短路径。
难处是它假设车知道自己在哪个格。
只要数错一个格子,或者有几次把 90° 转成了 88°,规划器就在为一台其实在别处的机器人解迷宫。症状让人抓狂:算法完美,接线也没问题,机器人却自信地撞进墙里。
所以下面的制作顺序把大部分精力都花在运动上,规划器放到最后加。你可以在迷宫求解模拟器里单独验证规划器,在那里位置按构造就是精确的——这正是先花时间做模拟值得的原因。
物料单
| 零件 | 数量 | 约价 | 说明 |
|---|---|---|---|
| Arduino Uno 或 Nano | 1 | $5 | RAM 很紧——16×16 的迷宫要小心。换 Mega 或 ESP32 就没这个顾虑 |
| VL53L0X | 3 | $15 | 左前右。三颗,不是一颗——见下 |
| MPU-6050 | 1 | $2 | 转弯航向;轮子正要紧处打滑 |
| N20 编码器电机 | 2 | $16 | 1:50 或 1:100。金属减速箱必不可少——背隙每次转弯都在累积 |
| TB6612FNG | 1 | $3 | |
| 两轮底盘 | 1 | $10 | 格子里转得开——宽 90 mm 下 |
| 电池包 | 1 | $8 | 2×18650 |
| 迷宫墙 | — | $10–30 | 泡沫板或胶合板。标准格 180 mm 墙 50 mm |
合计约 $70–95,加迷宫。
**用三个测距传感器,而不是一个。**单个前方传感器要观察就得转身,既费时间——更糟的是——每次观察都会引入航向误差。三个固定传感器能让机器人一动不动地在一瞬间读完一个格子的三面墙。这正是能可靠建图的迷宫鼠和每次查看墙面都在累积误差的迷宫鼠之间的区别。
记住三颗 VL53L0X 上电同地址 0x29,三 GPIO XSHUT 逐个唤醒改地址——每次开机重来,改完易失。
**留意 RAM。**一张 16×16 的洪水填充距离场按 uint8_t 存就是 256 字节,再加墙图和队列。在 Uno 的 2 KB 里塞得下,但前提是你有意识地精打细算——这本身就是很好的练习,也是很多人在这款机器人上换用 ESP32 的原因。
制作顺序
**1——拿到三路干净的距离读数。**用 VL53L0X 飞行时间传感器测前方、左侧和右侧。它们共用一条 I²C 总线,上电时地址相同,所以要靠把其余两颗保持在复位状态、开机时逐个唤醒并重新分配地址的方式把它们分别拉起来。在安装任何东西之前,先确认每一路都能读到已知距离上的墙面。
**2——让它走直线、转直角。**这才是真正的项目。按沿墙行走与精确转弯来做:在侧面传感器上跑一个 PID 循环保持居中,用陀螺仪积分来做转弯而不是靠编码器计数,并且只要前方有墙就用它来重新校方正。在这台机器人能连转十次仍然朝向正确之前,不要往下走。
**3——可靠地数格子。**编码器预测边界应该在哪里;侧面墙的下降沿确认它实际在哪里。当两者不一致时,信墙——因为它是一个物理地标,而不是一个累积出来的估计值。
**4——把墙记录进地图。**每个格子用两个 bit 表示四面墙,一张 16×16 的迷宫只占几百字节。看到什么就记什么。
**5——加入洪水填充。**现在规划器拿到的是诚实的数据了。每当新发现的墙让当前路径失效时就重算距离——这正是用洪水填充而不是一次性搜索的全部理由。
真正要紧的硬件注意事项
**小巧胜过快速。**机器人必须能在格子里转开。轮子靠近旋转中心的紧凑底盘转得干净利落;而车体一长,每次转弯都会蹭到墙,几何问题是调参修不好的。
**背隙就是航向误差。**每一次原地转向都会让电机换向,而一个松动的减速箱会丢掉最前面几度——在 42 mm 的轮子上,4° 的空程大约相当于 0.9° 的航向误差。N20 金属减速箱电机之所以存在,正是为了这个。
**把侧面传感器略微前移并带一点角度。**如果笔直朝外指,只有在正好与墙并排时才看得见它,于是机器人知道得太晚。一点前倾角度能给控制环提供一点预览。
**给传感器一路稳定的电源。**VL53L0X 在电源轨下垂时返回的是看起来很合理的错误数字,而不是明显地失败——这是最糟糕的一类故障,因为地图会被并不存在的墙填满。
做好长什么样
| 测量 | 第一只能用的迷宫鼠 | 调好之后 |
|---|---|---|
| 探索速度 | 0.2–0.3 m/s | 0.3–0.5 m/s |
| 二刷 | 0.4–0.6 m/s | 1.0–2.0 m/s |
| 十格后居中误差 | 10–20 mm | 5 mm 下 |
| 十转弯后航向误差 | 8–15° | 3° 下 |
| 墙检测准确率 | 必须 100% | 100% |
| 整 16×16 探索 | 3–6 分钟 | 1–2 分钟 |
两行强调。
**墙面检测没有部分得分。**一面墙记错就会污染地图,洪水填充随后会自信地规划出一条穿墙的路径,竞速跑就会一头撞上去。这里没有优雅降级,所以探索那一趟要慢慢跑。
**让那些行不再平行才是真正的项目。**算法不是难点——洪水填充大约四十行,而且你完全可以在模拟器里不用任何硬件就把它测完。难点在于:走过十个格子之后,机器人已经不在它以为的位置了,而一只每十个格子漂移 20 mm 的迷宫鼠,在迷宫另一侧就已经贴到墙了。让一台真正的迷宫鼠能跑起来的一切——沿墙修正、陀螺融合的转弯、编码器标定——存在的意义就是和这一个数字作斗争。
坏了看哪
| 现象 | 一般 |
|---|---|
| 自信地撞进墙里 | 格子数错了——是位置问题,不是规划问题 |
| 转几次弯后就歪了 | 陀螺偏置没有减掉,或者转弯后没有重新校方正 |
| 猛地冲进侧面的开口 | 跟随循环里缺少“墙是否存在”的检查 |
| 记录下并不存在的墙 | 传感器电源电压下垂,或者模块之间串扰 |
| 求解很慢,撞得很快 | 竞速跑相对运动层来说太快——先放慢,再提速 |
这张表里几乎每一条都是运动或传感故障,而不是算法故障。开工之前就知道这个分布是最有用的一件事,因为它告诉了你周末该把时间花在哪里。
如果你只想要建图和规划的想法而不想要硬件,迷宫求解模拟器会在浏览器里跑同样的两阶段策略,而路径规划与建图路线会把它继续带到 A* 和 SLAM。而作为便宜得多的第一台迷宫机器人,线迷宫机器人用胶带代替墙,完全不需要距离传感器。
项目路线图
搭建路径
沿着技术树,从零件一路走到一台能正常工作的机器人。每个节点在其前置条件完成后解锁,你的进度会保存在这台设备上。
已完成 0 / 16
元器件
- 控制器Arduino Uno对新手失误很宽容的 8 位开发板,大多数人正是通过它认识机器人的。
- 传感器VL53L0X ToF 激光测距传感器激光飞行时间测距——在声呐太粗糙的地方,给出一束又窄又精确到毫米的光。
- 传感器MPU-6050 惯性测量单元六轴运动传感器——机器人靠它感知自身的倾斜、转动和加速度。
- 执行器N20 编码器减速电机带金属减速箱的微型电机,尾部装有编码器,让机器人知道自己实际走了多远。
- 驱动器TB6612FNG 电机驱动板MOSFET 构成的 H 桥,把你花钱买来的电压真正留给电机。
- 底盘两轮驱动机器人底盘一块甲板:两个电机、一个自由万向轮和你的全部电子元件都固定在它上面。
- 电源机器人电池与电源包能正常运行的机器人和不停复位的机器人,差别就在它身上。
本路径中的教程
- 中级 · 1.5 小时迷宫机器人的沿墙行驶与精确转弯在两面墙之间保持居中,并精确转过 90°——迷宫机器人成败所系的两项技能。
- 中级 · 阅读约 16 分钟Micromouse 机器人的洪水填充迷宫求解洪水填充如何把一个部分已知的迷宫变成距离场,让机器人顺着它一路下降到目标。
- 入门 · 阅读约 17 分钟读取正交编码器,测出轮子的行驶距离与速度把正交编码器的脉冲变成可靠的车轮方向、距离和速度测量值。
- 入门 · 阅读约 18 分钟超声波与飞行时间(ToF)机器人传感器对比为障碍物检测选择、安装、标定并测试超声波或飞行时间传感器。
- 中级 · 阅读约 20 分钟用车轮编码器实现差速驱动里程计把左右轮的运动积分成移动机器人的位姿,再识别并标定漂移。
接线之前先练习
用在线模拟器把它调好
搭建路径会经过一个浏览器实验台。先在这里把行为调对,再把参数迁移到真实的机器人上。
常见问题解答
什么是微型迷宫鼠?
一种能求解墙式迷宫的小型自主机器人,也是世界上历史最悠久、至今仍在持续举办的机器人比赛。标准迷宫由 16 × 16 个格子组成,每格 18 厘米,目标在中心;机器人拿不到地图——它必须先探索、建出地图,然后跑它能找到的最快路线。它是装在一个盒子里的完整机器人问题:感知、精确运动、建图和规划都必须协同工作,其中任何一项出了问题都会立刻暴露出来。
为什么用飞行时间传感器而不用超声波?
有三个原因,而迷宫会让每一个都变得更糟。超声波波束会扩散约 15 度,所以在狭窄的通道里,它会打到你瞄准目标两侧的墙上。多个超声波传感器会互相干扰,听到彼此发出的声脉冲。而且每次读数都要花上几毫秒的飞行时间,这限制了你的控制循环能跑多快。VL53L0X 波束很窄,不受相邻传感器影响,大约 20 毫秒就能完成一次读数。
有了编码器还需要陀螺仪吗?
对迷宫来说需要。编码器测的是车轮的转动,而不是机器人的转动,每当车轮打滑,两者就会不一致——而原地转向时发生的恰恰就是打滑。每次转弯 2 度的误差,一次察觉不到,十次之后就是致命的。陀螺仪直接测量机器人的实际转动,所以不管车轮做了什么,转弯都能保持直角。
它和线迷宫机器人有什么不同?
它们是两种不同的机器人,只是碰巧共用了一个词。线迷宫是板上的黑色胶带,由朝下的反射阵列读取,LSRB 路径记忆从一串转弯中把死胡同压缩掉。微型迷宫鼠有实体墙,用距离传感器读取,并且必须真正为迷宫建出一张地图,才能规划穿过那些它从未开过的格子。线迷宫的制作成本低得多;而教会你建图的是微型迷宫鼠。
为什么我的机器人能解出迷宫,却在竞速跑时撞墙?
因为速度改变的是物理,而不是算法。开得更快意味着更多的车轮打滑、更长的停车距离,以及沿墙行走循环在进入下一个格子之前用来修正的时间更少。通常的解决办法不是继续调参,而是先用较慢的速度跑竞速趟,等运动层被证明可靠之后再提速。这也是竞赛迷宫鼠一有机会就借墙重新校方正的原因——这是唯一能消除累积误差、而不只是限制它的办法。
可以用 Arduino Uno 做微型迷宫鼠吗?
第一只迷宫鼠可以。Uno 能通过 I²C 驱动三个 VL53L0X 传感器和一个 IMU,并用几百字节存下一张 16 × 16 的墙面地图。它做不到的是参加比赛——认真的迷宫鼠会用更快的 32 位控制器,让运动控制循环以千赫兹级的频率运行,规划器也能不断重新计算。先做出慢的那一只;你学到的几乎所有东西都能迁移过去。