手把手教你实现基于RT-Thread的百度语音识别(二)

准备工作

在本次实践开始之前,你必须确保你已经做了以下两件事:

  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工具将这两个软件包添加进工程里。

好了,开始写代码:

#include <rtthread.h>
#include <bd_speech_rcg.h>

#include <sys/socket.h> //网络功能需要的头文件
#include <webclient.h>  //webclient软件包头文件
#include <dfs_posix.h>  //文件系统需要的头文件
#include <cJSON.h>      //CJSON软件包头文件

/* 使用外设需要的头文件 */
#include <rtdevice.h>
#include <board.h>


/* 获取RGB灯对应的引脚编号 */
#define PIN_LED_R		GET_PIN(E,  7)
#define PIN_LED_G		GET_PIN(E,  8)
#define PIN_LED_B		GET_PIN(E,  9)

#define RES_BUFFER_SIZE     4096        //数据接收数组大小
#define HEADER_BUFFER_SIZE      2048    //最大支持的头部长度

/* URL */
#define POST_FILE_URL  "http://vop.baidu.com/server_api?dev_pid=1536&cuid=lxzzzzzxl&token=25.9119f50a60602866be9288f1f14a1059.315360000.1884092937.282335-15525116"
/* 头部数据(必需) */
char *form_data = "audio/pcm;rate=16000";

/* 预定义的命令 */
char *cmd1 = "打开红灯";
char *cmd2 = "关闭红灯";
char *cmd3 = "打开蓝灯";
char *cmd4 = "关闭蓝灯";
char *cmd5 = "打开绿灯";
char *cmd6 = "关闭绿灯";



/************************************************
函数名称 : bd
功    能 : 将音频文件发送到百度语音服务器,并接收响应数据
参    数 : 音频文件名(注意在文件系统中的位置,默认根目录)
返 回 值 : void
作    者 : rtthread;霹雳大乌龙
*************************************************/
void bd(int argc, char **argv)
{	
	char *filename = NULL;
	unsigned char *buffer = RT_NULL;
	int content_length = -1, bytes_read = 0;
    int content_pos = 0;
	int ret = 0;
	
	/* 判断命令是否合法 */
	if(argc != 2)
	{
		rt_kprintf("bd <filename>\r\n");
		return;
	}
	
	/* 获取音频文件名 */
	filename = argv[1];
	
    /* 以只读方式打开音频文件 */
	int fd = open(filename, O_RDONLY, 0);
	if(fd < 0)
	{
		rt_kprintf("open %d fail!\r\n", filename);
		goto __exit;
	}
	
	/* 获取音频文件大小 */
	size_t length = lseek(fd, 0, SEEK_END);
	lseek(fd, 0, SEEK_SET);
	
    /* 创建响应数据接收数据 */
	buffer = (unsigned char *) web_malloc(RES_BUFFER_SIZE);
	if(buffer == RT_NULL)
	{
		rt_kprintf("no memory for receive response buffer.\n");
        ret = -RT_ENOMEM;
		goto __exit;
	}
	
	/* 创建会话 */
	struct webclient_session *session = webclient_session_create(HEADER_BUFFER_SIZE);
	if(session == RT_NULL)
	{
		ret = -RT_ENOMEM;
		goto __exit;
	}

	/* 拼接头部数据 */
	webclient_header_fields_add(session, "Content-Length: %d\r\n", length);
	webclient_header_fields_add(session, "Content-Type: %s\r\n", form_data);
	
	

	/* 发送POST请求 */
	int rc = webclient_post(session, POST_FILE_URL, NULL);
	if(rc < 0)
	{
		rt_kprintf("webclient post data error!\n");
        goto __exit;
	}else if (rc == 0)
    {
        rt_kprintf("webclient connected and send header msg!\n");
    }else
    {
        rt_kprintf("rc code: %d!\n", rc);
    }
        
	while(1)
	{
		rt_memset(buffer, 0, RES_BUFFER_SIZE);
		length = read(fd, buffer, RES_BUFFER_SIZE);
		if(length <= 0)
		{
			break;
		}
		ret = webclient_write(session, buffer, length);
		if(ret < 0)
		{
			rt_kprintf("webclient write error!\r\n");
			break;
		}	
		rt_thread_mdelay(100);
	}
	close(fd);
	rt_kprintf("Upload voice data successfully\r\n");
	
	if(webclient_handle_response(session) != 200)
    {
        rt_kprintf("get handle resposne error!");
        goto __exit;
    }

    /* 获取接收的响应数据长度 */
	content_length = webclient_content_length_get(session);
	rt_thread_delay(100);

    do
	{
		bytes_read = webclient_read(session, buffer, 1024);
        if (bytes_read <= 0)
        {
            break;
        }

		for(int index = 0; index < bytes_read; index++)
		{
			rt_kprintf("%c", buffer[index]);
		}
        
        content_pos += bytes_read;
		}while(content_pos < content_length);	

	/* 解析json数据 */
	bd_data_parse(buffer);
	
	__exit:
				if(fd >= 0)
					close(fd);
				if(session != NULL)
					webclient_close(session);
				if(buffer != NULL)
					web_free(buffer);
				
				return;
}

