1. 基于ESP32的唤醒词检测入门

任务目标

在ESP32上实现一个基于唤醒词检测的LED控制原型:当麦克风捕捉到预设唤醒词“Hi, 乐鑫”时,开发板上的LED点亮;未检测到唤醒词时LED保持熄灭。本案例聚焦于唤醒词检测的完整最小链路,不涉及命令词识别或多轮对话。

环境与依赖

  • 硬件:ESP32-S3-Korvo-2开发板(板载ES7210双麦克风阵列与ES8311音频编解码器)
  • 软件框架:ESP-SR(乐鑫语音识别库)v1.2及以上,ESP-IDF v5.2及以上
  • 唤醒词模型:使用ESP-SR预置的“Hi, 乐鑫”中文唤醒词模型(wakenet7)
  • LED连接:开发板GPIO 4(板载RGB LED的绿色通道,低电平点亮)

实现原理

ESP-SR的WakeNet模型持续从麦克风采集音频流并执行本地唤醒词检测。当模型置信度超过阈值时,回调函数被触发。本案例在回调中翻转LED状态,实现唤醒即点亮的直观反馈。音频采样率16kHz、单声道、16bit,由编解码器驱动自动完成。

关键完整代码


#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "esp_afe_sr_models.h"
#include "esp_wakenet.h"
#include "esp_audio_processing.h"
#include "board.h"

#define LED_GPIO  4
#define WAKE_WORD "Hi, 乐鑫"

static const char *TAG = "wake_demo";
static bool led_state = false;

// 唤醒回调:检测到唤醒词时翻转LED
static void wake_word_cb(void *arg)
{
    led_state = !led_state;
    gpio_set_level(LED_GPIO, led_state ? 0 : 1);  // 低电平点亮
    ESP_LOGI(TAG, "Wake word detected! LED %s", led_state ? "ON" : "OFF");
}

void app_main(void)
{
    // 配置LED GPIO
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << LED_GPIO),
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    gpio_config(&io_conf);
    gpio_set_level(LED_GPIO, 1);  // 初始熄灭

    // 初始化音频前端(AFE)
    afe_config_t afe_config = {
        .aec_init = true,
        .aec_dereverb = false,
        .se_init = true,
        .vad_init = true,
        .wakenet_init = true,
        .voice_activation_init = false,
        .vtsv_init = false,
        .afe_mode = AFE_MODE_LOW_COST,
        .afe_perferred_core = 0,
        .afe_perferred_priority = 5,
        .afe_ringbuf_size = 10,
        .memory_alloc_mode = AFE_MEMORY_ALLOC_MODE_AGGRESSIVE,
        .agc_init = true,
        .agc_gain = 10,
        .pcm_config = {
            .total_ch_num = 2,
            .mic_num = 2,
            .ref_num = 0,
            .sample_rate = 16000,
            .bits = 16,
            .channel = 2,
        }
    };

    // 加载WakeNet7模型(支持"Hi, 乐鑫")
    model_info_t *model_info = esp_wakenet_get_model_info(WAKE_WORD);
    if (model_info == NULL) {
        ESP_LOGE(TAG, "Wake word model not found");
        return;
    }

    // 创建AFE句柄
    afe_handle_t afe_handle = esp_afe_create(model_info, &afe_config);
    if (afe_handle == NULL) {
        ESP_LOGE(TAG, "Failed to create AFE");
        return;
    }

    // 注册唤醒回调
    esp_afe_register_wakenet_callback(afe_handle, wake_word_cb, NULL);

    // 启动音频采集与处理
    esp_afe_start(afe_handle);

    ESP_LOGI(TAG, "Wake word detection started. Say \"%s\"", WAKE_WORD);

    // 主循环保持运行
    while (1) {
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

编译与烧录


# 在ESP-IDF环境中执行
idf.py set-target esp32s3
idf.py menuconfig  # 在"ESP-SR"菜单中确认WakeNet7模型已启用
idf.py build
idf.py -p /dev/ttyUSB0 flash monitor

验证方法

  1. 烧录完成后,开发板串口输出日志显示 Wake word detection started。
  2. 在距开发板约0.5~1米处清晰说出“Hi,乐鑫”(注意与模型训练口音匹配)。
  3. 观察板载LED:检测成功时绿色LED点亮,同时串口打印 Wake word detected! LED ON。
  4. 再次说出唤醒词,LED熄灭,日志显示 LED OFF。
  5. 说其他词语(如“你好”)不应触发LED变化。

通过标准:连续测试10次唤醒词,至少8次成功触发LED翻转;非唤醒词不触发。若触发率偏低,可调整麦克风增益(agc_gain)或缩短说话距离。

常见问题

  • 编译报错找不到模型:确认在menuconfig中启用了CONFIG_ESP_SR_WAKENET7,且模型文件已通过idf.py flash烧录到spiffs分区。
  • 唤醒无响应:检查串口日志是否有AFE初始化错误;确认开发板麦克风阵列未被遮挡,且音频编解码器驱动(board_init())已在更早的初始化中调用。
  • 误唤醒频繁:可尝试在AFE配置中启用vad_init并调整VAD阈值,或更换为更严格的WakeNet8模型。