田小花语音机器人(六)基于Python的通过Baidu API语音控制stm32单片机灯光系统实现

心已入冬 提交于 2020-02-02 05:43:38

此工程所有代码全都上传到CSDN了。

系统功能和特点概述:

硬件:

1、在电脑上运行语音识别,电脑系统为Ubuntu19.0、使用的语音是python3.7;

2、单片机使用stm32f103rct6,板子是原子的mini开发板;

软件:

3、主要使用了百度的语音识别的API接口、线程、串口通讯;

4、实现过程只使用到了基础层次的模块和比较基础的方法,容易看懂,方便以后做更全面的升级开发;

5、使用pycham开发,后期改动在终端上可以直接运行;

6、单片机使用codemx进行配置,配置好了以后只做了很少的改动,实现了串口通信点灯的功能,具体代码和配置参考我之前的博客里:田小花语音机器人(二)使用串口实现和单片机数据互传,使用 python的seria0l模块实现基本的串口数据传输功能

………………………………………………………………………………

运行过程描述(没有录视频就简单描述一下吧^^):

运行后电脑控制单片机开发板上面的灯光流水灯闪动,然后进入语音识别,电脑会播放叮的一声,开始录音。对着电脑说出“开灯”,识别成功的话,电脑会播放语音“好的,正在为您开灯”。单片机灯光会全部打开。如果没有识别到“开灯”则会播放会播放“我没听清楚”。过一秒钟后再次播放叮的一声,进入关灯语音识别,过程同开灯。程序结束。语音识别运行过程中,电脑发送的串口信息都会通过串口再次发送回来并且在电脑上打印相关信息。

………………………………………………………………………………

代码解释:

……各个模块为了以后方便理解我已经做了详细的注释!在主线程运行后需要一个子线程用来接收串口的信息。实际目的只是为了方便,并没有实际的工作意义,以后需要改进。
……需要用户在百度上面注册自己的账号,具体教程我之前也写了博客:田小花语音机器人(一)使用百度语音API实现基础的语音转换python3.7、ubuntu19系统

……这是我第一在Ubuntu系统上做python,以前在win的pycharm上建立自己的模块的时候,都是直接使用import导入自己建立的模块,只要把文件放在同一个工作目录下面就不会有任何问题,但是在Ubuntu上面却怎么也导入不进去,最后只有参考了别人的解决办法:

python中怎么import自己写的模块

python模块以及导入出现ImportError: No module named 'xxx’问题

……感谢 [爱心]

主模块代码
文件名:

mian.py
#!/usr/bin/python3.7
# coding=utf-8
import threading
import time
import sys

"""自建模块需要手动导入模块路径!"""
sys.path.append("~/2PROGRAM/1-python/20.1.30-田小花语音机器人主程序/program/main")
"""串口通讯控制机器人运动模块"""
import contro_robot
"""语音识别模块"""
import speak

"""构建机器人主体,包含机器人一般和相关属性变化控制"""
class robot():
    def __init__(self,name):
        self.name = name
        self.local_value = ['10', '01', '11','00']
        self.Init_set_serial() #串口数据连接初始化

    """串口初始化,开始让串口发送数据等"""
    def Init_set_serial(self):
        self.Serial_port = contro_robot.SerialControRobot()
        """建立接收串口信息的独立线程"""
        self.Serial_seceve_robot = contro_robot.SerialReceveRobot()
        serial_seceve_robot_thread = threading.Thread(target=self.Serial_seceve_robot.recive_serial, name='子线程')  # 建立子线程
        serial_seceve_robot_thread.start()  # 线程开始

    """测试程序,无实际意义,未执行"""
    def fun_1(self):
        while True:
            time.sleep(0.5)
            self.Serial_port.sand_message(self.local_value[0])
            time.sleep(0.5)
            self.Serial_port.sand_message(self.local_value[1])



"""程序执行入口"""
if __name__ == "__main__":
    Tianxiaohua = robot("tiuan")
    Tianxiaohua.Serial_port.sand_message('10')
    time.sleep(1)
    Tianxiaohua.Serial_port.sand_message('01')
    time.sleep(1)

    Speak = speak.speaker()
    a = Speak.Sound_recording()
    if(a == "开灯"):
        Speak.distinguish("好的,正在为您开灯")
        Speak.play_sound()
        Tianxiaohua.Serial_port.sand_message('11')
    else:
        Speak.distinguish("我没听清楚")
        Speak.play_sound()

    a = Speak.Sound_recording()
    if (a == "关灯"):
        Speak.distinguish("关灯了哦")
        Speak.play_sound()
        Tianxiaohua.Serial_port.sand_message('00')
    else:
        Speak.distinguish("我没听清楚")
        Speak.play_sound()

………………………………………………………………………………………………

……串口调试过程之遇到了串口接收和发送不能使用同一个串口实例化对象的问题没有解决,我也没有继续向下研究,只是通过建立一个串口发送的对象和一个串口接收用的对象,并且两个对象独立运行在两个线程中,以后对数据进行处理的时候,接收和和发送的信息需要放在一起处理,那么线程见的数据管理问题将会是一个麻烦!!如果读者有好办法可以私我 [爱心]
……下面是串口服务模块:
文件名:

contro_robot.py
#!/usr/bin/python3.7
#encoding:utf-8
import time
import serial.tools.list_ports
#
"""串口发送和接收在两个类中打开使用,萹蓄在两个线程中运行
    实际测试过程中发现,串口读取和发送使用同一个串口对象会发生接受串口信息丢失的现象
    需要在两个子线程中分别实例化两个串口对象,一个用来发送,一个接收"""
