news 2026/10/29 1:07:28

ESP32 Wi-Fi遥控车DIY:从选型到UDP控制全攻略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ESP32 Wi-Fi遥控车DIY:从选型到UDP控制全攻略

1. 为什么我最终选了ESP32来做这台Wi-Fi遥控车

1.1 从一堆吃灰的开发板里翻出ESP32

前阵子收拾工作台,翻出来好几块开发板,STM32的、Arduino Uno的、还有两块ESP32。本来想随便搭个蓝牙小车打发周末,但转念一想,蓝牙控制距离太短,隔堵墙就断连,体验很差。既然手头有ESP32,它自带Wi-Fi,干脆直接做一台Wi-Fi遥控车,手机连上就能控制,距离和稳定性都比蓝牙强不少。

这个项目说白了就三件事:让ESP32连上Wi-Fi、让它能驱动电机、让它能接收手机发来的控制指令。听起来简单,但实际动手时会遇到不少细节问题,比如电机供电和主控供电怎么隔离、PWM频率设多少合适、Wi-Fi指令延迟怎么优化。这些坑我在下面会一个个拆开讲。

适合谁来参考这篇内容?如果你玩过Arduino,点过LED,对GPIO和PWM有基本概念,那这篇就是为你写的。如果你完全零基础,也没关系,我会把每个环节的原理和操作都讲清楚,你照着做也能跑起来。整台车的物料成本大概在80到150块之间,取决于你手头已经有哪些零件。

1.2 核心思路:为什么是Wi-Fi而不是蓝牙

很多人做遥控车第一反应是用蓝牙,毕竟HC-05、HC-06这些模块便宜又常见。但蓝牙有几个硬伤:一是传输距离短,Class 2的蓝牙模块有效距离也就10米左右,稍微远一点或者隔堵墙就断;二是蓝牙的配对过程比较繁琐,每次换设备都要重新配对;三是蓝牙的带宽有限,如果你想后续加个摄像头回传画面,蓝牙根本扛不住。

ESP32的Wi-Fi方案就不一样了。它可以直接工作在AP模式(自己建热点)或者STA模式(连你家路由器),AP模式下手机直连,延迟低、响应快;STA模式下只要手机和车在同一个局域网内,理论上你家的Wi-Fi覆盖范围有多大,控制距离就有多远。而且ESP32的Wi-Fi还支持UDP和TCP两种通信方式,UDP延迟更低适合实时控制,TCP更可靠适合传指令,你可以根据需求灵活选。

我最终选的是AP模式+UDP通信。原因很简单:AP模式不依赖家里的路由器,拿到户外也能用;UDP虽然不保证送达,但对于遥控车这种场景,丢一两个包无所谓,下一帧指令马上就补上了,反而比TCP的重传机制更跟手。

1.3 整车架构一览

在动手之前,先把整台车的架构理清楚,后面操作才不会乱。整台车分成四个部分:

  • 主控部分:ESP32开发板,负责Wi-Fi通信、指令解析、PWM输出
  • 驱动部分:L298N或TB6612电机驱动模块,负责把ESP32的弱信号放大成能驱动电机的强电流
  • 动力部分:两个直流减速电机+车轮,负责让车跑起来
  • 供电部分:电池组+降压模块,负责给主控和电机分别供电

信号流向是这样的:手机App发送UDP数据包→ESP32接收并解析→ESP32输出PWM信号→电机驱动模块放大信号→电机转动→车动起来。整个链路里,最容易出问题的环节是供电和电机驱动,这两块我会重点讲。

2. 物料清单与工具准备

2.1 核心物料选型与避坑

先列一下我实际用到的物料,以及选型时的考量:

物料型号/规格数量参考价格选型说明
主控板ESP32 DevKit V1125-35元经典款,引脚多,资料全
电机驱动TB6612FNG18-15元比L298N效率高,发热小
直流电机TT减速电机210-15元/个带轮子,扭矩够用
车轮65mm橡胶轮25元/个抓地力好
万向轮塑料万向轮13元前轮支撑
电池18650锂电池×2215元/节7.4V供电
电池盒双节18650电池盒15元带引线
降压模块LM2596可调降压13元降到5V给ESP32
车底盘亚克力底盘110元也可以用纸板代替
杜邦线公对公/公对母若干5元连接用

