2019-01-20 13:01:27 sinat_35162460 阅读数 7486
  • 树莓派+python 系统部分

    本课程主要讲如何安装树莓派操作系统,如何采购树莓派,如何联网,笔记本如何控制,树莓派如何共享网盘,桌面共享,如何使用souceinsight,如何使用Pycharm进行写代码

    884 人正在学习 去看看 程光淼

本文采用百度云语音识别API接口,实现低于60s音频的语音识别,也可以用于合成文本长度小于1024字节的音频,此外采用snowboy离线语音唤醒引擎可实现离线语音唤醒,实现语音交互。基于本内容可实现语音控制小车,语音控制音箱、语音交互。。。
可以查看我的github获取更多信息:https://github.com/dalinzhangzdl/AI_Car_Raspberry-pi
一、 百度云语音识别 python-SDK的安装
工欲善其事必先利其器,下面先来武装一下自己,申请属于自己的百度AI开发者账号,安装SDK(Software Development Kit,软件开发工具包)。
1、进入百度云平台,进入百度语音控制台后,创建自己的应用,获取属于你的ID号和密钥:
APP_ID = ‘114xxxx5’
API_KEY = ‘NYIvd23qqGAZxxxxxxxxxxxxxxx’
SECRET_KEY = ‘DcQWQ9Hxxxxxxxxxxxxxxxxxxxxxx’
2、SDK的下载与安装
应用创建完成后下载相应的开发SDK,这里采用python开发,下载python-SDK即可
在这里插入图片描述
SDK的安装:
将下载的SDK包拷贝到树莓派pi目录下,终端界面解压安装,安装过程如下:
解压包:unzip aip-python-sdk-2.0.0.zip
安装SDK包: sudo pip install baidu-aip
在这里插入图片描述
在这里插入图片描述
遵循以上步骤操作,就搭建好属于自己的语音识别和语音合成平台,再添加一个麦克风和一个喇叭或者音箱就可以进行语音识别方面的开发了,语音控制小车,控制智能家电等。

二、Python-SDK 实现语音识别和语音合成
1、python-SDK实现语音识别
遵循SDK文档进行快速开发,务必阅读文档。如果对自己的录音进行测试,需先采用格式工厂对录音文件进行转换,确保录音的音频参数符合云语音识别的要求。单通道、采样频率为16K PCM格式,也可先直接采用官方的音频进行测试。
程序如下:

#_*_ coding:UTF-8 _*_
# @author: zdl 
# 百度云语音识别Demo,实现对本地语音文件的识别。
# 需安装好python-SDK,录音文件不不超过60s,文件类型为wav格式。
# 音频参数需设置为 单通道 采样频率为16K PCM格式 可以先采用官方音频进行测试

# 导入AipSpeech  AipSpeech是语音识别的Python SDK客户端
from aip import AipSpeech
import os

''' 你的APPID AK SK  参数在申请的百度云语音服务的控制台查看'''
APP_ID = '114xxxx5'
API_KEY = 'NYIvd23qqGAZxxxxxxxxxxxxxxx'
SECRET_KEY = 'DcQWQ9Hxxxxxxxxxxxxxxxxxxxxxx'

# 新建一个AipSpeech
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)


# 读取文件
def get_file_content(filePath):   #filePath  待读取文件名
    with open(filePath, 'rb') as fp:
        return fp.read()

		
def stt(filename):         # 语音识别
    # 识别本地文件
    result = client.asr(get_file_content(filename),
                        'wav',
                        16000,
                        {'dev_pid': 1536,}      # dev_pid参数表示识别的语言类型 1536表示普通话
                        )
    print result

	# 解析返回值,打印语音识别的结果
    if result['err_msg']=='success.':
        word = result['result'][0].encode('utf-8')       # utf-8编码
        if word!='':
            if word[len(word)-3:len(word)]==',':
                print word[0:len(word)-3]
                with open('demo.txt','w') as f:
                    f.write(word[0:len(word)-3])
                f.close()
            else:
                print (word.decode('utf-8').encode('gbk'))
                with open('demo.txt','w') as f:
                    f.write(word)
                f.close()
        else:
            print "音频文件不存在或格式错误"
    else:
        print "错误"

# main函数 识别本地录音文件yahboom.wav
if __name__ == '__main__':
    
    stt('test.wav')
    

2、python-SDK实现语音合成
语音合成较语音识别简单,合成文本长度必须小于1024字节,如果本文长度较长,可以采用多次请求的方式。下面是合成本地文件demo程序:

#_*_ coding:UTF-8 _*_
# @author: zdl 
# 百度云语音合成Demo,实现对本地文本的语音合成。
# 需安装好python-SDK,待合成文本不超过1024个字节
# 合成成功返回audio.mp3 否则返回错误代码

# 导入AipSpeech  AipSpeech是语音识别的Python SDK客户端
from aip import AipSpeech
import os

''' 你的APPID AK SK  参数在申请的百度云语音服务的控制台查看'''
APP_ID = '114xxxx5'
API_KEY = 'NYIvd23qqGAZxxxxxxxxxxxxxxx'
SECRET_KEY = 'DcQWQ9Hxxxxxxxxxxxxxxxxxxxxxx'

# 新建一个AipSpeech
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)

# 将本地文件进行语音合成
def tts(filename):
    f = open(filename,'r')
    command = f.read()
    if len(command) != 0:
        word = command
    f.close()
    result  = client.synthesis(word,'zh',1, {
        'vol': 5,'per':0,
    })
	
# 合成正确返回audio.mp3,错误则返回dict 
    if not isinstance(result, dict):
        with open('audio.mp3', 'wb') as f:
            f.write(result)
        f.close()
        print 'tts successful'

# main

if __name__ == '__main__':

