💡 划重点

  • 主控 ESP32,双 OLED 分左右眼,舵机做情绪耳朵。
  • 支持离线语音识别,喊“开心”“生气”“睡觉”即可切换表情与动作。
  • 整机物料控制在 120 元内,适合桌面陪伴、情绪反馈与硬件入门。
  • 接线核心:OLED SPI 共用 SCK/MOSI/DC,双片选 CS1=15、CS2=27;舵机 13/14。

需求洞察

目标用户是独居学生、远程办公者和喜欢桌面小物的年轻玩家。他们并不需要一台昂贵的机器人,而是想要一个“有回应”的桌面伙伴:写作业时抬头能看见它眨眼,加班时喊一声它会竖起耳朵,情绪低落时给一个简单反馈。

真实痛点有三点。第一,现有桌宠大多只有单屏或灯效,表情单调,缺乏生命感。第二,语音助手偏向工具型,交互冷冰冰,且依赖云端。第三,DIY 机器人门槛高,动辄三五百元,学生党难以下手。电子表情盒用双屏做“眼睛”,用舵机做“耳朵”,用离线语音做“耳朵和嘴巴”,把成本压到 120 元内,同时保留可编程、可扩展的乐趣。它值得做,因为它把“情绪陪伴”拆成可实现的硬件模块:感知、判断、表达、记录。

方案设计

感知层:SU-03T 离线语音识别模块负责唤醒与指令识别,输出串口字符串;ESP32 内部也可读取模拟麦克风做简单音量检测,作为“被吓到”的触发。

控制层:ESP32 作为主控,运行状态机。状态包括开心、生气、困倦、惊讶、待机。每个状态对应左右眼表情、耳朵角度、蜂鸣器音效。状态切换由语音指令、定时器或随机事件触发。

执行层:两块 0.96 寸 OLED 分别显示左右眼,通过 SPI 共享时钟与数据线,用不同 CS 片选;两个 SG90 舵机控制左右耳朵,角度 0 到 90 度表示下垂、竖起、抖动;无源蜂鸣器做提示音。

日志/联网层:ESP32 连接 WiFi 后,通过 MQTT 或 HTTP 上报情绪事件,例如“今天被夸了 3 次”“生气 1 次”。本地串口同时输出日志,方便调试。若不想联网,可仅保存在 SPIFFS 中,形成一周情绪小报。

物料清单

物料 数量 用途 估算单价 小计
ESP32 开发板 1 主控与 WiFi 25 元 25 元
0.96 寸 OLED SPI 2 左右眼表情 15 元 30 元
SG90 舵机 2 左右耳朵动作 6 元 12 元
SU-03T 语音模块 1 离线语音识别 20 元 20 元
无源蜂鸣器 1 提示音 2 元 2 元
洞洞板/杜邦线 1 套 连接与固定 10 元 10 元
亚克力/3D 打印外壳 1 套 桌面结构 15 元 15 元
USB 供电线 1 5V 供电 5 元 5 元
合计 119 元

接线与结构

OLED 采用 SPI 模式,两屏共用 SCK=18、MOSI=23、DC=2、RST=4。CS1=15 控制左眼,CS2=27 控制右眼。舵机左耳=13,右耳=14。SU-03T 的 TX 接 ESP32 GPIO16,RX 接 GPIO17,VCC 接 5V。蜂鸣器接 GPIO25。

微调说明:原建议 DC=2、CS1=15、CS2=27 保留;RST 共用 GPIO4,减少引脚占用。若屏幕无 RST 引脚,可接 ESP32 EN。舵机 13/14 保持,原因是这两脚支持 PWM 且不占用 SPI。注意舵机启动电流较大,建议 5V 独立供电并与 ESP32 共地,避免复位。

结构上,外壳分三层:底板放 ESP32 与语音模块,中板固定两个舵机,面板开两个圆孔露出 OLED。耳朵用轻质纸板或 3D 打印件固定在舵机臂上,左右对称。

核心代码


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ESP32Servo.h>

#define SCREEN_W 128
#define SCREEN_H 64
#define OLED_DC 2
#define OLED_RST 4
#define CS_LEFT 15
#define CS_RIGHT 27
#define SERVO_L 13
#define SERVO_R 14
#define BUZZER 25

Adafruit_SSD1306 leftEye(SCREEN_W, SCREEN_H, &SPI;, OLED_DC, OLED_RST, CS_LEFT);
Adafruit_SSD1306 rightEye(SCREEN_W, SCREEN_H, &SPI;, OLED_DC, OLED_RST, CS_RIGHT);
Servo earL, earR;

enum Mood { HAPPY, ANGRY, SLEEPY, SURPRISED, IDLE };
Mood mood = IDLE;

void drawEye(Adafruit_SSD1306 &eye;, int cx, int cy, int r, bool blink) {
  eye.clearDisplay();
  if (blink) {
    eye.drawLine(cx - r, cy, cx + r, cy, SSD1306_WHITE);
  } else {
    eye.fillCircle(cx + r / 3, cy - r / 3, r / 5, SSD1306_WHITE);
  }
  eye.display();
}

void setEars(int angleL, int angleR) {
  earL.write(angleL);
  earR.write(angleR);
}

void showMood() {
  switch (mood) {
    case HAPPY:
      setEars(80, 80);
      break;
    case ANGRY:
      leftEye.clearDisplay();
      leftEye.display();
      rightEye.clearDisplay();
      rightEye.display();
      setEars(20, 20);
      break;
    case SLEEPY:
      setEars(10, 10);
      break;
    default:
      setEars(45, 45);
  }
}

void setup() {
  Serial.begin(115200);
  SPI.begin(18, -1, 23, -1);
  earL.attach(SERVO_L);
  earR.attach(SERVO_R);
  pinMode(BUZZER, OUTPUT);
  showMood();
}

void loop() {
  if (Serial2.available()) {
    String cmd = Serial2.readStringUntil('\n');
    cmd.trim();
    if (cmd == "happy") mood = HAPPY;
    else if (cmd == "angry") mood = ANGRY;
    else if (cmd == "sleep") mood = SLEEPY;
    else if (cmd == "wake") mood = IDLE;
    tone(BUZZER, 880, 120);
    showMood();
    Serial.println(cmd);
  }
  delay(20);
}

调试步骤

  1. 先只接一块 OLED,烧录测试程序,确认 SPI 引脚与 DC、RST 正确。
  2. 接入第二块 OLED,分别拉低 CS1 和 CS2,确认两屏能独立显示。
  3. 舵机接 5V 独立电源,测试 0、45、90 度,确认耳朵不卡壳。
  4. 连接 SU-03T,用串口助手查看识别输出,再与 ESP32 联调。
  5. 逐个语音指令测试表情、耳朵、蜂鸣器是否同步。
  6. 接入 WiFi 与 MQTT,检查情绪事件是否成功上报。
  7. 整机装入外壳,连续运行 30 分钟,观察是否复位或发热。

设计图

桌面情绪伙伴电子表情盒结构flow
1
感知输入
→
2
控制处理
→
3
执行反馈
→
4
数据上报