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

2023-05-16

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的博客-CSDN博客_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效果

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ESP32接入百度云,在线语音识别 的相关文章

  • Ardupilot-SITL仿真模拟调试

    1 配置SITL仿真调试 span class token punctuation span span class token operator span waf configure span class token operator sp
  • PX4——Range Finder 篇

    Range Finder 此处选用的是 Benewake 下的 Lidar 参数设置 General Configuration 除了官方的参数设置外 xff0c 我在 EKF2 中还找到了 EKF2 RNG AID 参数 xff0c 用来
  • STM32 时钟 定时器基础

    STM32 Clock Tree 时钟源 HSI xff1a xff08 High Speed Internal xff09 内部的 RC 震荡电路产生时钟信号 HSE xff1a xff08 High Speed External xff
  • Albumentation

    文章目录 AlbumentationClassificationSegmentationDetectionKeyPoints Augmentation Albumentation 所有实现的变换 变换以及支持的类型 此处 Classific
  • Pytorch 分布式训练

    文章目录 分布式训练OverviewDP or DDPDPDDP TCP 初始化Moco TCP 初始化例子 ENV 初始化可选后端进程间通信操作Template 区分概念 xff1a Machine vs Device 多机 Machin
  • FLANN C++ 使用

    FLANN FLANN 库 xff0c 包含 KNN 算法 众多工程 xff08 例如 OpenCV xff09 使用了 FLANN xff0c 这里单独介绍这个库 xff0c 方便以后单独使用 由官方 Latex 编译的文档链接 xff0
  • HDF5 C++ 使用

    HDF5 简介 HDF5 可以用来存储异构数据对象 xff0c 包括图片 xff0c 表 xff0c 图 xff0c 甚至 PDF 和 Excel HDF5 中的数据存储在不同组 Group 中 xff0c 类似于 Linux 文件树结构
  • Pandoc 使用

    文章目录 PandocInstallationLatex 到 Word命令详解 Pandoc Installation MacOS brew span class token function install span pandoc Lat
  • Docker -- DockerFile 讲解

    文章目录 DockerFile 指令讲解FROMCOPY 写在开头 xff1a 实验室给的电脑只能装 20 04 然后跑仿真需要在 18 04 20 04 的 Gazebo 居然不能支持 xff01 要是有人知道如何在 20 04 中使用
  • MySQL介绍及CRUD操作。

    目录 一 基本介绍 1 数据库结构 2 数据库增删改查 二 增删改查语句 1 insert 添加数据 2 update 修改操作 3 delete 删除操作 4 select 查询操作 5 加密和系统函数 6 流程控制函数 三 表的增删改查
  • Docker 容器

    文章目录 容器图形界面XserverVNC 容器 图形界面 Xserver 采用 ROS 官网的教程 这里相当于是将容器的图形信息发送给宿主的 Xserver 然后显示在你的电脑屏幕上 首先需要打开主机 Xserver 权限 xff1a x
  • C++ -- OpenMP 笔记

    64 toc OMP CMake Setup set CMAKE CXX STANDARD 14 set CMAKE CXX STANDARD REQUIRED ON find package OpenMP REQUIRED Set Fla
  • 转载:亚像素数值极值检测算法总结

    动机 在计算机视觉领域 xff0c 经常需要检测极值位置 xff0c 比如SIFT关键点检测 模板匹配获得最大响应位置 统计直方图峰值位置 边缘检测等等 xff0c 有时只需要像素精度就可以 xff0c 有时则需要亚像素精度 本文尝试总结几
  • C++动态库*.dll文件的Debug/Release版本是否可以混用(交叉用)?

    1 现象 xff1a 使用一些第三方的dll xff0c 比如opencv xff0c 会分别生成debug和release的dll xff0c 在exe中必须要引用指定版本的dll xff0c 不能混用 xff0c 否则会出错 xff1b
  • EditPlus编辑器选中列的方法

    1 主菜单 xff1a 编辑 gt 选择 gt 按列选择 2 先按下 Alt 43 C xff0c 释放 xff0c 然后移动鼠标或键盘上下左右键进行选择
  • 好教程推荐系列:收录常见的Qt面试题

    Qt面试题 xff1a 1 connect几个类型的区别 2 自绘控件 3 Qt常用线程几种方式 xff0c 数据竞争 xff0c 加锁同步等等 4 Model View Delegate的理解 5 Qt的插件机制是怎么做的 6 信号槽机制
  • Qt5多线程/线程池技术集锦(2)如何在子线程更新ui窗口

    上一篇介绍了基础知识 Qt5多线程 线程池技术集锦 xff08 1 xff09 基础知识篇 libaineu2004的博客 CSDN博客 qt5 线程池 Qt下多线程的几种使用方法 以及注意事项 第一种方法 1 创建一个类从QThread类
  • mysql8.x实践系列(1)centos7和win10安装mysql8.x的注意事项,与5.x版本有许多不同

    一 先看Centos7的安装情况 1 多年前写了一篇文章 xff1a centos7安装和卸载mysql5 7 18完整实用教程 https blog csdn net libaineu2004 article details 762121
  • halcon分别求取Region区域顶点和最高点

    Word编辑器可以生成很多形状 xff0c 举例七角星 求顶点和最高点的源码如下 xff1a 求取区域顶点 方法1 dev close window read image Image1 39 testpic 求取区域顶点 png 39 de
  • 3D激光线扫相机与结构光相机的区别

    激光线扫相机 激光相机基于三角测量 xff0c 可精确捕获3D形状 数百万个点 更精确地说 xff0c 它们的工作原理是将激光点或激光线投射到物体上 xff0c 然后用传感器捕获其反射 由于传感器的位置与激光源的距离已知 xff0c 因此可

随机推荐