tts('demo.txt')
2019-11-20 22:33:08 weixin_44897649 阅读数 76
  • 树莓派+python 系统部分

    本课程主要讲如何安装树莓派操作系统,如何采购树莓派,如何联网,笔记本如何控制,树莓派如何共享网盘,桌面共享,如何使用souceinsight,如何使用Pycharm进行写代码

    884 人正在学习 去看看 程光淼

基于树莓派的语音识别和语音合成

摘要

语音识别技术即Automatic Speech Recognition(简称ASR),是指将人说话的语音信号转换为可被计算机程序所识别的信息,从而识别说话人的语音指令及文字内容的技术。目前语音识别被广泛的应用于客服质检,导航,智能家居等领域。树莓派自问世以来,受众多计算机发烧友和创客的追捧,曾经一“派”难求。别看其外表“娇小”,内“心”却很强大,视频、音频等功能通通皆有,可谓是“麻雀虽小,五脏俱全”。本文采用百度云语音识别API接口,在树莓派上实现低于60s音频的语音识别,也可以用于合成文本长度小于1024字节的音频。
此外,若能够结合snowboy离线语音唤醒引擎可实现离线语音唤醒,实现语音交互。

材料:

树莓派3B+ ×1
USB声卡 ×1
麦克风 ×1
PC ×1
音视频线材若干

树莓派3B+

实现过程:

一、 百度云语音识别 python-SDK的安装

  1. 为了能够调用百度云语音识别API接口,需要申请属于自己的百度AI开发者账号,安装SDK(Software Development Kit,软件开发工具包)。
    申请属于自己的百度AI开发者账号

  2. 进入百度云平台,进入百度语音控制台后,创建自己的应用,获取属于你的ID号和密钥。
    创建应用获取ID号和密钥

  3. Python-SDK的下载与安装

    将下载的SDK包拷贝到树莓派pi目录下,终端界面解压安装,安装过程如下:
    解压包:unzip aip-python-sdk-2.0.0.zip
    安装SDK包: sudo pip install baidu-aip
    指令代码

二.修改编辑官方python测试程序

  1. 语音识别程序:
#_*_ coding:UTF-8 _*_
# @author: zdl 
# 百度云语音识别Demo,实现对本地语音文件的识别。
# 需安装好python-SDK,录音文件不不超过60s,文件类型为wav格式。
# 音频参数需设置为 单通道 采样频率为16K PCM格式 可以先采用官方音频进行测试

# 导入AipSpeech  AipSpeech是语音识别的Python SDK客户端
from aip import AipSpeech
import os

''' 你的APPID AK SK  参数在申请的百度云语音服务的控制台查看'''
APP_ID = '17xxxx11'
API_KEY = 'QZhVe5xxxxxvhYVA'
SECRET_KEY = 'bGlGGxbWLxxxxxxxxA8tshAGA'

# 新建一个AipSpeech
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)


# 读取文件
def get_file_content(test):   #filePath  待读取文件名
    with open(test, 'rb') as fp:
        return fp.read()

        
def stt(test):         # 语音识别
    # 识别本地文件
    result = client.asr(get_file_content(test),
                        'wav',
                        16000,
                        {'dev_pid': 1536,}      # dev_pid参数表示识别的语言类型 1536表示普通话
                        )
    print (result)


    # 解析返回值,打印语音识别的结果
    if result['err_msg']=='success.':
        word = result['result'][0].encode('utf-8')       # utf-8编码
        if word!='':
            if word[len(word)-3:len(word)]==',':
                print (word[0:len(word)-3])
                with open('demo.txt','wb+') as f:
                    f.write(word[0:len(word)-3])
                f.close()
            else:
                print (word.decode('utf-8').encode('gbk'))
                with open('demo.txt','wb+') as f:
                    f.write(word)
                f.close()
        else:
            print ("音频文件不存在或格式错误")
    else:
        print ("错误")

# main函数 识别本地录音文件yahboom.wav
if __name__ == '__main__':
    
    stt('test.wav')

  1. 语音合成程序:
#_*_ coding:UTF-8 _*_
# @author: zdl 
# 百度云语音合成Demo,实现对本地文本的语音合成。
# 需安装好python-SDK,待合成文本不超过1024个字节
# 合成成功返回audio.mp3 否则返回错误代码

# 导入AipSpeech  AipSpeech是语音识别的Python SDK客户端
from aip import AipSpeech
import os

''' 你的APPID AK SK  参数在申请的百度云语音服务的控制台查看'''
APP_ID = '17xxxx1'
API_KEY = 'QZhVxxxxxxxxxxxhYVA'
SECRET_KEY = 'bGlGGxxxxxxxxxxxxPGP8A8tshAGA'

# 新建一个AipSpeech
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)

# 将本地文件进行语音合成
def tts(demo):
    f = open(demo,'r')
    command = f.read()
    if len(command) != 0:
        word = command
    f.close()
    result  = client.synthesis(word,'zh',1, {
        'vol': 5,'per':0,
    })
    
# 合成正确返回audio.mp3,错误则返回dict 
    if not isinstance(result, dict):
        with open('audio.mp3', 'wb') as f:
            f.write(result)
        f.close()
        print ('tts successful')

# main

if __name__ == '__main__':

tts('demo.txt')

测试和分析:

测试过程中,我对此功能进行三次测试,测试用例分别为:

  1. 短句“北京理工大学”
  2. 短句“智能语音交互技术”
  3. 绕口令
    “刘奶奶找牛奶奶买牛奶,牛奶奶给刘奶奶拿牛奶,刘奶奶说牛奶奶的牛奶不如柳奶奶的牛奶,牛奶奶说柳奶奶的牛奶会流奶,柳奶奶听见了大骂牛奶奶你的才会流奶,柳奶奶和牛奶奶泼牛奶吓坏了刘奶奶,大骂再也不买柳奶奶和牛奶奶的牛奶”

此三条测试用例,分别从长句和短句,简单含义和复杂含义,是否有易混音三个方面对比进行测试,对百度语音技术的准确性提出了较高的要求。

