智能语音氛围灯带总结报告
本项目旨在开发一个基于XIAO ESP32S3 Sense的智能语音控制氛围灯带。该系统集成了语音识别、LED灯光控制以及按键控制等多种功能,使用音频信号来控制灯带的模式,提供了一种智能化的氛围灯光解决方案。在本报告中,将详细阐述该项目的整体设计思路、所涉及的硬件与软件组件、调试过程中遇到的问题及其解决方法,以及在项目实施中的心得体会。
1. 项目概述
随着智能灯光的不断发展,语音控制技术在日常生活中逐渐获得广泛应用。为了提升居家氛围,本项目开发了一个基于Arduino平台的智能语音控制氛围灯带。该项目的目标是实现通过语音控制或按钮输入来切换灯带的多种模式,如呼吸灯模式、彩虹灯模式、跑马灯模式等。除此之外,通过OLED显示屏展示当前的灯带模式和其他相关信息。
本次项目中,音频信号由I2S麦克风模块进行采集,通过声音识别判断用户的指令,并根据指令来控制灯带的显示模式。通过Edge impulse网站训练语言,让XIAO ESP32S3 Sense可以识别到个人的声音。用户还可以通过按键切换不同的模式,增加交互性。此项目的重点在于将硬件与软件的深度集成,使得语音控制和按钮控制能够无缝切换,并且能够对灯光信息进行实时反馈。
2. 硬件设计
本项目的硬件平台基于XIAO ESP32S3 Sense开发板,所有的硬件组件都通过XIAO ESP32S3 Sense的GPIO引脚与开发板进行连接。具体使用的硬件组件包括:
- XIAO ESP32S3开发板:作为主控板,负责接收输入信号并控制其他硬件设备的工作。
- NeoPixel LED灯带:用于显示各种灯光效果,支持RGB三色调节。通过控制LED的亮度和颜色,可以实现呼吸灯、彩虹灯等效果。
- OLED显示屏:通过I2C总线与Arduino连接,实时显示系统的工作状态,包括当前的灯光模式、亮度等信息。
- 无源蜂鸣器:用于提供声音提示,帮助用户更直观地感知系统状态。
- I2S麦克风模块:用于采集环境音频信号,配合语音识别算法判断用户指令。
- 按键开关:用于手动切换不同的灯光模式。
图1 总体方案框图
通过合理连接这些硬件设备,系统能够实现语音和按键的双重控制,灵活切换多种灯光效果,并通过OLED屏显示实时的温湿度信息,提升用户体验,如图1所示。
3. 软件设计
在软件设计方面,本项目采用了C/C++编程语言,使用Arduino IDE进行开发。首先通过初始化相关硬件,然后创建四个FreeRTOS任务循环如图2所示,系统的软件流程主要分为以下几个模块:

