ESP32接入百度云,在线语音识别

本文介绍了如何在ESP32_LyraTv4.3开发板上使用ESP-ADF进行百度语音识别,涉及环境配置、语音数据采集、API配置和实际应用示例。通过离线方式实现,并能在嘈杂环境下保持高识别率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1开发环境及工具

开发板使用的是ESP32_LyraTv4.3,入下图所示,开环境在是在Ubuntu20.04上搭建的ESP-IDF,在ESP-IDF中添加了支持语音开发的sdk,ESP-ADF。

2开发过程

参考的例程为adf中esp-adf/examples/speech_recognition/asr这个目录下面的程序,这个目录中包含了离线的语音识别,其中包含了原始语音数据的采集。

3注意事项

参考ESP32开发(6)esp-adf:百度语音识别_lovehanchenchen的博客-优快云博客_esp32 百度语音识别

上面这位大佬对语音数据的采集,其中在申请内存的时候需要在配置中开启SPIRAM,如下图所示。

 在配置菜单中添加自己在百度云平台申请的的API_key和access secret,这个配置是我在Kconfig.projbuild文件中添加的,添加后idf.py menuconfig后就会出现这个配置,然后编译后就会把配置项编译到build文件下面的"sdkconfig.h"文件,使用时只需要include就行。

 下面是全部的源码,烧写到板子上后,自动连接上wifi,然后点击Rec按键,说话就能支持显示出返回的汉字。

4源码

/* Examples of speech recognition with multiple keywords.

    This example code is in the Public Domain (or CC0 licensed, at your option.)

    Unless required by applicable law or agreed to in writing, this
    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    CONDITIONS OF ANY KIND, either express or implied.
*/

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "board.h"
#include "rom/spi_flash.h"
#include "audio_pipeline.h"
#include "fatfs_stream.h"
#include "i2s_stream.h"
#include "raw_stream.h"
#include "esp_audio.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "esp_wn_iface.h"
#include "esp_wn_models.h"
#include "esp_mn_iface.h"
#include "esp_mn_models.h"
#include "sdkconfig.h"
#include "mp3_decoder.h"
#include "filter_resample.h"
#include "rec_eng_helper.h"
#include "http_stream.h"
#include "esp_peripherals.h"
#include "periph_wifi.h"
#include "board.h"
#include "esp_http_client.h"
#include "baidu_access_token.h"
#include "audio_event_iface.h"
#include "periph_button.h"

#if __has_include("esp_idf_version.h")
#include "esp_idf_version.h"
#else
#define ESP_IDF_VERSION_VAL(major, minor, patch) 1
#endif

//添加wifi功能时,需要添加这个部分,如果不添加会出现一直重启的现象,我实验时是这样的。
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0))
#include "esp_netif.h"
#else
#include "tcpip_adapter.h"
#endif

static const char *TAG = "example_asr_keywords";

static char *baidu_access_token = NULL;
static char request_data[1024];
//http client处理函数  这个函数会在接到数据后打印出数据内容
esp_err_t _http_event_handle(esp_http_client_event_t *evt)
{
    switch (evt->event_id)
    {
    case HTTP_EVENT_ERROR:
        ESP_LOGI(TAG, "HTTP_EVENT_ERROR");
        break;
    case HTTP_EVENT_ON_CONNECTED:
        ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
        break;
    case HTTP_EVENT_HEADER_SENT:
        ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");
        break;
    case HTTP_EVENT_ON_HEADER:
        ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER");
        printf("%.*s", evt->data_len, (char *)evt->data);
        break;
    case HTTP_EVENT_ON_DATA:
        ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
        if (!esp_http_client_is_chunked_response(evt->client))
        {
            printf("%.*s", evt->data_len, (char *)evt->data);
        }
        break;
    case HTTP_EVENT_ON_FINISH:
        ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
        break;
    case HTTP_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
        break;
    }
    return ESP_OK;
}
//这个就是我们的语音识别任务
void asr_baidu_task(void *pv)
{

    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES)
    {
        // NVS partition was truncated and needs to be erased
        // Retry nvs_flash_init
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0))
    ESP_ERROR_CHECK(esp_netif_init());
#else
    tcpip_adapter_init();
#endif

#if defined CONFIG_ESP_LYRAT_V4_3_BOARD
    gpio_config_t gpio_conf = {
        .pin_bit_mask = 1UL << get_green_led_gpio(),
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = 0,
        .pull_down_en = 0,
        .intr_type = 0};
    gpio_config(&gpio_conf);
