ESP32接入百度智能云语音识别,实现在线语音识别

一、概述

  使用ESP32接入百度智能云实现在线语音识别。实现最基本的语音识别功能还是很简单的,但还是遇到了一些小问题,在这记录一下。
  使用了max9814麦克风模块用做语音输入,一个按键来控制数据的采集和上传。

二、步骤概括

  (1) 在百度云控制端选择“语音识别”并创建应用获取API Key和Secret Key
  (2) 根据创建应用生成的API Key和Secret Key来获取token
  (3) 采集音频数据,将数据打包成规定的格式,POST发送到请求API
  (4) 接收返回的数据

三、具体实现

一、创建语音识别应用

  登录百度云账号,选择语音识别,创建应用。

ESP32接入百度智能云语音识别,实现在线语音识别_第1张图片

二、根据创建应用生成的API Key和Secret Key来获取token

  创建好应用,点管理应用,会有API Key和Secret Key,如下图

ESP32接入百度智能云语音识别,实现在线语音识别_第2张图片

  有了API Key和Secret Key就可以得到token,下面附上ESP32进行get请求得到token的代码

void gain_token(void)   //获取token
{
    int httpCode;
    //注意,要把下面网址中的your_apikey和your_secretkey替换成自己的API Key和Secret Key
    http_client.begin("https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=your_apikey&client_secret=your_secretkey");
    httpCode = http_client.GET();
    if(httpCode > 0) {
        if(httpCode == HTTP_CODE_OK) {
            String payload = http_client.getString();
            Serial.println(payload);
        }
    }
    else {
        Serial.printf("[HTTP] GET... failed, error: %s\n", http_client.errorToString(httpCode).c_str());
    }
    http_client.end();
}

  请求成功会返回如下数据

{
  "refresh_token": "25.b55fe1d287227ca97aab219bb249b8ab.315360000.1798284651.282335-8574074",
  "expires_in": 2592000,
  "scope": "public wise_adapt",
  "session_key": "9mzdDZXu3dENdFZQurfg0Vz8slgSgvvOAUebNFzyzcpQ5EnbxbF+hfG9DQkpUVQdh4p6HbQcAiz5RmuBAja1JJGgIdJI",
  "access_token": "24.6c5e1ff107f0e8bcef8c46d3424a0e78.2592000.1485516651.282335-8574074",
  "session_secret": "dfac94a3489fe9fca7c3221cbf7525ff"
}

  access_token对应的值就是可用的token了,每次申请的token有效期为30天,过期需要重新申请,可以申请多个。不用每次都调用获取token的程序,申请一个可以用30天,定时更新就可以吧。

三、采集数据,POST发送到请求API

  数据上传 POST 方式有 2 种:JSON 格式和RAW 格式。
  这里介绍使用使用JSON格式上传的方式,下图为JSON格式上传的一些必要的参数说明

ESP32接入百度智能云语音识别,实现在线语音识别_第3张图片

  图中对数据类型和内容说的很明确了,只需要按照这个格式打包好数据然后发送就行,下面是ESP32的具体实现代码。