测试前,需要提前用录音软件录制好三段音频,然后用Adobe Audition软件对音频格式化处理,因为百度智能云语音识别技术支持原始 PCM 的录音参数必须符合 16k 采样率、16bit 位深、单声道,支持的格式有:pcm(不压缩)、wav(不压缩,pcm编码)、amr(压缩格式)。

结果及结论:

测试一:短句“北京理工大学”
短句“北京理工大学”

测试二:短句“智能语音交互技术”
短句“智能语音交互技术”

测试三:绕口令
绕口令

三个测试均成功运行。

语音识别方面,此程序成功运行后,会在python-IDE中产生返回值结果,并会在路径/home/pi内产生一个demo.txt文件,文件内容即为输入音频文件的文字识别结果。百度在语音识别方面做出的努力可见一斑,通过调整程序中的参数,可以识别除普通话以外其他语言的音频文件(如英语),而且准确度较高,尤其是短句识别甚高,在易混淆字音重复出现的绕口令中,仅将其中一个“柳”字错误识别为“牛”。
在这里插入图片描述

语音合成方面,程序以上述的demo.txt为输入,将文字上传到百度云数据库,转换成功后反馈“successful”到IDE界面,并在目录/home/pi文件夹下生成audio.wav音频文件,此文件即为由文字合成的语音。测试发现,次音频信号在生活中较为熟悉的停顿处有较为明显的顿挫感,但是在长难句中,无法做到顿挫处的智能识别。

遇到的问题:

在整个编程过程中,可以说是举步维艰,由于自身能力有限,初学python和Linux,导致在系统操作和规范方面有很多的盲区,导致犯了很多诸如Linux系统授权、python缩进、命令行书写等十分低级的错误,一度陷入程序不断报错却不知错在何处的尴尬境地。同时,由于百度语音识别技术对于上传的音频有着较为苛刻的要求,必须符合 16k 采样率、16bit 位深、单声道等,对于这些内容的不熟悉也走了很多弯路。
最令我惊艳的是,百度智能云计算AI开放平台为程序员搭建了一个十分全面,而且性能强悍的平台,从语音到图像,再到智能数据,涉猎了我们所熟知的绝大多数AI领域,其中对不同实现方式进行了细致的备注和说明,为我实现此项目扫清了障碍。
错误码

深入开发的设想:

在完成上述功能的实现之后,我尝试让树莓派实现类似与智能音箱的人机交互功能(全网已有大神实现),实现过程中无疑要用到snowboy引擎,它一款高度可定制的唤醒词检测引擎,可以用于实时嵌入式系统,并且始终监听(即使离线)。当前,它可以运行在 Raspberry Pi、(Ubuntu)Linux 和 Mac OS X 系统上。在一些棘手的解决方案中,它可以运行完整的自动语音识别(ASR,Automatic Speech Recognition)来执行热词检测。但是,我在尝试实现过程中遇到了几个无法解决的问题:

  1. 由于树莓派内置声卡没有麦克风,需要利用外接声卡执行热词唤醒,但是在Linux系统中更改声卡驱动成了我越不去的坎儿,尝试了网络上更改驱动的多种方式后,无一能更够成功更改,我仍需继续在Linux方向深入学习。
  2. 在树莓派上下载好portaudio后,编译过程中频繁报错,涉及到gcc相关内容,我在这方面仍需继续努力。

致谢:

感谢百度智能云提供的云计算支持

参考文献:

  1. https://ai.baidu.com/docs#/ASR-Online-Python-SDK/f55e8c00
  2. https://www.cnblogs.com/rnckty/p/8067115.html
  3. https://blog.csdn.net/sinat_35162460/article/details/86544772
  4. https://snowboy.kitt.ai/
  5. https://blog.csdn.net/sinat_35162460/article/details/86547013

成果
作者:Boyle Zhao
2019年11月于北京理工大学

2017-04-11 09:23:31 zyaiwmy 阅读数 17318
  • 树莓派+python 系统部分

    本课程主要讲如何安装树莓派操作系统,如何采购树莓派,如何联网,笔记本如何控制,树莓派如何共享网盘,桌面共享,如何使用souceinsight,如何使用Pycharm进行写代码

    884 人正在学习 去看看 程光淼

树莓派的基本概念和安装系统在系列文章一中介绍了.这篇准备介绍一下语音识别.

一直想研究一下语音识别,用来做家庭物联网的控制入口,未来也许就是这样,讯飞的叮咚音响可以连接京东的物联平台,苹果的homekit平台,华为的平台暂时落后的有点多...

国内语音识别领域,我个人比较欣赏讯飞.识别效果业界领先,这几年百度语音识别也在追赶,这次的研究让我对百度的语音识别效果刮目相看,Google的在国内不用想了...

言归正传

1讯飞语音识别接口.

这次在树莓派上实现语音识别控制家里的设备(插座,灯 等等)的研究,第一反应是找讯飞的解决方案,结果讯飞收回的arm平台开放的sdk,需要申请,有网友放出之前开放出来的sdk库,但是仍然收每天识别次数的限制.反感搞这些事情(申请需要在论坛里贴上研究过程,一个有效评论+1,申请后,三个星期发一次...),转而研究一下百度的语音识别接口.这里贴上网友的链接,里面有早期讯飞开放的sdk下载链接,有兴趣的可以去下载.

http://blog.csdn.net/yanghuan313/article/details/50992909


2百度语音识别接口.

百度语音开放平台号称永久免费,开发需要去注册账号,在平台上创建应用,这里不详细叙述了,平台操作比较简单,可以参考下面的链接(不用下载sdk什么的,这里使用语音识别 REST API ,只需要拿到API KEY、Secret KEY.)

http://www.tuicool.com/articles/z2m6V3v

平台支持android, ios.我们这里使用的是语音识别 REST API接口,也就是http传输识别.

使用python开发,在ubuntu上先尝试一下效果