/* 导出为命令形式 */
MSH_CMD_EXPORT(bd, webclient post file);
/************************************************
函数名称 : bd_data_parse
功    能 : 解析json数据,并作出响应动作
参    数 : data ------ 百度语音服务返回的数据(json格式)
返 回 值 : void
作    者 : RT-Thread;霹雳大乌龙
*************************************************/
void bd_data_parse(uint8_t *data)
{
    cJSON *root = RT_NULL, *object = RT_NULL, *item =RT_NULL;

    root = cJSON_Parse((const char *)data);
    if (!root)
    {
        rt_kprintf("No memory for cJSON root!\n");
        return;
    }
		
    object = cJSON_GetObjectItem(root, "result");

		item = object->child;

    rt_kprintf("\nresult	:%s \r\n", item->valuestring);
		
		rt_pin_mode(PIN_LED_R, PIN_MODE_OUTPUT);
		rt_pin_mode(PIN_LED_G, PIN_MODE_OUTPUT);
		rt_pin_mode(PIN_LED_B, PIN_MODE_OUTPUT);
		rt_pin_write(PIN_LED_R,1);
		rt_pin_write(PIN_LED_G,1);
		rt_pin_write(PIN_LED_B,1);
		
		if(strstr((char*)data, cmd1) != NULL)
		{
				/* 打开红灯 */
			rt_pin_write(PIN_LED_R,0);
		}		
		if(strstr((char*)data, cmd2) != NULL)
		{
				/* 关闭红灯 */
			rt_pin_write(PIN_LED_R,1);
		}
		if(strstr((char*)data, cmd3) != NULL)
		{
				/* 打开蓝灯 */
			rt_pin_write(PIN_LED_B,0);
		}
		if(strstr((char*)data, cmd4) != NULL)
		{
				/* 关闭蓝灯 */
			rt_pin_write(PIN_LED_B,1);
		}
		if(strstr((char*)data, cmd5) != NULL)
		{
				/* 打开绿灯 */
			rt_pin_write(PIN_LED_G,0);
		}
		if(strstr((char*)data, cmd6) != NULL)
		{
				/* 关闭绿灯 */
			rt_pin_write(PIN_LED_G,1);
		}
		

    if (root != RT_NULL)
        cJSON_Delete(root);
}

只需以上的代码,你就可以实现百度语音识别以及控制相应外设了。下面看看实际效果:

我使用的潘多拉开发板板载了stlink(且其为我们提供了一个虚拟串口),用usb数据线将开发板和电脑连接起来,将代码烧写进开发板后,我们利用这个虚拟串口,使用Xshell一类的终端软件,就可以看到如下的开机画面:
在这里插入图片描述
这便是RT-Thread提供的Finsh控制台组件,使用这个组件,我们可以方便地观察程序的运行状态,以命令行的形式调试运行程序,从图中我们可以看到,我们需要的文件系统和网络功能都已经初始化成功。

使用ls命令看看:
在这里插入图片描述
欸~,这便是我事先准备好的音频文件。

在上面的代码中,我们可以看到有这样一句:

MSH_CMD_EXPORT(bd, webclient post file);

通过这行代码,我们就可以在Finsh控制台里使用bd这个命令,这个命令就是将音频文件发送到百度语音服务器,试试看:
在这里插入图片描述
看,我使用bd命令将greenon.pcm发送到百度语音服务器,正确识别出结果:“打开绿灯”;于此同时,rgb灯也亮起了绿色
在这里插入图片描述
尝试其他音频文件,效果完美!!!

