一、任务介绍
本次基于乐鑫推出的ESP32-S3 Sense核心开发板,搭建了一个本地音频播放、可视化动态灯效、语音控制及远程网页交互的智能语音点歌音乐盒。
任务核心要求包括:
• 音频播放:预置至少3段旋律,通过外接蜂鸣器播放。
• 视觉反馈:利用RGB灯带根据音乐节拍或音符强弱实现动态律动效果。
• 智能交互:基于Edge Impulse部署麦克风关键词识别,实现“播放/暂停”、“切歌(上一首/下一首)”、“音量调节”等语音指令,且必须包含曲目切换功能。
• 本地显示:通过OLED屏幕实时显示曲目编号、播放进度百分比及当前音量等级。
远程管控:搭建Web服务器,允许用户通过网页远程选曲、监控进度及调整音量。

二、项目介绍
随着物联网与边缘人工智能的快速发展,边缘设备正向更自然的交互方向发展。本任务利用ESP32-S3 Sense强大的双核处理器,实现了智能的音乐播放功能,引入了Edge Impulse训练的轻量级语音模型,使得设备无需联网即可响应特定语音指令,保护了隐私并降低了延迟。同时,结合RGB灯带的可视化与OLED的状态显示,网页可视化的进一步扩展了设备的可视性和可控性,使其诞生成智能语音点歌音乐盒。
三、硬件介绍
本任务使用硬件如下:
四、方案框图和项目设计思路
系统方案框图:

项目设计思路:
在ESP32-S3 Sense开发板上构建一个集语音控制、物理旋钮调节音量与网页远程操作于一体的本地化智能音乐播放器,通过边缘AI(Edge Impulse)实现离线语音识别,结合蜂鸣器播放旋律、RGB灯带节拍同步、OLED状态显示,形成多模态人机交互体验,全程可离线运行、在线Web页面访问控制,实现高集成度的嵌入式智能系统设计理念。
五、软件流程图和关键代码介绍
开发环境与工具
• IDE: Arduino IDE,Edge Impulse导出的Arduino库兼容性较好。
• 语音识别AI工具: Edge Impulse Studio,用于数据采集、模型训练和代码压缩包导出。
• 调试工具:串口监视器、万用表。
软件准备、开发环境搭
1.下载安装Arduino IDE
官网地址:https://www.arduino.cc/en/software/
2.将Seeed Studio XIAO添加到Arduino IDE中
File > Preferences,并在 "Additional Boards Manager URLs" 中填入以下网址:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

在Tools > Board > Boards Manager 搜索esp32,安装即可
3.在IDE顶部选择COM口和对应的开发板

菜单栏:包含文件、编辑、草图、工具和帮助,如新建、保存、示例程序、选择串口等。
横向工具栏:包含多个常用功能按钮:验证、上传、调试、板选、串行绘图仪和串行显示器选择。
垂直工具栏:包含项目文件夹、板管理器、库管理器、调试和搜索的快捷方式。
代码编辑区:这是你写程序代码的地方,就像我们在Word窗口中通常输入文本一样。在这部分写代码。
串口显示器:输出窗口:在水平工具栏右侧,你可以打开或关闭串行显示器窗口。
Edge Impulse
1.创建新项目,在Edge Impulse界面新建训练项目,点击“Create new project”。 选择自己的项目名,选择“Audio”作为数据类型,创建即可。

2.采集语音样本,我这里使用自己手机录制的语音样本,如果采用ESP32-S3直接录制上传,应该会更精准。
3.检查并把效果不佳的数据删除,创建Impulse,生成并验证特征,在Feature explorer中记得查看不同关键词的图谱是否有差异

4.接着进行训练神经网络模型,等待2~5分钟,观察准确率(目标≥95%)
5.模型训练完成后,可以进入Model testing对模型进行测试,没问题后在Deployment中部署为Arduino库。
6.成到Arduino项目,在Arduino中选择导入库即可。使用时对库文件进行调用。
软件流程图