需要安装pycurl

sudo apt-get install libcurl4-gnutls-dev

pip install pycurl

安装好后,下面是python的代码:

#encoding=utf-8

import wave
import urllib, urllib2, pycurl
import base64
import json
## get access token by api key & secret key

def get_token():
    apiKey = "*******"
    secretKey = "***************"
    auth_url = "https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id=" + apiKey + "&client_secret=" + secretKey
    res = urllib2.urlopen(auth_url)
    json_data = res.read()
    return json.loads(json_data)['access_token']

def dump_res(buf):
    print buf


## post audio to server
def use_cloud(token):
    #  fp = wave.open('test.pcm', 'rb')
    fp = wave.open('cn_word.wav', 'rb')
    #  fp = wave.open('vad_1.wav', 'rb')
    nf = fp.getnframes()
    f_len = nf * 2
    audio_data = fp.readframes(nf)

    #mac addr
    cuid = "123456"
    srv_url = 'http://vop.baidu.com/server_api' + '?cuid=' + cuid + '&token=' + token
    http_header = [
        'Content-Type: audio/pcm; rate=16000',
        #  'Content-Type: audio/pcm; rate=8000',
        'Content-Length: %d' % f_len
    ]

    c = pycurl.Curl()
    c.setopt(pycurl.URL, str(srv_url)) #curl doesn't support unicode
    #c.setopt(c.RETURNTRANSFER, 1)
    c.setopt(c.HTTPHEADER, http_header)   #must be list, not dict
    c.setopt(c.POST, 1)
    c.setopt(c.CONNECTTIMEOUT, 30)
    c.setopt(c.TIMEOUT, 30)
    c.setopt(c.WRITEFUNCTION, dump_res)
    c.setopt(c.POSTFIELDS, audio_data)
    c.setopt(c.POSTFIELDSIZE, f_len)
    c.perform() #pycurl.perform() has no return val

if __name__ == "__main__":
    token = get_token()
    use_cloud(token)

识别结果如下:


这里使用的是讯飞sdk中的wav文件,所以代码中rate=16000.大家根据自己的音频数据去修改.识别结果完全正确,可见音频文件效果可以的话,百度语音识别接口完全可以用,不需要讯飞sdk.

这里插一下题外的话,因为考虑语音文件效果的问题,自然考虑到了麦克风硬件的优劣,这里又再次提到讯飞,讯飞出了六麦环形阵列的麦克风阵列,链接:http://www.xfyun.cn/services/mic#list_wrap

不得不说,虽然没有使用,但是我相信效果,只是好贵.......不考虑成本的可以试试.


说一下我最后选择的方案,语音识别效果可以的情况下,要考虑唤醒的问题,唤醒方案有很多,上讯飞麦克风阵列的可以用唤醒词,可以增加声音传感器,某宝上也就几块钱,但是声音传感器的阀值是我比较担心的,我并不想语音识别被莫名的声音唤醒,因为这种传感器只能检测声音的有无.大家根据自己的需求去增加特定的传感器去唤醒语音识别就好.对于我来说,考虑到家里有小米网关,插座等大量的小米设备,使用了树莓派nodejs homebridge插件(虚拟出一个HomeKit网关),这样就可以对接到苹果手机的家庭应用,用苹果的siri控制了.当然以后还是想上自己的语音识别的.

先把关系整理一下:

  1. nodejs是一个命令行下的javascript运行环境。
  2. npm是nodejs的插件社区,里面有无数的好东西和不好的东西,因为是不需要审核的。
  3. homebridge是npm社区上的插件之一,可以虚拟出一个HomeKit网关出来,但并不负责任何设备的适配。
  4. 其它设备要想使用homebridge和HomeKit互通,就要写一个homebridge的插件,现在这种插件也有上百个了
  5. 做homebridge-aquara,Aquara是做小米多功能网关的深圳绿米联创的自有品牌,最近出的墙壁开关和空调伴侣都是这个品牌的

最后具体的步骤参见小米bbs

http://bbs.xiaomi.cn/t-13198850


2018-12-17 22:21:36 zz531987464 阅读数 191
  • 树莓派+python 系统部分

    本课程主要讲如何安装树莓派操作系统,如何采购树莓派,如何联网,笔记本如何控制,树莓派如何共享网盘,桌面共享,如何使用souceinsight,如何使用Pycharm进行写代码

    884 人正在学习 去看看 程光淼

当前语音识别的sdk一般要求使用的 输入音频流的音频格式为pcm, 单声道,16bits, 小端序。采样率16k.

接下来我们在树莓派3B+的QT中设置一个录制音频,结束录制,播放音频的三个按钮.

void Widget::on_startRecord_clicked()
{
    audioDeviceListI = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
    QList<QAudioDeviceInfo>::iterator it;
    for (it = audioDeviceListI.begin(); it != audioDeviceListI.end(); it++) {
        qDebug() << "get ALL INPUT device name:"+(*it).deviceName();
        if ((*it).isNull()) {
            qDebug() << "is NULL device name:"+(*it).deviceName();
        }
    }
    qDebug() << "-------INPUT-------"+audioDeviceListI.at(14).deviceName();

    audioDeviceListI2 = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
    QList<QAudioDeviceInfo>::iterator it2;
    for (it2 = audioDeviceListI2.begin(); it2 != audioDeviceListI2.end(); it2++) {
        qDebug() << "get ALL OUTPUT device name:"+(*it2).deviceName();
        if ((*it2).isNull()) {
            qDebug() << "is NULL device name:"+(*it2).deviceName();
        }
    }
    qDebug() << "-------OUTPUT-------"+audioDeviceListI2.at(14).deviceName();


    qDebug() << "start record ..........";
    inputFile.setFileName("/home/pi/test.pcm");
    inputFile.open(QIODevice::WriteOnly | QIODevice::Truncate);
    QAudioFormat format;
    format.setSampleRate(16000);
    format.setChannelCount(1);
    format.setSampleSize(16);
    format.setCodec("audio/pcm");
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setSampleType(QAudioFormat::SignedInt);
    QAudioDeviceInfo info(audioDeviceListI.at(14));
    if (!info.isFormatSupported(format))
    {
        qWarning() << "default format not supported try to use nearest";
        format = info.nearestFormat(format);
    }
    audioInput = new QAudioInput(info,format, this);
    audioInput->start(&inputFile);
    qDebug() << "record begin!";
}

