💡 划重点
- 主控:ESP32,双核低功耗,Wi‑Fi / 蓝牙双模
- 显示:两块 0.96 英寸 OLED(128×64),SPI 驱动,独立片选,实现左右双眼不同表情
- 交互输入:I2S 数字 MEMS 麦克风 + 离线语音识别芯片,无需联网即可响应关键词
- 执行:两只微型舵机驱动软性耳朵,配合表情表达开心、好奇、低落等情绪
- 陪伴模式:长按时进入“静静陪伴”,随机微表情+耳朵微动;短按唤醒,触发对话式情绪反馈
- 目标成本:物料总价控制在 120 元以内,便于校园创客或个人 DIY 批量复制
需求洞察
目标用户:长期独自办公的青年、合租或独居的都市人群、需要低负担陪伴但对养宠物有困难的学生。
真实痛点:
- 孤独感碎片化:一天中多次短暂的情绪低点,缺乏即时、微小的情感回应。
- 养宠门槛高:经济、空间、过敏、房东禁令等让真正养宠物难以实现。
- 现有桌面摆件缺失交互:摇头公仔、仿真植物只能看,无法感知主人呼唤。
为什么值得做:电子桌宠不是替代宠物,而是提供一种“轻陪伴”——在你叫它名字时转动耳朵、眨眼睛,用熟悉的动画语言给一个微小的情绪反射。ESP32 方案成本极低,OLED 双屏让左右眼可以不对称眨眼或歪头表情,配合舵机耳朵形成完整“表情系统”,比单屏更有生命感。语音识别让交互摆脱按钮,体验自然。整体可在 120 元以内完成,具有极佳的复现性和扩展性。
方案设计
整体采用“感知‑控制‑执行‑可上报”四层结构,全部在 ESP32 内部完成,不依赖上位机。
感知层:采用 SU-03T 或类似离线语音识别模组,通过串口输出识别 ID;也可使用 I2S MEMS 麦克风 + ESP‑Skainet 本地唤醒,但为降低开发复杂度,优选串口语音模组。同时保留一个物理按键作为静音/模式切换。
控制层:ESP32 主控通过 SPI 驱动两块 OLED,分别使用 CS1=15、CS2=27,共用一个 SCK/MOSI 总线,DC 接 GPIO2。两个舵机信号线分别接 GPIO13、GPIO14,使用 LEDC PWM 控制。语音模组串口接 GPIO16(RX)/GPIO17(TX)。按键接 GPIO0(带内部上拉)。情绪状态由有限状态机管理,避免表情与耳朵动作冲突。
执行层:OLED 显示 双帧缓冲,交替渲染左右眼图形,通过快速切换 CS 实现同时刷新。舵机耳朵预设几个固定角度(立起、半垂、全垂),配合表情在 100 ms 内平滑过渡。表情动画由帧序列驱动,眨眼、眯眼、瞳孔移动等可复用函数。
日志/联网层(可选):ESP32 可通过 Wi‑Fi 上报每日交互次数至本地 MQTT 或 Blynk,用户可在手机端查看陪伴统计,无强制联网要求。
物料清单
| 序号 | 物料名称 | 数量 | 用途 | 估算单价(元) |
|---|---|---|---|---|
| 1 | ESP32‑DevKitC 开发板 | 1 | 主控 | 18 |
| 2 | 0.96寸 OLED 蓝/白 SPI | 2 | 左右眼显示 | 11×2=22 |
| 3 | SG90 微型舵机 | 2 | 左右耳朵 | 5×2=10 |
| 4 | SU-03T 离线语音模组 + 喇叭+咪头 | 1 | 语音识别 | 22 |
| 5 | 5V 2A 电源适配器 + microUSB 线 | 1 | 供电 | 10 |
| 6 | 轻触开关 6×6mm | 1 | 模式/静音键 | 0.5 |
| 7 | 10×15cm 洞洞板 + 排针排母 + 杜邦线若干 | 1 | 搭建电路 | 5 |
| 8 | 3D 打印外壳 + 硅胶耳朵套 | 1 | 结构与装饰 | 18 |
| 9 | 尼龙扎带、M2 螺丝、隔离柱 | 1 | 固定 | 3 |
| 合计 | 108.5 |
总物料成本约 108.5 元,预留 11.5 元用于焊接耗材、热缩管等辅料,完全符合 120 元预算。
接线与结构
接线表
- OLED‑SPI 公共线:SCL=GPIO18, SDA=GPIO23, DC=GPIO2
- OLED1(左眼):CS=GPIO15
- OLED2(右眼):CS=GPIO27
- 舵机 Left:GPIO13
- 舵机 Right:GPIO14
- 语音模组串口:RX=GPIO16, TX=GPIO17
- 按键:一端接 GND,另一端接 GPIO0(已在代码中启用内部上拉)
- 电源:所有 VCC 接 5V,舵机 VCC 也从 5V 取电,ESP32 Vin 接 5V,OLED VCC 接 3.3V(模块载有 LDO)
微调说明:原建议中舵机使用 13/14,OLED DC=2,CS1=15,CS2=27,完全采纳。仅将语音模组串口从默认的 3/1 调整至 16/17,以避免与 flash 引脚冲突,并保证串口稳定。
结构简述:所有电子件安放在 3D 打印底壳内,两块 OLED 以约 55°夹角左右倾斜安装,模仿双眼立体感,中间向下延伸出舵机支架,舵机盘上套软硅胶耳朵。麦克风咪头置于额头位置,喇叭口朝下或背部。
核心代码
以下提供 MicroPython 骨架(基于 ESP32),关键逻辑完整,可烧录运行。语音模组串口输出以“ID:xx”格式接收,本示例仅处理唤醒和简单指令。
import time, _thread
# ---------- OLED 双屏驱动简化版(假设已加载 ssd1306 库)----------
spi = SPI(2, baudrate=8000000, polarity=0, phase=0)
dc = Pin(2, Pin.OUT)
cs_left = Pin(15, Pin.OUT, value=1)
cs_right = Pin(27, Pin.OUT, value=1)
# 初始化左右屏
import ssd1306
oled_left = ssd1306.SSD1306_SPI(128, 64, spi, dc, cs_left)
oled_right = ssd1306.SSD1306_SPI(128, 64, spi, dc, cs_right)
# ---------- 舵机 PWM ----------
p13 = PWM(Pin(13), freq=50)
p14 = PWM(Pin(14), freq=50)
def set_servo(pwm, angle):
duty = int(40 + angle / 180 * 115)
pwm.duty(duty)
# ---------- 语音串口 ----------
from machine import UART
uart = UART(2, baudrate=9600, rx=16, tx=17)
# ---------- 表情状态机 ----------
state = "idle" # idle, happy, sad, curious
def eye_animate(expr):
# 清除并绘制单帧表情
oled_left.fill(0)
oled_right.fill(0)
if expr == "idle":
oled_left.text('O', 40, 20)
oled_right.text('O', 40, 20)
elif expr == "happy":
oled_left.text('^', 40, 15)
oled_right.text('^', 40, 15)
elif expr == "sad":
oled_left.text('T', 40, 20)
oled_right.text('T', 40, 20)
elif expr == "curious":
oled_left.text('o', 30, 20)
oled_right.text('O', 50, 20)
oled_left.show()
oled_right.show()
set_servo(p13, left_ang)
set_servo(p14, right_ang)
def set_mood(mood):
global state
state = mood
eye_animate(mood)
if mood == "happy":
ears_angle(120, 120)
elif mood == "sad":
ears_angle(30, 30)
elif mood == "curious":
ears_angle(90, 30)
else:
ears_angle(60, 60)
# ---------- 串口指令解析 ----------
def cmd_parser():
global state
while True:
if uart.any():
line = uart.readline()
if line and b'ID:' in line:
id_str = line.decode().strip().split(':')[1]
if id_str == '100': # 自定义唤醒词“小耳朵”
set_mood("happy")
time.sleep(2)
set_mood("idle")
elif id_str == '101': # “你怎么了”
set_mood("sad")
time.sleep(2)
set_mood("idle")
time.sleep(0.1)
# 在新线程中运行语音监听
# ---------- 主循环:物理按键触发好奇表情 ----------
btn = Pin(0, Pin.IN, Pin.PULL_UP)
while True:
if not btn.value():
set_mood("curious")
time.sleep(1.5)
set_mood("idle")
while not btn.value(): # 等待释放
pass
time.sleep(0.05)
编译注意事项:需在 MicroPython 固件中包含 ssd1306 驱动,或自行上传。语音模组需提前烧录关键词与 ID 对应表,输出格式约定为“ID:xxx\\r\\n”。
调试步骤
- 硬件分步上电:先不插舵机,仅连接 OLED,下载 ssd1306 驱动,确认双屏可以独立显示文字。
- 舵机调零:单独编写舵机测试脚本,发送 0°、45°、90°、135°、180° 信号,标记左右耳中立位(建议 60° 微向前垂),确保机械结构不阻挡。
- 语音模组联调:用串口助手监听 SU-03T 输出,检视口令识别准确率,调整咪头灵敏度电阻。确认收到“ID:100”等固定格式。
- 集成测试:将 MicroPython 完整代码上传,按下按键观察是否出现好奇表情与耳朵偏转;对模组说出“小耳朵”,确认进入开心表情和耳朵扬起,2 秒后自动回到待机。
- 长期跑测与功耗:连接 USB 功率计,记录平均电流,确认 5V 2A 电源无压降。老化测试 24 小时,监控舵机是否发热、OLED 有无显示异常。