使用ESP32接入百度智能云实现在线语音识别。实现最基本的语音识别功能还是很简单的,但还是遇到了一些小问题,在这记录一下。
使用了max9814麦克风模块用做语音输入,一个按键来控制数据的采集和上传。
(1) 在百度云控制端选择“语音识别”并创建应用获取API Key和Secret Key
(2) 根据创建应用生成的API Key和Secret Key来获取token
(3) 采集音频数据,将数据打包成规定的格式,POST发送到请求API
(4) 接收返回的数据
登录百度云账号,选择语音识别,创建应用。
创建好应用,点管理应用,会有API Key和Secret Key,如下图
有了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 方式有 2 种:JSON 格式和RAW 格式。
这里介绍使用使用JSON格式上传的方式,下图为JSON格式上传的一些必要的参数说明
图中对数据类型和内容说的很明确了,只需要按照这个格式打包好数据然后发送就行,下面是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库相关程序的使用说明,很详细。