好了,本次分享也就到这了,觉得不错的帮忙转发点个在看哦~

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RT-Thread作品秀】手语识别翻译发生装置作者:岁月触礁如梦 概述(说明应用产生的背景、实现功能)手语是聋人使用的语言,是由手形动作辅之以表情姿势由符号构成的比较稳定的表达系统,是一种靠动作/视觉交际的语言.手语识别的研究目标是让机器弄懂聋人的语言.因此我们选择基于 STM32 为主控,对手语识别进行识别和处理,再利用显示系统或者语音模块,从而实现利用 MCU 对手语翻译从而帮助发音障碍人士之间的交流。 开发环境(所采用的软、硬件方案)硬件:ART-PI+MPU6050 RT-Thread版本: 开发工具及版本:RT-Thread Studio RT-Thread使用情况概述(简要总结下应用中RT-Thread使用情况:内核部分、组件部分、软件包部分、内核、其他)使用rt-thread的i2c驱动部分驱动多个MPU6050,然后通过uart驱动发送出去 ART-PI 硬件框架(概述应用所采用的硬件方案框图,并对核心部分做介绍)MPU6050x6 电脑 STM32H750 采集来自 MPU6050 的数据,打包后通过uart模块发送到电 脑上进行数据处理 软件框架说明(介绍应用所采用的软件方案框图、流程图等,并加以解说)数据 声音单元 Sotfmax 全连接层 软件模块说明(介绍应用软件关键部分的逻辑、采用的实现方式等)使用 tensorflow 搭建模型判断手势,使识别成功率大大提高。模型包含一个输入层,两层全连接层,和一个输出的softmax层,最后比较输出结果,如果结果大于0.8则发出对应手势的声音 演示效果(演示效果请采用3张高清图片,并录制一段不少于1min视频解说应用所实现的效果,视频上传至B站或者腾讯视频或其他视频平台,给出链接即可)比赛感悟(可以围绕这次比赛学到了什么,克服了哪些困难,有哪些收获,不低于200字)这次比赛让我深入了解了rt-thread,对RT-Thread 软件包的使用有了丰富的经验。它是运行于 RT-Thread 物联网操作系统平台上,面向不同应用领域的通用软件组件,由描述信息、源代码或库文件组成。RT-Thread 提供了开放的软件包平台,这里存放了官方提供或开发者提供的软件包,该平台为开发者提供了众多可重用软件包的选择,这也是 RT-Thread 生态的重要组成部分。软件包生态对于一个操作系统的选择至关重要,因为这些软件包具有很强的可重用性,模块化程度很高,极大的方便应用开发者在最短时间内,打造出自己想要的系统。RT-Thread 已经支持的软件包数量已经达到60+,如下举例:。通过此次参赛,学习到了许多机器学习相关的知识,现在还处在入门阶段,对于过多数据的处理方法没有选对,使得手套动作的识别准确率不高,但后期一定会做更多的研究,做出一个完整的作品来
RT-Thread作品秀】智能家居的语音控制方案。作者:xqyjlj 概述智能家居是现在一个很火热的方向,随着人们生活水平的提高,我们都逐渐开始希望身边的电器都可以不用手来控制,本作品就是基于这种需求,开发出来了一个基于语音控制的智能家居方案。本智能家居方案,分为联网与不联网两种版本。其中,无论是联网与不联网,语音识别功能均能正常使用。在本作品没有连上网的情况下,可以进行语音对开关的控制,进行MP3等常用音频文件的播放,以及具有拍照功能,可以将拍下来的照片储存在SD卡内,在本作品连上网的情况下,还附加了以下功能,可以将一些数据上报到云平台(onenet),并且将一些工作日志通过邮件发送给用户。 开发环境硬件:ART_PI(主控) LD3320(语音识别芯片) VS1053(音频解码芯片) OV2640(摄像头) RT-Thread版本:RT-Thread V 4.0.3 开发工具及版本:RT-Thread Studio 2.0.0 RT-Thread使用情况概述内核:调度器,信号量。 组件:UART,DFS,SPI,IIC,PIN。 软件包:smtp_client,btstack,netuils,fal,easyflash,littlefs,onenet。 硬件框架主控:ART-PI ART-Pi 是 RT-Thread 团队为嵌入式软件工程师、开源创客设计的一款极具扩展功能的 DIY 开源硬件。致力打造一个开源的软硬件平台。 语音识别芯片:LD3320 LD3320是非特定人(不用针对指定人)语音识别芯片,即语音声控芯片。最多可以识别50条预先内置的指令。 音频解码芯片:VS1053 VS1053是一款利用SPI通讯的音频解码模块,支持大部分的音频文件的解码播放和编码保存 摄像头:OV2640 OV2640是OmniVision公司生产的一颗1/4寸的CMOSUXGA(1632*1232)图像传感器;支持自动曝光控制、自动增益控制、自动白平衡、自动消除灯光条纹等自动控制功能。 软件框架说明本项目采用的是多级联控模式。将多个模块的任务分为多个级别,以语音识别为主体,摄像头和语音播报为从体,在语音识别到关键字的时候,会出发相对应的函数,实现不同的效果,而onenet是与语音识别互相独立的,会源源不断的把数据实时发送到云端。 软件模块说明smtp_thread_entry:邮件线程,用于发送邮件。 ld3320_asr_thread:语音识别线程,用于语音识别,调用其他程序。 onenet_upload_entry:onenet线程,用于向云端发送数据。 语音识别过程: 首先初始化LD3320芯片,在对其写入需要识别的关键字数据,之后启动LD3320,之后等待其信号引脚拉低,在其信号引脚拉低后,通过读取其寄存器,我们便能知道LD3320获取到了什么样的关键字。之后便从关键字调取我们的相对应的函数。使之工作于不同的功能。 演示效果演示视频: 比赛感悟在报名这个比赛之后,我的目标其实是比现在的功能多得多的,这一点可以从我的Gitee上面的进度表可以看出,奈何原本打算三个人做的项目,到最后,也是我一个人来完成。自己之前画的板子,也是因为自己画板功力不足,还有焊接能力不足,导致本来拥有更多功能的拓展板也没完成。 不过比赛嘛,重要的不是结果,而是过程。通过这次比赛,我最起码收货到了以下知识: 安卓开发,微信小程序设计,web开发(以上由于个人能力问题,其实并未实现),音频处理,STM32H750的众多DMA的设置,以及bootloader,同时也知道了STM32还能片外运行的神奇事情,也学会了RT-Thread Studio的使用。最重要的事情就是明白了不要过分依赖别人,自己想的计划,就要自己去实现,不要总是把任务布置给其他人。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值