start按钮的槽函数中我们首先遍历当前树莓派3b+中所有的语音输入设备,在其中找到关键词 "plughw:CARD="的语音设备(一般我们使用语音设备时选择该项即可),这里我已经知道了是容器中下标为14的成员,直接给打印了出来,后续知道了我们可以直接给制定,不需要遍历了,因为此处似乎会影响运行速度,点击按钮后不能及时的录制音频.

void Widget::on_stopRecord_clicked()
{
    audioInput->stop();
    inputFile.close();
    delete audioInput;
    qDebug() << "record end!";
}

stop按钮的槽函数作用是停止录制保存音频文件.没什么好说的!接下来讲一下播放的槽函数.

void Widget::on_playRecord_clicked()
{
    outputFile.close();
    if (audioOutput) {
        delete audioOutput;
    }

    qDebug() << "play record file.....";
    outputFile.setFileName("/home/pi/test.pcm");
    outputFile.open(QIODevice::ReadOnly);
    QAudioFormat format;
    format.setSampleRate(16000);
    format.setChannelCount(1);
    format.setSampleSize(16);
    format.setCodec("audio/pcm");
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setSampleType(QAudioFormat::SignedInt);
    QAudioDeviceInfo info(audioDeviceListI2.at(14));
    if (!info.isFormatSupported(format))
    {
        qWarning() << "default format not supported try to use nearest";
        format = info.nearestFormat(format);
    }
    audioOutput = new QAudioOutput(info,format, this);
    audioOutput->start(&outputFile);
//    inputFile.close();
//    delete audioOutput;
    qDebug() << "play record file over.....";
}

头文件Widget.h

private:
    QList<QAudioDeviceInfo> audioDeviceListI;
    QList<QAudioDeviceInfo> audioDeviceListI2;
    QFile inputFile;
    QFile outputFile;
    QAudioInput *audioInput;
    QAudioOutput *audioOutput;

上面的代码仅仅是一个表示QT能正常录制pcm音频的demo,代码还有一些需要优化的地方.例如可以把QAudioFormat类的成员做内部私有变量,该成员的属性设置可以放在构造函数中,这样可以减少重复代码量等

2019-08-17 21:36:58 weixin_42683077 阅读数 1390
  • 树莓派+python 系统部分

    本课程主要讲如何安装树莓派操作系统,如何采购树莓派,如何联网,笔记本如何控制,树莓派如何共享网盘,桌面共享,如何使用souceinsight,如何使用Pycharm进行写代码

    884 人正在学习 去看看 程光淼

树莓派打造智能语音控制系统(附最终代码)

本系统采用的树莓派为3B+

1、语音识别系统在实际应用中的意义:

(1)为人们提供高效,便利的居住环境。
(2)摆脱以往必须手动操作的麻烦,通过语音就能达到控制相关设备的目的。
(3)智能语音对话:通过语音和机器人对话,询问想要知道的相关信息,节省自己手动搜索的时间。

2、系统方案设计

2.1 系统的整体结构

系统的整体结构如图2-1所示。

图2-1 系统整体结构图

本智能语音控制系统采用电器设备+树莓派+百度语音接口来实现,分为应用层、逻辑层和处理层。其中电气设备作为应用层,负责系统的处理结果显现出来。树莓派作为逻辑层,处理业务逻辑上的问题,其中包括对处理层返回的识别后的语音信号进行存储,以及采取相应的操作。百度语音接口作为处理层,对树莓派所录的语音信号进行识别,将识别后的语音信号再次返回给树莓派。

2.2 系统的硬件整体架构

本系统中我们的电气设备直接连接树莓派的GPIO口,具体的连线如图2-2所示。

图2-2 系统整体硬件架构图

2.3 系统的软件整体架构

智能语音控制系统的软件整体架构主要分为以下四部分:
语音信号的采集:通过树莓派自带的录音功能来采集语音信号,并保存。
语音信号的识别:通过python调用百度语音接口,识别采集的语音信号,将识别后的语音信号以wav文件的格式存储于树莓派中。
语音机器人的回复:读取存放识别语音信号的wav文件,调用图灵机器人接口,实现机器人智能回复。
电器设备的控制:电器设备的控制其实说到底就是对树莓派GPIO的控制,其中对风扇驱动的控制主要通过python实现,而led灯的控制主要通过C语言来实现。

3、系统设计与实现

3.1系统总体需求概述

从智能语音控制系统的使用者这个角度出发,我们应该尽量避免使用者去直接接触到我们这个系统的内部设计,而是应该提供简单的接口来供用户使用。本系统为智能语音系统,所以在功能的建设上应该具备以下三方面的需求:
(1)对于智能语音对话模块,我们通过百度AI开放平台的语音识别接口和图灵机器人来实现对话的功能,只要能采集到使用者的语音信号,系统就会去调用相应的接口来给予适当的回复。
(2)对于智能语音控制灯泡开关模块,系统会去识别用户下达的语音指令,并将其转换成相应的操作,达到控制灯泡开关的目的。
(3)对于语音控制风扇开关以及风扇档位模块,系统同样会去识别用户下达的语音指令,达到控制风扇开关以及调整风扇档位的目的。

3.2智能语音识别模块的具体实现

3.2.1语音信号的采集

本系统采用树莓派自带的录音arecord来录音,通过以下指令既可以启动树莓派的录音功能:

