我正在用 python 创建一个信号绘图应用程序。我想用蓝牙 hc05 从 arduino 接收数据。要使用过滤器,我需要分别以 5000 的采样率接收 4 个通道的数据。使用下面的代码,我可以接收一段时间的数据,但之后程序就卡住了。当我用ctrl+C中断程序时,发现卡在了BT.py中的
rv = self.ser.read(1)
行。我猜这是因为 python 的缓冲区已满或正在挨饿?在 arduino 代码中添加 Serial.print(val)
后,程序不会停止,但对于实时绘图来说它变得太慢了。有谁知道如何解决这个问题?
这是界面.py
import BT
# hint: You may design additional functions to execute the input command, which will be helpful when debugging :)
class interface:
def __init__(self):
print("")
print("Arduino Bluetooth Connect Program.")
print("")
self.ser = BT.bluetooth()
while(not self.ser.do_connect("COM40")):
self.ser.do_connect("COM40")
# self.write('s')
def read(self):
return self.ser.SerialReadInt()
def end_process(self):
self.ser.disconnect()
def write(self, input):
# print("write")
return self.ser.SerialWrite(input)
这里是 BT.py
from time import sleep
import serial
# these codes are for bluetooth
# hint: please check the function "sleep". how does it work?
class bluetooth:
def __init__(self):
self.ser = serial.Serial()
def do_connect(self,port):
self.ser.close()
print("Connecting...")
try:
self.ser = serial.Serial(port,115200,timeout=2)
self.ser.set_buffer_size(rx_size = 115200, tx_size = 115200)
print("connect success")
print("")
# self.ser.timeout=None
except serial.serialutil.SerialException as ex:
print("fail to connect")
print(ex)
print("")
return False
return True
def disconnect(self):
self.ser.close()
def SerialWrite(self,output):
# send = 's'.encode("utf-8")
if output.isdigit():
send = int(output).to_bytes(1, 'little')
else:
send = output.encode("utf-8")
self.ser.write(send)
def SerialReadInt(self):
waiting = self.ser.in_waiting
if waiting >= 0:
rv = self.ser.read(1)
rv=int.from_bytes(rv, byteorder='big', signed=False)
return rv
return
def SerialReadByte(self):
sleep(0.005)
waiting = self.ser.inWaiting()
rv = self.ser.read(waiting)
return rv
这里是 filter.py(这是主文件)
import scipy.io
import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import butter,iirnotch,lfilter
from scipy.fft import fft,fftfreq
from numpy import *
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import interface
import time
from PyQt5.QtWidgets import QApplication
def filter(data, notchcut,q,lowcut, highcut, fs, order=3):
avg=sum(data)/len(data)
b,a=iirnotch(notchcut,q,fs)
y = lfilter(b, a, data)+avg
nyq = 0.5 * fs
low = lowcut / nyq
high = highcut / nyq
b, a = butter(order, [low, high], btype='band')
y = lfilter(b, a, y)+avg
# print(y)
return y
interf = interface.interface()
### START QtApp #####
app = QApplication([]) # you MUST do this once (initialize things)
####################
win = pg.GraphicsLayoutWidget(title="Signal from arduino") # creates a window
p1 = win.addPlot(title="channel1",row=0, col=0) # creates empty space for the plot in the window
p2 = win.addPlot(title="channel2",row=1, col=0) # creates empty space for the plot in the window
p3 = win.addPlot(title="channel3",row=2, col=0) # creates empty space for the plot in the window
p4 = win.addPlot(title="channel4",row=3, col=0) # creates empty space for the plot in the window
p1.setYRange(0, 5, padding=0)
p2.setYRange(0, 5, padding=0)
p3.setYRange(0, 5, padding=0)
p4.setYRange(0, 5, padding=0)
curve=[p1.plot(),p2.plot(),p3.plot(),p4.plot()]
# curve1 = p1.plot() # create an empty "plot" (a curve to plot)
# curve2 = p2.plot() # create an empty "plot" (a curve to plot)
# curve3 = p3.plot() # create an empty "plot" (a curve to plot)
# curve4 = p4.plot() # create an empty "plot" (a curve to plot)
windowWidth = 5000 # width of the window displaying the curve
X =[linspace(0,0,windowWidth),linspace(0,0,windowWidth),linspace(0,0,windowWidth),linspace(0,0,windowWidth)]
# X1 = linspace(0,0,windowWidth) # create array that will contain the relevant time series
# X2 = linspace(0,0,windowWidth)
# X3 = linspace(0,0,windowWidth)
# X4 = linspace(0,0,windowWidth)
ptr = -windowWidth # set first x position
# filtRes=[linspace(0,0,windowWidth),linspace(0,0,windowWidth),linspace(0,0,windowWidth),linspace(0,0,windowWidth)]
# Realtime data plot. Each time this function is called, the data display is updated
def update():
global curve, ptr, X
ptr += 1 # update x position for displaying the curve
for i in range(4):
X[i][:-1]=X[i][1:] # shift data in the temporal mean 1 sample left
value = float(float(interf.read())*5/255) # read line (single value) from the serial port
X[i][-1] = value # vector containing the instantaneous values
# print(value)
filtRes=filter(X[i],60,0.5,10.2,410,5000)
curve[i].setData(filtRes) # set the curve with this data
# time.sleep(0.0002)
QApplication.processEvents() # you MUST process the plot now
win.show()
### MAIN PROGRAM #####
# this is a brutal infinite loop calling your realtime data plot
interf.write('s')
while True:
# print("update")
update()
### END QtApp ####
QApplication.exec_() # you MUST put this at the end
##################
最后是arduino文件
#include <SoftwareSerial.h>
SoftwareSerial BTSerial(8, 9);
int adc[4]={A0,A1,A2,A3};
byte val=0;
unsigned long cTime = 0;
bool start;
void setup()
{
BTSerial.begin(115200);
Serial.begin(9600);
pinMode(adc[0], INPUT);
pinMode(adc[1], INPUT);
pinMode(adc[2], INPUT);
pinMode(adc[3], INPUT);
start=false;
}
void loop()
{
if(BTSerial.available())
{
if(BTSerial.read()=='s')
{
start=true;
cTime=micros();
}
}
if (start&&cTime - micros() >= 200)
{
cTime=micros();
for(int i=0;i<4;i++)
{
val = map(analogRead(adc[i]), 0, 1023, 0, 255);
// Serial.println(val);
BTSerial.write(val);
}
}
}
我已经用AT命令设置了hc05的波特率到115200.