使用pyqt5 pyserial TTS模型vosk开发的语音串口工具
项目概述
这是一个集成了语音识别和串口通信功能的智能控制工具,旨在通过自然语言语音指令实现对硬件设备的远程控制。该工具采用pyqt5 GUI 界面设计,支持多种串口参数配置,能够实时识别语音指令并通过串口发送控制设备的指令集命令。
核心功能
1、智能语音识别:集成 Vosk 本地语音识别引擎,支持离线使用
2、灵活的串口配置:支持波特率、校验位、停止位、流控制等完整参数设置
3、实时状态显示:动态显示识别过程和系统状态
4、历史记录查看:完整记录所有识别结果和操作日志
5、用户友好界面:采用 PyQt5 构建的图形界面
代码如下:
主程序入口
import sys
from PyQt5.QtWidgets import QApplication
from ui import MainWindow
#主程序入口
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
语音识别具体实现
import vosk
import pyaudio
from PyQt5.QtCore import pyqtSignal, QThread
#VOSK语音识别模块
class SpeechRecognitionThread(QThread):
recognized_signal = pyqtSignal(str)
current_text_signal = pyqtSignal(str)
def __init__(self, serial_connection, model_path):
super().__init__()
self.serial_connection = serial_connection
self.model_path = 'model/voskmodelsmallcn'
self.stop_flag = False
def run(self):
try:
model = vosk.Model(self.model_path)
recognizer = vosk.KaldiRecognizer(model, 16000)
recognizer.SetWords(True)
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=4000)
while not self.stop_flag:
data = stream.read(4000)
if recognizer.AcceptWaveform(data):
result = recognizer.Result()
self.recognized_signal.emit(result)
self.process_command(result)
else:
partial_result = recognizer.PartialResult()
self.current_text_signal.emit(partial_result)
stream.stop_stream()
stream.close()
p.terminate()
except Exception as e:
self.recognized_signal.emit(f"语音识别错误: {str(e)}")
def stop(self):
self.stop_flag = True
def process_command(self, result):
command = result.lower()
if "打开 冻结" in command:
self.send_serial_command("\x02OFZ:1\x03")
elif "关闭 冻结" in command:
self.send_serial_command("\x02OFZ:0\x03")
def send_serial_command(self, command):
try:
if self.serial_connection and self.serial_connection.is_open:
self.serial_connection.write(command.encode())
self.recognized_signal.emit(f"发送指令: {command}")
else:
self.recognized_signal.emit("串口未打开")
except Exception as e:
self.recognized_signal.emit(f"发送指令错误: {str(e)}")
GUI界面
from PyQt5.QtWidgets import QMainWindow, QVBoxLayout, QWidget, QLabel, QPushButton, QLineEdit, QComboBox, QTextEdit
from PyQt5.QtCore import QCoreApplication
from serial_config import SerialConfig
from speech_recognition import SpeechRecognitionThread
import serial
import serial.tools.list_ports
# UI模块
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("语音控制工具")
self.setGeometry(200, 200, 500, 400)
self.serial_config = SerialConfig()
self.serial_connection = None
self.init_ui()
def init_ui(self):
self.layout = QVBoxLayout()
self.port_label = QLabel("串口号:")
self.layout.addWidget(self.port_label)
self.port_input = QComboBox()
self.layout.addWidget(self.port_input)
self.populate_ports()
self.baudrate_label = QLabel("波特率:")
self.layout.addWidget(self.baudrate_label)
self.baudrate_input = QLineEdit("19200")
self.layout.addWidget(self.baudrate_input)
self.parity_label = QLabel("效验位:")
self.layout.addWidget(self.parity_label)
self.parity_input = QComboBox()
self.parity_input.addItems(["None", "Even", "Odd"])
self.layout.addWidget(self.parity_input)
self.stopbits_label = QLabel("停止位:")
self.layout.addWidget(self.stopbits_label)
self.stopbits_input = QComboBox()
self.stopbits_input.addItems(["1", "1.5", "2"])
self.layout.addWidget(self.stopbits_input)
self.flowcontrol_label = QLabel("流控制:")
self.layout.addWidget(self.flowcontrol_label)
self.flowcontrol_input = QComboBox()
self.flowcontrol_input.addItems(["None", "Xon/Xoff", "RTS/CTS", "DTR/DSR"])
self.layout.addWidget(self.flowcontrol_input)
self.start_button = QPushButton("开始语音识别")
self.start_button.clicked.connect(self.start_recognition)
self.layout.addWidget(self.start_button)
self.stop_button = QPushButton("停止语音识别")
self.stop_button.clicked.connect(self.stop_recognition)
self.layout.addWidget(self.stop_button)
self.status_label = QLabel("状态: 等待开始")
self.layout.addWidget(self.status_label)
self.output_text = QTextEdit()
self.output_text.setReadOnly(True)
self.layout.addWidget(self.output_text)
container = QWidget()
container.setLayout(self.layout)
self.setCentralWidget(container)
def populate_ports(self):
try:
ports = serial.tools.list_ports.comports()
for port in ports:
self.port_input.addItem(port.device)
except Exception as e:
self.status_label.setText(f"串口获取错误: {str(e)}")
def start_recognition(self):
try:
self.serial_config.port = self.port_input.currentText()
self.serial_config.baudrate = int(self.baudrate_input.text())
self.serial_config.parity = self.get_parity(self.parity_input.currentText())
self.serial_config.stopbits = self.get_stopbits(self.stopbits_input.currentText())
self.serial_config.flowcontrol = self.get_flowcontrol(self.flowcontrol_input.currentText())
self.serial_connection = serial.Serial(self.serial_config.port, self.serial_config.baudrate,
parity=self.serial_config.parity,
stopbits=self.serial_config.stopbits,
bytesize=self.serial_config.bytesize, timeout=1)
self.status_label.setText(f"状态: 串口 {self.serial_config.port} 已打开")
model_path = "model/voskmodelsmallcn" # 本地模型路径
self.recognition_thread = SpeechRecognitionThread(self.serial_connection, model_path)
self.recognition_thread.recognized_signal.connect(self.update_output)
self.recognition_thread.current_text_signal.connect(self.update_status)
self.recognition_thread.start()
except Exception as e:
self.status_label.setText(f"启动识别错误: {str(e)}")
def stop_recognition(self):
try:
if self.recognition_thread:
self.recognition_thread.stop()
self.recognition_thread.wait()
if self.serial_connection and self.serial_connection.is_open:
self.serial_connection.close()
self.status_label.setText("状态: 语音识别已停止")
except Exception as e:
self.status_label.setText(f"停止识别错误: {str(e)}")
QCoreApplication.quit()
def update_status(self, text):
self.status_label.setText(f"当前识别: {text}")
def update_output(self, text):
self.output_text.append(text)
def get_parity(self, parity):
if parity == "None":
return serial.PARITY_NONE
elif parity == "Even":
return serial.PARITY_EVEN
elif parity == "Odd":
return serial.PARITY_ODD
def get_stopbits(self, stopbits):
if stopbits == "1":
return serial.STOPBITS_ONE
elif stopbits == "1.5":
return serial.STOPBITS_ONE_POINT_FIVE
elif stopbits == "2":
return serial.STOPBITS_TWO
def get_flowcontrol(self, flowcontrol):
if flowcontrol == "None":
return False
elif flowcontrol == "Xon/Xoff":
return serial.XONXOFF
elif flowcontrol == "RTS/CTS":
return serial.RTSCTS
elif flowcontrol == "DTR/DSR":
return serial.DTRDSR
Serial配置界面
import serial
#配置串口
class SerialConfig:
def __init__(self):
self.port = None
self.baudrate = 19200
self.parity = serial.PARITY_NONE
self.stopbits = serial.STOPBITS_ONE
self.flowcontrol = False
self.bytesize = 8 # 数据位,默认8

浙公网安备 33010602011771号