1. 项目概述:ESP32寻迹小车从零开始
作为一个玩了多年单片机的老鸟,我最近用ESP32做了个超好玩的寻迹小车。这玩意儿不仅能自动跟着黑线跑,还能自己判断路线调整方向,特别适合新手入门嵌入式开发。相比传统的51单片机方案,ESP32性能更强、价格更便宜,还自带WiFi功能,后续扩展空间很大。
做这个小车最爽的地方在于,你不需要从零开始造轮子(字面意思和比喻意义上都是)。淘宝上几十块钱就能买到现成的四轮车架,再配上ESP32开发板和几个基础模块,周末两天就能搞定。下面我就把整个制作过程掰开了揉碎了讲给你听,保证零基础也能跟着做出来。
2. 硬件准备与选型建议
2.1 核心部件清单
做寻迹小车需要准备以下硬件(淘宝都能买到):
- ESP32开发板(推荐NodeMCU-32S,约25元)
- L298N电机驱动模块(比TB6612更常见,约15元)
- 四轮小车底盘套件(含电机和轮子,约50-80元)
- 四路红外寻迹模块(约10元)
- 18650锂电池两节及电池盒(约20元)
- 杜邦线若干(公对公、公对母都要准备)
提示:第一次购买时建议选择"智能小车配件套餐",通常包含上述所有部件,比单买更划算。
2.2 硬件选型避坑指南
电机驱动为什么选L298N而不是TB6612?三个实际考量:
- 价格便宜近一半
- 驱动能力更强(2A持续电流)
- 散热更好,带金属散热片
红外寻迹模块要注意检测高度,最好选择可调高度的型号。我吃过亏,买过固定高度的模块,结果小车跑起来时高时低,检测很不稳定。
3. 电路连接详解
3.1 ESP32引脚分配策略
ESP32的引脚使用要特别注意,有些引脚在启动时有特殊功能:
- GPIO0:下载模式选择,不要接其他设备
- GPIO2:内部上拉,适合接LED
- GPIO12:启动时电平影响内存电压
- GPIO34-39:仅能做输入
推荐接线方案:
bash复制电机驱动:
ENA -> GPIO25
IN1 -> GPIO26
IN2 -> GPIO27
ENB -> GPIO14
IN3 -> GPIO12
IN4 -> GPIO13
红外模块:
OUT1 -> GPIO35
OUT2 -> GPIO34
OUT3 -> GPIO39
OUT4 -> GPIO36
3.2 电源系统设计
新手最容易忽视的就是电源系统。建议采用双电源方案:
- 电机电源:直接接18650电池(7.4V)
- 控制电源:通过AMS1117降压到5V给ESP32供电
重要经验:一定要在电机电源端加一个大电容(1000μF/16V),否则电机启动时电压骤降会导致ESP32重启。
4. 电机控制原理与实现
4.1 L298N驱动原理
L298N的驱动逻辑比TB6612更直观:
- ENA/ENB:PWM调速引脚
- IN1/IN2:控制电机A转向
- IN3/IN4:控制电机B转向
真值表如下:
| ENA | IN1 | IN2 | 电机A状态 |
|---|---|---|---|
| H | H | L | 正转 |
| H | L | H | 反转 |
| H | L | L | 刹车 |
| L | X | X | 停止 |
4.2 PWM调速实现
ESP32的LEDC库提供了硬件PWM支持,比analogWrite()更稳定:
cpp复制// PWM初始化
const int freq = 5000;
const int resolution = 8;
ledcSetup(0, freq, resolution); // 通道0
ledcAttachPin(ENA, 0); // 绑定引脚
// 设置速度
ledcWrite(0, speed); // speed范围0-255
5. 巡线算法深度优化
5.1 基础巡线逻辑
四路红外传感器的典型状态判断:
cpp复制void lineFollow() {
int s1 = digitalRead(IR1); // 最左
int s2 = digitalRead(IR2);
int s3 = digitalRead(IR3);
int s4 = digitalRead(IR4); // 最右
if(s2==LOW && s3==LOW) { // 居中
moveForward();
}
else if(s1==LOW || s2==LOW) { // 偏左
turnLeft();
}
else if(s3==LOW || s4==LOW) { // 偏右
turnRight();
}
}
5.2 进阶PID控制
想要更平滑的巡线效果,可以上PID算法:
cpp复制// PID参数
float Kp=0.5, Ki=0.001, Kd=0.2;
float error=0, lastError=0, integral=0;
void pidControl() {
int position = getLinePosition(); // 获取当前位置
error = position - 2000; // 假设2000是中心值
integral += error;
float derivative = error - lastError;
float output = Kp*error + Ki*integral + Kd*derivative;
// 应用输出
setMotorSpeed(leftSpeed + output, rightSpeed - output);
lastError = error;
}
6. 代码架构与调试技巧
6.1 模块化程序设计
我的代码结构是这样的:
code复制├── main.cpp
├── motor.cpp
├── motor.h
├── sensor.cpp
├── sensor.h
├── pid.cpp
└── pid.h
使用PlatformIO管理项目,比Arduino IDE更专业。
6.2 实用调试方法
- 串口绘图工具:用来看PID各分量变化
- 蓝牙调试:ESP32可以同时开启蓝牙串口
- 电压监测:随时检查电池电量
遇到电机不转的情况,按这个顺序排查:
- 检查电源指示灯
- 测量电机端子电压
- 单独测试电机好坏
- 检查程序是否正常输出PWM
7. 性能优化与扩展
7.1 速度优化技巧
- 使用ESP32的双核:一个核处理传感器,一个核控制电机
- 开启硬件看门狗防止死机
- 使用FreeRTOS任务管理
7.2 扩展功能设想
- 通过WiFi上传行驶数据
- 添加超声波避障功能
- 实现手机APP遥控
- 增加OLED显示屏
8. 常见问题解决方案
Q1: 小车走直线总是偏
解决方案:
- 校准电机:给两个电机相同的PWM值,实测速度并调整补偿值
- 检查轮子是否安装牢固
- 地面要平整,最好用专业赛道
Q2: 红外模块误检测
解决方法:
- 调整模块高度(离地1cm最佳)
- 在setup()中增加校准代码
- 添加软件去抖逻辑
Q3: 电机干扰导致ESP32重启
终极解决方案:
- 电源隔离:控制板和电机驱动完全分开供电
- 加磁珠滤波
- 在GPIO口加100Ω电阻
9. 项目总结与改进方向
这个项目我前后做了三个版本,第一个版本用的Arduino Uno,第二个换成了STM32,最后这个ESP32版是最满意的。主要改进点:
- 用PlatformIO代替Arduino IDE
- 引入FreeRTOS任务管理
- 增加了PID算法
- 优化了电源设计
下一步准备加入视觉识别,用ESP32-CAM做图像处理,让小车能识别更复杂的路线。其实玩单片机最爽的就是不断迭代升级的过程,每次改进都能学到新东西。
