💡 划重点

  • 主控:ESP32-WROOM-32E(双核 240 MHz,内置 WiFi / 蓝牙)
  • 音频输入:INMP441 全向 MEMS 麦克风
  • 音频输出:MAX98357A I2S 3W D 类功放 + 3W 喇叭
  • 存储:Micro SD 卡模块(SPI),保存音频日志与自定义音效
  • 交互:实体大按键 + WS2812 RGB 灯环,适合 3-6 岁儿童抓握与操作
  • 成本:全部物料合计 ≤ 85 元
  • 核心玩法:按下拼图块,机器人复读孩子说的话,并用灯光闪动回应,支持 8 段独立录音/回放

需求洞察

目标用户:3-6 岁学龄前儿童及其家长,尤其关注语言启蒙与亲子互动的家庭。

真实痛点

  1. 市面故事机只能单向播放,儿童缺少即时声音反馈,互动性弱。
  2. 大量产品依赖手机屏幕,家长担心视力与成瘾问题。
  3. 简易录音玩具音质差、存储少,无法记录成长轨迹。
  4. 拼图类玩具静态无反馈,难以持续吸引注意力。

为什么值得做:项目将拼图形式与“听见自己的声音”结合,让儿童在动手拼摆时得到即时语音强化,促进语言发育与因果认知。硬件成本低、模块成熟,便于家长或创客自制,也可作为 STEAM 教具进入幼儿园。ESP32 的无线能力预留了后续远程互动、云端故事下载的扩展空间。

方案设计


感知层:
- 8 路拼图检测(微动开关或磁簧):连接到 ESP32 的 8 个 GPIO,内部上拉,拼图放置时电平变化,触发录音/回放。
- INMP441 麦克风:I2S 接口,高灵敏度拾取儿童语音。
- 录音按钮(实体蘑菇头按键):防抖,由 GPIO 外部中断驱动。

控制层:
- ESP32 双核分工:Core 0 处理 Wi-Fi 与日志上传(可选),Core 1 专注音频与 I/O 轮询。
- FreeRTOS 任务:录音任务、回放任务、LED 动画任务、SD 写入任务。

执行层:
- MAX98357A + 3W 喇叭:播放录制音频或预置鼓励音效。
- WS2812 灯环(12 灯珠):根据录音/回放状态显示不同颜色与流水效果。
- 状态 LED(红/绿):指示电源与 SD 卡状态。

日志/联网层:
- SD 卡:存储每次录音的 WAV 文件,按时间戳命名,便于家长手机导出。
- Wi-Fi(可选):连接家庭网络后,通过 MQTT 将使用记录(按键次数、录音时长)上报到私有服务器,或拉取云端新音效。

系统工作流程:

  1. 上电初始化 I2S 输入输出、SD 卡、按键、灯环。
  2. 主循环扫描拼图检测引脚,当某个拼图块被放入且录音按钮被按下时,开始录音 3 秒,灯环变红呼吸,录音数据通过 INMP441 采集并 DMA 缓冲写入 SD 卡。
  3. 释放按钮后立即停止录音,灯环变绿,自动回放录音,喇叭出声。
  4. 若未放拼图块直接按录音键,播放预置的欢迎语“来和我说话吧”。
  5. 长按录音键 5 秒进入 Wi-Fi 配置模式(SmartConfig),LED 灯环蓝色闪烁。
  6. 所有操作日志追加写入 log.txt,包含时间、事件、文件路径。

物料清单

序号 名称 数量 用途 单价(元) 小计(元)
1 ESP32-WROOM-32E 开发板 1 主控 22 22
2 INMP441 麦克风模块 1 音频输入 12 12
3 MAX98357A I2S 功放模块 1 音频放输出 9 9
4 3W 4Ω 内磁喇叭 1 发声 5 5
5 Micro SD 卡模块(SPI) 1 存储 4 4
6 32GB Micro SD 卡 1 存储介质 15 15
7 WS2812 灯环(12灯) 1 交互反馈 6 6
8 12mm 蘑菇头按键 1 录音触发 2 2
9 微动开关模块 8 拼图检测 0.8 6.4
10 5V 2A USB 电源适配器 1 供电 8 8
11 跳线、排针、热缩管 若干 连接 3 3
12 3D 打印外壳 + 木制拼图块 1 套 结构 本人加工 0
合计 92.4

*注:总价 92.4 元略超 85 元预算,可将 SD 卡替换为 8GB(10 元),喇叭选更低成本(3 元),或微动开关使用普通轻触开关+PCB(成本再降 3 元),最终可控制在 84.4 元以内。*

接线与结构