关键代码介绍
1. 蜂鸣器播放单音
void playCurrentNote() {
int* mel = melodies[currentSong];
int idx = currentNoteIdx * 2;
int note = mel[idx];
int divider = mel[idx + 1];
int wholenote = (60000 * 4) / tempos[currentSong];
int noteDuration;
if (divider > 0) {
noteDuration = wholenote / divider;
} else {
noteDuration = (wholenote / abs(divider)) * 1.5; // 附点音符
}
if (note == NOTE_REST) {
ledcWrite(BUZZER_PIN, 0);
} else {
ledcChangeFrequency(BUZZER_PIN, note, LEDC_RES);
ledcWrite(BUZZER_PIN, (volume * 255) / 100);
}
noteEndTime = millis() + noteDuration * 0.92; // 留一点空隙防粘音
progress = (currentNoteIdx * 100) / melodyLens[currentSong];
}
此部分代码作用为音乐播放器的发声逻辑,根据当前曲目、当前音符索引,计算音高与时值→设置PWM频率→设置占空比(音量)→记录结束时间;
2. 主循环中的播放推进逻辑
if (isPlaying && !isPaused && millis() >= noteEndTime) {
currentNoteIdx++;
if (currentNoteIdx >= melodyLens[currentSong]) {
currentNoteIdx = 0;
progress = 0;
}
playCurrentNote();
}
此部分作为最核心的播放时序控制,每当当前音符时间到,就自动推进到下一个音符,到了曲尾就循环
3. 语音唤醒&命令识别
void handleVoice() {
if (microphone_inference_record()) {
signal_t signal;
signal.total_length = EI_CLASSIFIER_RAW_SAMPLE_COUNT;
signal.get_data = µphone_audio_signal_get_data;
ei_impulse_result_t result = {0};
if (run_classifier(&signal, &result, false) == EI_IMPULSE_OK) {
// 寻找置信度最高的标签
float max_val = 0;
const char* label = "";
for (size_t i = 0; i < EI_CLASSIFIER_LABEL_COUNT; i++) {
if (result.classification[i].value > max_val) {
max_val = result.classification[i].value;
label = result.classification[i].label;
}
}
if (max_val > 0.75) {
// 根据关键词执行对应操作
if (strstr(label, "播放") || strstr(label, "play")) { ... }
else if (strstr(label, "暂停") || strstr(label, "pause")) { ... }
else if (strstr(label, "下一首") || strstr(label, "next")) { ... }
else if (strstr(label, "上一首") || strstr(label, "prev")) { ... }
}
}
}
}
这里是整个代码中很关键的节点,离线语音指令识别(Edge Impulse模型),最有“智能”感的部分,也是代码复杂度最高的地方之一。训练模型的过程比较久,录了很多遍,最后也是找到点规律出来。
六、功能展示图及说明
实物展示:

智能语音点歌音乐盒整体的俯视图。板子右侧侧连接着一条点亮了的彩色WS2812B灯带,呈现出随音乐跳动的彩色波纹。板子正中间是OLED屏幕,屏幕上清晰显示着“Star”、“Playing”、“Vol: 2”。此图片展示了系统的整体硬件连接状态,OLED实时反馈播放信息,RGB灯带直观展示节拍律动。

屏幕显示内容:Song:Star
State:PLAYING
VoL:0% Prog:14%
语音控制演示:

此图片是串口监视器的打印日志。日志中显示:“Voice: play (85%)”,随后下一行显示“Voice: noise (99%)”。证明Edge Impulse模型成功部署并准确识别了“播放”指令,实现了离线语音控制播放。

此图片的日志中显示:“Voice: pause(93%)”,识别到了“暂停”指令,实现了离线语音控制暂停。

此图片的日志中显示:“Voice: prev(75%)”,识别到了“上一首”指令,实现了离线语音控制切歌。
Web远程控制台:

此图片是电脑浏览器界面的截图。界面设计简洁,在页面中可进行“上一首”、“播放/暂停”、“下一首”三个大按钮。界面数据与设备端OLED显示保持实时同步。
七、项目中遇到的难题及解决方法
1.Edge Impulse库导入后函数未声明
编译时报microphone_inference_start、microphone_inference_record等函数未声明,即使#include 已存在。
解决:手动删除文件夹--Documents\Arduino\libraries\找到对应的文件夹进行删除
再重新从Edge Impulse下载正确的ZIP,并导入Arduino IDE中。
2.语音识别准确率受环境噪音影响大
此问题是个大难题,好不容易训练好模型后,手机测试一切正常,但导入到开发板中很难准确的分析出来,这可能也是我使用的录制工具是手机本身的缘故;
解决:让"noise"类样本占比至少40-50%。增加模型训练次数,并提升代码中的置信度,提高置信度能过滤很大一部分的误识别。增加"unknown"类:除了"noise"(背景音),再加一类"unknown"(其他无关人说话、咳嗽、笑声等),防止模型把非关键词语音误判成指令。(这里录制其他类的方法在群中也看到有伙伴分享)。
八、心得体会
通过本次ESP32-S3 Sense的智能音乐播放盒项目(集成无源蜂鸣器旋律播放、RGB灯带节拍变化、电位器音量控制、OLED显示、网页远程控制及显示、Edge Impulse关键词语音识别),我深刻体会到了软硬结合与边缘智能的魅力。
过程中,Edge Impulse训练模型本身很快,但环境噪音在实际识别时,准确率会崩得特别惨。后来大量补噪声样本+ unknown类后,才从“基本不能用”变成“日常能用”。
远程控制与实时状态反馈这个闭环,极大提升了个人体验,也让我意识到,一个好的物联网项目,往往不是功能多,而是“与人交互是否自然、是否方便”。
在进行本活动时个人感觉最有成就感的时刻是第一次说播放,串口打印“play”并且开始播放、灯带开始变化。情绪价值拉满!
总的来说,这个项目虽然不大,但对XIAO这块“麻雀虽小五脏俱全”的开发板学习很多,后续还想尝试连接MQTT、Home Assistant等等功能。踩坑的过程很痛苦,但每解决一个问题,系统就更稳定、我个人也会成长一点。
最后,非常感谢硬禾科技举办2026年第6届“寒假在家一起练”,本次也是我第一次参加寒假在家一起练活动,刚开始还有点忐忑自己能不能全部完成,但看到直播老师很全面的讲解,安心很多。感谢群内非常专业靠谱的答疑老师,直播课讲解很细致的直播老师,让我学到了很多知识。让我们能够深入体验这块开发板的功能,期待后续能继续此类活动,并探索AI对话、视觉等更多有趣的硬件和技术。