ARTICLE DETAIL

资讯详情

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

用STM32做会听话的智能垃圾桶:语音识别+避障+差速驱动全攻略

用STM32做会听话的智能垃圾桶:语音识别+避障+差速驱动全攻略 我一个做嵌入式开发的朋友前阵子跟我说想给家里老人做个“听话”的垃圾桶不用弯腰、不用推着走喊一声就能自己过来扔完垃圾能自己开盖。本来以为就是个哄老人的小玩具结果我越做越觉得这项目太适合拿来练手了——语音识别、电机控制、传感器避障、嵌入式状态机一圈下来几乎把单片机开发的常见知识点全过了一遍而且成品是真能用的不是那种做完就吃灰的“实验室项目”。这项目说白了就是一台“会听口令、会自己跑、会开盖”的移动垃圾桶。核心主控我用的是 STM32F103C8T6语音部分用了离线识别模块底盘是双直流减速电机差速驱动前方挂一个超声波模块负责避障盖子由一个舵机控制开合。整体成本压在200块以内代码和硬件设计全部开源你在 GitHub 或 Gitee 上都能拉下来照着做。这篇文章就把我从零开始做这台垃圾桶的完整过程写下来包括硬件选型为什么这样做、语音指令怎么对接、电机和避障怎么调、还有我调试时踩进去的几个大坑给想动手的朋友一条能直接抄的路径。1. 项目定位与整体架构1.1 为什么做这个项目从痛点说起垃圾桶本身没什么技术含量但“移动垃圾桶”就有意思了。传统垃圾桶固定在一个位置你得走过去、弯腰、开盖、扔垃圾这对行动不便的老人、刚做完手术的病人或者纯粹想在沙发上瘫着的人都很不友好。我最初的需求很朴素能听懂“过来”“回去”“开盖”“关盖”能在家里自己走别撞到桌腿和墙就行。这个定位决定了项目的技术路线不会太难但也绝不是“点亮一个LED”那种入门级练手。它牵扯到几个独立的子系统语音识别子系统、运动控制子系统、避障测距子系统和执行机构。任何一个子系统单独拎出来都对应嵌入式开发里一个重要的知识点。把它们拼成一个完整的闭环产品这才是我觉得这个项目最有价值的地方——不是学某个孤立的功能而是学会怎么把多个模块组织成一个能稳定运行的系统。对于想入坑嵌入式但又不知道做什么项目的朋友我的建议是优先选这种“整机类”项目。面包板点灯、跑个串口打印都是片段做一台能动的机器你才会真正理解什么叫“系统级联调”什么叫“电源完整性”什么叫“软件状态机”。1.2 系统拓扑与数据流谁在听、谁在算、谁在走整个系统的数据流并不复杂但搞清楚每个模块之间怎么通讯是后面写代码和排查问题的基本功。我按信息流向把这个系统分成四层第一层是“感知层”负责接收外界信息。语音识别模块SU-03T负责接收人的口令超声波模块负责探测前方的障碍物距离。这两个模块用的通讯方式不一样——语音模块走串口USART超声波走 GPIO 电平时序。第二层是“决策层”也就是 STM32 主控。它把所有感知信息汇总运行一个状态机决定当前该前进、后退、转向、停止还是开盖。第三层是“执行层”电机驱动板接收 STM32 的 PWM 和方向信号来驱动两个直流电机舵机根据 PWM 脉宽带动垃圾桶盖开合。第四层是“电源层”电池组给所有模块供电中间通过降压模块分出不同电压轨。打个比方这就像一个外卖配送系统超声波和语音模块是“眼睛”和“耳朵”STM32 是“大脑”电机和舵机是“手和脚”电池是“心脏”。任何一个环节出问题整台机器就会“失明”“耳聋”或者“瘫痪”。做系统级项目时你花在排查这些问题上的时间往往比写代码的时间还多。2. 硬件选型与电路搭建2.1 主控选型为什么用 STM32F103C8T6 而不是 Arduino先说我踩过的一个认知误区。很多教程一上来就让你用 Arduino因为库多、语法简单。但如果你有了一点点编程基础我更推荐直接上 STM32F103C8T6 这颗芯片也就是俗称的“BluePill”开发板。原因有几个首先是性能余量。Arduino UNO 用的是 ATmega328P8 位 MCU16MHz 主频2KB RAM。而 STM32F103C8T6 是 32 位 Cortex-M3 内核72MHz 主频20KB RAM64KB Flash。虽然做这个项目的负载并不大但性能余量意味着你可以在同一个平台上继续扩展功能——比如加个 OLED 屏显示状态、挂个 ESP8266 做物联网远程报警。如果一开始就用 8 位单片机后期升级的空间非常小。其次是外设丰富度。STM32 有多个定时器可以输出互相独立的 PWM 通道这对控制双电机加一个舵机非常顺手。Arduino Uno 只有 6 个 PWM 脚也能勉强做但还得考虑超声波测距要用的输入捕获功能。STM32 的 TIM 定时器可以很优雅地实现超声波回波高电平时间测量精度比 Arduino 的 pulseIn() 高不少。最后是成本和学习曲线。BluePill 板子在主流电商平台十几块钱一片比 Arduino 便宜太多。虽然 STM32 的开发门槛比 Arduino 高国内市场 STM32 的资料和教程海量只要愿意花半天时间装好 Keil 或者 STM32CubeIDE、跑通一个点灯程序后面的路就顺了。2.2 语音识别方案对比LD3320、SU-03T 还是云端识别语音识别有好几条路线可以走这里我对比一下三种常见方案也说明为什么最终选了 SU-03T。第一种是 LD3320 这类专用语音识别芯片。它的特点是“非特定人识别”也就是说谁来说都能识别。但代价是需要额外外挂 Flash 来存储词条而且识别率对安静环境要求比较高家里开着电视或油烟机的时候误识别率会让你抓狂。第二种是 ESP32 云端语音识别比如百度、讯飞的在线 API。识别率最高几乎接近智能音箱的水平但缺点也很致命——必须联网。垃圾桶一旦断网就成了“聋子”而且涉及将语音上传云端很多 DIY 玩家对隐私有顾虑另外免费额度用完还要付费对一个本来想长期平稳运行的家用小机器来说并不划算。第三种就是我这台用的 SU-03T 离线语音识别模块。它最大的优势是“本地识别无需联网”支持自定义唤醒词和最多几十条命令词识别结果通过串口或 GPIO 输出。它在设计上把音频采集、前端降噪、识别算法都集成到模块内部了你只需要通过配套的网页工具把命令词烧录进去然后通过串口接收识别结果。实际测试下来在安静环境下识别率在95%以上开电视时的识别率能到80%左右对这个应用场景来说足够用了。2.3 电机驱动与供配电差速底盘的能量基础移动底盘我选择了双直流减速电机加万向轮的方案两个驱动轮分别由左右两个电机控制通过两个轮子的转速差实现前进、后退和转向这就是“差速驱动”。这种方式的优势是结构简单、控制逻辑直观特别适合室内平地环境。电机驱动芯片我选的是 TB6612FNG而不是很多人熟悉的大块头 L298N。TB6612 是 MOSFET 结构的驱动芯片内部压降小、发热低连续驱动电流 1.2A峰值 3.2A驱动这类小型直流减速电机绰绰有余。L298N 用的是三极管压降大发热严重用一会儿摸散热片就烫手而且体积巨大放在垃圾桶里非常占地方。同样是驱动两个电机TB6612 的板子只有拇指大小能轻松塞进底盘里。供电是整个项目里最容易出问题的地方我必须多说几句。整台机器用了两节 18650 锂电池串联电压约 7.4V。这个电压直接给电机驱动板供电驱动两个直流电机。控制逻辑部分则需要更低的电压STM32 需要 3.3V语音模块和超声波模块需要 5V舵机需要 5V。所以我用两路降压——先用一颗 AMS1117-5.0 把 7.4V 降到 5V给舵机和传感器供电再用一颗 AMS1117-3.3 从 5V 降压到 3.3V给主控和语音模块供电。唯一的注意点是 7.4V 输入到 AMS1117-5.0 压差有 2.4V如果舵机频繁堵转功耗上来后芯片会发热比较大后面我会说怎么解决这个问题。2.4 模块接线总览与引脚规划为了让后面讲代码的时候不糊涂这里先把我实际使用的引脚分配整理成一张表。注意STM32 的 GPIO 很多脚可以复用为定时器通道接 PWM 的设备必须挂在能输出 PWM 的引脚上这一点在画原理图的时候一定要提前规划好。模块信号线STM32F103C8T6 引脚SU-03T 语音模块TXPA10 (USART1_RX)SU-03T 语音模块RXPA9 (USART1_TX)SU-03T 语音模块VCC / GND5V / GNDHC-SR04 超声波 TrigGPIO 输出PA6HC-SR04 超声波 EchoGPIO 输入PA7TB6612 左电机 PWMAPWMPA8 (TIM1_CH1)TB6612 左电机 AIN1 / AIN2GPIOPB14 / PB15TB6612 右电机 PWMBPWMPA11 (TIM1_CH4)TB6612 右电机 BIN1 / BIN2GPIOPB12 / PB13SG90 舵机信号线PWMPA0 (TIM2_CH1)接线时有三个关键点新手容易踩坑第一所有模块的 GND 必须和 STM32 共地否则串口数据全是乱码超声波测距完全不工作第二TB6612 的逻辑电源和电机电源必须分别接逻辑电源一般接 3.3V 或 5V电机电源接电池正极第三SU-03T 和 STM32 之间是串口对接要让模块的 TX 接 STM32 的 RX模块的 RX 接 STM32 的 TX交叉连接不要接成直连。3. 会“听”语音模块的接入与词条训练3.1 SU-03T 的识别流程与硬件接口SU-03T 是一颗语音识别专用芯片模块上集成了麦克风、Flash 存储和功放电路。用它的第一步不是写代码而是去它的配套网页平台配置“唤醒词”和“命令词”配置好之后把固件下载下来放到 TF 卡里插到模块上启动烧录或者直接用 USB 烧录器下载这一步做完模块才“知道”自己该听什么。它的工作方式分两个阶段。第一阶段是“待唤醒”模块持续在低功耗状态下监听音频信号只有检测到唤醒词我设置的是“小桶小桶”才进入“识别”状态。第二阶段是“听命令”这时你再说“过来”“回去”“开盖”等命令词模块会把识别结果通过串口发送给主控。这个“唤醒词”机制非常重要没有它模块会一直处理环境中的各种声音误触发率会高到没法用。我选 SU-03T 还有一个理由是它的串口协议很灵活。识别结果可以配置成直接输出一句话的内容也可以输出一个自定义指令。为了简化主控解析我配置成指令输出模式——比如识别到“过来”串口就发一个固定的十六进制帧。这样 STM32 那边根本不用处理字符串只需要匹配指令码代码写起来干净利落。3.2 自定义唤醒词和命令词训练配置训练配置的完整流程如下打开模块厂商的在线配置平台一般是浏览器里操作的网页工具注册登录新建一个产品选择“智能家居”或“自定义”品类。在“唤醒词”一栏填写“小桶小桶”旁边会有合成的语音示例你也可以自己录制。在“命令词”列表里把需要的口令和对应的“回复语”都填进去。我配置的完整命令词表如下小桶过来 → 回复“好的我过来了”指令码 0x01小桶回去 → 回复“好的我回去了”指令码 0x02小桶停 → 回复“好的我停了”指令码 0x03打开盖子 → 回复“盖子打开啦”指令码 0x04关闭盖子 → 回复“盖子关上啦”指令码 0x05小桶干活 → 回复“开始巡逻”指令码 0x06配置完成后平台会生成一个固件。把它下载下来烧录进 SU-03T 模块。上电后模块会播报“设置已生效”此时叫一声“小桶小桶”它回应“我在”就说明唤醒成功。平台上的语音合成效果虽然有点机械味但一句“好的我过来了”从垃圾桶里传出来家里的体验感一下就上来了。如果想更有温度也可以自己录音替换回复语。3.3 串口协议对接从语音到指令SU-03T 默认的串口波特率是 96008 位数据位1 位停止位与 STM32 的 USART1 对接。我把 USART1 配成中断接收每次收到一帧数据就放到一个环形缓冲区里主循环再解析。不同固件版本默认的帧协议可能不同如果拿到模块先用串口助手看一下模块上电时有没有主动发数据、喊命令时发的是什么格式。我自己这套的帧格式是 5 字节帧头0xFF 数据长度0x01 命令码 校验位 帧尾0xFE。比如识别到“小桶过来”时串口收到的数据是 FF 01 01 02 FE其中命令码是 0x01校验位是前面几个字节的累加和取低 8 位。STM32 端解析代码的写法大致是这样的// 收到语音指令FF 01 CMD SUM FE void Voice_ParseFrame(uint8_t *buf, uint8_t len) { if (len 5) return; if (buf[0] ! 0xFF || buf[len - 1] ! 0xFE) return; // 帧头帧尾校验 uint8_t sum 0; for (uint8_t i 0; i len - 2; i) sum buf[i]; if (sum ! buf[len - 2]) return; // 校验和检查失败则丢弃 uint8_t cmd buf[2]; switch (cmd) { case 0x01: Robot_SetState(STATE_GO); break; case 0x02: Robot_SetState(STATE_BACK); break; case 0x03: Robot_SetState(STATE_STOP); break; case 0x04: Servo_SetAngle(LID_OPEN); break; case 0x05: Servo_SetAngle(LID_CLOSE); break; case 0x06: Robot_SetState(STATE_PATROL); break; default: break; } }这个解析逻辑的核心是“校验”。串口通讯在电机大量启动时容易受到干扰出现数据错误如果没有帧头帧尾和校验位一个误码就会让主控跑飞。很多新手直接读一个字节就执行动作结果机器经常“抽风”源头就在这。4. 会“走”电机控制与超声波避障4.1 差速驱动原理与双电机运动模型差速驱动是所有轮式机器人最基础的运动模型。两个驱动轮分别由独立电机控制当两个轮子转速相同方向相同时机器人直线前进当一个轮子转另一个不转时机器人原地转向两个轮子方向相反时机器人原地旋转。实际控制中我不直接给电机电压而是通过 STM32 定时器输出 PWM 波改变占空比就是改变电机的平均电压进而改变转速。TB6612 的每个通道有两根方向引脚AIN1/AIN2和一根 PWM 使能脚PWMA。比如想让左轮正转就 AIN11、AIN20PWMA 给一个 0% 到 100% 的占空比想让左轮反转就交换 AIN1 和 AIN2 的电平。右轮同理。差速转向的时候我常用的计算方式是这样的假设目标速度是 V转向系数是 D范围 -1 到 1那么左轮速度 V * (1 - D)右轮速度 V * (1 D)。D 为 0 时两轮同速直线前进D 为正时左慢右快机器人右转D 为负时相反。这套公式虽然简单但做后续扩展时很管用——如果你想接 PS2 手柄或者 App 遥控摇杆数据映射成 V 和 D 就能复用同一套底盘代码。4.2 超声波测距的原理与代码实现超声波模块用的是 HC-SR04原理说起来像“蝙蝠回声定位”Trig 脚给一个 10us 以上的高电平触发信号模块内部就会发出 8 个 40kHz 的超声波脉冲同时把 Echo 脚拉高。声波遇到障碍物反射回来模块检测到回波后把 Echo 脚拉低。所以 Echo 高电平持续的时间就是声波从发出到返回的来回时间。距离公式就是距离cm 高电平时间us/ 2 × 0.0340.034 是常温下声速 340m/s 换算成 cm/us 的值。除以 2 是因为时间是往返的。举个例子如果 Echo 高电平持续了 580us那障碍物距离大约是 580 / 2 × 0.034 ≈ 9.86cm。代码实现有两种思路。一种是用延时“死等”就是拉高 Trig 后轮询读取 Echo 引脚电平再用定时器计算高电平持续了多少。这种方法简单但会阻塞 CPU测距期间干不了别的事。另一种是用定时器输入捕获Capture 上升沿开始计数捕获到下降沿读出计数值主循环里异步读取结果。我这台用的是第二种因为测距期间 STM32 还要处理串口语音指令如果一直死等超声波语音指令的响应就会卡顿。实测下来 HC-SR04 的有效测距范围是 2cm 到 400cm对这个垃圾桶场景我主要关注 0 到 80cm。在干净的走廊环境下数据很稳定最大误差正负 1cm 左右够用了。4.3 避障策略与状态机设计避障不能只写“遇到障碍物就停”否则机器人一碰到桌腿就原地发呆。我设计了三级距离响应用一棵简单的判断树来处理当超声波测距值大于 40cm 时判断为“安全”机器人以 60% 占空比前进。当测距值在 20cm 到 40cm 之间时判断为“接近障碍物”机器人减速到 30% 占空比继续前进并观看下一步。当测距值小于 20cm 时判断为“危险”机器人立即停车进入避让决策。避让决策我用了一个“两轮扫描”的办法。停车后先原地左转 90 度测一次前方距离记为 LeftDist再原地右转 180 度测一次距离记为 RightDist然后比较哪边更开阔就往哪边转。如果两边都小于 20cm说明被困住了就原地后退 10cm 再做一次判断。这个决策逻辑看着简单但实际调试时发现一个现象如果每次碰到障碍物都比来比去机器人会走得很“犹豫”有点像一个消费者在两个商品之间反复横跳。后来我给决策加了一个“惯性因子”——如果上一次是左转避让成功的那么这次如果左边距离和右边距离差得不多就优先再左转这样机器人路径会连贯很多走起来动作干净利落。4.4 开盖机构舵机 PWM 脉宽与角度控制垃圾桶盖由一个 SG90 舵机控制。舵机的本质是一个闭环伺服机构你给它一个周期 20ms 的 PWM 信号脉宽决定了输出轴的转角。标准参数是0.5ms 脉宽对应 0 度1.5ms 脉宽对应 90 度2.5ms 脉宽对应 180 度。SG90 的机械范围是 0 到 180 度实际拧到极限位置会堵转所以程序里要做软限位。我的设计是把舵机臂和桶盖用一根铁丝连杆连接起来。舵机转到 0 度时盖子完全盖住转到 130 度时盖子完全开启。这样既避开了舵机极限位置的堵转风险又保证了开盖动作的视觉效果。STM32 用定时器输出 PWM 时需要计算自动重装载值和比较值。我配置 TIM2 的时钟源经过预分频后让它产生 50Hz周期 20ms的 PWM然后比较值每变化 1000 对应 0.5ms 脉宽、2000 对应 1ms、3000 对应 1.5ms以此类推。想转到 130 度脉宽大概是 0.5 (130/180) × 2.0 ≈ 1.94ms比较值设到 1940 附近再根据实际机械结构微调。5. 主控逻辑STM32 软件框架与核心代码5.1 状态机模块划分从“裸奔”到“有组织”整个固件我没用操作系统而是用一个“超循环 状态机”的结构来组织代码。这个结构对嵌入式初学者来说非常友好也是很多小型机器人项目的标准范式。所谓超循环就是 main 函数里的 while(1) 死循环循环里周期性地执行几个子任务读取超声波数据、轮询语音串口缓冲、根据当前状态执行运动逻辑、更新舵机角度。这个循环的周期我用一个 SysTick 定时器来管理比如每 20ms 跑一次主逻辑这样每个模块都能得到及时的响应。状态机是决策层的核心。我定义了以下几个状态状态含义进入条件退出条件STATE_IDLE待机状态电机停止盖关闭上电初始化完成收到语音指令或定时巡检触发STATE_GO向前行进语音指令“小桶过来”到达目标位置超声波距离小于阈值STATE_BACK向后倒车语音指令“小桶回去”持续5秒后停止STATE_PATROL自动巡逻模式语音指令“小桶干活”语音指令“小桶停”STATE_AVOID避障转向超声波距离小于20cm且正在行进转向完成状态切换的关键原则是“原子性”也就是说状态机的每个循环只能处理一个状态下的逻辑状态切换时只修改状态变量不直接跳出去执行别的动作代码。这样出问题的时候你只需要看当前状态和导致状态切换的条件就能很快定位到问题而不是在乱七八的 if 嵌套里翻车。5.2 核心代码主循环、语音轮询与避障逻辑我选 Keil MDK 加标准外设库开发代码结构分成几个 .c 文件main.c 负责超循环调度motor.c 封装电机控制ultrasonic.c 负责测距voice.c 解析语音servo.c 控制舵机robot.c 是状态机主体。每个模块独立成文件后续想改成 HAL 库或者移植到别的单片机平台只需要替换对应驱动文件就行。主循环和状态机的核心代码思路大致如下int main(void) { System_Init(); // 时钟、GPIO、定时器、串口全部初始化 Robot_SetState(STATE_IDLE); while (1) { if (g_flag_20ms) { // SysTick 每20ms置一次标志位 g_flag_20ms 0; Robot_Task(); // 状态机主任务 Ultrasonic_MeasureTask(); // 异步触发测距 Voice_Poll(); // 检查串口缓冲区是否有新指令 } } } void Robot_Task(void) { switch (g_state) { case STATE_IDLE: Motor_Stop(); Servo_SetAngle(LID_CLOSE); break; case STATE_GO: // 前进同时检测障碍物 Motor_Forward(BASE_SPEED_PWM); if (Ultrasonic_GetDistance() DIST_STOP) { Robot_SetState(STATE_AVOID); } break; case STATE_AVOID: // 先原地停下做两侧扫描 Motor_Stop(); DelayMs(200); uint16_t left Ultrasonic_ScanDirection(DIR_LEFT); uint16_t right Ultrasonic_ScanDirection(DIR_RIGHT); if (left right) Robot_SetState(STATE_TURN_LEFT); else Robot_SetState(STATE_TURN_RIGHT); break; case STATE_TURN_LEFT: Motor_TurnLeft(TURN_SPEED_PWM); g_turn_count; if (g_turn_count TURN_90_DEG_COUNT) { g_turn_count 0; Robot_SetState(STATE_GO); } break; // 其他状态类似... } }这里有个关键细节转向 90 度不是靠角度传感器而是靠“时间积分”——记录电机以固定 PWM 旋转旋转的时间乘以预先标定的旋转速度反推出转过的角度。这在实际工程里叫“开环控制”优点是便宜可靠缺点是会受地面摩擦力影响跑久了会有累计误差。每次转向后重新走直线误差不会无限放大对这个场景来说完全够用。想出更好的效果可以升级成带编码器的电机然后做 PID 闭环这就是后话了。5.3 可靠性设计看门狗、掉电保护和低功耗做嵌入式项目功能写完只算完成一半另一半是可靠性。一个家用垃圾桶不能跑着跑着就死机也不能放着三天电就漏光。首先是看门狗。STM32 内部有一个 IWDG独立看门狗它需要主程序每隔一段时间去“喂狗”也就是刷新一个特殊寄存器。如果主程序因为某种原因卡死看门狗计数器就会溢出强制复位整个芯片。这个机制成本极低但价值极高——它保证你的设备永远有一个“最后一根稻草”来把你从死循环中拉出来。我在超循环里每 20ms 喂一次狗就算语音模块串口数据把缓冲冲爆程序卡死一秒钟后系统自己重启恢复不会变成一块“哑巴砖头”。其次是掉电保护。锂电池的电压会随着电量下降越来越低如果不做保护过放会把电池搞坏。我在电池输出端加了一个电压检测分压电阻STM32 的 ADC 每 500ms 采样一次电池电压。当电压低于 6.4V相当于每节 3.2V时主控把喇叭播报“电量低请充电”然后进入停机状态不再驱动电机最大限度保护电池。最后是低功耗。垃圾桶不是时刻都在跑大多数时间它都在待机。待机时我给语音模块、主控和舵机供电但把电机驱动板完全断电同时让 STM32 进入睡眠模式。实测待机电流从 80mA 降到了 12mA 左右。两节 2600mAh 的 18650 电池正常使用频率下可以撑三四天已经够日常生活了。6. 调试实录我踩过的那些坑6.1 问题一电机一启动超声波就疯狂误报这是我调试过程中遇到的第一个也是让我最头疼的问题。现象很奇特只开超声波模块测距很准只转电机电机也很顺但电机一转超声波的数据就开始乱跳明明前面什么都没有却测出二三十厘米的距离机器人就自己原地打转。后来拿示波器一量就明白了。PWM 斩波驱动电机时电机两端的电压是高频开关波形电流突变会在线束上产生严重的电磁干扰。这个干扰通过电源线和地线传导到了 HC-SR04 的供电端导致超声波模块的参考电平抖动回波检测阈值被干扰就会误判。解决办法分成几步缺一不可。第一在所有模块的电源脚并联一个 100uF 电解电容和一个 104 陶瓷电容做电源去耦第二电机电源线和信号线物理上分开走线不要捆在一起第三测距时序和 PWM 错开超声波测距触发后 14ms 内不要改变 PWM 占空比第四软件上加滤波连续测 5 次取中位数不是平均值——平均值会被极端的毛刺拉偏中位数能稳定剔除异常值。6.2 问题二舵机一开盖主控直接复位重启这个问题比上一个更吓人。现象是叫它“打开盖子”舵机刚开始转整个系统就黑屏重启语音模块重新播报开机提示音垃圾桶在原地跳了一下盖子只开了一半。原因也出在电源上。SG90 舵机启动和堵转瞬间电流非常大可以达到 1A 以上而我的 AMS1117-5.0 线性稳压器最大输出电流只有 1A瞬时压降导致 5V 电压被拉低到 4V 以下STM32 的 3.3V 也崩了于是复位。解决思路是“别把所有怕堵转的东西放在同一个 5V 源上”。我给舵机单独加了一路 DC-DC 降压模块比如 MP1584 或 mini560输出 5V/3A只给舵机供电同时给舵机电源端并联一个大容量电解电容我用了两颗 470uF用来吸收瞬时浪涌。原来那路 AMS1117 只负责给超声波和语音模块供电负载轻了很多之后再也没出现过开盖重启的问题。6.3 问题三语音识别率忽高忽低同一个词说十次能错三次语音模块刚烧录完时识别率很高用了两天之后就感觉“耳背”了特别是家里开着电视时喊好几遍“小桶小桶”都没反应。查了官方文档才发现一个非常隐蔽的坑麦克风拾音孔的位置。SU-03T 模块上的麦克风是贴片驻极体麦克风有方向性麦克风孔正对的方向拾音效果最好。我把模块装在垃圾桶外壳内部外壳挡住了一部分声音而且麦克风孔正好朝着天花板人站着说话的声音传到它那里时已经衰减得差不多了。后面我把模块重新固定了一个位置让麦克风孔斜向下 45 度角朝向使用者识别率立刻回升。另外还有一个细节唤醒词和命令词之间要停顿一下。很多人喊“小桶小桶过来”习惯一口气说完模块还没从唤醒状态切换到识别状态后半句就丢了。正确做法是“小桶小桶”停半秒听到模块回应“我在”再说“过来”。这不算 bug是这种离线模块的工作方式在文档里写清楚使用者就不会以为坏了。6.4 常见问题速查表现象可能原因排查与解决语音模块无反应串口接线接反交叉 TX/RX确认共地语音串口数据乱码波特率不对或电平不匹配设置 96008-N-1确认供电 5V电机转但机器人不走万向轮卡死或减速齿轮打滑检查万向轮轴承拧紧电机固定螺丝一侧电机无力TB6612 某路输出虚焊重新焊接 BIN1/BIN2/PWMB锂电不耐用电机频繁启停 舵机待机耗电待机时让驱动板断电调低空转 PWM转向角度越来越不准开环控制累计误差每次避障后重新对准或升级编码器闭环7. 开源发布与后续扩展7.1 项目文档结构设计如何把项目“端”给全世界代码写完了机器跑通了这时候才是开源项目的真正开始。很多人以为开源就是代码往 GitHub 一传就算完了其实不然。一个没有文档的开源项目别人根本看不懂你的硬件怎么接代码怎么烧就算拉下来也跑不起来最后只会变成一堆“star”。我自己维护开源项目的经验是文档的重要性完全不亚于代码本身。我的开源仓库目录结构大致是这样smart-trash-can/ ├── README.md ├── LICENSE ├── docs/ │ ├── hardware_list.md # 元器件清单和购买渠道 │ ├── wiring.md # 接线说明和引脚图表 │ └── getting_started.md # 环境搭建、烧录步骤、常见问题 ├── firmware/ │ ├── Core/ # STM32 工程源码main.c、robot.c 等 │ └── Drives/ # 各模块驱动代码 ├── hardware/ │ ├── schematic.pdf # 电路原理图 │ └── gerber/ # PCB 制板文件如果打样了 └── 3dprint/ ├── shell.stl # 桶身外壳模型 └── lid.stl # 桶盖模型README.md 是门面我习惯第一屏就放三样东西一张成品实物图、一句话项目简介、一个“3步跑起来”的快速开始指引。不要上来就是大段原理分析读者先跑起来才有兴趣看你的设计文档。很多开发者犯的错是把 README 写成“论文”读三屏还不知道这项目到底干嘛的。7.2 License 选择与贡献指南开源不等于放弃版权选择开源许可证是有讲究的。我的项目分为硬件部分和软件部分它们适用不同的许可证。固件代码我选的是 MIT License。这种许可证极其宽松允许别人拿去随意修改、商用甚至闭源只需要保留原始版权声明即可。选择 MIT 是因为我希望这个项目能被更多人拿去二次开发比如有人想做商业化的桌面垃圾桶MIT 不会对他造成阻碍说不定他还会回来提交一些改进代码。硬件设计文档我选的是 CERN Open Hardware Licence v2 (OHL)。这个许可证是专门为硬件设计的它要求别人如果使用你的硬件设计文件打样必须保留你的署名并对修改后的设计文件沿用相同许可证。几何外壳的 3D 打印 STL 文件我用了 CC BY-SA 4.0这样既允许他人修改并分享又要求必须注明原项目来源。贡献指南方面我在仓库里放了 issue 模板和 pull request 模板。Issue 模板会提醒提问者说明硬件版本、固件版本、复现步骤和串口日志PR 模板会要求提交者写明改动目的、自测结果和涉及的文件。这些小细节看起来繁文缛节但它们能避免开源项目最常见的“失联问题”——用户报了一个怪问题你问他拿日志他第二天消失了问题永远悬着。7.3 可以继续玩的方向从语音到视觉这台机器已经具备“会听”“会走”两个核心能力但我做完之后觉得它还有很大的扩展空间这里列几个思路给后续想二开的朋友参考。如果你对“视觉感知”感兴趣可以加一个 OpenMV 或者 ESP32-CAM 摄像头训练一个简单的 YOLO 目标检测模型让机器人能识别地上的塑料瓶自己跑过去捡取。这个升级的本质是把“感知”从超声波这种单点测距升级成图像级的语义理解整个系统的复杂度会上一个台阶但挑战也更有意思。如果你对“自动回充”感兴趣可以借鉴扫地机器人的方案在垃圾桶底座装两组充电触点家里放一个充电桩用红外信号引导它自动归位。这是移动机器人的一个经典闭环场景低电量→导航回桩→对接充电→继续工作。如果只想做软件优化也可以把电机控制升级成闭环 PID。现在这套开环控制够用但精度和抗干扰能力有限。加装带霍尔编码器的减速电机用 STM32 的编码器接口读转速再用 PID 算法调 PWM 占空比机器人的直线走得更直、转弯角度更准对地面摩擦力的变化也没那么敏感。我个人在整套项目做完之后的体会是开源硬件项目的真正价值不在做出来的那台机器本身而在于你把它“开源”出去之后别人能踩在你的肩膀上继续走。我收到过一条留言说有个学生在我的电路图基础上改版加了一个紫外线消毒灯模块做成了防疫垃圾桶还拿了学校比赛的一等奖。这种事情给创作者的成就感比自己闷头玩大得多。最后再分享一个小习惯开源项目的文档里一定不要把“我踩过的坑”藏着掖着。那些电源干扰、舵机复位、麦克风朝向的问题都是新手一定会重复踩的雷。写在 README 里不仅显得你专业而且会帮你挡掉一大部分“我的机器人怎么一动就重启”的重复提问。开源本来就是“人人为我我为人人”的事别怕暴露自己的调试黑历史——那恰恰是你这个项目最值钱的部分。
返回列表