我使用Pyserial和PyQtgraph绘制实时数据。我正在从(一个arduino)和我的电脑读取数据的设备之间的连接工作正常,我的意思是我可以读取数据。问题在于,当我断开设备时,数据仍在绘图中。并且,如果我让它继续阅读,过了一会儿,情节会崩溃,我必须重新开始。
我正在阅读一些帖子,我发现了这个:
implementing pyqtgraph for live data graphing
所以,我认为问题在于,在我的代码中,数据附加到列表然后是绘图,这使得它变慢,也许这就是它崩溃的原因。
这是我的代码:
class MyApplication(QtGui.QApplication):
def __init__(self, *args, **kwargs):
super(MyApplication, self).__init__(*args, **kwargs)
self.t = QTime()
self.t.start()
self.data = deque()
self.cnt = 0
self.win = pg.GraphicsWindow()
self.plot = self.win.addPlot(title='Timed data')
self.curve = self.plot.plot()
self.tmr = QTimer()
self.tmr.timeout.connect(self.update)
self.tmr.start(100)
self.cnt = 0
print "Opening port"
self.raw=serial.Serial("com4",9600)
print "Port is open"
def update(self):
line = self.raw.read()
ardString = map(ord, line)
for number in ardString:
numb = float(number/77.57)
self.cnt += 1
x = self.cnt/20
self.data.append({'x': x , 'y': numb})
x = [item['x'] for item in self.data]
y = [item['y'] for item in self.data]
self.curve.setData(x=x, y=y)
如何修改我的代码以使用上面帖子中编写的代码?或者我如何绘制即将发布的数据而不将其附加到列表中?
抱歉,我是PyQtGraph
的新人,现在我很困惑。希望您能够帮助我。
我尝试过这样一个更简单的代码:
import serial
import numpy
import matplotlib.pyplot as plt
print "Opening port"
port = "com4"
arduinoData = serial.Serial(port, 9600)
while True:
if arduinoData.inWaiting()>0:
print "Reading data"
arduinoString = arduinoData.read(arduinoData.inWaiting())
bytes = map(ord, arduinoString)
for byte in bytes:
print byte
else:
print "There is no data"
因此,在命令提示符中显示数据后,我断开设备,我可以看到数据仍然显示几秒钟。然后,出现“没有数据”文本。那么,可能是什么问题呢?我知道,它是缓冲数据,但在我看来,它与其他代码发生的情况相同。
我终于完成了我需要做的事情。感谢@busfault的所有帮助和耐心。
这是update
方法的代码:
def update(self):
line = self.raw.read([1])
ardString = map(ord, line)
for number in ardString:
numb = float(number/77.57)
self.data.append(numb)
self.yData.append(numb)
if len (self.yData)>300 :
self.yData = []
self.raw.flush()
self.curve.setData(self.yData)
我现在所做的是数据分为两个不同的列表:self.yData
和self.data
。
在self.yData
中,我最多只能附加300个数据项(这是随机的,我本可以选择500个),然后我清空所有数据并“清除”列表再重新开始。
Whit我可以毫不拖延地查看实时数据,并将所有数据保存在另一个安全的地方。
答案 0 :(得分:1)
我认为如果你创建列表你应该看到加速,如果你设置使用deque,那么我建议移动for循环之外的x和y列表的生成,因为那可能是你可能没有必要花很多时间。
def __init__(self, *args, **kwargs):
super(MyApplication, self).__init__(*args, **kwargs)
self.t = QTime()
self.t.start()
#self.data = deque()
self.xValues = []
self.yValues = []
self.cnt = 0
self.win = pg.GraphicsWindow()
self.plot = self.win.addPlot(title='Timed data')
self.curve = self.plot.plot()
self.tmr = QTimer()
self.tmr.timeout.connect(self.update)
self.tmr.start(100)
self.cnt = 0
print "Opening port"
##EDIT CHANGED THIS LINE TO INCLUDE TIMEOUT
self.raw=serial.Serial("com4",9600, timeout=0)
print "Port is open"
def update(self):
line = self.raw.read()
ardString = map(ord, line)
for number in ardString:
numb = float(number/77.57)
self.cnt += 1
x = self.cnt/20
self.xValues.append(x)
self.yValues.append(numb)
#self.data.append({'x': x , 'y': numb})
#x = [item['x'] for item in self.data]
#y = [item['y'] for item in self.data]
self.curve.setData(x=x, y=y)
来自PySerial文档: https://pythonhosted.org/pyserial/pyserial_api.html#serial.Serial.read
从串口读取大小字节。如果设置了超时,则可能会根据请求返回较少的字符。没有超时,它将阻塞,直到读取所请求的字节数。
并从构造函数
控制read()行为的参数超时的可能值:
- timeout =无:永远等待/直到收到请求的字节数
- timeout = 0:非阻塞模式,在任何情况下立即返回,返回零或更多,直到请求的字节数
- timeout = x:设置超时为x秒(允许浮点数),当请求的字节数可用时立即返回,否则等到超时到期并返回之前收到的所有字节。
因此默认情况下(timeout=None
),当执行self.raw.read()
并且没有数据时,它会尝试读取一个字节,然后永远等待。对于要写入的字节。
==================================
我正在考虑更多关于断开连接后代码崩溃的原因。我想我知道为什么,self.tmr每隔100毫秒就会生成一次信号,你的插槽(更新)会一遍又一遍地被调用,而且,self.raw.read()一直被调用(我想?)
尝试更改update()
中的代码:
def update(self):
self.tmr.stop()#Prevent the timer from entering again.
line = self.raw.read()
ardString = map(ord, line)
for number in ardString:
numb = float(number/77.57)
self.cnt += 1
x = self.cnt/20
self.xValues.append(x)
self.yValues.append(numb)
#self.data.append({'x': x , 'y': numb})
#x = [item['x'] for item in self.data]
#y = [item['y'] for item in self.data]
self.curve.setData(x=x, y=y)
self.tmr.start()#restart the timer (resets the timeout)
我不知道保持100毫秒脉冲是否至关重要?如果是这样,您可以使用锁定,以便在再次调用更新时,它不会再次运行相同的代码。 https://docs.python.org/2/library/threading.html#rlock-objects
我认为这个例子表明它很容易实现。
import threading some_rlock = threading.RLock() with some_rlock: print "some_rlock is locked while this executes"
答案 1 :(得分:0)
我可以建议如下:将数据上传到db(数据库)。
这会涉及到为现有程序添加更多代码=)
但这可以使用任何db:sqlight,couchdb,mongodb..etc等轻松实现
或者只是创建一个跟踪已处理值的文件? 我注意到你没有使用列表,而是使用元组来存储你的密钥:值对。
self.data.append({'x': x , 'y': numb})
x = [item['x'] for item in self.data]
y = [item['y'] for item in self.data]
self.curve.setData(x=x, y=y)
因此对于第二个选项
tracking_file = open("filename.txt", "w") #w indicates write
tracking_file.writelines(the data) #instead of appending to a tuple or list
track_file.close()
此序列打开一个文件并将数据写入其中,以获取有关输入/输出的更多信息https://docs.python.org/2/tutorial/inputoutput.html
随后,您可以从您创建的文件中读取数据,如果程序崩溃,则不会删除文件,并且您可以通过在读取模式下打开文件,从崩溃或断开连接之前的程序中恢复,检查最后一个输入并继续添加值...