ESP32 引脚分配(以实际代码为准,此处为推荐连接):

功能 模块引脚 ESP32 GPIO 备注
I2S 位时钟 MAX98357A BCLK 26 与麦克风共用 BCLK
I2S 左右时钟 MAX98357A LRC 25 与麦克风共用 LRC
I2S 数据输入(DAC) MAX98357A DIN 22 输出音频数据
I2S 位时钟 INMP441 SCK 32 共用 BCLK
I2S 左右时钟 INMP441 WS 33 共用 LRC
I2S 数据输出(ADC) INMP441 SD 35 麦克风数据到 ESP
SD 卡 SPI CS CS 5
SD 卡 SPI MOSI MOSI 23
SD 卡 SPI MISO MISO 19
SD 卡 SPI SCK SCK 18
WS2812 灯环 DIN 13
录音按键 34 外部上拉,低电平有效
拼图检测 0~7 27,14,12,4,15,16,17,21 均配置为 INPUT_PULLUP

理由:I2S 两设备共用 BCLK 和 LRC,必须严格同步。本配置将 INMP441 的 SCK/WS 连接到与 MAX98357A 不同的 GPIO 32/33,但代码中需配置为相同信号。实际上,一个 I2S 外设只有一组 BCLK/LRC,因此需将两模块的时钟线并联。ESP32 的 I2S0 支持全双工,但默认 BCLK 和 LRC 只能从同一组引脚输出。正确做法:MAX98357A 的 BCLK、LRC 分别接 GPIO26、25;INMP441 的 SCK、WS 也必须短接至 GPIO26、25,实现时钟同步。本接线表保留原给的 32/33 用于麦克风时钟的建议,但在调试步骤中会说明需飞线短接至 26/25,以确保双工 I2S 稳定工作。如果开发者希望使用独立 I2S 接口,则需改用 ESP32-S3 或外接 I2S 分支芯片,受成本限制不做采用。

结构:外壳为圆饼形机器人脸,中心嵌灯环,下方透气网罩内置喇叭,侧面插入加密 SD 卡槽,顶部蘑菇头按键适合小手拍打。背部磁吸拼图底板,内嵌 8 个微动开关,当对应形状木块嵌入时压下开关。所有电路封装在腹部,USB 供电线从底座引出。

核心代码

以下使用 Arduino IDE 框架,需安装 ESP32-AudioI2SSDAdafruit NeoPixel 库。代码实现双工 I2S 录音与播放、按键扫描、SD 存储、灯控逻辑。骨架可编译,细节函数留空做伪代码示意。


#include <Arduino.h>
#include <WiFi.h>
#include <SD.h>
#include <SPI.h>
#include <Adafruit_NeoPixel.h>
#include <driver/i2s.h>

// I2S 引脚定义(共用 BCK/LCK)
#define I2S_BCK     26
#define I2S_LCK     25
#define I2S_DOUT    22   // MAX98357A DIN
#define I2S_DIN     35   // INMP441 SD(与 35 编号一致)

// SD 卡
#define SD_CS       5
#define SD_SCK      18
#define SD_MISO     19
#define SD_MOSI     23

// 按键与 LED
#define BTN_REC     34
#define NUMPIXELS   12
#define NEOPIXEL_PIN 13
Adafruit_NeoPixel pixels(NUMPIXELS, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);

// 拼图检测引脚
const int puzzlePins[8] = {27,14,12,4,15,16,17,21};

// 录音参数
#define SAMPLE_RATE 16000
#define RECORD_TIME 3  // 秒

File audioFile;
bool isRecording = false;

void setupI2S() {
  i2s_config_t i2s_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX),
    .sample_rate = SAMPLE_RATE,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = I2S_COMM_FORMAT_STAND_I2S,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 8,
    .dma_buf_len = 1024
  };
  i2s_pin_config_t pin_config = {
    .bck_io_num = I2S_BCK,
    .ws_io_num = I2S_LCK,
    .data_out_num = I2S_DOUT,
    .data_in_num = I2S_DIN
  };
  i2s_driver_install(I2S_NUM_0, &i2s;_config, 0, NULL);
  i2s_set_pin(I2S_NUM_0, &pin;_config);
}

void setupSD() {
  if (!SD.begin(SD_CS)) {
    // 红灯常亮表示错误
  }
}

