软件包应用分享|基于RT-Thread的百度语音识别(一)
百度AI简介语音识别服务是百度AI众多服务中的一项,应用该服务,你可以将语音识别为文字,适用于手机应用语音交互、语音内容分析、智能硬件、呼叫中心智能客服等多种场景。下面,我将分享一个基于...
百度AI简介
语音识别服务是百度AI众多服务中的一项,应用该服务,你可以将语音识别为文字,适用于手机应用语音交互、语音内容分析、智能硬件、呼叫中心智能客服等多种场景。下面,我将分享一个基于RT-Thread将该服务应用于STM32上的案例。
本期分享来自RT-Thread的社区小伙伴霹雳大乌龙,如果你也有文章愿意分享/希望获得官方的写作指导,可以发送文章/联系方式邮件至邮箱:xuqianqian@rt-thread.com
一. 项目介绍
硬件:IoT Board(正点原子 - 潘多拉L475开发板)
平台:RT-Thread + 百度AI
使用RT-Thread的 stm32l475-atk-pandora BSP 或 RT-Thread IoT-Board SDK;
挂载elm FatFS文件系统,用于存放待识别音频;
初始化板载WIFI模块 AP6181 或 使用AT组件+ESP8266,使开发板具备网络功能;
使用Audio组件,实现录音功能,并将音频存入文件系统;
使用webclient软件包,将文件系统中的音频上传到百度AI服务端,识别后返回Json数据;
使用cJson软件包解析数据,根据解析出的数据作出响应动作(控制RGB灯);
将中文字库烧写进外部spi flash,使用SUFD+FAL软件包读写flash,实现LCD显示识别结果。
因为项目的重点以及难点在于百度语音识别,所以接下来的文章将着重讲解上述的4-7点,其他部分大家自行前往RT-Thread的文档中心学习。
二. 百度语音识别服务使用流程
在项目开始之前,我们需要先熟悉一遍百度语音服务的调用流程,不然直接写代码,你可能会一脸懵逼。百度语音识别简单来说就是百度AI通过API的方式给开发者提供一个通用的HTTP接口,开发者通过这个接口上传音频文件,服务器返回识别结果,就这么简单,具体怎么做我们接着往下看:
1. 首先我们要注册一个百度开发者账号,然后创建一个语音识别的应用
1.1 搜索 “百度AI” ,进入如下页面,点击右上方控制台(未注册的需注册):
1.2 点击“语音技术”,进入如下页面,点击“创建应用”:
1.3 填写相关信息后点击创建,创建成功后可以在应用列表看到你新创建的应用:
2.语音识别的过程
2.1 获取 Access Token:
向授权服务地址https://aip.baidubce.com/oauth/2.0/token 发送请求(推荐使用POST),并在URL中带上以下参数:
grant_type:必须参数,固定为client_credentials;
client_id:必须参数,应用的API Key;
client_secret:必须参数,应用的Secret Key;
● 使用浏览器获取Access Token:
1https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id=Gqt6jzFQDB1UrfVlkTBxr43k&client_secret=dsAQulSVgXEUq2xxyUGFegQOpUWVDpx2
● 使用Postman获取Access Token:
这里给大家推荐一个好用的软件Postman,其是一款功能强大的网页调试与发送网页HTTP请求的接口测试神器,使用它你可以方便的体验百度语音识别的完整流程:
2.2 使用Access Token进行语音识别
有了Access Token,就可以开始进行语音识别了,我们采用raw方式,上传本地文件(使用官方提供的16k采样率pcm文件样例),还是用Postman来测试:
● 语音识别调用地址:https://vop.baidu.com/pro_api
● 语音数据的采样率和压缩格式在 HTTP-HEADER 里的Content-Type 表明,例:Content-Type: audio/pcm;rate=16000
● 填写URL参数
● 上传本地音频文件,发送识别,返回结果
自此完整的百度语音识别流程就结束了,更多详细内容,大家参考百度AI文档中心的相关部分:https://ai.baidu.com/docs#/ASR-API/77e2b22e
三. 动手实践
实践开始之前,先确保你已经做了以下两件事:
注册百度开发者账号,并创建了一个语音识别应用,而且成功获取了Access Token;
建立一个基于你自己的STM32平台的RT-Thread工程,它必须具备Finsh控制台,文件系统,网络功能(不明白的参见RT-Thread文档中心,网络功能推荐使用AT组件+ESP8266,因为这是最简单快捷的方法)
如果上面说的准备事项没有问题,那么请继续往下看:这次我们将先跳过录音功能,而使用事先准备好的音频文件进行语音识别并控制板载RGB灯(项目介绍的5,6点),所以你还需要准备一些音频文件,比如“红灯开”,“蓝灯关”。。。我是用手机录的音频,然后使用ffmpeg工具将音频转为百度语音官方认为最适合的16k采样率pcm文件,最后将这些音频文件放进sd卡中,我们的文件系统也是挂载在sd卡上的。
本次工程会用到RT-Thread的两个软件包:webclient 和 cJson 软件包,你需要使用ENV工具将这两个软件包添加进工程里。
● 添加webclient和cJson软件包
好了,开始写代码:
1/* bd_speech_rcg.c */
2
3#include <rtthread.h>
4#include <bd_speech_rcg.h>
5
6#include <sys/socket.h> //网络功能需要的头文件
7#include <webclient.h> //webclient软件包头文件
8#include <dfs_posix.h> //文件系统需要的头文件
9#include <cJSON.h> //CJSON软件包头文件
10
11/* 使用外设需要的头文件 */
12#include <rtdevice.h>
13#include <board.h>
14
15
16/* 获取RGB灯对应的引脚编号 */
17#define PIN_LED_R GET_PIN(E, 7)
18#define PIN_LED_G GET_PIN(E, 8)
19#define PIN_LED_B GET_PIN(E, 9)
20
21#define RES_BUFFER_SIZE 4096 //数据接收数组大小
22#define HEADER_BUFFER_SIZE 2048 //最大支持的头部长度
23
24/* URL */
25#define POST_FILE_URL "http://vop.baidu.com/server_api?dev_pid=1536&cuid=lxzzzzzxl&token=25.9119f50a60602866be9288f1f14a1059.315360000.1884092937.282335-15525116"
26/* 头部数据(必需) */
27char *form_data = "audio/pcm;rate=16000";
28
29/* 预定义的指令 */
30char *cmd1 = "打开红灯";
31char *cmd2 = "关闭红灯";
32char *cmd3 = "打开蓝灯";
33char *cmd4 = "关闭蓝灯";
34char *cmd5 = "打开绿灯";
35char *cmd6 = "关闭绿灯";
36
37
38
39/************************************************
40函数名称 :bd
41功 能 : 将音频文件发送到百度语音服务器,并接收响应数据
42参 数 : 音频文件名(注意在文件系统中的位置,默认根目录)
43返 回 值 :void
44作 者 :rtthread;霹雳大乌龙
45*************************************************/
46void bd(int argc, char **argv)
47{
48 char *filename = NULL;
49 unsigned char *buffer = RT_NULL;
50 int content_length = -1, bytes_read = 0;
51 int content_pos = 0;
52 int ret = 0;
53
54 /* 判断命令是否合法 */
55 if(argc != 2)
56 {
57 rt_kprintf("bd <filename>\r\n");
58 return;
59 }
60
61 /* 获取音频文件名 */
62 filename = argv[1];
63
64 /* 以只读方式打开音频文件 */
65 int fd = open(filename, O_RDONLY, 0);
66 if(fd < 0)
67 {
68 rt_kprintf("open %d fail!\r\n", filename);
69 goto __exit;
70 }
71
72 /* 获取音频文件大小 */
73 size_t length = lseek(fd, 0, SEEK_END);
74 lseek(fd, 0, SEEK_SET);
75
76 /* 创建响应数据接收数据 */
77 buffer = (unsigned char *) web_malloc(RES_BUFFER_SIZE);
78 if(buffer == RT_NULL)
79 {
80 rt_kprintf("no memory for receive response buffer.\n");
81 ret = -RT_ENOMEM;
82 goto __exit;
83 }
84
85 /* 创建会话 */
86 struct webclient_session *session = webclient_session_create(HEADER_BUFFER_SIZE);
87 if(session == RT_NULL)
88 {
89 ret = -RT_ENOMEM;
90 goto __exit;
91 }
92
93 /* 拼接头部数据 */
94 webclient_header_fields_add(session, "Content-Length: %d\r\n", length);
95 webclient_header_fields_add(session, "Content-Type: %s\r\n", form_data);
96
97 /* 发送POST请求 */
98 int rc = webclient_post(session, POST_FILE_URL, NULL);
99 if(rc < 0)
100 {
101 rt_kprintf("webclient post data error!\n");
102 goto __exit;
103 }else if (rc == 0)
104 {
105 rt_kprintf("webclient connected and send header msg!\n");
106 }else
107 {
108 rt_kprintf("rc code: %d!\n", rc);
109 }
110
111 while(1)
112 {
113 rt_memset(buffer, 0, RES_BUFFER_SIZE);
114 length = read(fd, buffer, RES_BUFFER_SIZE);
115 if(length <= 0)
116 {
117 break;
118 }
119 ret = webclient_write(session, buffer, length);
120 if(ret < 0)
121 {
122 rt_kprintf("webclient write error!\r\n");
123 break;
124 }
125 rt_thread_mdelay(100);
126 }
127 close(fd);
128 rt_kprintf("Upload voice data successfully\r\n");
129
130 if(webclient_handle_response(session) != 200)
131 {
132 rt_kprintf("get handle resposne error!");
133 goto __exit;
134 }
135
136 /* 获取接收的响应数据长度 */
137 content_length = webclient_content_length_get(session);
138 rt_thread_delay(100);
139
140 do
141 {
142 bytes_read = webclient_read(session, buffer, 1024);
143 if (bytes_read <= 0)
144 {
145 break;
146 }
147
148 for(int index = 0; index < bytes_read; index++)
149 {
150 rt_kprintf("%c", buffer[index]);
151 }
152
153 content_pos += bytes_read;
154 }while(content_pos < content_length);
155
156 /* 解析json数据 */
157 bd_data_parse(buffer);
158
159 __exit:
160 if(fd >= 0)
161 close(fd);
162 if(session != NULL)
163 webclient_close(session);
164 if(buffer != NULL)
165 web_free(buffer);
166
167 return;
168}
169
170/* 导出为命令形式 */
171MSH_CMD_EXPORT(bd, webclient post file);
1/* bd_speech_rcg.c */
2
3/************************************************
4函数名称 :bd_data_parse
5功 能 : 解析json数据,并作出响应动作
6参 数 :data ------ 百度语音服务返回的数据(json格式)
7返 回 值 :void
8作 者 :RT-Thread;霹雳大乌龙
9*************************************************/
10void bd_data_parse(uint8_t *data)
11{
12 cJSON *root = RT_NULL, *object = RT_NULL, *item =RT_NULL;
13
14 root = cJSON_Parse((const char *)data);
15 if (!root)
16 {
17 rt_kprintf("No memory for cJSON root!\n");
18 return;
19 }
20
21 object = cJSON_GetObjectItem(root, "result");
22
23 item = object->child;
24
25 rt_kprintf("\nresult :%s \r\n", item->valuestring);
26
27 rt_pin_mode(PIN_LED_R, PIN_MODE_OUTPUT);
28 rt_pin_mode(PIN_LED_G, PIN_MODE_OUTPUT);
29 rt_pin_mode(PIN_LED_B, PIN_MODE_OUTPUT);
30 rt_pin_write(PIN_LED_R,1);
31 rt_pin_write(PIN_LED_G,1);
32 rt_pin_write(PIN_LED_B,1);
33
34 if(strstr((char*)data, cmd1) != NULL)
35 {
36 /* 打开红灯 */
37 rt_pin_write(PIN_LED_R,0);
38 }
39 if(strstr((char*)data, cmd2) != NULL)
40 {
41 /* 关闭红灯 */
42 rt_pin_write(PIN_LED_R,1);
43 }
44 if(strstr((char*)data, cmd3) != NULL)
45 {
46 /* 打开蓝灯 */
47 rt_pin_write(PIN_LED_B,0);
48 }
49 if(strstr((char*)data, cmd4) != NULL)
50 {
51 /* 关闭蓝灯 */
52 rt_pin_write(PIN_LED_B,1);
53 }
54 if(strstr((char*)data, cmd5) != NULL)
55 {
56 /* 打开绿灯 */
57 rt_pin_write(PIN_LED_G,0);
58 }
59 if(strstr((char*)data, cmd6) != NULL)
60 {
61 /* 关闭绿灯 */
62 rt_pin_write(PIN_LED_G,1);
63 }
64
65
66 if (root != RT_NULL)
67 cJSON_Delete(root);
68}
只需以上的代码(代码参考自论坛各位小伙伴),你就可以实现百度语音识别以及控制相应外设了。下面看看实际效果:我使用的潘多拉开发板板载了stlink,且其为我们提供了一个虚拟串口,用usb数据线将开发板和电脑连接起来,将代码烧写进开发板后,我们利用这个虚拟串口,使用Xshell一类的终端软件,就可以看到如下的开机画面:
这便是RT-Thread提供的Finsh控制台组件,使用这个组件,我们可以方便地观察程序的运行状态,以命令行的形式调试运行程序,从图中我们可以看到,我们需要的文件系统和网络功能都已经初始化成功。
使用ls命令看看:
欸~,这便是我事先准备好的音频文件。
在上面的代码中,我们可以看到有这样一句:
1MSH_CMD_EXPORT(bd, webclient post file);
通过这行代码,我们就可以在Finsh控制台里使用bd这个命令,这个命令就是将音频文件发送到百度语音服务器,试试看:
使用bd命令将greenon.pcm发送到百度语音服务器,正确识别出结果:“打开绿灯”;与此同时,rgb灯也亮起了绿色。
尝试其他音频文件,效果完美!
RT-Thread线上/下活动
1、【RT-Thread开发者大会报名】上海站马上开始!2019年RT-Thread开发者大会将登入成都、上海、深圳与开发者们见面,还有RT-Thread在中高端智能领域的应用、一站式RTT开发工具、打造IoT极速开发模式等干货演讲,期待您的参与!
立即报名
#题外话# 喜欢RT-Thread不要忘了在GitHub上留下你的STAR哦,你的star对我们来说非常重要!链接地址:https://github.com/RT-Thread/rt-thread
你可以添加微信17775982065为好友,注明:公司+姓名,拉进 RT-Thread 官方微信交流群
RT-Thread
让物联网终端的开发变得简单、快速,芯片的价值得到最大化发挥。Apache2.0协议,可免费在商业产品中使用,不需要公布源码,无潜在商业风险。
长按二维码,关注我们
点击“阅读原文”报名开发者大会
更多推荐
所有评论(0)