图2 软件流程图
- 音频采集与处理:音频信号通过I2S麦克风模块采集后,系统对采集到的音频数据进行处理,提取出特征并送入分类器进行识别。分类器基于预先训练好的模型,通过对音频特征的分析,判断用户的指令并做出响应。
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 };
EI_IMPULSE_ERROR r = run_classifier(&signal, &result, debug_nn);
if (r != EI_IMPULSE_OK) {
ei_printf("ERR: Failed to run classifier (%d)\n", r);
return;
}
int pred_index = 0; // Initialize pred_index
float pred_value = 0; // Initialize pred_value
// print the predictions
ei_printf("Predictions ");
ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
result.timing.dsp, result.timing.classification, result.timing.anomaly);
ei_printf(": \n");
for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
ei_printf(" %s: ", result.classification[ix].label);
ei_printf_float(result.classification[ix].value);
ei_printf("\n");
if (result.classification[ix].value > pred_value){
pred_index = ix;
pred_value = result.classification[ix].value;
}
}
- 语音识别:语音识别模块通过音频信号中的音量特征来判断用户是否发出了有效指令。当音量超过预设的阈值时,系统会识别出用户的指令,并根据指令切换不同的灯光模式。
for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
ei_printf(" %s: ", result.classification[ix].label);
ei_printf_float(result.classification[ix].value);
ei_printf("\n");
if (result.classification[ix].value > pred_value){
pred_index = ix;
pred_value = result.classification[ix].value;
}
}
if (result.classification[1].value > 0.7f) {
next_flag = 1;
}
else if (result.classification[0].value > 0.7f) {
close_flag = 1;
}
else if (result.classification[2].value > 0.8f) {
open_flag = 1;
}
- LED控制:系统通过NeoPixel库控制LED灯带的显示效果。根据用户的指令或按键输入,系统通过状态机来切换不同的灯光模式,例如呼吸灯、彩虹灯、跑马灯等。每个模式都有其独特的控制算法,通过调整LED的亮度和颜色来实现不同的视觉效果。
switch (led_mode){
case 0:
strip.clear(); //关闭灯光
strip.show();
break;
case 1:
light_PWM_run();//呼吸灯
break;
case 2:
light_rgb_rainbowrun();//彩虹灯
break;
case 3:
singleDotMarquee();//跑马灯
break;
default:
break;
- 按键控制:用户可以通过按键来切换不同的灯光模式。按键的输入通过模拟读取,并进行去抖动处理,以确保按键的准确识别。
if(open_flag == 1){
led_mode = 1;
buzzer_run();
open_flag = 0;
}
if(next_flag == 1 && led_mode != 0){
buzzer_run();
led_mode = (led_mode + 1) % 4; // 循环切换 1,2,3
if(led_mode == 0)
led_mode = led_mode + 1;
next_flag = 0;
}
if(close_flag){
led_mode = 0;
buzzer_run();
close_flag = 0;
}
if(PWM_flag){
lightness += 10;
buzzer_run();
if(lightness > 250)
lightness = 50;
PWM_flag = 0;
}
- OLED显示:OLED显示屏通过I2C通信协议与Arduino进行连接,实时显示灯光模式、亮度以及温湿度数据,增强系统的交互性。
switch (led_mode){
case 0:
display.clearDisplay();
display.setCursor(0, 0); // 设置光标位置 (x, y)
display.print("mode: ");
display.setCursor(0, 10); // 第二行文本,y 坐标下移
display.print("lightness: ");
display.setCursor(0, 20); // 第二行文本,y 坐标下移
display.print("PWM: ");
display.display();
break;
case 1:
display.clearDisplay();
display.setCursor(0, 0); // 设置光标位置 (x, y)
display.print("mode:Breathing");
display.setCursor(0, 10); // 第二行文本,y 坐标下移
display.print("lightness: ");
display.print(lightness);
display.setCursor(0, 20); // 第二行文本,y 坐标下移
display.print("PWM: ");
display.print(breathStep);
display.display();
break;
case 2:
display.clearDisplay();
display.setCursor(0, 0); // 设置光标位置 (x, y)
display.print("mode:rianbow");
display.setCursor(0, 10); // 第二行文本,y 坐标下移
display.print("lightness: ");
display.print(lightness);
display.setCursor(0, 20); // 第二行文本,y 坐标下移
display.print("PWM: ");
display.print(breathStep);
display.display();
break;
case 3:
display.clearDisplay();
display.setCursor(0, 0); // 设置光标位置 (x, y)
display.print("mode:Marquee");
display.setCursor(0, 10); // 第二行文本,y 坐标下移
display.print("lightness: ");
display.print(lightness);
display.setCursor(0, 20); // 第二行文本,y 坐标下移
display.print("PWM: ");
display.print(updateInterval);
display.display();
break;
default:
break;
- 主函数代码:使用了FreeRTOS,采用了2个核来运行,对于语音采集和识别用了内核0,而模式切换、按键和灯光效果用了内核1。
// 创建任务
xTaskCreatePinnedToCore(capture_samples,"CaptureSamples",1024 * 8,NULL,3,NULL,0);
xTaskCreatePinnedToCore(Sound_Run_TASK, "TaskA", 18000, NULL, 2, &TaskAHandle, 0);
xTaskCreatePinnedToCore(get_digital_value, "TaskB", 4096, NULL, 1, &TaskBHandle, 1);
xTaskCreatePinnedToCore(mode_Run_TASK, "TaskC", 4096, NULL, 2, &TaskCHandle, 1);
xTaskCreatePinnedToCore(updateDisplay_TASK, "TaskD", 4096, NULL, 1, &TaskDHandle, 1);
- 滑动窗口算法:送进模型的一整段音频,代码中对应的 1 秒,每次窗口往前挪120ms,让识别变得更丝滑。
static void sliding_window_push(const int16_t *newData, size_t newLen)
{
if (newLen >= INFER_WINDOW_SAMPLES) {
memcpy(slidingWindow,
newData + (newLen - INFER_WINDOW_SAMPLES),
INFER_WINDOW_SAMPLES * sizeof(int16_t));
windowFilled = INFER_WINDOW_SAMPLES;
return;
}
memmove(slidingWindow,
slidingWindow + newLen,
(INFER_WINDOW_SAMPLES - newLen) * sizeof(int16_t));
memcpy(slidingWindow + (INFER_WINDOW_SAMPLES - newLen),
newData,
newLen * sizeof(int16_t));
if (windowFilled < INFER_WINDOW_SAMPLES) {
windowFilled += newLen;
if (windowFilled > INFER_WINDOW_SAMPLES) {
windowFilled = INFER_WINDOW_SAMPLES;
}
}
}
static int sliding_audio_signal_get_data(size_t offset, size_t length, float *out_ptr)
{
for (size_t i = 0; i < length; i++) {
out_ptr[i] = (float)slidingWindow[offset + i];
}
return 0;
}
软件设计中的主要难点在于音频信号的采集与处理,尤其是如何根据采集到的音频信号准确判断用户的指令。在这个过程中,我们通过调整音频处理算法、优化分类模型,提高了系统对环境噪声的鲁棒性,确保语音识别的准确性。
4. 项目调试与挑战
实物展示


图3 实物展示
在项目开发和调试过程中,我们遇到了一些挑战,主要包括以下几个方面:
- 语音识别准确性问题:由于环境噪声的影响,语音识别的准确性在初期表现较差。为了解决这个问题,通过加入噪音进去迭代并调整阈值,而且还加入了滑动窗口算法让语音识别更流畅,确保只有有效的音频信号能够被识别为指令。
- 硬件兼容性问题:在初步搭建硬件时,XIAO ESP32S3 Sense开发板与Arduino版本的兼容性出现问题,特别是在I2S麦克风模块的配置上。通过查阅资料并更新相关库文件,最终解决了硬件兼容性问题。
- LED控制延迟问题:在测试过程中,LED灯带的控制响应有时存在延迟,影响了用户的体验。我们通过优化LED控制算法,减少了代码执行中的延迟,显著提高了灯带的响应速度。
5. 项目心得体会
通过本项目的开发与调试,我学到了很多关于Arduino平台开发的知识,尤其是在硬件控制、传感器数据采集、音频信号处理和语音识别等方面。在硬件设计方面,我掌握了如何将多个硬件组件连接并通过XIAO ESP32S3进行控制;在软件开发方面,我深入学习了如何进行音频信号处理,并应用机器学习算法进行语音识别。通过调试,我还学到了如何在遇到问题时通过分析代码和硬件数据进行排错,优化系统性能。
最重要的是,本项目让我理解了XIAO ESP32S3 Sense的集成与应用。从硬件的选择到软件的编写,再到系统的调试与优化,每一步都充满了挑战,也让我体验到了开发一个实际可用产品的成就感。这次项目的经验为我未来从事嵌入式系统开发和智能硬件设计打下了坚实的基础。
6. 结语
总的来说,本项目成功实现了通过语音和按键控制的智能氛围灯带,系统能够根据语音或按钮指令切换灯带模式。虽然在开发过程中遇到了一些技术挑战,但通过不断的调试与优化,最终实现了预期的功能。这个项目不仅让我深入理解了嵌入式开发的流程,也让我对XIAO ESP32S3 Sense的应用有了更深入的了解。未来,我希望能在此基础上,进一步提升语音识别的精度,并增加更多智能功能,使其成为更加完善的智能氛围灯带系统。