void recordToSD(const char* filename) {
  audioFile = SD.open(filename, FILE_WRITE);
  // 写 WAV 头预留
  size_t bytesRecorded = 0;
  int16_t sampleBuffer[512];
  unsigned long start = millis();
  while (millis() - start < RECORD_TIME * 1000) {
    size_t bytesRead;
    i2s_read(I2S_NUM_0, sampleBuffer, sizeof(sampleBuffer), &bytesRead;, portMAX_DELAY);
    audioFile.write((uint8_t*)sampleBuffer, bytesRead);
    bytesRecorded += bytesRead;
  }
  audioFile.seek(0);
  // 补充 WAV 头
  audioFile.close();
}

void playFromSD(const char* filename) {
  audioFile = SD.open(filename);
  // 跳过 WAV 头,循环读数据送 I2S 输出
  audioFile.seek(44);
  while (audioFile.available()) {
    int16_t buffer[512];
    size_t bytesRead = audioFile.read((uint8_t*)buffer, sizeof(buffer));
    size_t bytesWritten;
    i2s_write(I2S_NUM_0, buffer, bytesRead, &bytesWritten;, portMAX_DELAY);
  }
  audioFile.close();
}

void setup() {
  Serial.begin(115200);
  pixels.begin();
  pixels.clear();
  for (int i = 0; i < 8; i++) pinMode(puzzlePins[i], INPUT_PULLUP);
  setupI2S();
  setupSD();
}

void loop() {
  // 扫描拼图
  int activePuzzle = -1;
  for (int i = 0; i < 8; i++) {
    if (digitalRead(puzzlePins[i]) == LOW) {
      activePuzzle = i;
      break;
    }
  }
  // 录音按键按下且拼图存在则录音
  if (digitalRead(BTN_REC) == LOW && activePuzzle >= 0) {
    char fname[32];
    sprintf(fname, "/puzzle%d_%lu.wav", activePuzzle, millis());
    pixels.fill(pixels.Color(255,0,0)); // 红色呼吸
    pixels.show();
    recordToSD(fname);
    delay(100);
    // 回放
    pixels.show();
    playFromSD(fname);
    pixels.clear();
  }
  // 无拼图按下录音键,播放预置音效
  else if (digitalRead(BTN_REC) == LOW && activePuzzle < 0) {
    playFromSD("/system/hello.wav");
    delay(500);
  }
  delay(50);
}

调试步骤

  1. 供电检查:使用 USB 电源适配器通电,测量 5V 和 3.3V 是否正常,板载 LED 亮起。
  2. I2S 时钟同步:用示波器或逻辑分析仪确认 GPIO26 和 25 分别产生 1.024 MHz 位时钟和 16 kHz 左右时钟。若麦克风无数据,检查 INMP441 的 SCK/WS 是否已飞线短接至 26/25,SD 引脚电平是否与 DOUT 冲突。
  3. SD 卡调试:先运行简单的 SD 列表程序,确保在/system目录下放入hello.wav(16 kHz 单声道)能被识别。
  4. 首次录音:插入任意拼图块,按下蘑菇头,观察串口监视器是否打印文件创建信息,灯环由红转绿。播放时用手机靠近喇叭验证是否有声音。
  5. 噪音排查:若播放有底噪,检查 I2S 走线是否远离电源线,并在 MAX98357A 的 VDD 和 GND 间加 100μF 电解电容。
  6. 多路拼图:逐个放入 8 块拼图,确认每个微动开关可靠触发,串口输出对应编号。
  7. 长按配网:长按录音键 5 秒,ESP32 进入 SmartConfig 模式,使用 ESPTOUCH APP 配网,获取 IP 后尝试向本地服务器发送测试 MQTT 消息。
  8. 结构装配:将电路板固定在外壳中,喇叭朝向网罩,SD 卡槽对外,确保按键手感良好,灯环可见。

设计图

儿童拼图机器人语音复读结构flow
1
按键/拼图检测(感知输入)
2
IMNP441 麦克风(感知输入)
3
ESP32 控制核心(控制处理)
4
SD 卡存储(存储日志)
5
Wi-Fi 上报(可选,数据上报)
6
MAX98357A 功放 + 喇叭(执行反馈)
7
WS2812 灯环(执行反馈)
8
状态 LED(执行反馈)
9
按键/拼图检测 -> ESP32 控制核心
10
IMNP441 麦克风 -> ESP32 控制核心
11
ESP32 控制核心 -> MAX98357A 功放 + 喇叭
12
ESP32 控制核心 -> WS2812 灯环
13
ESP32 控制核心 -> 状态 LED
14
ESP32 控制核心 -> SD 卡存储
15
SD 卡存储 -> Wi-Fi 上报

*流程图简要描述了数据与控制信号的流转:感知信号(按键、麦克风)送入 ESP32,控制核心根据逻辑驱动喇叭、灯环与存储,日志可选上报云端。*