这里重点说几个选型上的坑。电机驱动模块我强烈建议用TB6612而不是L298N。L298N便宜是便宜,但它的导通压降大,大概有1.4V左右,意味着你7.4V的电池经过它之后只剩6V给电机,动力损失明显,而且发热严重。TB6612的导通压降只有0.5V左右,效率高很多,体积也小。

电池方面,我用的是两节18650串联,标称7.4V。为什么不直接用一节3.7V?因为TT电机的额定电压一般在3-6V,但实际测试下来,7.4V供电时转速和扭矩都更充沛,通过PWM限幅就能控制速度。如果你用3.7V,电机可能转起来没劲,尤其是爬个小坡就卡住了。

2.2 工具准备

工具方面不需要太多,但有几样必须要有:

  • 电烙铁:焊接电机引线和电池盒引线,如果你买的是带线的电机,可以省掉这一步
  • 螺丝刀套装:组装底盘和固定电机
  • 万用表:调试时测电压、查通断,非常关键
  • USB数据线:给ESP32烧录程序,注意要选支持数据传输的线,有些线只能充电
  • 电脑:安装Arduino IDE,用来写代码和烧录

提示:买ESP32开发板的时候,注意看是不是带CH340或CP2102 USB转串口芯片的版本。有些廉价板子用的是冷门芯片,驱动装起来很折腾。CH340的最省心,Windows和Mac都有现成驱动。

2.3 供电方案的计算过程

供电是整个项目里最容易翻车的地方,我单独拿出来算一下。ESP32的工作电压是3.3V,但它开发板上的USB口和VIN引脚可以接受5V输入,板载的LDO会降到3.3V。所以我们需要把电池的7.4V降到5V给ESP32。

用LM2596降压模块,输入7.4V,输出调到5V。这里要注意,LM2596的输出电流最大是3A,但实际使用时建议不要超过2A,留点余量。ESP32在Wi-Fi工作时峰值电流大概在240mA左右,所以5V这一路完全够用。

电机那一路直接接电池的7.4V,不经过降压。因为电机启动瞬间电流很大,如果和ESP32共用一路降压后的电源,电机一启动就会把电压拉低,导致ESP32复位。这就是为什么必须分开供电的原因。

注意:ESP32和电机驱动模块必须共地。也就是说,电池的负极、降压模块的负极、ESP32的GND、TB6612的GND要全部连在一起。不共地的话,PWM信号没有参考电平,电机不会转。

3. 硬件接线与电路搭建

3.1 ESP32与TB6612的接线

先搞定主控和驱动模块之间的连线。TB6612的引脚定义如下:

  • VM:电机电源输入,接电池正极(7.4V)
  • VCC:逻辑电源输入,接ESP32的3.3V
  • GND:接地,接电池负极和ESP32的GND
  • STBY:待机引脚,接高电平(3.3V)才能工作
  • AIN1/AIN2:控制A路电机的方向
  • BIN1/BIN2:控制B路电机的方向
  • PWMA/PWMB:控制A/B路电机的速度
  • AO1/AO2:A路电机输出
  • BO1/BO2:B路电机输出

我选的ESP32引脚分配是这样的:

TB6612引脚ESP32引脚说明
AIN1GPIO 25左电机方向1
AIN2GPIO 26左电机方向2
BIN1GPIO 27右电机方向1
BIN2GPIO 14右电机方向2
PWMAGPIO 32左电机速度
PWMBGPIO 33右电机速度
STBY3.3V常开
VCC3.3V逻辑供电
GNDGND共地

选这些引脚的原因:GPIO 25、26、27、14都是普通的数字引脚,没有特殊功能冲突;GPIO 32和33支持PWM输出,而且属于ESP32的LEDC(LED Control)外设可以驱动的引脚。ESP32的PWM不是用analogWrite,而是用ledcSetup和ledcAttachPin这套API,后面代码部分会详细讲。

3.2 电机与电源接线

电机接线比较简单,每个TT电机有两根线,分别接到TB6612的AO1/AO2和BO1/BO2。如果发现电机转向反了,不用改代码,直接把电机的两根线对调一下就行。

电源部分稍微复杂一点,我画个文字版的接线图:

电池正极(7.4V) ──┬── TB6612的VM │ └── LM2596的IN+ 电池负极 ────────┬── TB6612的GND │ ├── LM2596的IN- │ └── ESP32的GND LM2596的OUT+ (5V) ── ESP32的VIN LM2596的OUT- ──────── ESP32的GND

这里有个细节:LM2596的输出电压在接负载之前,最好先用万用表调准。模块上有个蓝色电位器,顺时针转电压升高,逆时针转电压降低。先不接ESP32,只接万用表,调到5.0V左右再接上去。我见过有人没调就直接接,结果输出12V把ESP32烧了的。

3.3 底盘组装与走线

底盘组装没什么技术含量,但走线有讲究。电机线、电源线、信号线尽量分开走,尤其是PWM信号线不要和电机线捆在一起,否则电机换向时产生的电磁干扰可能让PWM信号抖动,表现为电机转速不稳或者突然抽一下。

我的做法是用扎带把电机线固定在底盘下方,信号线从底盘上方走,电源线走侧面。虽然看起来不那么整洁,但实测稳定性好很多。

实操心得:TB6612的STBY引脚一定要接高电平,我第一次做的时候忘了接,调试了半天以为代码有问题,结果是芯片处于待机状态,电机根本不转。这个坑很隐蔽,因为TB6612不会发热也不会报错,就是安静地不工作。

4. 开发环境搭建与代码实现

4.1 Arduino IDE配置ESP32开发环境

如果你还没装Arduino IDE,先去官网下载。版本建议用1.8.19或2.x都行,我用的是1.8.19,比较稳定。装好之后,需要添加ESP32的开发板支持。

打开Arduino IDE,点“文件”→“首选项”,在“附加开发板管理器网址”里填入:

https://espressif.github.io/arduino-esp32/package_esp32_index.json

然后点“工具”→“开发板”→“开发板管理器”,搜索“esp32”,找到“esp32 by Espressif Systems”,点安装。这里有个坑:在线安装经常因为网络问题失败或者特别慢。如果你遇到这种情况,可以下载离线包手动安装。离线包是一个zip文件,解压后放到Arduino的hardware目录下,具体路径是:

  • Windows:C:\Users\你的用户名\AppData\Local\Arduino15\packages\
  • Mac:~/Library/Arduino15/packages/

放好之后重启Arduino IDE,在开发板列表里就能看到ESP32的选项了。我一般选“ESP32 Dev Module”,如果你的板子是ESP32-S3或者ESP32-C3,选对应的型号。

4.2 Wi-Fi AP模式与UDP通信代码

先上核心代码,我把它分成几个部分来讲。第一部分是Wi-Fi和UDP的初始化:

#include <WiFi.h> #include <WiFiUdp.h> const char* ssid = "ESP32_CAR"; const char* password = "12345678"; WiFiUDP udp; unsigned int localPort = 8888; char packetBuffer[255]; void setupWiFi() { WiFi.softAP(ssid, password); IPAddress IP = WiFi.softAPIP(); Serial.print("AP IP address: "); Serial.println(IP); udp.begin(localPort); }

这段代码把ESP32设成AP模式,热点名字叫“ESP32_CAR”,密码是“12345678”。手机连上这个热点后,ESP32的IP地址默认是192.168.4.1。UDP监听8888端口,收到的数据存在packetBuffer里。

为什么用UDP而不是TCP?前面说过,UDP延迟低。实测下来,UDP的往返延迟在5-15ms之间,TCP因为要建立连接和确认重传,延迟在20-50ms。对于遥控车来说,这个差别在高速行驶时能明显感觉到。

4.3 电机控制与PWM配置

ESP32的PWM配置和Arduino Uno不一样,不能用analogWrite。需要用ledcSetup和ledcAttachPin:

