此工程所有代碼全都上傳到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模塊以及導入出現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