#endif
    ESP_LOGI(TAG, "[ 1 ] Initialize Buttons & Connect to Wi-Fi network, ssid=%s", CONFIG_WIFI_SSID);

    //外设配置与初始化wifi  这是添加的wifi功能
    esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
    esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg);
    periph_wifi_cfg_t wifi_cfg = {
        .ssid = CONFIG_WIFI_SSID,
        .password = CONFIG_WIFI_PASSWORD,
    };
    // 初始化wifi
    esp_periph_handle_t wifi_handle = periph_wifi_init(&wifi_cfg);

    // Initialize Button peripheral  这个是添加的按键功能,通过板子上的Rec按键开始录音
    periph_button_cfg_t btn_cfg = {
        .gpio_mask = (1ULL << get_input_mode_id()) | (1ULL << get_input_rec_id()),
    };
    esp_periph_handle_t button_handle = periph_button_init(&btn_cfg);

    esp_periph_start(set, button_handle);
    esp_periph_start(set, wifi_handle);
    periph_wifi_wait_for_connected(wifi_handle, portMAX_DELAY);

    audio_pipeline_handle_t pipeline;
    audio_element_handle_t i2s_stream_reader, filter, raw_read, http_stream_reader;
    bool enable_wn = true;
    uint32_t mn_count = 0;

    ESP_LOGI(TAG, "[ 2.0 ] Create audio pipeline for recording");
    audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
    pipeline = audio_pipeline_init(&pipeline_cfg);
    mem_assert(pipeline);

    ESP_LOGI(TAG, "[ 2.1 ] Create i2s stream to read audio data from codec chip");
    i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
    i2s_cfg.i2s_config.sample_rate = 48000;
    i2s_cfg.type = AUDIO_STREAM_READER;

    i2s_stream_reader = i2s_stream_init(&i2s_cfg);
    ESP_LOGI(TAG, "[ 2.2 ] Create filter to resample audio data");
    rsp_filter_cfg_t rsp_cfg = DEFAULT_RESAMPLE_FILTER_CONFIG();
    rsp_cfg.src_rate = 48000;
    rsp_cfg.src_ch = 2;
    rsp_cfg.dest_rate = 16000;
    rsp_cfg.dest_ch = 1;
    filter = rsp_filter_init(&rsp_cfg);

    ESP_LOGI(TAG, "[ 2.3 ] Create raw to receive data");
    raw_stream_cfg_t raw_cfg = {
        .out_rb_size = 8 * 1024,
        .type = AUDIO_STREAM_READER,
    };
    raw_read = raw_stream_init(&raw_cfg);

    ESP_LOGI(TAG, "[ 3 ] Register all elements to audio pipeline");
    audio_pipeline_register(pipeline, i2s_stream_reader, "i2s");
    audio_pipeline_register(pipeline, raw_read, "raw");

    ESP_LOGI(TAG, "[ 4 ] Set up  event listener");
    audio_event_iface_cfg_t evt_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();
    audio_event_iface_handle_t evt = audio_event_iface_init(&evt_cfg);
    ESP_LOGI(TAG, "[4.2] Listening event from peripherals");
    audio_event_iface_set_listener(esp_periph_set_get_event_iface(set), evt);

    audio_pipeline_register(pipeline, filter, "filter");
    ESP_LOGI(TAG, "[ 4 ] Link elements together [codec_chip]-->i2s_stream-->filter-->raw-->[SR]");
    const char *link_tag[3] = {"i2s", "filter", "raw"};
    audio_pipeline_link(pipeline, &link_tag[0], 3);

    ESP_LOGI(TAG, "[ 5 ] Start audio_pipeline");
    audio_pipeline_run(pipeline);

    while (1)
    {
        audio_event_iface_msg_t msg;
        if (audio_event_iface_listen(evt, &msg, portMAX_DELAY) != ESP_OK)
        {
            ESP_LOGW(TAG, "[ * ] Event process failed: src_type:%d, source:%p cmd:%d, data:%p, data_len:%d",
                     msg.source_type, msg.source, msg.cmd, msg.data, msg.data_len);
            continue;
        }
        if (msg.cmd == PERIPH_BUTTON_PRESSED)
        {
            printf("--------------------Button press!--------------------------------\n");
//这个地方需要在meke menuconfig中开始对SPIRAM的支持
            char *buff = (char *)heap_caps_malloc(96 * 1024, MALLOC_CAP_SPIRAM);
            if (NULL == buff)
            {
                ESP_LOGE(TAG, "Memory allocation failed!");
                // return;
            }
            memset(buff, 0, 96 * 1024);
            ESP_LOGI(TAG, "have key");
            for (size_t i = 0; i < 12; i++)
            {
                raw_stream_read(raw_read, (char *)buff + i * 8 * 1024, 8 * 1024);
            }
            esp_http_client_config_t config =
                {
                    .url = "http://vop.baidu.com/server_api?dev_pid=1537&cuid=123456PHP&token=这儿是你自己的token",
                    .event_handler = _http_event_handle,
                };
            esp_http_client_handle_t client = esp_http_client_init(&config);

            esp_http_client_set_method(client, HTTP_METHOD_POST);
            esp_http_client_set_post_field(client, (const char *)buff, 96 * 1024);
            esp_http_client_set_header(client, "Content-Type", "audio/pcm;rate=16000");
            esp_err_t err = esp_http_client_perform(client);
            if (err == ESP_OK)
            {
                ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %d",
                         esp_http_client_get_status_code(client),
                         esp_http_client_get_content_length(client));
            }
            else
            {
                ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
            }
            esp_http_client_cleanup(client);
            free(buff);
            buff = NULL;
        }
    }
    ESP_LOGI(TAG, "[ 6 ] Stop audio_pipeline");
    audio_pipeline_stop(pipeline);
    audio_pipeline_wait_for_stop(pipeline);
    audio_pipeline_terminate(pipeline);

    /* Terminate the pipeline before removing the listener */
    audio_pipeline_remove_listener(pipeline);

    audio_pipeline_unregister(pipeline, raw_read);
    audio_pipeline_unregister(pipeline, i2s_stream_reader);
    audio_pipeline_unregister(pipeline, filter);

    /* Release all resources */
    audio_pipeline_deinit(pipeline);
    audio_element_deinit(raw_read);
    audio_element_deinit(i2s_stream_reader);
    audio_element_deinit(filter);

    ESP_LOGI(TAG, "[ 7 ] Destroy model");
    vTaskDelete(NULL);
}
void app_main()
{
    esp_log_level_set("*", ESP_LOG_INFO);
    esp_log_level_set(TAG, ESP_LOG_INFO);
    xTaskCreate(asr_baidu_task, "asr_baidu_task", 2 * 4096, NULL, 5, NULL);
}

