ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

ESP32与TB6612驱动的microduck小车:硬件选型到避障实现

ESP32与TB6612驱动的microduck小车:硬件选型到避障实现 1. microduck 到底是什么项目全貌与设计思路最近两周我一直在折腾 microduck 这个小车机器人项目从硬件选型到跑通第一行代码前前后后花了两个完整的周末。说实话这个 GitHub 上公开的开源项目名字挺讨喜——microduck就是一只小鸭子造型的双轮小车。它的核心玩法很朴素用一块主控板控制两个电机配上几个传感器让它在桌面上自己避开障碍、沿着黑线跑特殊情况还能用手机蓝牙遥控。听起来不复杂但实际上手之后你会发现从芯片选型到电机死活不转的排查每一步都藏着坑也每一步都有收获。我本职是写软件的硬件这边不算老手所以这篇文章里的路线图可能特别适合两类人一类是会写代码但没怎么焊过板子的软件工程师另一类是刚接触嵌入式的学生朋友。如果你想找一个低成本、高信息密度的练手项目microduck 是一个非常好的起点。1.1 一句话讲清 microduck 的定位microduck 本质上是一个轻量级的双轮差速机器人平台。所谓轻量级指的是它对材料、工具、金钱的投入都压到了极低主控板用 ESP32 系列开发板市价大概 30 到 50 块钱电机是常见的 TT 减速电机或者 N20 微型减速电机一对一二十块驱动芯片用 TB6612FNG 或 DRV8833几块到十几块传感器按需购买寻迹、避障、测距每样都是几块钱的模块全部物料加起来不算工具、外壳和电池总成本能控制在 150 元以内。这个成本比买成品套件还便宜——当然重点是成品套件不会让你理解每一个零件为什么存在。它解决的问题也很明确让一个只写过软件的人用最短路径把硬件选型—接线—烧录—跑起来这一整条链路走通。它刻意保持简单简单到每个模块都能看懂、能替换、能修。这种可修复性恰恰是商业成品给不了你的学习价值。1.2 从原理图到成品整体系统怎么拆我一开始就给自己定了个原则不追求一步到位而是把整个系统拆成五个可以独立验证的模块。供电模块电池、电源开关、稳压电路负责给主控和电机分别供能控制模块ESP32 主控负责读传感器、做决策、输出 PWM 信号运动模块电机驱动板加两个减速电机加两个轮子感知模块ED330 红外寻迹传感器、HC-SR04 超声波测距模块交互模块0.96 寸 OLED 显示当前状态蓝牙负责手机遥控拆完之后每个模块都能单独测试。比如先把电机驱动这块焊好单独写一小段代码让电机转起来再往下做别的。这个思路救了我很多次——如果一次性把所有东西接好再写代码任何一环出了问题你都不知道该从哪里查起。模块化拆解不只是代码架构的概念硬件调试同样适用。1.3 为什么选这条路方案对比与取舍做这种小车机器人市面上其实有几条经典路线。最省事的是直接买成品套件说明书一翻半个小时装完。但那样你学不到东西因为你没有做过任何一个选型决策出了问题也只能问客服。第二条路是照着网上的 Arduino 入门教程用 UNO 板子加 L298N 驱动模块。这个方案的资料堆积如山但有两个硬伤一是 Arduino UNO 用的是 AVR 单片机性能太弱跑不了复杂逻辑以后想加摄像头基本没戏二是 L298N 模块内部是双极型晶体管导通压降能到 2V 以上电池电压 6V 时真正到电机上的不到 4V续航和扭力都受影响。第三条路也就是 microduck 采用的路线ESP32 加 TB6612 驱动配合模块化传感器。ESP32 自带 Wi-Fi 和蓝牙性能最高能到 240MHz 双核以后想加摄像头做视觉、做联网控制都留了余地。TB6612 是 MOS 管驱动压降低、效率高两路电机只需要一路 PWM 加一路方向信号接线也简洁。这个方案在学习成本、性能、扩展空间三者之间是最平衡的。2. 硬件选型全解析从主控到每一个螺丝这一节详细说说选型过程包括当时为什么这么选、有什么替代方案以及我实际踩过的坑。硬件选型是这个项目里最容易让人纠结的地方因为每个零件都有几十种选择但不代表你需要把所有选择都搞明白才能下手。2.1 主控芯片ESP32 系列为什么是首选主控是整台 microduck 的脑子。为什么不是 STM32因为 STM32 的开发门槛对新手极不友好光环境搭建和调试器配置就够劝退一大批人。为什么不是树莓派因为它太大、太贵、太耗电对一台桌面小车来说属于杀鸡用牛刀。ESP32 则是折中得最好的选项性能足够跑实时控制开发环境可以用 Arduino 框架快速上手后期想深入还能切换到 ESP-IDF。具体选哪一颗 ESP32我给三个参考建议ESP32-WROOM-32经典款双核 240MHz520KB RAM开发板价格 30 到 50 块社区资料最全适合绝大多数人。ESP32-C3单核 RISC-V性能弱一些但价格能压到十几块引脚也够用适合低成本改装。ESP32-S3性能和功能最强带向量指令加速如果你已经想好后续要接摄像头做视觉识别直接上它。我自己用的是经典款 ESP32 DevKitC原因很简单microduck 仓库里的示例代码几乎都按这块板子的引脚布局来写抄作业的时候不用自己改引脚映射能省下不少排查时间。2.2 电机与驱动TT 电机 TB6612 的经典组合电机这块microduck 默认配置是 TT 减速电机。网上搜TT 电机 3-6V 减速马达能出来一大片通常配橡胶轮子一起卖。TT 电机的优势是便宜、结实扭矩对桌面小车来说绰绰有余缺点是转速一致性一般同一批次的两个电机实际转速可能差 5% 到 10%这个问题后面我会讲怎么在代码里做软件校准。驱动芯片我强烈建议用 TB6612FNG而不是新手教程里常见的 L298N。我把两者的关键差异整理成一张表对比项TB6612FNGL298N输出器件场效应管MOSFET双极型晶体管导通压降约 0.5V2V 以上最大电流单路 1.2A单路 2A逻辑电压2.7V-5.5V5V模块体积很小很大带散热片价格十几块十几块压降这个参数最要命。L298N 在 6V 供电下电机实际只能拿到不到 4V扭矩直接掉一截电池稍微没电就趴窝。TB6612 的压降几乎可以忽略这也是 microduck 项目选择它的核心原因。TB6612 的接线逻辑非常清晰每个电机需要三个信号一个 PWM 脚负责调速两个方向脚决定正反转。我把引脚定义留到第三节的表格里一起讲避免重复。2.3 传感器与显示ED330 模块和它的兄弟们microduck 的寻迹功能靠的是灰度传感器。我在淘宝买的是很常见的 ED330 红外寻迹模块——就是板子上印着 ED330 字样、中间一个红外发射管加一个接收管的小板子。它的原理是反射式红外探测红外光打到地面后反射回来接收管根据反射光的强弱输出不同的电平信号。黑色胶带吸光反射弱白色桌面反射强模块就能分辨当前压没压到线。ED330 模块通常只有三根线VCC、GND、OUT其中 OUT 是数字输出。板上有一个可调电位器用来设置触发阈值。校准的时候有个小技巧把模块放在白色桌面上看 OUT 输出是什么电平再放到黑色胶带上看输出是否翻转。电位器要调到黑白两种状态都能稳定区分不能只调到一边灵敏。如果你发现模块在两个场景下输出始终不变先怀疑电位器没调好再怀疑模块坏了。除了 ED330我还加了两个辅助模块HC-SR04 超声波测距模块用来检测前方障碍物0.96 寸 OLED 显示屏用 I2C 接口接主控实时显示当前状态和传感器数值。OLED 表面看起来是装饰品实际是调试利器——不接屏幕的话你只能靠串口打印而小车跑起来之后根本没法连着电脑看串口屏幕能让你直观看到程序内部的状态。2.4 机械结构与供电方案两个最容易翻车的部分很多教程只讲电路不讲结构但机械部分恰恰是让 microduck 像一只鸭子的关键。车身我用的是一块 3mm 亚克力板两层结构上层放 ESP32 和屏幕下层放电池盒和驱动板。如果你没有切割条件直接用塑料盒、甚至硬纸板加扎带也能凑合但要保证两个电机轴平行否则小车会跑偏。供电是自制小车里翻车率最高的部分没有之一。TT 电机瞬间启动电流能到 1A 以上如果主控和电机共用一个电源电机一启动电压瞬间跌落ESP32 会直接掉电重启。我前几次调试反复遇到这个问题一度以为是代码死循环。我的解决方案是两节 18650 锂电池串联成 7.4V 给电机驱动板供电同时从电池端接一个 5V 降压模块我用的 MP1584输出电流 1A 以上单独给 ESP32 供电。这样在物理上做到电机和主控电源分离电机的电流冲击不会干扰主控。线材方面单独提醒一句杜邦线便宜但接触不可靠尤其是电机这种大电流线路。建议至少用 20AWG 的硅胶线直接焊接到驱动板焊盘上。我踩过的坑就是电机线用杜邦线插在驱动板上小车一跑就抖动断电排查半天最后发现是杜邦线虚接。3. 开发环境与工程骨架从 GitHub 到第一行代码硬件都齐了接下来就是很多人最头疼的环境搭建环节。这一节把工具链安装、引脚规划和工程拉取的完整过程写清楚照做就行。3.1 工具链安装Arduino IDE 还是 ESP-IDFmicroduck 的示例代码基于 Arduino 框架所以最省事的路径就是用 Arduino IDE 开发。建议直接装 2.x 版本界面比 1.x 舒服自带串口监视器增强还能自动补全。装完 IDE 之后需要在文件 → 首选项 → 附加开发板管理器网址里填上 ESP32 官方的 JSON 地址然后在工具 → 开发板 → 开发板管理器里搜索 ESP32 并安装支持包。这一步要下载几十 MB 的数据国内网络偶尔会卡多试几次就行或者手动下载安装包解压到 Arduino 的 hardware 目录下。装好支持包后在工具 → 开发板里选择 ESP32 Dev Module 或对应板型。还有一个很多人忽略的点串口驱动。经典款 DevKitC 用的 USB 转串口芯片是 CP2102Windows 系统第一次插入需要装 CP210x 驱动否则电脑设备管理器里根本看不到串口。如果你买的板子是 CH340 芯片对应驱动又不一样买板子的时候最好问清楚。3.2 引脚分配表一次规划省掉三次飞线接线之前强烈建议先把引脚分配画成一张表。microduck 的参考接线可以这样规划我直接把有效的引脚分配表放出来功能模块信号ESP32 引脚电机 A PWMPWMAGPIO 25电机 A 方向AIN1 / AIN2GPIO 26 / 27电机 B PWMPWMBGPIO 14电机 B 方向BIN1 / BIN2GPIO 12 / 13ED330 寻迹模块OUTGPIO 34HC-SR04 超声波Trig / EchoGPIO 5 / 18OLED 显示屏SDA / SCLGPIO 21 / 22我特意避开了 GPIO 0、GPIO 2、GPIO 12、GPIO 15 这些有特殊功能的引脚。比如 GPIO 0 是 BOOT 引脚如果接了强下拉设备可能导致开发板无法进入下载模式GPIO 12 是 MTDI 引脚在某些板子上会影响启动电压。新手最容易犯的错误就是随手选一个引脚结果烧录之后板子没法正常工作还不明所以。3.3 拉取工程模板与仓库结构GitHub 上搜 microduck 能找到官方仓库通常会有 examples 目录放着几个不同难度层级的示例代码。如果你从 GitHub 下载 ZIP 包比较慢可以去国内的代码托管平台找找镜像仓库搜 microduck 一般能搜到别人同步过来的副本下载速度快不少。但我要给一个操作上的建议不要直接把仓库里的代码整个复制过来用而是建立一个自己的工程目录。虽然 Arduino 的示例通常是一个.ino文件但当代码超过一百行之后我强烈建议按模块拆文件。我的目录结构供参考microduck/ ├── src/ │ ├── main.cpp │ ├── motor.cpp │ ├── motor.h │ ├── sensor.cpp │ ├── sensor.h │ └── config.h ├── lib/ ├── docs/ └── README.md这样做的核心价值在于后面每加一个功能就新建一个模块文件出了问题定位收缩得极快。很多人一上来就在一个 main 文件里堆几百行代码出 bug 的时候头都要大运行日志和功能逻辑搅在一起改一处崩三处。4. 核心代码实现点灯、转电机、站起来这一节是大家最关心的部分——怎么把硬件变成真正能动起来的 microduck。我从最基础的第一行代码讲起再说电机控制、传感器读取最后给出一个完整的运动逻辑用例。4.1 第一行代码前的烧录测试很多人拿到板子第一件事就是写业务代码我的建议是先做一个最小验证插上电脑打开 Arduino IDE先烧一个 Blink 例程。这个例程让板载 LED 一闪一闪通过它你能确认三件事电脑能识别串口、IDE 的编译链路正常、烧录过程顺畅。Blink 的代码核心就三行pinMode(LED_BUILTIN, OUTPUT)设脚为输出digitalWrite(LED_BUILTIN, HIGH)点亮digitalWrite(LED_BUILTIN, LOW)熄灭中间夹着delay(500)。这个例程如果跑通说明开发环境没问题接下来写任何代码都有底。如果这个都跑不通不要急着往下走先检查串口是不是选对了、驱动装了没有。4.2 电机控制PWM 是什么怎么调电机驱动最关键的概念是 PWM即脉冲宽度调制。说人话就是用高电平在一个固定周期内占的比例也就是占空比来模拟不同的输出电压。占空比 100% 就是全速转50% 就是半速0% 就是停。电机本质上是惯性器件它在每个脉冲周期内来不及反应到完全停止所以平均电压决定了它的平均转速。Arduino 框架下有一个大坑ESP32 的 PWM 和 Arduino UNO 不一样UNO 上的analogWrite()在 ESP32 上不可用。ESP32 必须用ledcSetup()和ledcAttachPin()来配置。下面是一个简化版的电机控制代码可以直接抄#define PWM_FREQ 1000 // 1kHz 频率 #define PWM_RES 8 // 8 位分辨率占空比 0-255 void motorInit() { ledcSetup(0, PWM_FREQ, PWM_RES); // 配置通道 0 ledcAttachPin(25, 0); // GPIO25 绑定到通道 0 } void setMotorA(int speed) { // speed 范围 -255~255 if (speed 0) { digitalWrite(26, HIGH); digitalWrite(27, LOW); ledcWrite(0, speed); } else { digitalWrite(26, LOW); digitalWrite(27, HIGH); ledcWrite(0, -speed); } }思路很简单速度值的正负决定方向绝对值决定大小。正数让 AIN1 高、AIN2 低电机正转负数就反过来。这样上层逻辑只需要传一个带符号的数不用操心方向引脚的状态。关于 PWM 频率的选择有个知识点。频率太低电机会发出明显的高频嗡嗡声而且转动不均匀频率太高驱动芯片的开关损耗增大芯片发热。对 TT 电机这种惯性较大的负载1kHz 到 10kHz 都能工作我最终选了 1kHz噪音和发热平衡得好。如果你换用 N20 微型电机可以把频率提到 20kHz 以上避开人耳敏感区——这也是为什么有些 N20 小车跑起来几乎静音。4.3 传感器读取让 microduck 有知觉读 ED330 寻迹模块是数字 IO 的入门操作直接digitalRead()就能拿到结果。但实际用的时候要注意单次读值偶尔会有抖动尤其是在黑白边缘附近电平会在高低之间快速跳动。所以我在代码里加了一个简单的软件滤波——连续读三次取出现次数最多的值作为最终结果。这个三取二的算法虽然简单但对付传感器抖动非常有效。超声波测距模块 HC-SR04 稍微复杂一点它的工作流程是主控给 Trig 脚发送一个 10 微秒的高电平脉冲模块内部发出声波然后 Echo 脚输出一个高电平高电平持续的时间就是声波往返的时间。换算公式如下float readDistance() { digitalWrite(TRIG, LOW); delayMicroseconds(2); digitalWrite(TRIG, HIGH); delayMicroseconds(10); digitalWrite(TRIG, LOW); long duration pulseIn(ECHO, HIGH); return duration * 0.034 / 2; // 声速约 340m/s取一半是单程 }有人会问为什么除以 2——因为声波发出去再从障碍物反射回来走的是两倍距离所以要折半。返回值单位是厘米。这里有个使用限制HC-SR04 的最小测量距离约 2 厘米最大约 4 米对桌面小车来说绰绰有余。4.4 主逻辑一个简单的运动状态机各个模块都测通之后终于可以写主逻辑了。microduck 最简单也最好玩的玩法是避障巡逻我给它的整体逻辑设计了一个三态状态机前进、左转、右转。enum State { FORWARD, TURN_LEFT, TURN_RIGHT }; State state FORWARD; void loop() { float dist readDistance(); bool onLine digitalRead(ED330_PIN); switch (state) { case FORWARD: if (dist 15.0) { state TURN_RIGHT; // 前方有障碍向右转 } else if (onLine LOW) { state TURN_LEFT; // 压到黑线向左躲 } break; case TURN_LEFT: setMotorA(-150); setMotorB(150); delay(200); // 原地左转 200ms state FORWARD; break; case TURN_RIGHT: setMotorA(150); setMotorB(-150); delay(200); // 原地右转 200ms state FORWARD; break; } if (state FORWARD) { setMotorA(180); setMotorB(180); } delay(20); }这个逻辑非常朴素但它是理解传感器输入 → 决策 → 执行器输出闭环的最小样例。你可以看到整个程序就是在不断重复读数据、判断状态、控制电机。后面无论是换成 PID 直线校准、还是加上蓝牙遥控指令解析核心框架都不会变。4.5 锦上添花OLED 状态显示与避障提示在调试过程中我发现 OLED 屏幕还能帮助做可视化排错。我写了一个简单的显示函数把当前状态、前方距离、寻迹传感器电平三个值循环刷新在屏幕上void updateDisplay(float dist, int sensorVal, int state) { display.clearDisplay(); display.setTextSize(1); display.setCursor(0, 0); display.println(MicroDuck v1.0); display.print(Dist: ); display.println(dist); display.print(Line: ); display.println(sensorVal); display.print(State: ); display.println(state); display.display(); }这段代码有个实际价值小车在跑的时候你不需要连电脑串口只要低头看屏幕就能知道它的内心活动。比如电机不动屏幕显示 State 一直在切换那问题多半在电机驱动如果屏幕显示距离一直是 0那先查超声波模块的接线。用显示模块辅助定位问题效率翻倍。5. 常见问题与排查技巧实录最后这部分我把做 microduck 过程中遇到的、以及星友群里其他朋友反馈过的高频问题整理出来每个都附上排查思路和解决方案。这些内容大多不会写在官方 README 里属于实战经验。5.1 上电反复重启的元凶供电不足现象插上电池之后ESP32 板载 LED 亮一下灭一下OLED 显示一下又黑屏串口监视器里反复输出 Brownout detector was triggered。原因分析ESP32 内部有一个欠压检测器当供电电压低于阈值通常是 3.0V 左右时它会强制系统复位防止程序在电压不稳的状态下跑飞。这不是代码 bug而是电源问题。解决办法首先确认电池电压两节 18650 串联是 7.4V经降压模块到 5V 没问题其次确认降压模块输出电流能力ESP32 加 OLED 加传感器峰值电流可能到 300mA建议降压模块至少支持 1A最后在 ESP32 的 5V 和 GND 之间并联一个 470uF 电解电容滤掉电机启动瞬间的电压毛刺。这个电容几乎成了我所有项目的标配。5.2 电机不转三种最常见的故障电机不转是新手遇到概率最高的问题我总结下来基本逃不出三个原因。第一种驱动板电源接错。TB6612 的 VM 和 VCC 是两个不同的电源脚VM 接电池正极VCC 接主控的 3.3V 或 5V 逻辑电源。两者接反或者漏接芯片都不会正常工作。注意 VM 和 VCC 千万不能混在一起。第二种使能脚没接。TB6612 上有一个 STBY 待机控制脚这个脚必须拉高驱动器才会实际输出。很多接线图为了简化没有画出这个脚导致电机死活不动。处理方法是把 STBY 直接接到 3.3V 或者主控的一个 GPIO 并拉高。第三种PWM 通道冲突。ESP32 有多个独立的 PWM 通道如果你在代码里把两个电机配置到同一个通道就会出现一个转一个不转或两个一起转但调速失效的怪现象。所以电机 A 用通道 0电机 B 一定要换一个通道编号。5.3 排查方法论从现象定位到根因我用了这么多年嵌入式项目总结出一个固定排查顺序先看电源再看接线最后看代码。这个顺序不要乱。很多时候大家第一反应就是代码写错了查了半天最后发现是杜邦线松了——这种经历一次就够了。我的排查动作拆开来讲看电源用万用表量各节点电压VM 有没有 7.4VVCC 有没有 3.3V 或 5V共地点是否连通看接线对照引脚表逐根检查特别是 GND 必须所有模块共地看代码用Serial.println()把传感器原始值、状态变量打印出来确认程序运行到了哪一步还有一个我反复强调的小技巧把每个部分拆开单独测。电机不转就先注释掉传感器逻辑只跑电机的代码看电机本身有没有问题传感器读不到数据就单独打印传感器值看有没有跳动。能拆就拆拆到最后剩下的问题才是真正的问题。我自己用得最多的调试工具是两样串口打印和万用表。这两样加起来能解决掉 90% 的问题。示波器当然更好但新手没必要一开始就投入那么多等真遇到难啃的定时问题再上仪器也不迟。做 microduck 这个项目给我最大的感受是它让你亲手把想法变成实物这个过程中学到的每一个小坑都是单纯写代码永远碰不到的。最后再分享一个实际建议——从开工第一天就用文档记录每个模块的测试结果哪怕只是几行字。等你做到第三版、第四版回头看这些记录它们会比任何教程都珍贵。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表