arecord -D "plughw:1" -f S16_LE -r 16000 -d 3 wav文件。

其中-D后面所带的为设备名、-f后面所带的为采样格式、-r后面所带的为采样频率。因为百度语音接口所要求的采样频率为16000或者8000,所以在本系统中我们采用了16000的采样频率。后面所带wav文件是我们录音所存储的文件。

3.2.2百度AI语音接口的调用

首先要使用百度AI语音接口,要先去百度AI平台申请语音识别账号,申请成功会得到API Key和Secret Key,如图3-1所示。后续我们在python代码中需要填入这两个key,如下所示:

body = { “grant_type”:“”, “id” :”API Key”, “secret”:”Secret Key”, }。

这样我们的程序就可以调用到百度语音接口了。

图3-1 AppID和API Key

3.2.3智能语音识别的实现

智能语音识别提交的数据格式如Data所示:

Data = { “format” : “wav”, “rate” : 16000, “channel” : 1, “cuid” : “”, “token” : tok, “speech” : wav_data, “len” : wav_length }。

format为提交录音文件的格式,在这里为wav。rate为采样速率,在这里为16000,要和录音的采样速率等同。token为上小节调用百度语音接口所返回的内容。speech和len则为录音文件的内容以及长度。在这里使用urllib2这个库(树莓派自带,只需要导入即可)来进行网络的交互,只需要把Data提交到相应的url路径。就可以得到从接口返回的识别后的语音数据。

3.3智能语音对话模块的具体实现

3.3.1图灵机器人服务平台的调用

关于智能语音对话模块的实现,我们在基于语音识别的基础上,增加了一个图灵机器人接口的使用。图灵机器人是一个免费的开放平台,这个平台为广大开发群众以及企业合作伙伴提供一系列智能语义处理的服务。话不多说,我们来看具体实现。
首先要使用这个平台,我们需要去图灵机器人官网注册一个账号,注册后我们就可以申请机器人,同时得到一个apikey,如图3-2所示。通过这个apikey我们就可以去请求调用到图灵机器人服务平台。

图3-2 图灵机器人的apikey

3.3.2智能语音回复的实现

我们通过在python代码中加入这个apikey。请求的数据格式如下所示:
body = {"key":Tuling_API_KEY,"info":words.encode("utf-8")}。
其中,key填写的就是所申请到的机器人的apikey,info就是通过百度语音接口识别后的语音数据。 r = requests.post(url,data=body,verify=True),其中的url为图灵机器人接口的路径,r为图灵机器人返回的语音数据。
因为后续还需要根据识别后的语音数据来执行一些相应的操作以及通过音箱播放图灵机器人所返回的语音信息,所以在这里需要额外多加一步,对语音数据进行合成。同样是利用百度AI语音合成接口来实现。
音箱播放图灵机器人的回复是通过mpg123来实现的。mpg123为音频解码的软件,通过它可以对音频进行解码,同时调用驱动来播放音频。上述调用语音合成接口后会返回一个url = “http://tsn.baidu.com/text2audio?tex=“+tex+”&lan=zh&cuid=”+cuid+”&ctp=1&tok=”+tok+”&per=3” 。有了这个url,就可以通过os.system(‘mpg123 “%s”’%url)这个指令,来使树莓派播放合成后的音频。下面一些功能模块也会用到mpg123来播放一些相应的音频。

3.4语音控制led灯模块的具体实现

3.4.1 语音识别具体操作指令部分的实现

语音控制led灯模块是基于智能语音识别的基础上来实现的。主要分为三个步骤:
(1) 通过录音功能,将语音指令记录于wav文件中。
(2) 读取wav文件,调用语音识别接口进行识别,并用一个info字段记录识别后的语音信号。
(3) 在python代码中对info字段进行比对,如若info字段中存在例如“开灯”、“关灯”等字段,即执行相应的操作。

3.4.2控制led灯的具体实现

本系统中控制led灯是采用了WiringPi这个函数库来实现的。WiringPi是树莓派的GPIO控制库函数,其本身采用C语言或者C++来开发,可以嵌入到其他函数中,如python或者PHP中。在本系统中,我们通过控制WiringPi模式下树莓派的4号引脚来实现控制led灯的开关。当识别到开灯指令,运行./light on指令给予4号引脚高电平,led灯亮,当识别到关灯指令,运行./light off给予4号引脚低电平,led灯灭。注意一个事项:在执行light文件时候,我们需要给他一个执行的权限,因为linux系统中对于文件权限的管控比较严格,我们可以用以下命令chmod u+x light来给灯泡脚本一个执行的权限。

3.5 语音控制风扇驱动模块的具体实现

3.5.1 语音识别各种控制指令的实现

语音识别各种控制指令同上述。只是在其中加入了其他一些控制指令,当识别到如“风扇一档”这样的指令,可以改变风扇的转速。

3.5.2 L298N模块的介绍

改变风扇转速是基于PWM技术,在这里我们采用L298N电机驱动板模块来帮助我们实现这个功能,L298N电机驱动模块的外观及连线方式如图3-3所示。

图3-3 L298N电机驱动模块的外观以及接口连线介绍

3.5.3控制电机转速的实现

控制电机转速的软件实现主要采用了python。p = GPIO.PWM(32,50)通过这条指令设置树莓派GPIO引脚中32引脚为输出,PWM的频率为50hz。p.start(0)这个指令让信号开始输出。最后是改变转速的指令p.ChangeDutyCycle(N),通过改变N来改变其占空比(N的取值在0-100之间),就可以达到控制转速的目的,占空比越大,电机的转速越快。
在本系统中,我们只控制一个电机的转速,所以在这里只使用了L298N电机驱动模块IN1这个引脚。树莓派32GPIO口发出PWM信号,连接到L298N电机驱动模块的IN1引脚,既可以达到控制电机转速的目的,L298N电机驱动模块与树莓派连线图如3-5所示。

