一手拿着万用表,一手捏着烙铁,桌面乱得像刚被炸过的迷宫——这就是我做 NeuroMouse V2.0 那段时间最常见的状态。这台基于 ESP32-S3 的 Micromouse(微型鼠机器人在 AAMC 2026 上拿了第三名,成绩听起来不算最亮眼,但熟悉这个圈子的人都知道,能从近百台参赛机器人里杀进前三,比的不是谁口号响,而是谁在每个细节上少犯错。这篇文章我会把 V2.0 从选型、机械、电路、算法到比赛现场踩坑的完整过程复盘一遍,给正在做迷宫机器人、或者纯粹想把手头小车的速度和稳定性再往上顶一格的朋友,提供一份能直接抄作业的参考。
先交代背景。微型鼠比赛不是简单的"写个迷宫搜索算法"就完事,它是一个完全自主的移动机器人在 16×16 格的迷宫里,没有遥控、没有外部定位,纯靠自己测墙、建图、规划路径,最终用最短时间从起点冲到中心格。比赛分探索和冲刺两轮,探索轮允许慢慢扫描迷宫,冲刺轮必须全速跑最短路径。NeuroMouse V2.0 在这两轮里的具体表现是:探索 1 分 58 秒完成全图扫描,冲刺最快单圈 9.47 秒,综合排名第三。为了做到这个水平,V2.0 把上一代所有我认为"能用就行"的模块全部推翻重做,下面逐个拆开讲。
1. 项目概述:为什么第三名值得写一篇长文
1.1 微型鼠比赛到底在考什么
很多人第一次看微型鼠比赛,以为考的是"算法熟不熟"——DFS、Flood Fill、A* 背得滚瓜烂熟就能夺冠。实际完全不是这回事。比赛规则里,迷宫每格 18cm,墙高 5cm,一次完整的冲刺需要在高速移动的同时精确知道自己在哪个格子、墙在哪个方向、下一步转向哪边。真正拉开差距的地方不在"找得到路",而在"高速状态下每一步是否稳定可复现"。
AAMC(亚洲自主微型鼠竞赛)这类赛事的风格我概括成一句话:算法大家都会,难的是让机器人在 1.2 米每秒的速度下,每一毫米的直线、每一次 90 度弯、每一次停车重定位都像排练过一百遍那样稳定。第三名就是这样一点一点"抠"出来的,不是某一个灵光一闪的优化能替代的。
1.2 V2.0 立项时给自己定的三个目标
V1.0 时代我用的是一块低主频 MCU 加外挂传感器模块,跑到 800mm/s 以上时系统明显吃力:TOF 数据采集速度跟不上,转弯时姿态结算滞后,地图经常推到一半就毁掉。V2.0 立项时我给自己写了三条硬指标:
- 主控换成 ESP32-S3,用双核异构接管传感采集和运动控制,彻底解决实时性瓶颈。
- 所有传感器数据更新频率从 100Hz 级别提升到 400Hz 级别,IMU 的原始数据和 TOF 的距离数据在同一个调度循环里完成融合。
- 冲刺速度从 800mm/s 提到 1200mm/s,且重点优化转弯的动态减速轨迹,而不是只把直线最高速度拉上去。
这三条指标在最终比赛里都达到了。回头看,第三条其实是最折磨人的,因为直线速度翻倍之后,几乎所有模块的可靠性都要跟着翻倍,差一点都不行。
2. 主控选型:为什么是 ESP32-S3 而不是 STM32 或树莓派 Pico
2.1 双核加向量指令,解决实时性矛盾
微型鼠的实时性要求是硬性的:控制环路低于 500Hz 基本没法稳定跑高速,TOF 传感器的 I2C 读取想在 400Hz 下不丢数据,调度的容错空间非常小,而迷宫路径决策在竞速时又必须和运动控制抢 CPU 时间。V1.0 用单核 MCU 的时候,我只能在"控制优先"和"建图优先"之间二选一,很难两头兼顾。
ESP32-S3 用的是双核 Xtensa LX7,最高 240MHz,支持向量浮点指令。V2.0 的软件架构里,我把运动控制、IMU 读取、PID 计算全部放在 core 0,把三颗 TOF 的采集、地图维护、路径决策放在 core 1,两个核之间用消息队列通信。实测最忙的时刻 core 0 占用率约 66%,core 1 约 70%,这个余量在后面对我加入一个轻量级神经网络补偿器非常关键。
2.2 一个板子集成全部外设,省掉二十根飞线
上一代的硬件方案是典型的学生作品拼盘:MCU 一块板,TOF 分线板一块,IMU 模块一块,电机驱动一块,模块之间的飞线加起来二十多根,每一根都是潜在的接触不良点。V2.0 改成把所有器件放在同一块我画好的 PCB 上,三颗 VL53L1X TOF 挂在同一条 I2C 总线上,电机驱动用两路 PWM 加两路方向信号,剩下 GPIO 还够接四个拨码开关和一个状态 LED。
ESP32-S3 板载 WiFi/BLE 这个特性,比赛时虽然完全不用,但调试阶段绝对是效率神器。我直接在手机上开了一个 TCP 调试页面,随时看实时速度、陀螺仪偏航角、每颗 TOF 的距离数据,不用一次次接线插串口。现场修 bug 的时候,这个功能至少帮我省了一个小时的重复拔插时间。
2.3 几款常见主控的横向对比
设计阶段我做了一张选型表,把当时考虑过的几款方案放在一起比:
| 方案 | 核心架构 | 主频 | 浮点能力 | 调试便利性 | 我最终放弃/选择的原因 |
|---|---|---|---|---|---|
| STM32F405 | Cortex-M4 单核 | 168MHz | 硬件 FPU | 需要 J-Link,串口调试 | 单核抢占严重,要双核得上 F7/H7,成本上去了 |
| 树莓派 Pico | Cortex-M0+ 双核 | 133MHz | 无硬件 FPU | 拖 Arduino/Rust 还行 | 主频偏低,姿态解算要手动定点化,太折腾 |
| nRF52840 | Cortex-M4 单核 | 64MHz | FPU 较弱 | 烧录简单 | 性能余量不够跑 400Hz 传感融合 |
| ESP32-S3 | Xtensa LX7 双核 | 240MHz | 向量浮点指令 | WiFi 调试,Arduino/ESP-IDF 双栈 | 性能和调试体验同时满足需求,最终选择 |
这里补充一句:选型不只看峰值性能,更要看你能不能把性能变成实时性。ESP32-S3 的 FreeRTOS 双核调度对我来说是刚好够用且不折腾的选择,它的 WiFi 调试能力在比赛高压环境下更是隐形加成。
3. 机械与硬件设计:每一毫米都是收益
3.1 底盘尺寸和结构布局
标准微型鼠的体积限制是长宽各 25cm,V2.0 的目标是压到长 11.2cm、宽 9.8cm、高 6cm。为什么要做小?因为在同样的速度下,转弯半径直接决定能不能走出更紧致的路径。a = v²/R,半径越小,同样的速度下离心力越大,对机械刚性的要求越高,但比赛成绩的收益也越大。V2.0 的实测数据是:250.6mm 轮距的差速底盘做一次 90 度原地转弯约 168ms,比上一代缩小底盘前快了约 25%。
底盘材料我用了 1.6mm 的 FR4 玻纤板,两层叠装。上层放主控和电池,下层放电机驱动和传感器。铜柱间距是重新排过的,因为第一版打样时电池出线和 IMU 安装孔打架,返工了一次,这种问题在设计阶段用 3D 预览完全可以避免。
3.2 电机和减速箱:1:30 而不是 1:50
微型鼠的老玩家都知道,电机减速比选择是个典型的平衡问题。V2.0 用 N20 有刷电机配霍尔磁编码器,减速比 1:30。很多人第一次做会选择 1:50,觉得扭矩更大更稳,但我在实测中发现 1:50 在 1200mm/s 时反电动势比较大,编码器分辨率反而是瓶颈。1:30 在轮径 30mm 的前提下,1000-1200mm/s 刚好落在电机效率比较高的转速区间。
给一个具体数据参考:N20 电机 1:30 输出轴转速上限约 1000rpm,配 30mm 轮径时最大线速度能到 1500mm/s。实际冲刺取 1200mm/s,PWM 占空比大概 80%,电机比较接近效率区。霍尔编码器每转产生 11 个脉冲,配合 1:30 减速比后大约每毫米 29.37 个计数,用于位置闭环完全够用。选 1:50 的话,同样的编码器换算到每毫米计数虽然更高,但电机转速逼近极限,控制反而更难。
3.3 传感器布局:三颗 TOF 加一颗九轴 IMU
V2.0 的感知系统由三颗 VL53L1X 长距 TOF 测距传感器、一颗 ICM-20948 九轴 IMU、两颗轮子上的磁编码器组成。TOF 传感器布置在机器人的左、前、右三个方向,正好覆盖迷宫三个墙面方向。VL53L1X 相比上一代的 VL53L0X,优势是测量范围更大、精度更高,短板是快速模式下单颗的采样率并不高。
我实际的处理方式是三颗 TOF 轮询触发:每颗以约 130Hz 的频率采集,三颗交替采样合并成 400Hz 的融合更新率。IMU 以 400Hz 读取原始数据,经过四元数解算后输出到控制环。这样视觉和惯性数据在同一个调度循环里完成融合,控制稳定性相比上一代是质的飞跃。
3.4 电源和抗干扰:被很多人忽略的魔鬼
电源系统是"看起来简单、做起来全是坑"的部分。V2.0 用 1S 3.7V 500mAh 锂电池给电机供电,数字电路经低静态功耗 LDO 降到 3.3V。电机瞬时堵转电流能到 2A,如果 LDO 和滤波设计不当,EMI 会直接干扰 I2C 总线,TOF 读数在高速加减速瞬间会出现大量毛刺。
我的解决办法是在电机驱动 VBAT 侧并联 100μF 陶瓷电容和 47μF 钽电容,在 I2C 数据线上各串 1kΩ 电阻。实测干扰毛刺完全压下去了,这个成本不到两块钱,却能省掉后期无数排查时间的坑。再说一次:微型鼠里没有任何一个模块是可以随便糊弄的,电源就是最典型的例子。
4. 软件架构与控制算法:从 500mm/s 到 1200mm/s 的跨越
4.1 四状态机:标定、探索、回库、冲刺
V2.0 的软件整体是一个四状态状态机:CALIB(标定)、EXPLORE(探索)、BACKTRACK(回库)、RUSH(冲刺)。
- 标定状态:上电后自动检测三颗 TOF 的 I2C 地址、IMU 是否能正常读取、电池电压是否在安全范围。
- 探索状态:以相对保守的 500mm/s 速度走迷宫,Flood Fill 算法决定下一步转向,边跑边建图。
- 回库状态:探索完成后从中心格高速回到起点,为冲刺做准备。
- 冲刺状态:用已知的最优路径全速跑向中心,速度提到 1200mm/s,加速度提到 2500mm/s²。
探索和冲刺的运动参数必须分开存,这是第一次做微型鼠的人最容易忽略的坑。我用同一套 PID 参数试过探索和冲刺,低速时稳稳当当,一旦换到冲刺模式就开始震荡。V2.0 里直接维护了两套独立的 PID,探索和冲刺之间切换时直接替换参数,干净省事。
4.2 姿态解算与控制回路:互补滤波加串级 PID
姿态控制的核心是用 ICM-20948 的加速度计和陀螺仪数据做互补滤波,得到偏航角。控制回路是典型的串级结构:内环是频率 1500Hz 的角速度环,外环是频率 100Hz 的位置环。为什么用互补滤波而不是卡尔曼滤波?我在微型鼠这个低速度高振动的场景里实测下来,互补滤波一个 alpha 系数就能平衡动态响应和噪声,而卡尔曼需要调协方差矩阵,调参周期长,性价比不高。
具体控制参数如下,给需要的朋友直接抄作业:速度环 PI,Kp=40,Ki=0.15;位置环 PD,Kp=2.8,Kd=0.04。两个电机独立闭环,转弯时利用左右轮差速。这套参数在 500mm/s 到 1200mm/s 范围内都能稳定工作。探索模式的位置环 Kp 我降到 1.6,因为低速下过冲比超调更麻烦。
4.3 迷宫搜索:带转向代价的 Flood Fill
迷宫地图用 16×16 字节数组表示,每个字节的高四位存墙信息(N/E/S/W 各占一位),低四位存距离值。Flood Fill 从中心格开始 BFS 灌水,每个格子的距离值表示到达中心的最短步数。探索时,每到一个格子中央就做一次决策:如果周边有未探索区域,就优先走最短路径;如果发现新墙和预期不符,就重新灌水。
这是教科书级的标准做法,但竞速型的微型鼠必须做一个改造:按步数最短的路并不一定是时间最短,因为 90 度转弯的时间远大于直行通过一个格子。V2.0 在 Flood Fill 里直接引入"转向代价":每个直行动作的基础代价是 1.0,转弯动作额外加 0.6 个等效步长(根据实测转弯 168ms 对直行 110ms 换算而来)。这样搜索出的路径会天然避开不必要的直角转弯,探索效率高了很多。
4.4 Neuro 在哪里:轻量级神经网络补偿器
这是 NeuroMouse 名字的由来,也是我第二版比较大的改动。冲刺阶段我发现一个问题:不同电池电压下,同样的 PWM 占空比产生的实际速度不一样,导致转弯半径漂移。传统做法是查电压表做开环补偿,但这个方法在轮胎磨损、地面摩擦系数变化后又会失效。
V2.0 的做法是训练了一个很小的 MLP 网络:12 个输入,包括当前速度、目标速度、左右轮编码器速度、IMU 偏航角、电池电压、上一时间步的 PWM 输出;32 个隐藏单元;输出是左右轮 PWM 修正量。训练数据来自 200 组手动标定的轨迹,跑在 ESP32-S3 上每次推理约 0.8ms。实测加了补偿网络后,1200mm/s 下的直线偏移从 ±16mm 降到 ±5mm,转弯终点偏移从 ±12mm 降到 ±4mm。用 ESP32-S3 的向量指令做矩阵乘法,算力完全不是瓶颈。
5. 实操过程:从焊接、标定到参数整定
5.1 电路板焊接与接线注意事项
V2.0 的 PCB 我打样了 5 块,焊接时最需要小心的是 IMU 的安装方向和 I2C 上拉电阻。ICM-20948 的坐标轴方向如果和底盘坐标系对不上,后面所有姿态补偿都会变成灾难。焊接完成后第一件事就是写一个简单的测试程序,打印三轴加速度和陀螺仪原始值,确认方向。I2C 总线上三颗 TOF 的地址分配靠 XSHUT 引脚分时上电实现:先全部拉低,然后逐颗唤醒并分别写入不同地址,实测可以稳定分配到 0x32、0x33、0x34。如果地址冲突,表现就是 I2C 扫描时偶尔丢设备,这种问题在比赛现场极难排查。
5.2 TOF 传感器标定流程
TOF 标定是拿到稳定数据的前置条件。具体做法是让机器人在已知距离的位置上采集读数,比如正对墙 10cm、20cm、30cm、40cm 各采 50 组数据,做线性拟合,得到每颗传感器的 offset 和斜率修正值。出厂数据经常有固定偏移,不做修正的话近距离测距误差可能到 2mm,在格宽 18cm 的迷宫里这是致命的。
这里有一个重要参数:VL53L1X 的 timing budget。竞速模式下我把单次测量预算设成 33ms,比默认的 20ms 更长,换来的是更稳的读数。代价是单颗传感器最大采样率下降,但因为我用三颗 TOF 轮询,总体融合频率还能维持 400Hz。实测在 20-250mm 这个微型鼠常用的测距范围内,误差稳定在 2mm 以内。
5.3 PID 整定的实操流程
整定 PID 我有一套非常机械的流程,适合新手直接复制:
- 先把内环(速度环)和外环(位置环)都设成纯 P,P 从 0 开始逐步增加,直到出现高频抖动。记录这个临界 P 值,退回一半作为初始值。
- 加 D 项抑制振荡。D 从 0 开始,每次加 0.01,直到直线跑起来没有明显来回摆。
- 最后加 I 项消除稳态误差。I 从 0.05 开始往上加,直线位移误差收敛到 ±2mm 以内就停。
- 调完速度环再调位置环,两个环不要同时整定,否则问题出现时你根本分不清是哪一层在振荡。
这套流程跑下来,速度环 Kp=40、Ki=0.15,位置环 Kp=2.8、Kd=0.04。比赛现场如果出现参数轻微振荡,优先调 D 而不是调 P,这是屡试不爽的应急方案。
5.4 迷宫搜索的仿真与实测
算法上线的第一步永远是在桌面仿真器里跑通。我先用自己写的 16×16 迷宫仿真器验证修正版 Flood Fill 的输出路径,确认转弯次数比普通 BFS 少了大约 20%,然后再烧进真机。真机调试时要特别注意一点:迷宫格和格之间的中心对齐,机器人必须稳定停在格子中心才能做墙检测。V2.0 的做法是利用轮子编码器做位置积分,到达目标位置后短暂停车,等 TOF 读数稳定再决策。
6. 比赛现场的问题排查实录
6.1 强环境光让 TOF 数据波动
凌晨排位后的第一轮探索,我发现左侧 TOF 在靠近某面墙时读数跳变,误差突然到了 8mm。排查后定位到:场地灯光的红外成分让 VL53L1X 产生了额外的串扰。解决办法是给三颗 TOF 各套一个黑色热缩管做的遮光罩,并把测量模式从 Short 改成 Long,timing budget 从 20ms 调到 33ms。现场几分钟就解决,但这类问题往往要真的被它坑过一次才想起来预防。
6.2 冲刺时陀螺仪漂移加剧
冲刺模式下转速快、振动大,ICM-20948 的陀螺仪读数毛刺明显增加,偏航角快速漂移。我在冲刺状态加了处理逻辑:直线高速段主要信任陀螺仪积分,格子中心静止的极短窗口里用加速度计做一次校准。互补滤波的 alpha 系数从探索模式的 0.6 改成冲刺模式的 0.85,也就是更信任陀螺仪的短期精度。这样改完,一整个 16×16 迷宫跑完的角度误差控制在 1.5 度以内。
6.3 地图复用前提:起点重定位
探索完成后回到起点,机器人会因为惯性停在起点格的不同位置。如果直接按存储的地图开始冲刺,起点偏差会随着路径累积。我的办法是加了一个"定位扫描"模式:冲刺开始前原地旋转 180 度,用左右两颗 TOF 测两侧墙的距离,反算实际停在格子里的横向偏移和角度偏差,然后修正起始位姿。这个步骤耗时不到 300ms,但对冲刺成功率的影响是决定性的。
6.4 电机温度导致的参数漂移
连续跑了几轮之后,电机温度上升,内部摩擦系数变化,速度环出现轻微超调。现场临时把速度环微分项从 0.15 加到 0.18,问题立刻缓解。这个问题的根本原因是整定时没有给温度留余量,事后复盘时我认为正确做法是整定阶段就在持续跑 10 分钟后做参数复核,而不是到比赛现场才仓促改参数。
| 赛场问题 | 根因 | 现场处理 | 预防建议 |
|---|---|---|---|
| TOF 跳变 8mm | 红外环境光串扰 | 加遮光罩,改 Long 模式 | 赛前在相似光线下标定 |
| 陀螺仪漂移 | 高速振动加积分误差 | 分段信任策略,调 alpha | 增加静止校准窗口 |
| 起点偏差累积 | 停车位置不一致 | 旋转 180 度重新定位 | 探索结束自动加定位步骤 |
| 参数振荡 | 电机温度变化 | 临时调大 D 项 | 整定后跑 10 分钟复核参数 |
7. 手搓微型鼠的一点体会和后续方向
这次做 NeuroMouse V2.0 最大的收获,不是那一张第三名的证书,而是我彻底理解了嵌入式系统里没有"一个大优化"这回事。所谓的高速稳定,其实就是一百个 1% 的优化叠在一起:底盘小 1mm、电源滤波多一个电容、TOF 遮个黑罩、PID 多留 5% 余量、转弯路径多算一步等效时间,每一个单独拿出来都不起眼,组合起来才能变成比赛现场"稳得让人放心"的机器人。
如果看完这篇文章想入坑微型鼠,我的建议是:先在仿真器里把 Flood Fill 和 PID 调到闭着眼都能复现,再花几百块钱打样硬件。不要一上来就买最贵的传感器和电机,第一版做的目标是跑通流程,不是拿冠军。工具方面,ESP32-S3 的手机 TCP 调试方案、三颗 TOF 的标定脚本、轻量级 MLP 在 MCU 上的推理代码,我后续都会整理出来单独写文章分享。至于下一版,我准备加两颗侧向 TOF 做五向感知,探索算法引入贝叶斯墙检测来过滤异常读数,顺便试试闭环步进电机的方案能不能把 90 度转弯压进 120ms。V2.0 的故事暂时到这里,迷宫里的每一堵墙,下一版再慢慢拆。