"""向串口发送数据类"""
class SerialControRobot():
    def __init__(self):
        self.plist = list(serial.tools.list_ports.comports())
        if len(self.plist) <= 0:
            print("没有发现端口!")
        else:
            self.plist_0 = list(self.plist[0])
            serialName = self.plist_0[0]
            self.serialFd = serial.Serial(serialName, 9600, timeout=60)
            print("可用端口名>>>"+self.serialFd.name)
        self.ser = serial.Serial(self.serialFd.name, 115200)  # 设置了第一个串口号,波特率,读超时设置
        print("正常连接中")
#
    '''PC端向单片机通过串口发送数据'''
    def sand_message(self,message):
        message = str(message)
        self.ser.write((message+'\r\n').encode())
#
    """测试方法,无实际意义"""
    def fun(self):
        while True:
            self.sand_message('10')
            time.sleep(0.2)
            self.sand_message('01')
            time.sleep(0.2)
#
"""从串口接受数据类"""
class SerialReceveRobot():
    def __init__(self):
        self.plist = list(serial.tools.list_ports.comports())
        if len(self.plist) <= 0:
            print("没有发现端口!")
        else:
            self.plist_0 = list(self.plist[0])
            serialName = self.plist_0[0]
            self.serialFd = serial.Serial(serialName, 9600, timeout=60)
            print("可用端口名>>>" + self.serialFd.name)
        self.ser = serial.Serial(self.serialFd.name, 115200)  # 设置了第一个串口号,波特率,读超时设置
        print("正常连接中")
#
    '''PC端通过串口接收单片机数据'''
    def recive_serial(self):
        ser = serial.Serial( self.serialFd.name, 115200)  # 设置了第一个串口号,波特率,读超时设置
        while True:
            count = ser.inWaiting()
            if count > 0:
                print("PC端串口接受到的信息:", ser.read(count))
                #recive = ser.read(count)
                #if recive == b'01\r\n':
                    #print("识别成功")

"""
a = ControRobot()
a.fun()
"""

……………………………………………………………………………………

下面是基于百度语音识别的模块。参考前面我写的博客也不重复写了:田小花语音机器人(一)使用百度语音API实现基础的语音转换python3.7、ubuntu19系统

文件名:

speak.py
#!/usr/bin/python3.7
# coding=utf-8
from aip import AipSpeech #导入百度语音的api !!!:pip install baidu-aip
import os
#
"""
建立基于百度语音识别api的类有两个主要方法:
        1、Sound_recording:直接录音,该方法返回值是识别到的语音转成的字符串
        2、Sound_recording:此方法的输入值是想要转成语音的字符串,此方法会将字符串直接转换成语音播放出来
"""
class speaker():
    def __init__(self):
        app_id = "18342916"
        API_Key = "ZUmYyI8ViFGDL5cpDEbC1hlA"
        Secret_Key = "KcgQsVbBQFSTbq1Umj4EK9kw4Y2P8MvH"
        self.client = AipSpeech(app_id, API_Key, Secret_Key)#代入相关的账户信息创建了语音识别对象clien
        self.length = 2 #创建录音文件的时候规定的录音的时长,单位秒
#
    """使用话筒进行录音,返回值是识别到的话转换成的字符串"""
    def Sound_recording(self):
        os.system("aplay resource/ding.wav")#使用aplay程序打开录音播放叮的一声
        os.system("arecord -d %d -r 16000 -c 1 -t wav -f S16_LE resource/record.wav" % (self.length,) )#使用录音软件arecord进行录音,相关录音参数设置如函数内部所示。百度使用文件形式为.wav
        os.system("aplay resource/ding.wav")
        with open("resource/record.wav", 'rb') as fp:#打开刚刚录好的音频文件,上传给百度并且可以得到一个字典,字典内容包含相关返回值
            result = self.client.asr(fp.read(), 'wav', 16000, {'dev_pid': 1536, })
        """把录音结果进行打印,实际中会遇到网络和录音无结果的情况,使用try进行应对"""
        try:
            print("___识别结果___:",result)
            print(result['result'][0])
            return result['result'][0]
        except:
            print("___识别不成功____")
#
    """把识别到的内容以字符串的形式传递给百度,生成可以播放的MP3文件,无返回值"""
    def distinguish(self,Speaker_say_message):
        """result代表文字转换成语音的二进制数据,从百度转换,需要良好的网络连接"""
        result = self.client.synthesis(Speaker_say_message,  #要翻译的文字
                                     "zh",#表示是中文
                                     1,   #表示第一个
                                     {"vol":5,#表示音量
                                      "spd":5,#表示音速
                                      "pit":9,#表示语调
                                      "per":4#1是女生 2男生 3逍遥 4萝莉
                                      })
        with open("resource/sprak.mp3", "wb") as f:#创建并写入mp3文件对象
            f.write(result)#把转换出来的二进制语音文件写入到文件中
        self.play_sound()#播放转换结果
#
    """播放语音"""
    def play_sound(self):#播放转换后的内容
        os.system("mpg123 resource/sprak.mp3")#这里的mpg123是一个程序插件,可以用来播放MP3文件

"""
a = speaker()
x = a.Sound_recording()
if(x == "关灯"):
    a.distinguish("好的 正在为您关灯")
    a.play_sound()
else:
    a.distinguish("我没听清楚")
    a.play_sound()
"""

整个系统构建完成后还有好多的问题没有解决,主要有线程间数据互传的问题、串口通信不能在同一个线程中、功能实现过于简单等,可以当成是入门吧。

田小花语音机器人持续更新中……

结束!
23333333333333

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!