#define AIN1 25 #define AIN2 26 #define BIN1 27 #define BIN2 14 #define PWMA 32 #define PWMB 33 void setupMotors() { pinMode(AIN1, OUTPUT); pinMode(AIN2, OUTPUT); pinMode(BIN1, OUTPUT); pinMode(BIN2, OUTPUT); ledcSetup(0, 1000, 8); // 通道0,1000Hz,8位分辨率 ledcSetup(1, 1000, 8); // 通道1,1000Hz,8位分辨率 ledcAttachPin(PWMA, 0); ledcAttachPin(PWMB, 1); } void setMotor(int leftSpeed, int rightSpeed) { // leftSpeed和rightSpeed范围:-255到255 if (leftSpeed >= 0) { digitalWrite(AIN1, HIGH); digitalWrite(AIN2, LOW); ledcWrite(0, leftSpeed); } else { digitalWrite(AIN1, LOW); digitalWrite(AIN2, HIGH); ledcWrite(0, -leftSpeed); } if (rightSpeed >= 0) { digitalWrite(BIN1, HIGH); digitalWrite(BIN2, LOW); ledcWrite(1, rightSpeed); } else { digitalWrite(BIN1, LOW); digitalWrite(BIN2, HIGH); ledcWrite(1, -rightSpeed); } }

PWM频率我设的是1000Hz,8位分辨率。为什么选这个参数?频率太低电机会有啸叫声,太高TB6612可能响应不过来。1000Hz是人耳能听到的范围边缘,实际听起来是轻微的嗡嗡声,不刺耳。8位分辨率意味着速度可以分256级调节,够用了。

4.4 主循环与指令解析

主循环里不断检查有没有收到UDP数据,收到就解析并执行:

void loop() { int packetSize = udp.parsePacket(); if (packetSize) { int len = udp.read(packetBuffer, 255); if (len > 0) packetBuffer[len] = '\0'; String cmd = String(packetBuffer); if (cmd == "F") { setMotor(200, 200); // 前进 } else if (cmd == "B") { setMotor(-200, -200); // 后退 } else if (cmd == "L") { setMotor(-150, 150); // 左转 } else if (cmd == "R") { setMotor(150, -150); // 右转 } else if (cmd == "S") { setMotor(0, 0); // 停止 } } }

指令格式很简单,单个字符:“F”前进、“B”后退、“L”左转、“R”右转、“S”停止。速度值我设的是200,不是满速255,留一点余量,避免电机堵转时电流过大。

实操心得:UDP接收这里有个细节,packetBuffer一定要在读取后手动加结束符\0,否则String转换时可能读到上一次的残留数据,导致指令解析错误。我一开始没加,偶尔会出现车自己乱动的情况,查了半天才发现是这个原因。

5. 手机端控制方案

5.1 用现成App快速测试

代码烧录进去之后,先别急着写手机App,用现成的UDP调试工具测一下。手机连上ESP32的热点,打开任意一个UDP发送工具(应用商店搜“UDP Sender”就有),目标IP填192.168.4.1,端口8888,发送“F”,看车是不是往前跑。

这一步很关键,能帮你快速定位问题。如果车不动,先检查硬件接线和供电;如果车动了但方向不对,调整电机线或者代码里的方向逻辑。把硬件问题排除掉之后,再去做手机App,否则你会分不清是App的问题还是硬件的问题。

5.2 自己做一个简单的控制界面

如果你想让控制体验更好,可以用MIT App Inventor做一个简单的手机App。App Inventor是图形化编程,拖拖拽拽就能做出一个带方向按钮的界面。核心逻辑就是按下按钮时通过UDP发送对应的字符。

具体步骤:新建项目,拖一个UDP组件进来,设置目标IP为192.168.4.1,端口8888。然后放五个按钮,分别对应前进、后退、左转、右转、停止。每个按钮的点击事件里调用UDP发送对应的字符。

App Inventor的UDP组件有个坑:它默认是异步发送的,如果你快速连续按按钮,可能会出现指令乱序。解决办法是在发送前先调用一次关闭再打开,或者用时钟组件做一下节流,限制发送频率在50ms以上。

5.3 进阶:用WebSocket做网页控制

如果你不想装App,还有一个更优雅的方案:让ESP32同时跑一个Web服务器,手机浏览器直接打开网页就能控制。这个方案需要用到ESP32的WebServer库和WebSocket库,代码量比UDP方案大一些,但用户体验更好,不用装任何东西。

核心思路是ESP32建一个网页,网页里用JavaScript监听按钮事件,通过WebSocket把指令发给ESP32。ESP32收到后执行对应的电机控制。这个方案的好处是跨平台,安卓、苹果、电脑都能用,只要有浏览器就行。

6. 调试过程中踩过的坑与排查技巧

6.1 电机不转的排查流程

电机不转是最常见的问题,我整理了一个排查顺序:

  1. 先测电压:用万用表测TB6612的VM引脚,看有没有7.4V。如果没有,检查电池和接线。
  2. 再测STBY:测STBY引脚是不是3.3V。如果是0V,检查接线。
  3. 测PWM输出:用万用表测PWMA引脚,发送前进指令时应该有电压变化。如果没有,说明代码没跑起来。
  4. 测电机输出:测AO1和AO2之间有没有电压。如果有电压但电机不转,可能是电机坏了或者线断了。
  5. 检查共地:确认ESP32的GND和TB6612的GND是连通的。

这个顺序是从电源到信号、从简单到复杂,能帮你快速缩小问题范围。

6.2 Wi-Fi连接不稳定怎么办

有时候手机连上了ESP32的热点,但发送指令没反应。这种情况一般是IP地址或者端口不对。先在串口监视器里看ESP32打印的IP地址,确认是192.168.4.1。然后检查手机端的目标IP和端口是不是和代码里一致。

还有一个可能:手机连上ESP32热点后,因为热点没有互联网,手机会自动切换到移动数据,导致UDP包发不出去。解决办法是在手机Wi-Fi设置里,把ESP32的热点设为“始终连接”或者关闭“自动切换网络”。

6.3 电机干扰导致ESP32复位

这个问题很隐蔽:车一跑起来ESP32就重启,停下来就正常。原因是电机启动瞬间电流很大,把电池电压拉低,导致ESP32的5V供电不稳,触发欠压复位。

解决办法有两个:一是在电池和降压模块之间并联一个大电容(1000uF以上),起到缓冲作用;二是给ESP32单独供电,比如用一块充电宝给ESP32供电,电池只给电机供电。我用的是第一种方案,加了个2200uF的电解电容,问题就解决了。

6.4 常见问题速查表

现象可能原因解决方法
电机完全不转STBY没接高电平把STBY接到3.3V
电机只往一个方向转方向引脚接线错误检查AIN1/AIN2接线
车跑起来就复位电源干扰加电容或分开供电
Wi-Fi连不上热点名称或密码错误检查代码中的ssid和password
UDP指令无响应IP或端口不对确认目标IP为192.168.4.1,端口8888
电机转速不稳PWM频率不合适调整ledcSetup的频率参数
串口监视器乱码波特率不匹配设置串口监视器波特率为115200

7. 后续可以扩展的方向

这台车跑起来之后,其实还有很多可以玩的方向。比如加一个超声波模块做避障,ESP32检测到前方有障碍物就自动停车或者转向。或者加一个MPU6050陀螺仪,做姿态检测,防止翻车。再进阶一点,可以加一个ESP32-CAM模块,把摄像头画面通过Wi-Fi回传,做成FPV遥控车。

软件方面,可以把UDP控制改成WebSocket,做一个更漂亮的网页控制界面,加上速度滑块和实时状态显示。还可以接入MQTT协议,让车接入智能家居系统,用语音助手控制。

我个人最想尝试的是加一个边缘AI功能,用ESP32-S3跑一个简单的手势识别模型,通过摄像头识别手势来控制车。虽然ESP32的算力有限,但跑一些轻量级的神经网络还是可以的,这个方向值得折腾。

最后分享一个小技巧:如果你觉得每次烧录程序都要插拔USB线很麻烦,可以在ESP32的EN引脚和GND之间接一个按钮,按一下就能复位,省得反复拔插。这个改动很小,但用起来舒服很多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/29 1:06:39

SAP GUI 770 安装配置与多环境连接实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/29 1:04:38

TPS259483AYWPR与PIC18F4553构建工业级电源路径保护系统

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/29 1:04:16

技能不是标签,而是一套系统:可复制的技能建设方法论

聊到“skills”这个词&#xff0c;很多人第一反应是简历上那几个技能栏位&#xff0c;或者是招聘JD里罗列的岗位要求。我在职场泡了十几年&#xff0c;带过团队、也亲手面试过几百人&#xff0c;越来越觉得“技能”这件事被严重低估了——它不是贴在简历上的标签&#xff0c;而…

作者头像 李华
网站建设 2026/10/29 1:03:58

TPS259483AYWPR+STM32F215RE构建可编程电源路径主权系统

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/29 1:03:06

RK3588交叉编译实战:从工具链配置到嵌入式AI部署

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华