5效果

 测试了一下在背景嘈杂的情况下也能有较好的识别成功率。初次使用语言识别功能,在此记录下步骤。

### ESP32 语音识别实现方案与教程 #### 使用 ESP32-A1S 开发板实现离线语音控制 LED 灯 ESP32-A1S 是一款基于乐鑫 ESP32 芯片设计的开发板,专为离线语音识别应用而优化。该开发板集成了唤醒词引擎(WakeNet)、离线语音命令识别引擎(MultiNet)以及前端声学算法[^1]。通过这些功能模块,开发者能够快速构建支持语音交互的产品原型。 以下是利用 ESP32-A1S 实现离线语音控制 LED 的基本原理: - **唤醒词检测**:当设备听到预设的唤醒词时被激活。 - **语音命令解析**:在唤醒状态下接收用户的语音指令,并将其转换为对应的控制信号。 - **执行动作**:根据解析后的指令完成特定操作,例如点亮或熄灭 LED 灯。 为了进一步扩展此项目,可以参考官方文档中的 esp-skainet 库来增强系统的灵活性和性能[^2]。 #### 基于 ESP32-S3 的语音识别实践 对于更先进的应用场景,可以选择使用 ESP32-S3 处理器作为核心组件来进行语音处理任务。这款微控制器不仅具备强大的计算能力,还内置了专用硬件加速单元用于运行神经网络模型,从而提高了实时性和效率[^3]。 具体来说,在该项目中采用了 MiniMax 对话系统配合摄像头模组共同工作,形成了一个多模态感知平台。它允许用户通过自然语言提问并与机器互动交流信息。同时提供了详细的安装指导和技术支持资料供初学者学习研究。 以下是一个简单的 Arduino 示例程序片段展示如何初始化并配置麦克风输入参数: ```cpp #include <driver/i2s.h> void setup() { i2s_config_t i2sConfig = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX), .sample_rate = SAMPLE_RATE, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, .communication_format = I2S_COMM_FORMAT_I2S_MSB, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 8, .dma_buf_len = 64, .use_apll = false, .tx_desc_auto_clear = true, .fixed_mclk = 0}; i2s_driver_install(I2S_PORT, &i2sConfig, 0, NULL); } void loop(){} ``` 上述代码展示了如何设置 I2S 接口以捕获来自外部麦克风阵列的声音数据流以便后续分析处理。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值