news 2026/9/20 23:43:12

ESP32智能小车从零到一:蓝牙遥控、超声波避障与红外循迹完整实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ESP32智能小车从零到一:蓝牙遥控、超声波避障与红外循迹完整实战

简介:面向ESP32开发者与智能小车入门者,这份压缩包提供从零搭建智能小车的完整源码与配套文档,解决硬件选型、电路设计、固件编程到无线控制的全流程问题。内容以构建指南为主线,覆盖ESP32双核、Wi-Fi/蓝牙特性,包含模块匹配、PCB布局、焊接组装及常见故障应对;编程部分讲解Arduino IDE与ESP-IDF环境,并提供Wi-Fi、蓝牙、TCP/IP通信及传感器数据处理的实现思路。压缩包仅11KB,共4个文件,以Markdown说明文档和网页版资源为主,配合编辑器配置与Git忽略规则,便于初学者直接阅读和后续代码管理。已有101人学习。通过该资源可掌握从电路搭建到高级应用的关键步骤,并获得图像处理、电源管理、固件更新等进阶优化方向,是快速上手ESP32智能小车项目的高性价比参考资料。 玩 ESP32 智能小车,最痛苦的不是买零件,也不是焊线,而是资料东拼西凑,代码到处抄,最后编译报错一脸懵。我前前后后做了三版小车,从最开始的 51 单片机到后来的 STM32,最后稳定在 ESP32 方案,原因很简单:Wi-Fi 和蓝牙都在一颗芯片上,省掉一堆外设,而且用 Arduino 写起来特别顺手。这篇就把整个构建过程、踩过的坑、以及我最终在用的源码架构一次性讲清楚,你照着做,大概率能少走一两个月的弯路。

这个项目最终完成的小车具备三种玩法:手机蓝牙遥控、超声波自动避障、红外循迹行驶。整机成本控制在 150 元以内,代码全部开源,工程结构清晰,拆解下来单个模块的代码量都不大,非常适合嵌入式入门玩家、电子设计竞赛备赛学生,以及想拿 ROS 2 做硬件底层的开发者当作起步平台。

1. 项目整体设计与思路拆解

1.1 为什么选 ESP32 而不是 STM32 或 51 单片机

很多人一上来就问:做智能小车不是应该用 STM32 吗?竞赛里清一色都是它。这话没错,但要看场景。STM32F103ZET6 这类芯片的优势在于外设资源丰富、生态成熟,可如果你只是想快速把小车跑起来,而不是深入研究寄存器操作,那 ESP32 的性价比就体现出来了。

先看芯片本身的差异。ESP32 集成了 2.4GHz Wi-Fi 和蓝牙双模,这意味着遥控不再需要外接蓝牙模块或无线收发模块,板载解决。而我早期用 STM32 做小车时,光是一个 HC-05 蓝牙模块就要二十多块钱,还得单独接稳压电路。ESP32 自带 320KB SRAM 和 4MB Flash,跑一个 RTOS 系统加几个传感器完全够用,主频 240MHz 双核,处理四路编码器数据、超声波测距、PID 运算这些任务,简直绰绰有余。

再说开发门槛。Arduino 框架下的 ESP32 支持度已经非常完善,官方维护的 esp32 库函数据我用了三年基本没遇到严重 Bug。相比之下,STM32 如果不用 CubeMX 自动生成代码,光配置时钟树和 GPIO 就能劝退一批新手。51 单片机就更不用提了,做做课程设计还行,性能上限摆在那里,想扩展个摄像头或者跑个 Micro-ROS,基本没戏。

1.2 功能模块划分与整体架构

我的习惯是先把整个系统按功能拆成独立模块,再逐个实现,最后组装联调。这个思维模式在做任何嵌入式项目时都适用。

整辆小车的逻辑架构分四层:

  • 感知层:超声波传感器负责测距避障,红外传感器负责循迹检测,两者互不干扰,通过 GPIO 读取数据
  • 决策层:ESP32 主控芯片,运行状态机逻辑,根据传感器数据判断当前应该直行、转弯还是后退
  • 执行层:TB6612FNG 电机驱动模块,接收 ESP32 的 PWM 信号,控制四个 TT 电机的转速和方向
  • 交互层:手机 APP 通过蓝牙发送指令,也可以在调试时通过串口监视器直接查看传感器数据

