💡 划重点
- ESP32 主控,双 OLED SPI 屏做左右眼表情,两颗舵机驱动耳朵摆动。
- 离线语音识别模块负责命令输入,支持开心、生气、困倦、惊讶四种情绪切换。
- 整机成本控制在 111 元,低于 120 元目标,适合桌面陪伴与编程入门。
- 可扩展 WiFi 上报,把情绪状态同步到手机或云端日志。
需求洞察
目标用户是独居青年、考研学生、远程办公者和桌搭爱好者。他们每天长时间面对电脑,桌面设备虽然多,却缺少有生命感的反馈。真实痛点不是缺一个智能音箱,而是缺一个低成本、低打扰、能对情绪做出即时回应的桌面伙伴。手机通知太冷,智能音箱又太贵且常涉及隐私。电子表情盒用双屏眼睛和舵机耳朵表达情绪,语音识别让交互自然,成本却压到百元级。它值得做,因为 ESP32 生态成熟,OLED 与舵机资料丰富,语音模块即插即用,既能当陪伴摆件,也能作为嵌入式学习项目。
方案设计
感知层:SU-03T 离线语音识别模块通过 UART2 输出识别结果,支持自定义唤醒词和命令词,不依赖网络,隐私友好。控制层:ESP32 运行情绪状态机,把语音命令映射为 HAPPY、ANGRY、SLEEPY、SURPRISE 四种状态,并调度双屏与舵机。执行层:两块 0.96 寸 OLED 分别显示左右眼,通过不同圆斑大小、位置和眨眼动画表达情绪;两颗 SG90 舵机控制耳朵角度,开心时竖起,生气时压低,困倦时缓慢下垂。日志/联网层:ESP32 通过串口输出调试日志,并可选连接 WiFi,用 MQTT 把情绪状态和在线时长上报到巴法云或私有服务器,方便后续做情绪统计。
物料清单
| 物料 | 数量 | 用途 | 估算单价 | 合计 |
|---|---|---|---|---|
| ESP32 开发板 | 1 | 主控与 WiFi | 25 元 | 25 元 |
| 0.96 寸 OLED SPI | 2 | 左右眼表情 | 12 元 | 24 元 |
| SG90 舵机 | 2 | 耳朵动作 | 6 元 | 12 元 |
| SU-03T 语音识别模块 | 1 | 离线语音命令 | 25 元 | 25 元 |
| 3D 打印外壳 | 1 | 桌面结构件 | 15 元 | 15 元 |
| 杜邦线、USB 电源、螺丝 | 1 套 | 供电与连接 | 10 元 | 10 元 |
| 合计 | 111 元 |
接线与结构
OLED 双屏共用 SPI 总线:SCK=18,MOSI=23,DC=2,RST=4。CS 独立选通,OLED1 CS=15,OLED2 CS=27,这样 ESP32 可以用同一组数据线分别刷新左右眼。舵机左耳=13,右耳=14。语音模块 TX 接 GPIO16,RX 接 GPIO17,波特率 9600。舵机必须使用外部 5V 供电,并与 ESP32 共地,避免电流不足导致复位。结构上,两块 OLED 并排嵌入面板,舵机藏在顶部两侧,耳朵用轻质亚克力片固定,整体做成 80mm×60mm×50mm 的桌面盒。
核心代码
#include <SPI.h>
#include <Adafruit_SSD1306.h>
#include <ESP32Servo.h>
Adafruit_SSD1306 eyeL(128, 64, &SPI;, 2, 4, 15);
Adafruit_SSD1306 eyeR(128, 64, &SPI;, 2, 4, 27);
Servo earL, earR;
enum Mood { HAPPY, ANGRY, SLEEPY, SURPRISE };
Mood mood = HAPPY;
void drawEye(Adafruit_SSD1306 &d;, int cx, int cy, int r) {
d.clearDisplay();
d.display();
}
void setEars(int a, int b) {
earL.write(a);
earR.write(b);
}
void applyMood() {
switch (mood) {
case HAPPY:
setEars(60, 120); break;
case ANGRY:
setEars(30, 150); break;
case SLEEPY:
setEars(90, 90); break;
case SURPRISE:
setEars(20, 160); break;
}
}
void parseVoice(String cmd) {
if (cmd.indexOf("happy") >= 0) mood = HAPPY;
else if (cmd.indexOf("angry") >= 0) mood = ANGRY;
else if (cmd.indexOf("sleep") >= 0) mood = SLEEPY;
else if (cmd.indexOf("wow") >= 0) mood = SURPRISE;
applyMood();
}
void setup() {
Serial.begin(115200);
SPI.begin(18, -1, 23, -1);
earL.attach(13);
earR.attach(14);
applyMood();
}
void loop() {
if (Serial2.available()) {
String cmd = Serial2.readStringUntil('\n');
cmd.trim();
parseVoice(cmd);
Serial.println("Voice: " + cmd);
}
delay(20);
}
调试步骤
- 单独连接 OLED1,运行屏幕测试,确认 CS=15 选通正常。
- 接入 OLED2,检查 CS=27 是否独立刷新,避免双屏同时亮起。
- 舵机接外部 5V,测试 13、14 引脚角度范围,确认耳朵不卡壳。
- 语音模块通过 USB-TTL 连接电脑,用串口助手确认命令词输出格式。
- 整合代码,依次触发四种情绪,观察双屏与舵机是否同步。
- 连接 WiFi,配置 MQTT 主题,验证情绪状态上报。
- 装配外壳,整理走线,连续运行 2 小时,检查电源发热与复位情况。