博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
软件包应用分享|基于RT-Thread的百度语音识别(一)
阅读量:2111 次
发布时间:2019-04-29

本文共 8692 字,大约阅读时间需要 28 分钟。

百度AI简介

语音识别服务是百度AI众多服务中的一项,应用该服务,你可以将语音识别为文字,适用于手机应用语音交互、语音内容分析、智能硬件、呼叫中心智能客服等多种场景。下面,我将分享一个基于RT-Thread将该服务应用于STM32上的案例。

本期分享来自RT-Thread的社区小伙伴霹雳大乌龙,如果你也有文章愿意分享/希望获得官方的写作指导,可以发送文章/联系方式邮件至邮箱:xuqianqian@rt-thread.com  

一. 项目介绍

硬件:IoT Board(正点原子 - 潘多拉L475开发板)

平台:RT-Thread + 百度AI

  1. 使用RT-Thread的 stm32l475-atk-pandora BSP 或 RT-Thread IoT-Board SDK;

  2. 挂载elm FatFS文件系统,用于存放待识别音频;

  3. 初始化板载WIFI模块 AP6181 或 使用AT组件+ESP8266,使开发板具备网络功能;

  4. 使用Audio组件,实现录音功能,并将音频存入文件系统;

  5. 使用webclient软件包,将文件系统中的音频上传到百度AI服务端,识别后返回Json数据;

  6. 使用cJson软件包解析数据,根据解析出的数据作出响应动作(控制RGB灯);

  7. 将中文字库烧写进外部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

三. 动手实践

实践开始之前,先确保你已经做了以下两件事:

  1. 注册百度开发者账号,并创建了一个语音识别应用,而且成功获取了Access Token;

  2. 建立一个基于你自己的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 
4#include 
5 6#include 
 //网络功能需要的头文件 7#include 
  //webclient软件包头文件 8#include 
  //文件系统需要的头文件 9#include 
      //CJSON软件包头文件 10 11/* 使用外设需要的头文件 */ 12#include 
13#include 
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 
\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    }else107    {108        rt_kprintf("rc code: %d!\n", rc);109    }110111    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");129130    if(webclient_handle_response(session) != 200)131    {132        rt_kprintf("get handle resposne error!");133        goto __exit;134    }   135136    /* 获取接收的响应数据长度 */137    content_length = webclient_content_length_get(session);138    rt_thread_delay(100);139140    do141    {142        bytes_read = webclient_read(session, buffer, 1024);143        if (bytes_read <= 0)144        {145            break;146        }147148        for(int index = 0; index < bytes_read; index++)149        {150            rt_kprintf("%c", buffer[index]);151        }152153        content_pos += bytes_read;154        }while(content_pos < content_length);   155156    /* 解析json数据 */157    bd_data_parse(buffer);158159    __exit:160                if(fd >= 0)161                    close(fd);162                if(session != NULL)163                    webclient_close(session);164                if(buffer != NULL)165                    web_free(buffer);166167                return;168}169170/* 导出为命令形式 */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;1314    root = cJSON_Parse((const char *)data);15    if (!root)16    {17        rt_kprintf("No memory for cJSON root!\n");18        return;19    }2021    object = cJSON_GetObjectItem(root, "result");2223    item = object->child;2425    rt_kprintf("\nresult    :%s \r\n", item->valuestring);2627        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);3334        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        }646566    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协议,可免费在商业产品中使用,不需要公布源码,无潜在商业风险。

长按二维码,关注我们

点击“阅读原文”报名开发者大会

转载地址:http://hanef.baihongyu.com/

你可能感兴趣的文章
【Loadrunner】性能测试报告实战
查看>>
【面试】一份自我介绍模板
查看>>
【自动化测试】自动化测试需要了解的的一些事情。
查看>>
【selenium】selenium ide的安装过程
查看>>
【手机自动化测试】monkey测试
查看>>
【英语】软件开发常用英语词汇
查看>>
Fiddler 抓包工具总结
查看>>
【雅思】雅思需要购买和准备的学习资料
查看>>
【雅思】雅思写作作业(1)
查看>>
【雅思】【大作文】【审题作业】关于同不同意的审题作业(重点)
查看>>
【Loadrunner】通过loadrunner录制时候有事件但是白页无法出来登录页怎么办?
查看>>
【English】【托业】【四六级】写译高频词汇
查看>>
【托业】【新东方全真模拟】01~02-----P5~6
查看>>
【托业】【新东方全真模拟】03~04-----P5~6
查看>>
【托业】【新东方托业全真模拟】TEST05~06-----P5~6
查看>>
【托业】【新东方托业全真模拟】TEST09~10-----P5~6
查看>>
【托业】【新东方托业全真模拟】TEST07~08-----P5~6
查看>>
solver及其配置
查看>>
JAVA多线程之volatile 与 synchronized 的比较
查看>>
Java集合框架知识梳理
查看>>