这种分层设计的最大好处是:哪一层出了问题,直接隔离排查,不用推翻重来。比如电机不转了,先量执行层的 PWM 信号,再查决策层代码逻辑,两个小时的活压缩到二十分钟。

2. 硬件选型与搭建细节

2.1 核心硬件清单与选型理由

硬件清单我在下面盘了一下,都是实际用过验证过的型号,不是纸上谈兵。

硬件型号/规格数量参考价备注
主控ESP32-DevKitC(30引脚)125别买 38 引脚的,体积大且多数引脚用不上
电机驱动TB6612FNG112比 L298N 体积小一半,效率高,发热低
电机TT 减速电机(带编码器)420(4个)编码器版本方便后续做 PID 测速
小车底盘四驱亚克力底盘130买带铜柱和螺丝包的套装,省事
超声波HC-SR0414便宜好用,测距精度在 2cm-400cm
循迹模块TCRT5000 红外传感器39(3个)三路布局,比两路更好覆盖黑线
电池18650 电池两节 + 电池盒118电压 7.4V,正好驱动电机和给 ESP32 供电
稳压模块AMS1117-3.312给 ESP32 提供稳定 3.3V
蓝牙ESP32 板载--不需要额外买

这里特别要提一下电机驱动的选择。L298N 是很多教程的首选,但我强烈建议你用 TB6612FNG。L298N 的压降高达 2-3V,意味着 7.4V 的电池组到了电机端只剩 4-5V,四驱小车根本跑不快。TB6612FNG 的 MOSFET 导通电阻只有 0.4Ω 左右,几乎无压降,同样电压下电机转速更高,续航也更好。

2.2 GPIO 引脚分配与电气接线

ESP32 的引脚资源丰富,但有些引脚有默认功能,不能乱接。比如 GPIO 12 是 MTDI 引脚,上电时如果拉高会导致 Flash 电压异常,直接进不了下载模式。我踩过这个坑,后来固定用下面的分配方案。

ESP32 引脚功能连接对象
GPIO 14PWM 通道 ATB6612FNG PWMA
GPIO 27方向 AIN1TB6612FNG AIN1
GPIO 26方向 AIN2TB6612FNG AIN2
GPIO 25PWM 通道 BTB6612FNG PWMB
GPIO 33方向 BIN1TB6612FNG BIN1
GPIO 32方向 BIN2TB6612FNG BIN2
GPIO 5超声波 TrigHC-SR04 Trig
GPIO 18超声波 EchoHC-SR04 Echo
GPIO 19/21/22循迹传感器TCRT5000 数字输出
GPIO 16/17编码器 A/B左侧电机编码器(后续扩展)

接线时需要注意:TCRT5000 模块是 3.3V-5V 供电都支持,但数字输出引脚电平与供电电压一致。如果你给传感器供 5V,那输出高电平就是 5V,直接接到 ESP32 的 GPIO 上会伤芯片。我的做法是传感器统一供 3.3V,虽然红外 LED 的亮度略降,但实测 2cm-3cm 的检测距离完全够用。

2.3 供电方案:双电源 vs 单电源

供电是整个小车最容易出问题的地方。我第一版小车就翻车了,四个电机一启动,ESP32 直接重启,后来查了半天是电源跌落导致的。

问题根源在于电机启动瞬间的电流冲击。TT 电机堵转电流可以达到 1A 以上,四个电机同时启动就是 4A 的瞬时电流,别说 AMS1117 扛不住,就是 18650 电池组也会有明显的电压跌落。

解决方案是采用电源隔离设计:

  • 电机电源:两节 18650 电池(7.4V)直接给 TB6612FNG 的 VM 供电
  • 逻辑电源:从电池组引线,接 AMS1117-3.3 稳压后给 ESP32 供电
  • 共地:把电池负极同时接到电机驱动和 ESP32 的 GND,保证信号参考电平一致