图3-5 L298N电机驱动模块与树莓派的连线图

4 调试

4.1 语音唤醒功能的调试

本设计的程序运行之后,首先会停留在第一个录音环节,为时2秒,如图4-1所示。其功能作用为语音唤醒,就是在每次你下达语音指令之前,需要说一声“你好”来唤醒系统,然后才可以继续下达语音指令。唤醒系统后系统会播报“我来啦”的语音,屏幕上也会显示“我来啦”字样,如图4-2所示。

在这里插入图片描述
4-1 语音唤醒录音

4-2 语音唤醒成功显示

经多次测试发现,正常情况下语音唤醒功能都能较好的实现,但同时也存在特殊情况,主要发生在系统没有录到音时,因为我给语音唤醒的录音时间为2秒,在这两秒内如果没有录到音就会出现问题。所以给的解决方法是对语音唤醒这个函数进行递归调用,如果第一次没有录到音,程序就会重新调用语音唤醒这个函数,无限循环,直到录到音为止。

4.2 语音控制调试

设计中所用到的语音控制指令如下表所示:

指令 功能
打开灯 Led灯打开
关掉灯 Led灯关闭
打开风扇 驱动电机开始转动
风扇二档 驱动电机加快转速
关掉风扇 驱动电机停止转动

在经历多次测试后发现,一般情况下系统的的控制功能和对话功能都能够较好的实现,互不干扰。但是存在一些特殊情况,比如说你下达的是控制命令,但是系统却启用了对话功能,控制功能没有生效。经过对系统进行重重排查,将原因归结于录音设备的问题,比如说你“打开灯”但是系统并没有收集到这个完整的指令,可能录音到的为“打”或者“打开”,系统判定你没有说出完整的控制指令,因此就会调用对话功能来对此次录音到的信息来做一个回复。针对这种情况,因为本系统采取的录音设备质量比较一般,所以目前无法很好的去解决。

//使用如下代码记得修正缩进问题,python格式要求
系统程序如下:
代码1
# coding: utf-8
import RPi.GPIO as GPIO 
import numpy as np 
from datetime import datetime 
import wave 
import time 
import urllib, urllib2, pycurl 
import base64 
import json 
import sys 
import requests  
import os
import yuyinhecheng
import tulin
import yuyinshibie
 
token = yuyinshibie.get_access_token()
def yuyinhx():
   os.system('arecord -D "plughw:1" -f S16_LE -r 16000 -d 3 /home/pi/Desktop/yyhx.wav')
   meg =yuyinshibie.asr_main("/home/pi/Desktop/yyhx.wav",token)
   if any(['好'.encode("utf-8") in meg,'你'.encode("utf-8")in meg,"你好".encode("utf-8")in meg,"您".encode("utf-8")in meg]):
       f=open('/home/pi/Desktop/yyhx.wav','wb')
       f.close()
       url="http://tsn.baidu.com/text2audio?tex=我来啦&lan=zh&cuid=B8-27-EB-BA-24-14&ctp=1&tok="+token+"&per=3"
       os.system('mpg123 "%s"'%url)
       global flag
       flag = True
   else:
       time.sleep(3)
       yuyinhx()
​​
def controllPwm(speed):
   #atexit.register(GPIO.cleanup)
   os.system('cd /home/pi/Desktop&&./start on')​#这句应该可以不要
   servopin = 32                      #用到树莓派哪个口
   GPIO.setmode(GPIO.BOARD)​      #设置模式
   GPIO.setup(servopin, GPIO.OUT, initial=False) #设置32为输出
   p = GPIO.PWM(servopin,50) #50HZ #设置32为PWM 频率50Hz
   p.start(0)
   p.ChangeDutyCycle(speed)
   time.sleep(0.02) 
def controlldevices():
   switch = True
   while switch:
       yuyinhx()
       if flag:
           while True:
               os.system('sudo arecord -D "plughw:1" -f S16_LE -r 16000 -d 3 /home/pi/Desktop/pwm.wav')
               info =yuyinshibie.asr_main("/home/pi/Desktop/pwm.wav",token)
               if '打开风扇'.encode("utf-8") in info:
                   url = "http://tsn.baidu.com/text2audio?tex=正在为您开风扇&lan=zh&cuid=B8-27-EB-BA-24-14&ctp=1&tok="+token+"&per=3"
                   os.system('mpg123 "%s"'%url)
                   os.system('cd /home/pi/Desktop&&./start on')
                   servopin = 32
                   GPIO.setmode(GPIO.BOARD)
                   GPIO.setup(servopin,GPIO.OUT,initial=False)
                   p = GPIO.PWM(servopin,50)
                   p.start(0)
                   p.ChangeDutyCycle(50) 
                   break
               
​​​​             elif '二档'.encode("utf-8") in info:
                   url = "http://tsn.baidu.com/text2audio?tex=正在开风扇一档&lan=zh&cuid=B8-27-EB-BA-24-14&ctp=1&tok="+token+"&per=3"
                   os.system('mpg123 "%s"'%url)
                   os.system('cd /home/pi/Desktop&&./start on')
                   servopin = 32
                   GPIO.setmode(GPIO.BOARD)
                   GPIO.setup(servopin,GPIO.OUT,initial=False)
                   p = GPIO.PWM(servopin,50)
                   p.start(0)
                   p.ChangeDutyCycle(100)
                   break
 
               elif '关掉风扇'.encode("utf-8") in info:
                   url = "http://tsn.baidu.com/text2audio?tex=正在为您关风扇&lan=zh&cuid=B8-27-EB-BA-24-14&ctp=1&tok="+token+"&per=3"
                   os.system('mpg123 "%s"'%url)
                   os.system('cd /home/pi/Desktop&&./start off')
                   servopin = 32
                   GPIO.setmode(GPIO.BOARD)
                   GPIO.setup(servopin,GPIO.OUT,initial=False)
                   p = GPIO.PWM(servopin,50)
                   p.start(0)
                   p.ChangeDutyCycle(0)
                   break
