我有一个Arduino板,每秒发出一个像这样的字符串“287,612,109,1134”。我的代码尝试读取此字符串并将其转换为风速和风向。最初它工作正常但最终在其中一个readines上它只读取字符串中导致错误的第一个数字。如何让代码获得完整的字符串,而不仅仅是第一个数字?
import serial, time, csv, decimal
#for Mac
port = '/dev/cu.usbserial-A401316V'
ser = serial.Serial(port , baudrate=57600, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, timeout=2)
while True:
time.sleep(2)
data = ser.readline( eol="\r\n").strip()
data = data.split(',')
if len(data) > 0:
if data[0] != '2501':
s = float( 1000 / float(data[0]) )
print 'wind speed %.1f' %(round(float((2.5 * s)), 1))
print 'wind direction', round((int(data[1]) - (50)) * .39, 0)
print 'software version', data[2], '\n'
else:
print 'wind speed is zero'
print 'wind direction', round((int(data[1]) - (50)) * .39, 0)
print 'software version', data[2]
ser.close()
答案 0 :(得分:3)
如果没有看到来自串口的更多错误数据,我可以说最常见的原因是你会看到行上的单个数字(甚至是空白行)是由于Arduino程序发送数据之间的非同步尝试读取该数据的端口和程序。如果您在data
之后打印data=ser.readline()
并注释掉剩余的处理结果,我会下注,您会在输出中找到类似以下内容的行:
252, 236, 218, 1136
251, 202, 215
2, 1353
199, 303, 200, 1000
259, 231, 245, 993
28
4, 144, 142, 1112
245, 199, 143, 1403
251, 19
2, 187, 1639
246, 235, 356, 1323
跨行或甚至空行分割数据的原因是程序试图在写入期间或写入之间从串行连接读取数据。发生这种情况时,readline()
会获得可用的内容(即使已部分/未写入),并在其找到的内容中引发\n
。
解决这个问题的方法是确保Arduino在我们阅读之前已经完成了数据发送,并且有数据供我们阅读。处理这个的一个好方法是使用一个生成器,它只在完成时产生到主循环的行(例如,它们以\r\n
结束,表示写入端口的结束)。
def get_data():
ibuffer = "" # Buffer for raw data waiting to be processed
while True:
time.sleep(.1) # Best between .1 and 1
data = ser.read(4096) # May need to adjust read size
ibuffer += data # Concat data sets that were possibly split during reading
if '\r\n' in ibuffer: # If complete data set
line, ibuffer = ibuffer.split('\r\n', 1) # Split off first completed set
yield line.strip('\r\n') # Sanitize and Yield data
yield
使这个函数成为一个生成器,你可以调用它来获取下一个完整的数据集,同时保持缓冲区中read()
分割的任何东西等待下一个{{1}其中数据集的各个部分可以连接在一起。将read()
视为yield
,但不是传递值并离开函数/循环,而是传递值并等待return
被调用,它将在哪里拾取它离开下一次通过循环。使用此功能,程序的其余部分将如下所示:
next()
根据您的设置,您可能希望在import serial, time, csv, decimal
port = '/dev/cu.usbserial-A401316V'
ser = serial.Serial(port , baudrate=57600, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, timeout=2)
def get_data():
"""
The above function here
"""
ser_data = get_data()
while True:
data = ser_data.next().replace(' ','').split(',')
if len(data) > 0:
"""
data processing down here
"""
ser.close()
中抛出条件,例如,如果串行连接丢失,或get_data()
声明周围的try/except
。
值得注意的是,除了上述内容之外我做过的一件事就是data
到字节大小为ser.readline(eol)
。具有ser.read(4096)
的PySerial readline()
实际上是deprecated,其中包含最新版本的Python。
希望这会有所帮助;或者如果你有更多问题,希望它至少能给你一些想法以便走上正轨。