这个方案实测非常稳定,即使四个电机急停急转,ESP32 的供电电压也稳定在 3.3V 附近。要注意的是,AMS1117 的输入输出压差需要至少 1V,7.4V 输入降到 3.3V 完全没问题,但会有一部分能量以热量形式消耗,所以我在 AMS1117 上加了一个小铝散热片,效果不错。

3. 源码架构与核心代码实现

3.1 开发环境搭建:Arduino IDE 还是 ESP-IDF

做 ESP32 开发主要有两条路:Arduino IDE 和乐鑫官方的 ESP-IDF 框架。我的建议很明确:如果是初学者或者追求开发效率,用 Arduino IDE;如果后续要做 Micro-ROS 2 或者需要精细控制硬件资源,再切 ESP-IDF 不迟。

Arduino 框架下的 ESP32 核心库封装得非常完善,模拟输入输出、PWM、I2C、SPI、蓝牙、Wi-Fi 都有现成接口。一个简单的 GPIO 控制代码在 ESP-IDF 里要写几十行结构体配置,在 Arduino 里就一行pinMode()。但 Arduino 也有缺点,就是隐藏了太多底层细节,出了问题不容易排查,而且 float 运算效率不如 ESP-IDF 的原生驱动。

我目前的习惯是:功能验证阶段用 Arduino 快速搭原型,产品化阶段再把关键模块迁移到 ESP-IDF。这个策略帮我节省了大量调试时间。

安装 ESP32 开发支持时,有几个细节容易踩坑。Arduino IDE 的“开发板管理器 URL”需要手动添加乐鑫的 JSON 链接,国内网络环境下下载可能很慢,建议使用乐鑫国内镜像地址。安装完成后,在开发板列表里选择 “ESP32 Dev Module” 即可,Flash Mode 一定要选择 “QIO”,否则可能出现烧录成功但运行异常的情况。

3.2 源码模块划分

整个项目的源码我按功能模块拆成了五个文件,结构非常清晰:

esp32_car/ ├── esp32_car.ino // 主逻辑,状态机 ├── motor.h/cpp // 电机控制封装 ├── ultrasonic.h/cpp // 超声波测距封装 ├── tracking.h/cpp // 循迹传感器封装 └── bluetooth.h/cpp // 蓝牙指令解析

这种分层的好处是:每个文件只干一件事,出了问题直接打开对应文件排查。比如小车循迹不灵敏,你只需要看 tracking 相关的代码,不用在动辄几百行的主逻辑里翻来找去。

主控制逻辑采用一个简单的状态机方案。状态机是嵌入式开发里非常基础且高效的思想——把复杂的决策过程拆解为有限个状态,每个状态下只处理对应的输入信号。

我用枚举类型定义了小车的几个运行状态:

enum CarState { STATE_STOP, STATE_FORWARD, STATE_BACKWARD, STATE_LEFT, STATE_RIGHT, STATE_AVOID };

然后设置mode变量来切换运行模式:蓝牙遥控、避障、循迹。每种模式下,状态机的跳转逻辑都不一样。避障模式下,超声波检测到前方障碍物小于 20cm 就进入转弯状态;循迹模式下,根据三个红外传感器的组合值决定走直线还是修正方向。

3.3 电机控制:PWM 调速与方向控制

电机控制核心就两个点:速度用 PWM 调,方向用电平组合切。TB6612FNG 的控制逻辑其实很简单,每个通道有三个控制引脚:PWMA 负责调速,AIN1 和 AIN2 负责方向。

电机方向控制真值表如下:

AIN1AIN2PWMA电机状态
HIGHLOWPWM正转,速度由 PWM 决定
LOWHIGHPWM反转
LOWLOW任意停止(刹车)
HIGHHIGH任意停止(惰性)

有了这个表,写代码就非常容易了。下面是电机控制的封装函数:

void motor_left_set(int speed, bool forward) { digitalWrite(PIN_AIN1, forward ? HIGH : LOW); digitalWrite(PIN_AIN2, forward ? LOW : HIGH); ledcWrite(PWM_CHANNEL_LEFT, map(speed, 0, 100, 0, 255)); }

这里用ledcWrite而不是 Arduino 原生的analogWrite,是因为 ESP32 的 Arduino 核心并没有完整实现analogWrite,用了也是基于ledc的封装,而且指定的引脚通道不同。我在初始化里配置了 PWM 通道参数:

ledcSetup(PWM_CHANNEL_LEFT, 1000, 8); // 频率 1kHz,分辨率 8 位 ledcAttachPin(PIN_PWMA, PWM_CHANNEL_LEFT);

PWM 频率我选了 1kHz,这个值对 TT 电机的刷式换向器来说是很合适的。频率太低(比如 100Hz)电机会有明显噪音和抖动,频率太高(比如 50kHz)则会因为电机线圈电感的滤波作用导致实际电流很小,扭矩不足。10kHz-20kHz 之间是听不见噪音的常见选择,但 1kHz 在实际调试中已经够用且好观察。

3.4 超声波避障与循迹实现

超声波测距的原理很简单:Trig 引脚拉高 10us,模块自动发射 8 个 40kHz 的脉冲,Echo 引脚输出高电平,高电平的持续时间就是声波往返的时间。距离等于时间乘以声速(340m/s)再除以 2。

float ultrasonic_read() { digitalWrite(PIN_TRIG, LOW); delayMicroseconds(2); digitalWrite(PIN_TRIG, HIGH); delayMicroseconds(10); digitalWrite(PIN_TRIG, LOW); long duration = pulseIn(PIN_ECHO, HIGH, 30000); // 超时 30ms return duration * 0.034 / 2; }

加超时参数很重要,因为如果超声波前方没有遮挡物,Echo 引脚会一直保持高电平,pulseIn会阻塞程序执行。我设定 30ms 超时,对应最大测距距离约为 5m,超出就返回 0,让上层逻辑当作无障碍处理,这样就不会卡死。

循迹部分就更直接了。TCRT5000 是一个红外反射传感器,当它对准黑色跑道线时,红外光被黑线吸收,输出高电平;当它偏离到白色地面时,红外光被反射回来,输出低电平。三个传感器并排安装在小车底盘前方,形成一个简单的检测阵列,就能判断小车相对黑线的位置状态。

int tracking_read() { int s1 = digitalRead(PIN_TRACK_LEFT); int s2 = digitalRead(PIN_TRACK_MIDDLE); int s3 = digitalRead(PIN_TRACK_RIGHT); return (s1 << 2) | (s2 << 1) | s3; }

三个传感器返回的二进制组合对应不同的循迹动作:传感器值组合中,如果只有中间传感器检测到黑线,说明小车正直前行;如果左边或右边的传感器偏了,就分别向左或向右修正。判断逻辑在状态机里统一处理,这样代码就不零散。

3.5 蓝牙遥控与手机 APP 对接

蓝牙遥控这块,ESP32 双模蓝牙支持经典蓝牙(Bluetooth Classic)和低功耗蓝牙(BLE)。APP 遥控我用的是经典蓝牙,因为它支持 SPP 串口透传协议,手机连接后虚拟出一个串口,收发数据就像串口一样简单。

在 Arduino 框架下使用经典蓝牙,核心就几行代码:

#include "BluetoothSerial.h" BluetoothSerial SerialBT; void setup() { SerialBT.begin("ESP32_Car"); // 蓝牙设备名称,手机可搜索到 } void loop() { if (SerialBT.available()) { char cmd = SerialBT.read(); handle_command(cmd); } }

关键是设计一套简洁的指令协议。我自定义的协议是单字符指令,简单高效:

指令含义
'F'前进
'B'后退
'L'左转
'R'右转
'S'停止
'A'切换避障模式
'T'切换循迹模式
'H'切换手动遥控模式

为什么要用单字符?因为嵌入式设备的内存和带宽都有限,协议越简单越可靠。你当然可以用 JSON 格式传指令,但解析 JSON 在 ESP32 上要额外引入库,占用资源,还容易出错。单字符协议在串口监视器里调试也直观,一看就知道发的是什么。

手机 APP 端我用一个开源的蓝牙串口调试工具,也可以用 Arduino IDE 自带的串口监视器配合调试。APP 里设置一个方向按键面板,四个方向键加一个停止键,按下时发送对应字符,松开时发送停止指令。这里有一个从实际调试中总结的经验:按键按下立即发指令,松开后不要马上发停止指令,而是延迟 100ms 再发。否则电机会频繁启停,电流冲击很大,容易触发保护。

4. 联调流程与功能验证

4.1 先分模块测试,再整机联调

我犯过最蠢的错误,就是所有模块焊接完之后直接上代码,结果小车纹丝不动,查了一下午才发现是电机驱动的两个接口线序接反了。从那以后,我坚持一个基本原则:模块先单独测试,确认无误再整机联调。

具体的测试顺序如下:

  1. 电源板测试:焊好电源模块后,先用万用表量输出是否稳定在 3.3V 和 5V。这一步非常关键,如果这一步电压不对,后续所有测试都是白搭,甚至会烧毁传感器。
  2. 电机测试:单独写一个测试代码,让四个电机依次正转、反转、停止,确认每个电机的方向控制逻辑都正常。同时用记号笔在每个电机上做个方向标记,方便后续组装的轮向判断。
  3. 传感器测试:超声波模块可以通过串口打印当前测距值,用手在传感器前方移动,观察数值是否线性变化。循迹模块则可以在白纸上放一段黑色胶带,看串口输出是否在黑线上方产生跳变。
  4. 蓝牙通信测试:手机连接 ESP32 的蓝牙,发送各指令字符,观察串口输出是否收到正确的指令数据。
  5. 整机联调:所有模块单独确认无误后,再合并到主代码里做整机测试。先地板擦干净放好黑线,然后一个小功能一个小功能地验证。

这个过程看起来繁琐,但实际上是帮我节省了大量时间。每个模块单独出问题时,排错范围很小,基本看一眼串口输出就能定位。整机联调如果出问题,哪哪都像嫌疑犯,排查效率低到令人崩溃。

4.2 四种模式的切换测试

联调完成后,我在不同场景下对四种模式做了验证测试,这里把测试记录整理出来,供你参考对照。

手动遥控模式是最基本的,测试时主要观察几个指标:手机的连接是否稳定、指令响应是否及时、电机转向是否和按键方向一致。实测下来,ESP32 蓝牙的连接稳定性不错,在无障碍物的情况下,直线距离 10 米内都能稳定控制。这里有个小坑:如果你同时开了 Wi-Fi 和蓝牙,两者共用 2.4GHz 频段,会导致蓝牙响应变慢,我通常测试时直接关掉 Wi-Fi。

避障模式的测试场景是客厅,我用纸箱摆了一个简单的障碍物布局。小车的逻辑是:直行遇到障碍物,停车,测距判断是向左还是向右转避开,然后继续直行。这里有一个需要调优的细节:转弯角度如果固定,小车在被障碍物围住的“死胡同”里可能会来回打转。我的做法是引入一个“连续转向”计数,如果连续三次转向都在同一个方向,就大幅增加转向角度,让小车有更大的机动空间。

循迹模式的测试在地上贴了两条黑线胶带,一条直线和一条 S 弯。直线循迹基本没有悬念,S 弯是对 PID 参数的考验。我一开始用固定速度直行,结果在 S 弯的弯心处小车冲出去线了。后来把弯道的线速度降到了直道的 60%,效果立竿见影。

4.3 关键参数调优记录

下面是几个我在调试过程中记录的关键参数,供大家参考:

参数名初始值调优后说明
直行 PWM 占空比50%40%四驱车空载时速度太快,循迹易冲出线
转弯 PWM 占空比50%35%转弯速度过高,容易甩尾
避障触发距离30cm20cm30cm 触发太早,频繁转向,行动效率低
循迹传感器阈值中值 800用模拟量读取判断阈值更可靠
蓝牙响应延时停止延迟 100ms防止电机瞬间刹车导致过流

循迹传感器的阈值调优让我折腾了一晚上。TCRT5000 的数字输出在阈值附近会产生抖动,导致传感器状态频繁跳变。我的解决方案是:把传感器切到模拟量读取模式,在串口监视器里观察黑线和白地的模拟值差异,取两者的中间值作为判断阈值。这样比直接用数字输出稳定得多,特别是环境光线变化的情况下。

5. 常见问题与排查技巧实录

5.1 烧录失败与驱动问题

ESP32 烧录失败是新手遇到最多的问题,表现是编译成功,但上传时串口一直报 “Connecting...”,然后超时失败。

我遇到这个问题的排查路径是:

  1. 检查串口驱动:ESP32 开发板用的串口芯片通常是 CP2102 或 CH340,需要安装对应驱动。Windows 系统一般会自动安装,但需要确认设备管理器里是否识别到 COM 口。
  2. 按住 BOOT 键上传:如果驱动没问题,按住开发板上的 BOOT 键不放,再点上传,等出现 “Connecting” 时松手。这是因为 ESP32 的上电时序偶尔会异常,进入不了下载模式,手动按 BOOT 可以强制进入。
  3. 检查数据线:这个问题非常隐蔽。很多 USB 线只有充电功能,没有数据线芯,特别是那种细的白色安卓线。换一根短的、品牌靠谱的数据线,能解决 80% 的烧录问题。

烧录成功后,还有一个经常被忽略的坑:上传代码后没有任何反应。这时候在串口监视器里看输出,如果卡在乱码或者没有任何输出,尝试按下开发板的 EN 复位键,大概率就能恢复。

5.2 电机抖动与小车跑偏

小车通电后电机抖动、转速不均匀,甚至伴随异常电流声,这个问题我排查过很多次,最终归因到三个可能:

最普遍的原因是电池电压不足。刚买来的 18650 电池可能没有充满电,四个电机同时启动时,电压被拉低到电机驱动芯片的最小工作电压以下,导致 PWM 信号不稳定。解决方法是先充满电再测试,并且不要吝啬电池的放电能力参数,建议买容量 2500mAh 以上的动力型 18650。

其次是共地问题。驱动板和主控板之间如果没有连接 GND,控制信号就会因为参考电位不一致而失效,表现为电机动作异常、传感器数据漂移。我的接线规范是:所有模块的 GND 全部拧到一起,形成一个星型接地结构。

最后是 PWM 频率不匹配。我之前用模拟输出口直接驱动电机,TT 电机内部的减速齿轮结构在低转速段天然存在力矩波动,如果 PWM 频率又正好落在机械共振区间,抖动就会特别严重。可以试着把 PWM 频率调高或者调低一个量级(比如从 1kHz 调到 500Hz),看抖动是否改善。

跑偏问题就更常见了,尤其是四驱小车。四个电机的转速不可能完全一致,即使给定相同的 PWM 占空比,由于电机内部绕组、碳刷和机械齿轮的差异,实际转速也会有 5%-10% 的偏差。早期方案里我直接用开环控制,跑着跑着就歪了。解决办法有两个层级的:

  • 简单方案:在代码里给慢速的电机加上补偿值,比如左侧电机 PWM 设为 40%,右侧设为 36%,反复调直到小车能走直线
  • 进阶方案:利用编码器测速,跑一个闭环 PID 调速算法,把四个电机的实际转速都锁定到目标值附近

如果要做竞赛项目,或者对线的准确性有很高要求,强烈建议直接上 PID 方案,开环补偿只能保证当前电池电压下的直线度,电池电量下降后参数又要重调。

5.3 传感器误触发与数据漂移

超声波传感器在电机同时工作时经常出现数据跳变,原因有两个。

第一是电源干扰。电机产生的电磁噪声会通过共地回路耦合到超声波模块的供电线上,导致测距值偶尔跳变。我在模块供电输入端加了一个 10uF 电解电容和一个 0.1uF 陶瓷电容做滤波,问题就改善了一大半。

第二是壁面反射和斜射误差。超声波束是一个锥形区域,如果探测目标是一个斜面或者墙角,回波会被反射到其他地方,导致测不出来或者数据偏大。处理办法是对测量数据做中值滤波——连续读五次,取中间值作为有效数据,可以有效消除单次大概率错数据。

循迹传感器对环境光非常敏感。太阳光中的红外成分有一定概率直接触发传感器,导致它在明亮环境下误判。我一般给传感器加上一个遮光罩(黑色热缩管或者电工胶带),把环境光线挡掉,只让地面反射光进入传感器。

5.4 蓝牙连接不稳定与串口调试技巧

蓝牙连接不稳定,容易出现连接后又断开、或者指令延迟严重的情况。我的排查结论是:ESP32 的蓝牙和 Wi-Fi 同时启用时,两者在 2.4GHz 频段互相干扰,尤其是在 Wi-Fi 传输数据量大的时候,蓝牙的时延会明显升高。

如果你只做遥控,不打算联网,那就在代码里把 Wi-Fi 彻底停掉:

#include "nvs_flash.h" nvs_flash_erase(); nvs_flash_init(); esp_wifi_deinit();

实测关闭 Wi-Fi 后,蓝牙连接稳定性和响应速度都有明显提升。

还有一个调试技巧:在代码里大量使用Serial.println()输出调试信息,然后通过 USB 串口监视器观察。但要注意,一旦连接了手机蓝牙,蓝牙和 USB 串口会共用同一个 UART,两个都开的时候,数据会在两个方向来回串,导致串口监视器输出混乱。我的做法是:调试蓝牙指令时,断开 USB 连接,直接通过手机 APP 发指令,然后把 ESP32 的日志输出到另一个 GPIO 映射的串口上。

6. 源码获取与后续扩展方向

源码组织方式刚才说过了,这里补充几个核心逻辑的细节。主循环里我用了一个简单的switch-case来处理不同模式下的状态机,结构清晰,方便扩展新的传感器和执行器。

void loop() { switch (mode) { case MODE_REMOTE: handle_remote_command(); break; case MODE_AVOID: handle_avoid_mode(); break; case MODE_TRACK: handle_track_mode(); break; default: car_stop(); break; } }

每个handle_xxx函数内部再根据传感器输入执行对应的状态跳转。这套代码的总量不大,全部加起来也就三四百行,很适合作为学习素材。在实现时,我尽量保持了代码的可读性,变量命名都是完整单词,关键逻辑段有中文注释,你拿到手之后直接烧录就能跑。

6.1 从 Arduino 到 Micro-ROS:走上机器人系统开发之路

如果你在完成基础功能后,想把小车接入 ROS 2 系统,就可以进一步了解 micro-ROS 在 ESP32 上的移植和应用。这正好是近几年机器人开发的一个热点方向。

Micro-ROS 是一个在 MCU 上运行的 ROS 2 客户端,它通过串口或 Wi-Fi 与上位机(比如树莓派或装有 ROS 2 Humble 的 PC)通信。在 ESP32 上跑 Micro-ROS,等于把你的小车变成了一个真正的分布式机器人节点,传感器数据可以发到 ROS 2 的 Topic 里,控制指令也可以从 ROS 2 的节点发下来。

移植 micro-ROS 到 ESP32 需要用到乐鑫的micro_ros_espidf_component组件库。大致步骤是:先安装 ESP-IDF 环境,然后克隆 micro-ROS 的 ESP32 组件库到工程的 components 目录,在 menuconfig 里根据你的板子性能选择合适的传输方式和内存配置,编译烧录即可。Wi-Fi 通信模式下,ESP32 作为 UDP 客户端连接上位机的 micro-ROS Agent;串口模式下,则通过物理串口连接,稳定性和实时性更高,是机器人竞赛中更常用的方式。

6.2 项目扩展的四个方向

项目跑通之后,你会发现自己对 ESP32 和外设的控制方式都有了比较全面的理解。这时候可以往下面几个方向扩展:

  • 视觉识别方向:给小车加一个摄像头模块(比如 ESP32-CAM 作为独立视觉节点),通过 Wi-Fi 传输图像到上位机,在 OpenCV 里做目标检测和巡线。这样一来,就不只局限在红外循迹了。
  • 高精度定位方向:给底盘加装霍尔编码器,并融合 MPU6050 六轴陀螺仪,配合 PID 闭环就能实现走直线不跑偏,再往下做可以完成简单的轨迹规划,这也是很多工业物流小车方案的简化版。
  • 语音交互方向:在手机 APP 端集成语音识别,把识别出的文本转成蓝牙指令,比如“前进”“左转”这些指令,车就能听懂人话。这也算是个比较讨巧的炫酷功能。
  • 多机协作方向:用两块 ESP32 分别控制两台小车,通过两个开发板上的 Wi-Fi 建立 TCP 通信,实现一主一从的编队控制。这个方向的扩展比较有挑战性,适合作为毕设或竞赛课题。

顺便提一句,如果你手边只有 STM32F103ZET6 或树莓派,这套思路也可以直接平移。STM32 需要外接蓝牙和 Wi-Fi 模块,代码上用 HAL 库重写一遍;树莓派则可以直接用 Python 的gpiozero库或者 ROS 2 的驱动包,逻辑一模一样,区别主要在于底层 API 不同。

6.3 最后分享三个实操心得

从我做了三版小车、前后折腾了两个多月的经验来看,有三件事对你可能最有帮助。

第一,第一次做小车,一定要选择成熟的方案而不是追求配置堆料。我见过太多人一开始就想要机械臂、摄像头、激光雷达全加上,结果项目进行到一半连轮子都转不起来。先把基础版跑通,建立信心和手感,再去逐项加功能,这个节奏是最舒服的。

第二,把调试接口留足。我的每一版小车都保留了一个串口调试接口和一个状态 LED 灯。遇到问题时,串口打日志、LED 看状态,信息越丰富,定位越快速。有人觉得这些冗余设计浪费时间,等真正出问题的夜晚,你才知道它们是你最忠实的朋友。

第三,选择一个由浅入深的项目路线。如果你的目标是参加竞赛,直接参考近期工创赛智能物流小车的题目,这类比赛大多数以视觉识别、色块抓取、物品搬运为主,底层底盘和电机控制就是今天这套 ESP32 平台的变体。提前把底盘稳了,比赛时就有了底牌。如果是课程设计,加一路循迹加避障就足够拿高分,剩余的精力用来把代码注释和报告写好,反而更容易出彩。

我这套小车源码已经在文末给出了完整工程,包含了硬件的接线图、Arduino 版的全部源码以及规避的一堆坑。照着做,一个周末的时间,你就能看到自己的小车在地板上撒欢跑了。

本文还有配套的精品资源,点击获取

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

极验无感验证码技术解析与实战优化

1. 项目概述"无感验证码"这个概念最近两年在互联网产品圈越来越火&#xff0c;作为从业者我亲身体验过市面上几乎所有验证码方案&#xff0c;今天要聊的极验无感验证码确实让我眼前一亮。不同于传统需要用户点击、拖拽或输入的验证方式&#xff0c;它能在用户几乎无感…

作者头像 李华
网站建设 2026/9/20 23:43:04

FT2DR操作手册实战指南:C4FM、APRS与菜单设置全解析

简介&#xff1a;这份资源是YAESU八重洲FT2DR对讲机的官方操作手册&#xff0c;以PDF格式提供&#xff0c;面向业余无线电爱好者、户外通信用户以及初次接触数字对讲机的新手&#xff0c;可解决从开箱安装、触摸屏操作到中继台、APRS与GPS功能配置的全流程使用疑问。压缩包内为…

作者头像 李华
网站建设 2026/9/20 23:42:43

oMLX分层KV缓存实战:SSD当后备存储,32GB内存跑32K上下文

先说结论&#xff1a;在 Apple Silicon 的机器上&#xff0c;把 SSD 当成 KV 缓存的后备存储&#xff0c;是让 32GB 内存跑 30B 级别模型并撑住上万 token 上下文的性价比方案。我这几个月一直在折腾 oMLX 的分层 KV 缓存&#xff0c;拿它当 Claude Code 的本地后端&#xff0c…

作者头像 李华
网站建设 2026/9/20 23:41:06

Atlas 300V 24G推理卡部署YOLO实战:从环境搭建到模型转换全解析

最近不少人在群里问同样的问题&#xff1a;Atlas 300V 24G 是不是一块运算加速卡&#xff0c;能不能拿来跑 YOLO&#xff1f;我的回答是&#xff1a;它不但是加速卡&#xff0c;而且是专门为推理场景设计的&#xff0c;拿来部署 YOLO 非常合适&#xff0c;但前提你得先把昇腾的…

作者头像 李华