if(digitalRead(key)==0) //按键按下
{
    Serial.printf("Start recognition\r\n\r\n");
    digitalWrite(led,HIGH);
    adc_start_flag=1;	//数据开始采集
    
    timerStart(timer);
    while(!adc_complete_flag)  //等待数据采集完成
    {
        ets_delay_us(10);
    }
    timerStop(timer);
    adc_complete_flag=0;   //采集完成,清标志

    digitalWrite(led,LOW);
    
    memset(data_json,'\0',strlen(data_json));   //将数组清空
    strcat(data_json,"{");
    strcat(data_json,"\"format\":\"pcm\",");
    strcat(data_json,"\"rate\":8000,");         //采样率    如果采样率改变了,记得修改该值,只有16000、8000两个固定采样率
    strcat(data_json,"\"dev_pid\":1537,");      //中文普通话
    strcat(data_json,"\"channel\":1,");         //单声道
    strcat(data_json,"\"cuid\":\"123456\",");   //识别码    随便打几个字符,但最好唯一
   	strcat(data_json,"\"token\":\"XXXXXXXXXXXXXXXXXX\",");  //token		这里需要修改成自己申请到的token
    strcat(data_json,"\"len\":32000,");         //数据长度  如果传输的数据长度改变了,记得修改该值,该值是ADC采集的数据字节数,不是base64编码后的长度
    strcat(data_json,"\"speech\":\"");
    strcat(data_json,base64::encode((uint8_t *)adc_data,sizeof(adc_data)).c_str());     //base64编码数据   这里使用的base64编码的库,在base.h头文件中
    strcat(data_json,"\"");
    strcat(data_json,"}");

    int httpCode;
    http_client.begin("http://vop.baidu.com/server_api");		//请求API
    http_client.addHeader("Content-Type","application/json");	//设置固定头部:Content-Type:application/json
    httpCode = http_client.POST(data_json);		//POST请求

    if(httpCode > 0) {
        if(httpCode == HTTP_CODE_OK) {
            String payload = http_client.getString();	//接收数据
            Serial.println(payload);
        }
    }
    else {
        Serial.printf("[HTTP] GET... failed, error: %s\n", http_client.errorToString(httpCode).c_str());
    }
    http_client.end();

    while (!digitalRead(key));
    Serial.printf("Recognition complete\r\n");
}

  上面代码是将数据拼接成要求的JSON的格式并通过POST的方式发送到请求API,并接收打印返回的数据消息。使用的定时器设置成8K频率定时采集音频数据,上面代码中并未展示,后面会附上完整代码。
  ESP32是有JSON库的,在 “cJSON.h” 头文件中,但是我没有用,因为我发现数据太长时不知道为啥会出现莫名其妙的错误,也没深究,就使用函数strcat()将数据拼接成规定的格式,好使,就是写的时候麻烦一些,但问题不大。
  POST发送数据有一个固定头部:Content-Type:application/json,POST前需要设置一下。

四、接收数据

  在上一步的代码中实现了接收数据,这里列一下返回的数据。

{"corpus_no":"6990616182318679817","err_msg":"success.","err_no":0,"result":["天气真好。"],"sn":"440339165021627629665"}
{"corpus_no":"6990616203881655850","err_msg":"success.","err_no":0,"result":["中午吃什么?"],"sn":"204332180621627629670"}
{"corpus_no":"6990616272746191297","err_msg":"success.","err_no":0,"result":["开灯。"],"sn":"657868059871627629686"}

  数据发送成功则会返回正确的识别数据,当然声音信号不好时返回的语音识别也会不准确。
  谨记,返回的语音识别结果是UTF-8 方式编码,开始我还纳闷为啥返回的是繁体字似的,我选的是中文普通话呀,然后尝试改改这,改改那也不好使,小郁闷。因为是晚上了,后来我都躺床上了,突然想到返回的语音结果是中文编码,错乱那不就是编码方式不同的问题吗,又从床上爬起来开了电脑,改用UTF-8编码方式,尝试了一下,好了!

四、总结

  以上所有的代码都是使用Vscode+Platformio编写的,基于Arduino开发的。
  百度智能云的语音识别服务是可以免费领取到一定使用次数的,150万次好像,足够我们测试使用了。
  ESP32有base64编码的库,在"base64.h"头文件中。
  上面的实现步骤和一些展示代码都只是一些关键的,有一部分没列出来,如ESP32联网部分,数据采集部分,虽没列出来,但实现也简单。下面会上传一下完成的代码,能实现最基本的短语音识别的代码。
  写这个主要是为了记录一下,其中尝试时还是遇到一些问题的,我网上搜索ESP32接入百度语音识别这方面的资源例子不多,自己弄好了就记录分享一下,助人助己。当然只是实现了最基本的。

以上纯属个人经验,并且个人能力也有限,可能出现差错,如有问题请指正,我就改。

代码上传到了CSDN,不需要积分就可以下载: https://download.csdn.net/download/wojueburenshu/20649571.
麦克风和按键连接的引脚在程序中很明显的体现出来,方便更改。

下面附上一些相关链接:
百度语音识别文档: https://ai.baidu.com/ai-doc/SPEECH/Vk38lxily.包含了请求说明、返回说明、错误码等等。
token申请说明文档: https://ai.baidu.com/ai-doc/REFERENCE/Ck3dwjhhu.介绍了如何使用API Key和Secret Key来申请token。
一个在线HTTP请求模拟工具:https://www.jsonla.com/http/test.html.可以用来模拟post、get请求,可以用来获取token。
ESP32 JSON库说明: https://blog.csdn.net/qq_36347513/article/details/116481167.别人写的,介绍了ESP32 JSON库相关程序的使用说明,很详细。

你可能感兴趣的:(经验分享,百度,语音识别)