做这个小车的想法其实来得挺简单——手头刚好有一块吃灰的 ESP32 开发板,又刷到别人玩的全向轮移动视频,那种“横着走、斜着走、原地转圈”的灵活劲儿确实很戳人。于是干脆组了一台三轮全向轮机器人,用手机连 WiFi 直接控制,整个过程从硬件搭建到写代码、调车,前后花了大概两个周末。这篇就把完整的方案、原理、代码和踩坑记录都整理出来,给想做同款或者正在纠结“ESP32 到底能不能带动全向轮平台”的朋友一个参考。
先说结论:ESP32 做全向轮机器人的主控非常合适。它自带 WiFi 和蓝牙,双核 240MHz 的处理能力跑运动学解算绰绰有余,GPIO 也够用,最关键的是 Arduino 生态成熟,代码写起来不费劲,OTA 无线升级也方便,后期想加摄像头、加传感器都不用换主控。这篇教程适合有一定 Arduino 基础、想玩移动机器人但不想上树莓派那么重负担的爱好者,也适合正在做课设或比赛底盘验证的同学。我会把三轮全向轮的运动学公式、手机端虚拟摇杆的实现、WebSocket 低延迟通信这些核心细节都讲清楚,尽量做到照着操作就能跑起来。
1. 项目整体设计与思路拆解
1.1 三轮全向轮 vs 四轮麦克纳姆轮
现在市面上常见的全向移动底盘主要有两种:一种是三轮全向轮(Omni Wheel),另一种是四轮麦克纳姆轮(Mecanum Wheel)。我在这个项目里选了三轮全向轮,原因很直接:结构简单、驱动少、逻辑清楚。
全向轮的特点是轮子外圈安装了一圈小滚子,滚子轴线与轮子转动方向垂直。这意味着轮子可以在主动驱动方向正常转,同时在滚子的被动方向上几乎无摩擦滑动。三个轮子按 120 度均布在底盘上,通过三个轮的转速组合,机器人就能实现平面内的任意方向平移和自转——也就是全向移动。
四轮麦克纳姆轮固然承载能力和稳定性更好,但它需要四个电机和四个驱动,硬件成本更高,代码里要处理的电机数量也翻倍。对于手机遥控这种应用场景,三轮全向轮的机动性完全足够,而且运动学公式更简洁,调试起来也快。如果你打算后期加机械臂、加沉重负载,再考虑换四轮底盘;但如果只是为了玩控制、验证算法,三轮全向轮是性价比最高的起点。
1.2 为什么主控选 ESP32
做 WiFi 无线控制的小车,主控的选择其实不多。传统 Arduino Uno 这类板子没有 WiFi,需要外接 ESP8266 模块做串口透传,构架复杂且延迟不好控制;树莓派算力强但启动慢、功耗大、成本高,对小尺寸底盘来说有点杀鸡用牛刀。
ESP32 把 WiFi、蓝牙、双核处理器、丰富的外设接口全集成在一块板子上,价格却只要几十块。实际测试下来,WebSocket 通信加运动学解算加 PWM 输出,ESP32 的 CPU 占用率还不到 20%,运行得相当轻松。更关键是 ESP32 的 LEDC 硬件 PWM 模块支持多路独立输出,三路电机控制信号可以直接由硬件产生,不占用 CPU 时间,这对后续扩展传感器和算法很有价值。
还有一个非常实用的点:ESP32 支持 OTA 无线升级。小车装好之后,改代码不用再拆壳子接 USB 线,直接在 Arduino IDE 里选择网络端口就能烧录新固件,调试效率高了一个量级。这一点在后面我会单独讲配置方法。
1.3 整体系统架构
这个项目的系统架构不算复杂,分三层:
- 控制端:手机浏览器打开一个本地网页,页面上有一个虚拟摇杆。手指在摇杆区域滑动,页面通过 WebSocket 把摇杆的偏移量(对应机器人期望的 Vx、Vy 和角速度)发送给 ESP32。
- 主控端:ESP32 同时扮演 WiFi 接入点和 WebSocket 服务器。它接收控制指令后,先做运动学反解,把 Vx、Vy、ω 换算成三个轮的转速,再通过 LEDC 生成 PWM 信号驱动电机。
- 执行端:三个带减速箱的直流电机,分别由一路 TB6612 驱动模块控制,电源由 7.4V 锂电池统一供给。
选 WebSocket 而不是普通的 HTTP 请求,是因为控制类的指令对实时性要求高。HTTP 每次通信都要建立连接、发送请求头、等待响应,一轮下来几十毫秒就过去了,遥控手感会明显发肉。WebSocket 建立一次长连接后,数据以帧为单位直接推送,实测从手机摇杆变化到电机响应,延迟能控制在 50 毫秒以内,虽然不能和有线遥控比,但日常玩足够跟手了。
2. 硬件准备与底盘搭建
2.1 核心硬件清单
这个项目的硬件清单不算复杂,我把选型和一些关键参数列出来,方便你照着采购或替换:
| 部件 | 型号/规格 | 数量 | 说明 |
|---|---|---|---|
| 主控板 | ESP32 DevKitC / NodeMCU-32S | 1 | 任选一款 GPIO 引出完整的开发板即可 |
| 电机 | N20 减速电机 6V(1:30 减速比) | 3 | 带霍尔编码器版本更好,后续可以做闭环 |
| 电机驱动 | TB6612FNG 模块 | 2 | 一块驱动两路,三路用两块;不推荐 L298N |
| 全向轮 | 45mm 或 60mm 三轮全向轮 | 3 | 带滚子,注意孔径要和电机轴匹配 |
| 锂电池 | 7.4V 2S 锂电池 | 1 | 容量 1200mAh 左右就够玩半小时 |
| 降压模块 | MP1584 / LM2596 | 1 | 5V 降压给 ESP32 供电 |
| 底盘 | 亚克力板或 3D 打印底盘 | 1 | 三轮 120 度均布结构 |
| 其他 | 杜邦线、铜柱、开关、焊锡 | 若干 | 用于固定和接线 |
电机我选的是 N20 减速电机,主要看中它体积小、自带减速箱、转速合适。全向轮小车不需要太高的转速,配合 1:30 减速比,输出轴转速大概在每分钟 200 转左右,配上 48mm 的小轮子,线速度大约 0.5 米每秒,室内遥控刚好合适。如果你手头只有 28BYJ-48 步进电机,理论上也能用,但那个电机转速太低、发热大,控制起来不如直流减速电机顺手,不建议优先考虑。
2.2 电机驱动的选择:为什么不用 L298N
电机驱动这块我踩过不少坑,最想提醒的就是:别用 L298N。市面上最常见的 L298N 模块压降太大,电源输入 7.4V,到电机端可能只剩下 6V 左右,扭力损失明显;而且模块上自带的 5V 稳压输出纹波大,直接给 ESP32 供电容易导致 WiFi 模块工作不稳定。
TB6612FNG 是更好的选择。它的导通内阻低,压降小,同样 7.4V 输入能更有效地传到电机;而且逻辑电压输入可以直接接 ESP32 的 3.3V 引脚,不需要额外电平转换。TB6612 的缺点是一块模块只能驱动两路电机,三路电机需要两片,多花十来块钱,但换来的稳定性和效率完全值得。
接线方面,每片 TB6612 有 PWMA、AIN1、AIN2 三个控制脚和 AO1、AO2 两个电机输出脚。另外要特别注意 VM 接电池正极、VCC 接 3.3V 逻辑电源、GND 要跟 ESP32 共地。这个共地问题很关键,如果驱动板和 ESP32 的地没连在一起,PWM 信号参考电位不一致,电机会出现抖震或直接不转。
2.3 供电方案与布线注意事项
供电方案我踩过好几次坑,这里展开讲一下。三轮车满负荷运行时,三个电机同时启动的瞬时电流能达到 1.5A 到 2A,如果直接把 7.4V 电池接到 ESP32 的 5V 引脚上,轻则稳压芯片发烫,重则直接烧板。
我的做法是:电池正极先接总开关,然后分成两路。一路接 TB6612 的 VM 电机电源端,另一路经过 MP1584 降压模块降到 5V,再给 ESP32 的 5V 引脚供电。这样电机的大电流和逻辑电源完全隔离,电机启停造成的电压波动不会影响 ESP32 的稳定运行。实测在电机堵转瞬间,电池电压最多掉到 6.5V 左右,但 ESP32 端依然稳定在 5V 附近,没有再出现过随机重启的毛病。
布线的时候还有几个细节要注意。第一,所有功率线的线径不要小于 0.5 平方毫米,特别是电池到驱动板的线,细线在大电流下发热明显。第二,电机两端要并联一个 104 瓷片电容或者电解电容,吸收换向产生的反向电动势,这个对减少 ESP32 的复位问题和电机干扰有很大帮助。第三,PWM 信号线尽量远离电机线和电池线,如果空间实在紧张,就用杜邦线交叉绑扎的走法,避免平行长距离走线。
3. 全向轮运动学基础
3.1 三轮全向布局的运动学反解推导
做全向轮机器人绕不开运动学。好在这个项目的三轮全向布局公式推导并不复杂,只要理解了方向关系,代码就是几行三角函数的事。
设定机器人的坐标系:以底盘中心为原点,正前方为 X 轴正方向,朝左为 Y 轴正方向,逆时针旋转为角速度 ω 正方向。三个轮子的安装角分别为 0 度、120 度和 240 度,也就是说一号轮在正前方,二号轮在左后,三号轮在右后。
每个全向轮的驱动方向沿着安装点所在圆的切线方向。机器人的整体速度 (Vx, Vy, ω) 投影到每个轮的切线方向上,就能得到这个轮需要的线速度。公式如下:
v1 = -Vx·sin(0°) + Vy·cos(0°) + L·ω v2 = -Vx·sin(120°) + Vy·cos(120°) + L·ω v3 = -Vx·sin(240°) + Vy·cos(240°) + L·ω其中 L 是轮子安装点到机器人中心的距离。代入三角函数值后:
v1 = Vy + L·ω v2 = -0.866·Vx - 0.5·Vy + L·ω v3 = 0.866·Vx - 0.5·Vy + L·ω这个结果可以当作自行车转向那种直觉来理解:机器人要正着往前走,一号轮(正前方这个)其实是不转的,它的驱动方向和前进方向正好垂直,全靠在二号、三号轮的差动配合下被动滚动过去。要往左边平移,一号轮就是主力,三号轮配合。要原地转圈,三个轮子朝同一个圆周方向一起转。这种特性第一次接触会觉得反直觉,但实际跑起来运动非常顺滑。
3.2 从摇杆输入到轮速的换算流程
手机上虚拟摇杆的输出量是一个二维向量,摇杆偏离中心越远,向量越大。我把它映射成机器人的期望速度:摇杆前后拨动对应 Vx,左右拨动对应 Vy,另外用一个滑块或者摇杆旋转手势来控制角速度 ω。为了让操作更直观,我直接采用“摇杆方向决定机器人平动方向”的映射,不做相机视角跟随,避免新手一上来就晕头转向。
换算流程是这样的:手机端把摇杆位移归一化到 -255 到 255 的整数值,和角速度值一起打包成字符串,比如vx:128,vy:-64,rot:32,通过 WebSocket 发给 ESP32。ESP32 收到后先做归一化,再套入上一节的反解公式,算出三个轮的线速度,最后根据电机减速比和轮径换算成 PWM 占空比。
这里有个重要细节:反解公式算出的是线速度,单位是米每秒,但实际控制电机用的是 PWM 值。这两者之间是近似线性关系,需要在实机上调一个比例系数。我的办法是先用 50% 占空比让小车跑直线,用秒表和卷尺实测出实际线速度,算出“PWM 值到线速度”的换算系数,然后把这个系数写进代码里作为常量。这样遥控软件端可以直接以物理速度为单位下发指令,语义清楚,后续调整也更加方便。
4. 软件架构与核心代码实现
4.1 开发环境与整体框架
软件部分我用的 Arduino IDE 2.x,ESP32 开发板支持包直接在“开发板管理器”里搜索 ESP32 安装即可。注意安装后要选择正确的开发板型号,我用的 NodeMCU-32S,对应的板卡选项是ESP32 Dev Module,Flash 大小默认选 4MB 就行。
整个固件逻辑分为几个模块:WiFi 连接模块负责开启热点或连接路由;WebSocket 服务模块负责接收手机指令;运动学解算模块把 Vx、Vy、ω 换算成轮速;电机控制模块负责输出 PWM 和方向信号。模块之间通过全局变量传递数据,WebSocket 收到新指令就更新期望速度,主循环里做一次解算并更新 PWM 输出。这种设计简单直接,也方便以后加入 PID 闭环或传感器融合。
代码里我用了几个现成的库,最核心的是 Arduino WebSockets,在库管理器里搜 WebSockets 安装即可。这个库同时支持 WebSocket 客户端和服务器,对 ESP32 适配得很好,开箱即用,不需要自己处理握手协议和帧解析。
4.2 WiFi 接入方式:AP 模式还是 STA 模式
ESP32 作为控制对象,WiFi 接入方式有两种选择:一是让 ESP32 开热点(AP 模式),手机直连 ESP32 的热点;二是让 ESP32 连接家里路由器(STA 模式),手机和 ESP32 在同一局域网内通信。
两种方案我都试过,各有适用场景。AP 模式的优势是极简、零配置,小车通电后手机就能搜到名为 OmniBot 的热点,连上就能控制,适合户外、实验室、比赛场地这些没有现成路由器的场合。缺点是手机连了 ESP32 热点后就不能正常上网了,而且 ESP32 热点的覆盖范围有限,隔一堵墙就容易丢包。
STA 模式的优点是可以借助路由器扩展通信距离,手机不用切换网络就能边上网边控制,后期如果要做室内定位、多机器人协作这些功能也更方便。缺点是第一次要给 ESP32 配置 WiFi 账号密码,我建议把配网信息做成一个简单的配置页,或者直接写死在代码里方便调试。
考虑到教程的通用性,我把默认方式设为 AP 模式,然后在代码里留了 STA 模式的配置入口,你只需要把两个 ssid、password 变量改成自己路由器的信息就行。AP 模式的密码我建议设简单一点,毕竟是局域网控制用的,搞太复杂每次连接都难受。
4.3 手机端网页与虚拟摇杆的实现
手机控制端我直接写了一个网页,不依赖任何 App,手机浏览器打开就能用。网页部分存在 ESP32 的 SPIFFS 文件系统里,也可以通过代码里的 HTML 字符串直接输出,为了少一个文件烧录步骤,我选择把网页代码直接拼成一个字符串常量存在固件里,这样只刷一次固件就全搞定。
网页的核心是一个虚拟摇杆,实现思路是用一个圆形区域和一个小圆点。手指在屏幕上滑动时,通过 touch 事件算出触点相对圆心偏移量,映射到 -255 到 255 的范围,再以 50 毫秒的间隔通过 WebSocket 发送给 ESP32。
这里有个手感细节:摇杆的返回中心需要加死区处理。手指离开屏幕时,如果摇杆直接归零,可能导致电机瞬间反转,小车会抖一下。我加了 15 的阈值判断,摇杆偏移量小于这个值的都当作归零处理,这样电机不会因为细微抖动来回摆动。另一个细节是虚拟摇杆区域要设置touch-action: none,否则手机浏览器默认手势会干扰摇杆操作。
4.4 电机控制与运动学解算的代码实现
电机驱动的代码我单独封装了两个函数,一个负责设置某路电机的方向和 PWM,另一个负责接收三个速度值并做解算输出。方向控制通过两个 IN 引脚的组合实现,PWM 值则用到 ESP32 的 LEDC 硬件通道。
这里特别说明一下 ESP32 的 PWM 用法。LEDC 模块分为 0 到 15 共 16 个通道,先通过ledcSetup(channel, freq, resolution)配置频率和分辨率,再用ledcAttachPin(pin, channel)把引脚绑定到通道。分辨率我选了 8 位,也就是 0 到 255 的占空比,频率选 5000Hz,这个频率下电机噪声适中,控制线性度也不错。
下面是省略了引脚定义和头文件的电机控制核心代码:
void setMotor(int pwmPin, int in1, int in2, int speed) { // speed 范围 -255 到 255,正数正转,负数反转 speed = constrain(speed, -255, 255); if (speed >= 0) { digitalWrite(in1, HIGH); digitalWrite(in2, LOW); } else { digitalWrite(in1, LOW); digitalWrite(in2, HIGH); speed = -speed; } ledcWrite(pwmChannelMap[pwmPin], speed); } void updateWheels(float vx, float vy, float rot) { float L = 0.105f; float v1 = vy + L * rot; float v2 = -0.866f * vx - 0.5f * vy + L * rot; float v3 = 0.866f * vx - 0.5f * vy + L * rot; // 乘以速度系数,把线速度换算成 PWM setMotor(MOTOR1_PWM, MOTOR1_IN1, MOTOR1_IN2, v1 * PWM_PER_MPS); setMotor(MOTOR2_PWM, MOTOR2_IN1, MOTOR2_IN2, v2 * PWM_PER_MPS); setMotor(MOTOR3_PWM, MOTOR3_IN1, MOTOR3_IN2, v3 * PWM_PER_MPS); }运动学解算写完之后,一定要先做一轮“空转验证”。把小车架起来不让轮子碰地,给三个轮子分别下发纯前向、纯横向、纯旋转的速度指令,用肉眼观察三个轮子的转向是否符合公式预期。比如下发纯前向 Vx=1 时,应该有如图所示的特征:一号轮不转,二号轮反转,三号轮正转。如果转向不对,多半是电机接线方向反了,交换一下该路电机的两个 IN 引脚就行。
WebSocket 接收指令的部分也贴一下,核心就是解析收到的字符串并调用更新函数:
void wsEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) { if (type == WStype_TEXT) { char* data = (char*)payload; float vx = 0, vy = 0, rot = 0; sscanf(data, "vx:%f,vy:%f,rot:%f", &vx, &vy, &rot); updateWheels(vx / 255.0f, vy / 255.0f, rot / 255.0f); } }手机端网页发送数据的核心代码也很短,这里展示关键部分,完整代码我整理后可以发在评论区或网盘:
if (ws.readyState === WebSocket.OPEN) { ws.send('vx:' + vx + ',vy:' + vy + ',rot:' + rot); }为了省电和降低干扰,我还加了一个超时保护机制:ESP32 在 500 毫秒内没有收到新的控制指令,就默认把三个轮子全部停止。这个机制非常重要,因为手机网页在锁屏或切后台时 WebSocket 会断连,如果不加这个保护,小车会保持最后一条指令状态,变成一个脱缰的野马。
4.5 OTA 无线升级配置
OTA 是 ESP32 最实用的功能之一,尤其对车载设备来说,避免频繁插拔 USB 线这件事能省下大量时间。Arduino 环境下配置 OTA 非常简单,只需要引入 ArduinoOTA 库,在 setup 里初始化,在 loop 里调用处理函数。
#include <ArduinoOTA.h> void setup() { // ... 其他初始化 ArduinoOTA.setHostname("omni-bot"); ArduinoOTA.setPassword("admin123"); ArduinoOTA.begin(); } void loop() { ArduinoOTA.handle(); // ... 其他循环逻辑 }配置好之后,在 Arduino IDE 的端口列表里会多出一个网络端口,选择它再点上传,就会通过 WiFi 把新固件推送到 ESP32。第一次烧录 OTA 必须用 USB 线,但之后只要不把 OTA 功能弄崩,基本可以彻底告别 USB 线。要注意的是,OTA 升级期间 ESP32 会短暂重启断开 WiFi,手机端的 WebSocket 连接会自动断开,升级完成后需要刷新网页重新连接,这是正常现象,不用慌。
还有一点:如果你启用了 OTA,一定要保证固件里没有在 setup 阶段阻塞太久的操作,比如长时间的业务逻辑初始化。因为 OTA 需要 ArduinoOTA.handle() 在 loop 里持续运行才能维持网络协议。我曾经因为一段卡 5 秒的配置读取把 OTA 搞废过一次,最后只能重新接 USB 线救回来。血的教训,提醒大家 OTA 的循环一定不能阻塞。
5. 实机联调与参数标定
5.1 通电前的硬件安全检查清单
硬件装好、代码写完之后,千万别急着通电。我这个项目前后改了五版接线,前两版都因为低级错误返工,总结出一个通电前检查清单,照着走一遍能避免九成事故:
- 电池电压是否正常?7.4V 锂电充满约 8.4V,低于 6V 说明电池亏电或保护板触发了。
- 电机驱动板 VM 和 ESP32 的电源是否分开?绝对不能把电机驱动板的 VM 直接接到 ESP32 的 5V 引脚。
- 所有 GND 是否已经共地?包括电池负极、驱动板 GND、ESP32 GND。
- 电机线是否短路?用万用表蜂鸣档测电机两端电阻,短路的电机上电就会烧驱动。
- PWM 信号线是否接错脚位?对照代码里的引脚定义逐根核对。
- 螺旋桨效应检查:轮子和电机轴的顶丝是否锁紧?如果没锁紧,上电后轮子会原地打滑飞出去。
检查通过后,先不要通电,用手转动每一个轮子,感受是否有卡顿。全向轮的滚子在转动时如果被卡住,运动学就会失效,表现为小车往特定方向推不动或者跑偏。
5.2 电机方向与速度的逐一标定
第一次通电后,不要急着用手机控制,先在串口监视器里手动下发指令,逐个检查每个电机的转向。我这里写了一个简单的测试指令:发送t1 128表示让一号轮正转 128 占空比,发送t1 -128表示反转。
逐个测试时,要先确定“正方向”的定义。在运动学公式里,一号轮的线速度正方向约定为沿着安装点切线的某个方向。如果你接电机线接反了,公式里的符号就会反,小车往前的指令会变成往后,往左的指令会变成往右。这种错误在最终整车测试时才会暴露,排查起来很费劲。所以我的建议是:在标定阶段就为每个轮子定义一个“正方向”,并记录在文档里,让代码里的公式、实机转向和文档完全对应,避免一错错到底。
方向确认后,再标定 PWM 最低启动值。直流减速电机都有启动电压,PWM 占空比太小的时候电机不转,加大到某个值才开始动,这个值我实测在 60 到 90 之间(8 位分辨率下约 25% 到 35%)。这个最低启动值是运动学线性化的关键参数,如果你在反解公式里直接用了 0 到 255 的全范围,就会发现小速度指令下轮子纹丝不动,只有指令超过阈值才有反应,整个摇杆手感会特别差。我的处理办法是把速度值做一个映射,将 [-255, 255] 映射到 [-255, -(min+20)] 和 [min+20, 255] 两个区间,保证指令不为零时电机一定在转。
5.3 无线控制延迟的实测与优化
装好之后,第一件事肯定是拿手机连上热点控制一下。初次上手你会发现几个问题:延迟、抖动、还有方向感混乱。我这里先把延迟问题说清楚。
我用手机拍了一段包含摇杆移动和车轮转动的慢动作视频,通过逐帧分析估算整个控制链路的延迟。实测 AP 模式下摇杆移动到轮子响应约在 40 到 60 毫秒,这个数字对遥控来说还算可以,但还有优化空间。优化手段主要有三个:一是把 WebSocket 数据发送间隔从 50 毫秒缩短到 30 毫秒,提高指令刷新率;二是取消网页端不必要的动画帧,让摇杆位移直接读取原始 touch 坐标;三是把 ESP32 的 CPU 频率从默认的 160MHz 提升到 240MHz,减少解算时间。
值得注意的是,AP 模式的延迟和 STA 模式差异不大,因为 ESP32 的 WiFi 模块本身延迟就很低,瓶颈往往在手机端浏览器的触摸事件采样频率上。如果追求极致的实时性,可以考虑把 WebSocket 换成 UDP 协议,但那样又要处理丢包,对一般的遥控场景收益不大。
5.4 开环控制下的直线与转向调校
由于这个版本没有装编码器反馈,属于开环控制,小车的直线行走并不会非常直。造成跑偏的因素很多:三个电机的一致性问题、轮子滚子的摩擦差异、底盘重心偏移、地面不平整等等。开环状态下我实测跑 3 米直线,横向偏移大约在 10 到 15 厘米,作为玩具绰绰有余,但如果想更稳,就得做闭环控制。
最简单的补救方案是给每个轮子加一个速度补偿系数。我让小车分别以正向和反向跑 2 米,记录实际走的位移偏差,然后微调每个轮子的 PWM 系数,让三个轮子在实际地面上的线速度尽量一致。这个方法能在一轮调校内把 3 米直线偏移压到 5 厘米以内。
如果你后期想追求更高的控制精度,建议换用带霍尔编码器的 N20 电机,在 ESP32 上通过 PCNT 脉冲计数模块读取编码器,再加上一个简单的 PID 闭环。这个扩展方向所需硬件改动不大,编码器信号接 ESP32 的 PWM 输入捕获引脚即可,固件里只需要新增一个速度环的 PID 函数。这个后面可以单独开一篇来说,这里就不展开了。
6. 常见问题与排查实录
6.1 问题速查表
做这个项目过程中遇到的坑不少,我把最典型的几类整理成了一个速查表,方便你先自查再问问题:
| 现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 电机完全不转 | 驱动板供电断开、共地缺失 | 万用表测 VM 和 GND 电压 | 重新接线,确保共地 |
| 部分电机不转 | PWM 引脚配置错误或驱动通道损坏 | 用测试指令分别驱动每路电机 | 核对引脚定义,更换驱动板 |
| 电机抖动但不转 | PWM 占空比低于启动阈值 | 串口打印占空比数值 | 增加最低启动值映射 |
| WiFi 搜不到热点 | ESP32 未能正常启动或热点崩溃 | 看串口日志 | 复位重启,检查电源稳定性 |
| 手机连上热点但打不开网页 | 静态 IP 未配置或网页服务未启动 | 手机浏览器访问 192.168.4.1 | 检查 server.begin() 是否调用 |
| 控制指令有延迟 | 发送间隔太长或 CPU 降频 | 查看 WebSocket 日志时间戳 | 缩短发送间隔,提高 CPU 频率 |
| 小车跑偏严重 | 电机一致性差或轮子打滑 | 逐轮测转速 | 加补偿系数或换编码器电机 |
| 小车突然狂转不停 | 控制指令丢失 | 确认网页连接状态 | 启用超时停止保护机制 |
| 电池掉电快 | 电机堵转或驱动板静态功耗高 | 测工作电流 | 避免长时间堵转,选用低功耗待机 |
6.2 几个值得记录的实战心得
第一个心得是:电源问题永远是 ESP32 项目的第一大坑。这个项目里 80% 的“ESP32 莫名其妙重启”“WiFi 连接不上”的故障,最后都追查到了供电上。ESP32 的 WiFi 发射瞬间电流可以冲到 300mA 以上,如果供电端压降太大,芯片就会进入欠压复位循环。所以做移动机器人的时候,电源这一块宁可多花点心思,也不要图省事直接并电池。
第二个心得是:运动学公式的符号定义比公式本身更容易出错。我在第一次整车调试时,发现前移变成斜移,查了很久才发现是二号轮的正方向定义搞反了。后来我养成了习惯,用一个简单的正向运动学验证反解:给定一组轮速,算出理论上的机器人速度,再对照实机运动方向,全部对上了才进行下一步。
第三个心得是:手机热点的兼容性问题比想象中多。有些手机开放热点时会启用 AP 隔离,导致连上热点的 ESP32 无法和手机上的其他设备互通。排查这个问题的方法是看手机端能否从 ESP32 获取到网页,如果打不开网页但 WiFi 信号又是满格,基本就是 AP 隔离在作怪。这种情况建议改用 ESP32 的 AP 模式,或者换成普通路由器测试。
6.3 WiFi 掉线的排查思路
最后单聊一下 WiFi 掉线问题,这是所有无线控制项目里最常见的幺蛾子。我在调试过程中遇到过好几种掉线表现:连上之后几秒钟就断开、运行一段时间后随机断开、以及指令卡顿但不完全断开。针对不同表现,排查思路也不一样。
对于“连上就断”的情况,优先怀疑供电。把 ESP32 的供电改成单独的 5V 2A 电源适配器测试,如果问题消失,就基本坐实了供电不足。对于“运行一段时间后随机断开”的情况,优先怀疑 WiFi 信道干扰。ESP32 默认的信道可能和附近路由器重叠,我在代码里手动指定了信道 1 到 6 之间比较空闲的一个,掉线概率明显降低。对于“指令卡顿但不完全断开”的情况,通常是手机端网页在后台被系统省电策略挂起了,这个问题只能靠提醒自己保持网页前台运行来解决,手机浏览器端没法完全绕过系统策略。
另外一个非常实用的排查思路是在 ESP32 固件里加状态日志。我在 WebSocket 断开和重连的回调函数里都加了串口打印,记录断开时间和原因编号。跑了几个小时之后,通过分析日志就能发现掉线的规律,比盲猜要有用得多。这也是我在做任何 ESP32 通信项目时都会保留的调试手段。
用了一个多月之后,这台小车现在成了我桌子上最常开机的东西。周末改改代码、换个控制界面,或者单纯推着它在阳台地砖上转两圈,都挺解压。我的建议是,先照着开环版本把整套流程跑通,把 WiFi 通信和运动学这两块底座打稳,再根据自己的兴趣往闭环、传感器、自动导航这些方向延伸。全向轮底盘的乐趣不在于车本身多高级,而在于它验证控制逻辑的速度足够快,让你今天写完公式,明天就能看到车按你的预期做出动作。这种即时反馈的成就感,就是继续往下做的最大动力。