​​​​
​​​​		elif '打开灯'.encode("utf-8") in info:
                   url = "http://tsn.baidu.com/text2audio?tex=正在为您开灯&lan=zh&cuid=B8-27-EB-BA-24-14&ctp=1&tok="+token+"&per=3"
                   os.system('mpg123 "%s"'%url)
                   os.system('cd /home/pi/Desktop&&./light on')
                   break
 
 
               elif '关掉灯'.encode("utf-8") in info:
                   url = "http://tsn.baidu.com/text2audio?tex=正在为您关灯&lan=zh&cuid=B8-27-EB-BA-24-14&ctp=1&tok="+token+"&per=3"
                   os.system('mpg123 "%s"'%url)
                   time.sleep(0.5)
                   os.system('cd /home/pi/Desktop&&./light off')
                   break
​​​​
​​​​elif info is not None:
                   if'风扇'.encode("utf-8") not in info:
                      if '灯'.encode("utf-8") not in info:
                          if'二档'.encode("utf-8")not in info:
                              tex = tulin.Tuling(info)
​​​​​           if any(['那就换个方式看看'.encode("utf-8") in tex , '扫码出现问题了吗'.encode("utf-8")in tex,'是失效了吗'.encode("utf-8")in tex,'有没有联网呀'.encode("utf-8")in tex,'不会是假的吧'.encode("utf-8")in tex]):
                                    url="http://tsn.baidu.com/text2audio?tex=请语音输入指令&lan=zh&cuid=B8-27-EB-BA-24-14&ctp=1&tok="+token+"&per=3"
                                    os.system('mpg123 "%s"'%url)
                                    continue
​​​​​​​​else:​
                                     url = yuyinhecheng.yuyinhecheng_api(tok,tex)
                                     os.system('mpg123 "%s"'%url)
                                      time.sleep(0.5)
​​​​​                     break
               
​​​​else:
                   url = "http://tsn.baidu.com/text2audio?tex=请语音输入指令&lan=zh&cuid=B8-27-EB-BA-24-14&ctp=1&tok="+token+"&per=3"
                   os.system('mpg123 "%s"'%url)
                   continue
​​​​​
​​​​​
​​​​
if __name__ == '__main__':
controlldevices()
 
代码2:
# coding: utf-8
import sys 
import json 
import urllib2 
import base64 
import requests
reload(sys) 
sys.setdefaultencoding(“utf-8”)
def get_access_token(): 
url = “https://openapi.baidu.com/oauth/2.0/token” 
body = { 
“grant_type”:”client_credentials”, 
“client_id” :”此处填写自己的client_id”, 
“client_secret”:”此处填写自己的client_secret”, 
}
r = requests.post(url,data=body,verify=True)
respond = json.loads(r.text)
return respond["access_token"]
def yuyinshibie_api(audio_data,token): 
speech_data = base64.b64encode(audio_data).decode(“utf-8”) 
speech_length = len(audio_data) 
post_data = { 
“format” : “wav”, 
“rate” : 16000, 
“channel” : 1, 
“cuid” : “B8-27-EB-BA-24-14”, 
“token” : token, 
“speech” : speech_data, 
“len” : speech_length 
}
url = "http://vop.baidu.com/server_api"
json_data = json.dumps(post_data).encode("utf-8")
json_length = len(json_data)
#print(json_data)
 
req = urllib2.Request(url, data=json_data)
req.add_header("Content-Type", "application/json")
req.add_header("Content-Length", json_length)
 
#print("asr start request\n")
resp = urllib2.urlopen(req)
#print("asr finish request\n")
resp = resp.read()
resp_data = json.loads(resp.decode("utf-8"))
if resp_data["err_no"] == 0:
  return resp_data["result"]
else:
   print(resp_data)
   return None
def asr_main(filename,tok): 
try: 
f = open(filename, “rb”) 
audio_data = f.read() 
f.close() 
resp = yuyinshibie_api(audio_data,tok) 
return resp[0] 
except Exception,e: 
print “e:”,e 
return “识别失败”.encode(“utf-8”)
 
代码3:
# coding: utf-8
 
import requests
import json
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
 
 
def Tuling(words):
   Tuling_API_KEY = "此处填写自己的Turling KEY"
 
   body = {"key":Tuling_API_KEY,"info":words.encode("utf-8")}
 
   url = "http://www.tuling123.com/openapi/api"
   r = requests.post(url,data=body,verify=True)
 
   if r:
       date = json.loads(r.text)
       print date["text"]
       return date["text"]
   else:
       return None
 
 
代码4:
# coding: utf-8
import sys 
import urllib2 
import json 
import os 
import yuyinshibie
reload(sys) 
sys.setdefaultencoding(“utf-8”)
def yuyinhecheng_api(tok,tex): 
cuid = “B8-27-EB-BA-24-14” 
spd = “4” 
url = “http://tsn.baidu.com/text2audio?tex=“+tex+”&lan=zh&cuid=”+cuid+”&ctp=1&tok=”+tok+”&per=3” 
#print url 
#response = requests.get(url) 
#date = response.read() 
return url
def tts_main(filename,words,tok): 
voice_date = yuyinhecheng_api(tok,words)
f = open(filename,"wb")
f.write(voice_date)
f.close()
 
代码5:
//脚本light的内容
#!/bin/bash
if [ $# > 1 ]
then
/usr/local/bin/gpio mode 4 out
   if [[ "$1" = "on" ]]
   then
/usr/local/bin/gpio write 4 on
   fi
 
   if [[ "$1" = "off" ]]
   then
/usr/local/bin/gpio write 4 off
   fi
fi
 
 
//给灯泡脚本权限
chmod u+x light
 
//测试灯泡亮
1 ./light on
2 ./light off
没有更多推荐了,返回首页