ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ESP32+离线语音,DIY一台会听指令的智能移动垃圾桶

ESP32+离线语音,DIY一台会听指令的智能移动垃圾桶 周末下午我坐在沙发上吃薯片包装袋很快堆满了手边的小纸碗。垃圾桶就在两米外的墙角可我就是不想起身。这个瞬间我意识到一台会听指令、自己跑到你面前的垃圾桶大概能解决不少“懒人”的真实痛点。于是我从开源社区翻了一圈现成方案再结合自己的嵌入式底子决定动手做一台开源DIY智能移动垃圾桶它听得懂“过来”“回去”“开盖”能自己绕过桌腿还能在没电前乖乖回到墙角。这篇文章就记录下这台机器的完整设计思路、硬件选型、核心代码和调试过程中遇到的各种坑希望能给同样想折腾的朋友一个可以直接下手的参考。1. 先从需求说起这台垃圾桶到底要“会”什么1.1 “会听会走”的功能边界怎么定做项目最忌讳一上来就想着“什么都要有”。我最初也动过加摄像头、加激光雷达、连手机APP、搞自动垃圾分类的念头但冷静下来一算时间、成本、调试难度全都不止翻一倍。对于一台定位在室内的移动垃圾桶真正核心的需求其实就三条被动值班平时待在墙角待机不耗电、不吵人像个正常垃圾桶。语音召唤用户喊“小桶过来”它能识别指令并朝用户方向移动喊“回墙角”它能自动返回待机点。安全行走移动过程中能避开椅子腿、桌腿、拖鞋这类常见障碍物遇到台阶边缘不往前冲快没电时会告警。至于自动开盖、自动打包垃圾袋、识别什么垃圾能扔什么不能扔我全归到二期或者三期再折腾。先把“听”和“走”这两个主功能做扎实比盲目堆功能靠谱得多。这也算我给自己画的边界线一开始只允许自己动MCU、电机驱动和几个传感器不碰视觉、不碰导航避免项目烂尾。定了功能边界之后整个系统就清晰了一个负责语音识别和交互的模块一套负责底层运动的差速底盘一颗负责统筹调度和避障决策的主控再加一块把7.4V电池电压合理分给各个模块的电源板。每一块都能独立测试最后再拼起来联调排查问题的时候不会像一团乱麻。1.2 技术选型ESP32还是STM32语音方案怎么选主控选型是第一个要做的决定。我在STM32F103C8T6蓝丸和ESP32-WROOM-32之间纠结了一阵最后选了ESP32核心原因是“语音”这条链路。ESP32的优势在联网和双核处理。虽然这台垃圾桶不依赖云但ESP32的算力做离线语音指令词解码、传感器数据融合和电机控制同时跑非常从容。更重要的一点ESP32自带WiFi/蓝牙后续如果我想加手机调试、Web控制面板、甚至用蓝牙遥控简直零成本。STM32F103当然也能做很多开源四轴和智能小车都用它但你要额外接一个语音识别芯片比如SU-03T还要处理编解码和模型文件开发效率会低不少。下面是当时对比的两个方案对比项ESP32-WROOM-32STM32F103C8T6离线语音识别支持乐鑫官方ESP-SR框架可跑命令词识别需要外挂语音模块或自己移植算法无线扩展原生WiFi 蓝牙需要外接ESP8266或BLE模块电机控制外设LEDC PWM通道足够定时器PWM充足开发门槛Arduino框架上手快也有ESP-IDFKeil HAL库偏传统嵌入式成本约15-25元约8-15元典型失败案例PWM引脚复用冲突、GPIO电平注意语音链路复杂集成成本高语音识别方案我当时列了三种SU-03T离线语音模块、ESP32原生的ESP-SR离线识别、在线云ASR百度/讯飞那种。在线方案直接淘汰了——垃圾桶要的是一个“随时喊得动”的设备依赖WiFi和云服务网络一波动就成了哑巴这不行。SU-03T模块最省事模块内置了麦克风、语音识别固件和串口输出上位机里配置好唤醒词和命令词烧写进去就能用。ESP-SR的优点是少一块硬件但ESP32原版跑ESP-SR中文命令词支持不如ESP32-S3好实测识别距离也短一些所以我最后选了“主控ESP32 语音模块SU-03T”这个组合稳、准、开发量小。电机驱动选的是TB6612FNG不是很多人习惯用的L298N。L298N太老、压降大、发热严重TB6612FNG体积小、管教少最大连续输出1.2A/通道驱动N20减速电机这种小功耗电机绰绰有余。N20电机我选的是带霍尔编码器的版本减速比1:30额定电压6V空载转速约300RPM左右配合橡胶轮速度体感不会太疯也不会慢得像蜗牛。2. 硬件清单与供电设计别让垃圾桶半路趴窝2.1 核心部件清单与选型理由整个项目的BOM其实不复杂大部分模块都能在淘宝上十块钱左右买到。这里给一份我当时采购的完整清单价格按单件估算方便你按预算取舍部件型号/参数大致价格作用主控ESP32-WROOM-32开发板20-30元负责运动控制、逻辑调度、避障决策语音模块SU-03T 离线语音识别模块15-25元识别唤醒词和命令词通过串口输出结果电机 ×2N20微型减速电机带编码器减速比1:3015-25元/个驱动左右轮电机驱动TB6612FNG模块8-15元给电机提供正反转PWM驱动超声波模块 ×3HC-SR043-6元/个检测前方、左前、右前障碍物距离TOF测距模块VL53L0X15-20元检测低矮台阶和桌面边缘电池18650电池 ×2 双节电池盒30-50元7.4V供电降压模块MP1584 DC-DC降压模块 ×25-8元/个分别输出5V和3.3V舵机SG90 9g舵机5-8元控制垃圾桶盖开合数据线/排针若干10元供电和信号连接这里多说一句为什么选HC-SR04而不是只用VL53L0X。HC-SR04在中近距离表现稳定指向性虽然不算特别窄但对桌腿、墙壁这类大目标很够用缺点是对斜面的反射容易丢数据。VL53L0X是激光测距适合检测前方低矮台阶或者地面突然变深的情况但成本更高照射面积小。我做的是三层感知前方用三个HC-SR04覆盖左右45°和正前方底盘边缘往下装一个VL53L0X专门防跌落这样互补各自的盲区。2.2 供电架构为什么电池和降压要分开设计供电是整个项目里最容易埋雷的地方。我见过不少人图省事拿一个AMS1117-3.3把7.4V直接降到3.3V给主控供电结果板子一通电就发烫运行几分钟后自动重启。原因是AMS1117是线性稳压器输入输出压差大时多余的功率全部变成热量散发电流稍微大一点就扛不住。我的方案是7.4V电池母线走两级第一级用MP1584 DC-DC把7.4V降到5V给超声波模块、SU-03T语音模块和舵机供电第二级再用一个MP1584把5V降到3.3V给ESP32和编码器供电。DC-DC的转换效率高发热小纹波在电机的干扰下也能保持在可接受范围内。当然3.3V这路也可以换成AMS1117但输入电压最好控制在5V以内不然热损耗仍然很难看。电机驱动的VM脚直接接7.4V电池母线逻辑电平脚VCC接5VSTBY接3.3V或者5V看手册推荐。有一点必须注意所有模块的地线要共地电机电源地、主控地、传感器地必须连成一个完整的参考点否则串口通信和PWM信号会出现莫名其妙的跳变。我还在电池母线两端并联了一只1000uF电解电容和一只0.1uF瓷片电容用来吸收电机启动瞬间的大电流冲击实测对重启复位问题改善非常明显。3. 底盘与运动学决定垃圾桶“走得稳”的底层逻辑3.1 两轮差速底盘结构与改装底盘结构我选了最经典的两轮差速加万向轮方案没有上四驱。原因很简单垃圾桶不需要越野室内地面是瓷砖或木地板两个驱动轮加一个万向轮足够稳定而且差速转向的控制模型比四驱简单太多。四驱要解决四个电机的速度同步问题不然转弯的时候反而容易互相较劲。具体布局上两个驱动轮装在底盘中轴线靠前一点的位置万向轮装在尾部形成一个稳定的三角形支撑。左右轮间距我实测取220mm底盘宽度约240mm这样在原地旋转时不会碰到周围障碍物核心区域而且转向半径的计算也方便。垃圾桶本体的固定也很关键我用一块亚克力板做底盘桶身底部用双面胶和扎带双重固定重心尽量压低电池和主控板都放在底盘最底层。有个实际教训得说垃圾桶平时是被动放置的如果重心偏高在承载垃圾时一旦急转弯离心力很容易把桶掀翻。所以我把重的东西全压在底盘底部桶身内壁的固定点要选靠近桶底1/3的位置不要只固定桶口。这一点看起来不起眼但直接决定了机器人是“稳稳走”还是“三步一翻”。3.2 速度与转向控制的数学模型两轮差速底盘的运动学模型其实高中物理就够用。设左右轮线速度分别为 vL 和 vR轮距为 L我这里是0.22m则机器人的整体线速度和角速度分别为v (vL vR) / 2ω (vR - vL) / L当 vL vR 时两个轮子速度相等机器人直线前进当 vL -vR 时机器人原地旋转当 vL 和 vR 不相等时机器人走弧线弧线半径 R L * (vL vR) / (2 * (vR - vL))。实现里最大的难点不是公式本身而是怎么让实际速度尽量接近设定的 vL 和 vR。N20电机带霍尔编码器左右轮各有一个编码器输出可以拿来做速度闭环。比如我用外部中断对编码器脉冲计数每100ms结算一次得到当前轮速单位RPM或者m/s然后和目标速度做PD控制调整PWM占空比。PD控制器的输入是速度误差 e targetSpeed - currentSpeed输出是PWM占空比修正量。参数整定时从kp1.0起步先把比例调上去如果看到轮子抖或者有金属摩擦声就说明PWM修正量太大了需要减小kp或者加一点微分项kd来抑制振荡。这一步虽然枯燥但值得耐心试左右轮速度不一致时直线行走会明显偏斜这是很多新手做小车时“走着走着就拐弯”的根本原因。4. “听”的实现语音识别链路与指令处理4.1 离线语音模块的选型与接入SU-03T模块的使用体验相当“友好”它内置了麦克风、放大器、离线识别引擎和语音提示功能你在PC端的上位机软件里创建一个产品上传唤醒词和命令词对应的条目然后生成固件烧录到模块里。它的典型工作流程是先喊唤醒词我设置的是“小桶小桶”唤醒后3到5秒内识别命令词识别结果通过UART输出同时模块自带的喇叭会播报自定义的提示音。接线非常简单SU-03T的VCC接5VGND接主控GNDTXD接ESP32的RXRXD接ESP32的TX。有一点容易踩坑SU-03T的串口电平虽然是3.3V但部分模块的TXD在启动瞬间会有短暂的电平跳动如果你接的ESP32开发板RX引脚没有外部下拉偶尔会收到一个误码字符。解决办法是在初始化时清空串口缓存或者在主控串口配置里加一段延时再开始监听。4.2 指令集设计与串口通信协议语音模块能识别多少条命令词不是重点重点是命令词和运动状态要一一对应。我设计的指令集分成三类指令类型唤醒后说主控行为移动指令“过来”进入前进状态执行避障移动指令“回墙角”转向180度博文方向并返回移动指令“停止”原地停车运动控制“左转”“右转”原地左转/右转微调方向桶盖控制“开盖”“关盖”舵机打开/关闭垃圾桶盖系统查询“你在哪”“嘟一声”播报提示音或短闪灯SU-03T的上位机里设置命令词后识别结果默认以“字符串”形式从串口输出例如“{“cmd”:”过来”,“res”:”0”}”这类JSON格式也可能根据固件配置输出纯字符串。我在ESP32端用字符串匹配处理解析到“过来”就切换状态解析到“左转”就往左原地转500ms简单直接。如果你想更结构化可以在模块配置里把输出格式改成固定帧头命令ID的协议比如“AA 01 BB”解析起来更可靠。4.3 代码实现从识别结果到运动指令ESP32端我用的是Arduino框架主循环里同时处理串口语音数据和超声波测距状态判断放在一个简单的if-else链里。核心逻辑大概是这样的#define MOTOR_LEFT_PWM 13 #define MOTOR_RIGHT_PWM 14 String voiceCmd ; void setup() { Serial1.begin(9600); // 接SU-03T的串口 ledcSetup(0, 10000, 8); // PWM频率10kHz分辨率8bit ledcAttachPin(MOTOR_LEFT_PWM, 0); ledcSetup(1, 10000, 8); ledcAttachPin(MOTOR_RIGHT_PWM, 1); } void loop() { // 读取串口语音识别结果 if (Serial1.available()) { voiceCmd Serial1.readStringUntil(\n); voiceCmd.trim(); Serial.println(Voice CMD: voiceCmd); } // 根据指令或状态控制电机 if (voiceCmd 过来) { moveForward(150); // 前进PWM占空比150/255 state MOVING; } else if (voiceCmd 停止) { stopMoving(); state IDLE; } else if (voiceCmd 开盖) { openLid(); } else if (voiceCmd 关盖) { closeLid(); } // 在全速移动时检测障碍物 if (state MOVING) { float frontDist readUltrasonic(FRONT_TRIG, FRONT_ECHO); if (frontDist 15.0f) { avoidObstacle(); } } delay(50); // 每50ms循环一次 }这段代码只展示了最基础的指令响应。实际工程里我还会加入“防抖”机制同一个指令如果在短时间内被重复识别只执行一次防止模块误识别连续输出导致机器人抽搐。另外不同指令之间最好留一个500ms的“冷却窗口”因为人说话时可能有“嗯”“啊”之类的尾音被识别成杂音冷却窗口可以过滤掉大部分误动作。5. “走”的实现运动控制状态机与避障策略5.1 速度闭环与PWM控制让垃圾桶“走得稳”光靠直接把PWM占空比设成固定值是不够的。不同电压下、不同地面摩擦下同样的占空比转速并不相同。我用编码器测每个轮子的实时速度然后做一个比例-微分控制volatile int leftCount 0; volatile int rightCount 0; // 编码器中断 void IRAM_ATTR leftEncoderISR() { leftCount; } void IRAM_ATTR rightEncoderISR() { rightCount; } // 每100ms调用一次计算转速并执行PD void updateSpeedControl() { static int lastLeftCount 0; int leftDelta leftCount - lastLeftCount; lastLeftCount leftCount; int rpm leftDelta * 600 / (encoderPPR * 100 / 1000); // 粗略换算 int targetRpm 200; int error targetRpm - rpm; static int lastError 0; int output kp * error kd * (error - lastError); lastError error; ledcWrite(0, constrain(150 output, 0, 255)); }实际调参时我把左右轮的目标RPM设为一致然后打印两轮的实际RPM看偏差是否稳定在5%以内。如果左轮快右轮慢就单独给右轮加一个补偿偏置。这个小补偿值是根据恒流PWM下实测的不同地面要微调所以我会把补偿参数放到全局变量里方便通过手机串口实时调。5.2 状态机设计待机/前来/返回/避障整个机器人的行为用状态机管理能省掉很多逻辑混乱。我定义了四个主状态IDLE、COME_HERE、GO_BACK、AVOIDING。IDLE状态下所有电机停止只有语音模块和主控在低功耗待机语音一旦识别到“过来”进入COME_HERE识别到“回墙角”进入GO_BACK。在COME_HERE和GO_BACK状态下如果超声波检测到前方障碍物距离小于15cm就进入AVOIDING。AVOIDING状态是纯自动的不需要用户参与。它会根据三个HC-SR04的读数决策是左转还是右转。如果只是前方近处有障碍、两侧空闲就选择转向方向转向完成后重新回到原来的移动状态。如果左、右两侧同时有障碍那很可能是卡在一个窄缝里或者被围困了就原地旋转180度尝试反向突围。状态机的完整代码骨架在4.3节里其实已经露出了一些这里再补充一个关键点状态切换时一定要驱动电机的状态彻底落定。比如从AVOIDING切回COME_HERE如果避障时带着一个转向余量直接继续前进很容易再撞上同一障碍物所以我会先恢复直行0.3秒让机器人摆脱当前转向趋势再开始前进。5.3 避障逻辑超声波测距与绕行决策超声波避障的原理不复杂HC-SR04发射超声波测量回波时间乘以声速除以2得到距离。Adafruit官网都给了例程唯一要注意的是测距频率HC-SR04每次测量需要大约30ms三个传感器轮流测就是90ms加上状态机判断主循环实际频率大概10Hz左右这在室内低速场景下完全够用。传感器布局上正前方一个左右各45度角一个。这样开发决策时就能这样判断左前距离前方距离右前距离决策20cm20cm20cm继续直行15cm15cm15cm向空侧偏转15cm15cm15cm右转15cm15cm15cm左转15cm15cm15cm停车后原地掉头这套决策表虽然粗糙但我在客厅实测效果还不错桌腿能绕过去垃圾桶底座也能绕过去就是遇到那种宽度极窄的椅子缝时它可能转半天这种场景我建议直接语音喊一声“停止”没必要让它死磕。毕竟它只是一台垃圾桶不是扫地机器人。6. 实测调试记录那些文档里不会写的坑6.1 电压跌落导致的主控复位第一次整机联调时我发现只要电机一启动ESP32就会像触电一样重启串口打印还能看到一堆乱码。排查到根因是瞬间电流过大N20电机启动瞬间电流接近800mA两轮同时启动接近1.6A电池直接输出电压瞬间被拉到6.5V以下主控供电跟着抖。解法就是前面提到的电源架构分级给逻辑电路用独立的DC-DC降压并在电池母线上加大电容同时把电机启动改成“软启动”——PWM占空比从0逐步爬升到目标值而不是一下拉满。软启动的效果非常明显垃圾桶起步不再有猛窜的感觉同时电压跌落几乎消失。6.2 语音误触发与电机噪声调试中我遇到过一种“灵异现象”垃圾桶在音乐放大声时偶尔会自己执行“过来”的指令。原因很简单SU-03T的麦克风是开放的高音量音乐里的某段频响特征和唤醒词/命令词撞上了。解决办法是在SU-03T的上位机里开启“识别阈值”调节把阈值调高一点同时尽量让麦克风方向朝上别对着喇叭或者电机方向。电机PWM频率如果设在1kHz附近电机的高频啸叫也会干扰拾音我把PWM频率调到20kHz既减弱了人耳可闻的电机噪声也减少了对语音采样的影响。6.3 避障盲区单传感器布局的代价初期我图省事只在正前方装了一个HC-SR04结果垃圾桶老老实实撞上了斜45度角的墙。原因不是传感器坏了而是超声波束角有限正前方探头根本看不见侧面的障碍。后来我改成三传感器布局把左右两个朝向斜前方45度才算解决了这个问题。这里也提醒各位传感器的覆盖范围一定要预留“设计余量”室内墙角、桌腿都可能在机器人的斜前方只盯着正前方就等于半个瞎子。6.4 万向轮卡死与卫生死角万向轮到现在我还是没找到完全满意的方案便宜的小万向轮在地毯上非常容易卡住纤维转弯时会被异物缠住导致机器人跑偏。一种常见修法是换直径更大、支架更顺滑的万向轮或者在轮子外部加一个防缠绕罩盖。另外垃圾桶毕竟是装垃圾的桶身底部和电子舱之间要留出隔离层。我用了一片亚克力板把电子舱完全封死只留出传感器和喇叭的开孔不然扫地时扬起的灰尘和液体撒漏对电路板是致命的。7. 扩展方向与个人经验7.1 还能往哪些方向折腾这台垃圾桶做成以后我把硬件框图、接线方式和关键代码整理发布到了自己的开源仓库目的就是让更多人能做出来并且改出属于自己的版本。如果按优先级来说我觉得接下来最值得折腾的几个方向是加入麦克风阵列单麦克风没有方向定位垃圾桶接到“过来”指令只能盲目直行。用ReSpeaker 2-Mic或者4-Mic阵列可以做声源定位也能在一定程度上判断声音来自左还是右这个对“被召唤”场景提升非常明显。加视觉识别OpenMV、K210或者直接用ESP32-S3接摄像头模组识别人的位置并往人方向移动甚至可以对垃圾做简易分类比如只看颜色。全屋定位在室内布置UWB锚点或者用编码器里程计做简单的航迹推算至少让垃圾桶知道自己大概在哪、墙角在哪。这一块工作量不小但做完整个系统就有“回充”“归位”能力了。7.2 做完这台机器我的一些经验体会整套做下来我最大的体会是DIY项目真正的难点不是把模块拼在一起跑通而是让它跑得稳、跑得持久。你得为电压跌落想办法、为轮子转速不一致写补偿、为误识别调阈值这些细节没有高深理论但每一个都能让你多熬一个晚上。如果你也准备动手我的建议很简单先按这篇文章的清单把基础版本做出来哪怕外观丑、走线乱先把“听”和“走”的闭环打通后面的优化都是在已有的系统上做减法和加法。别一上来想着什么都要项目死在“过度设计”上的案例我见得太多了。
返回列表