在转换为浮点数时难以使用pyserial解释字节流

时间:2017-10-09 15:23:38

标签: python usb pyserial

我使用pyserial从USB设备获取数据流。 当我使用他们的专有软件时,我会得到一个更新和滚动的情节,如下所示:

enter image description here

制造商提供此信息表非常有用:

enter image description here

所以我编写的代码对我来说似乎完全符合逻辑,并且它应该可以工作:

import serial
import struct

device = '/dev/cu.usbserial-DM003616' #osx
ser = serial.Serial(device, 115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE,
                    stopbits=serial.STOPBITS_ONE, rtscts=False, dsrdtr=False)

bytes = ser.read(500)

splitby = 11
for i in range(splitby):
    offset = i
    for i in range(len(bytes)//splitby):
        datum = bytes[i*splitby+offset:(i+1)*splitby+offset]
        float = datum[2:6]
        float = struct.unpack('!f',float)
        print(float)

鉴于上面的情节以及数据文件中的示例,我预计浮动可能是-100到+100范围。

但我得到完全的胡言乱语:

(5.502899069403557e-41,)
(-2.350988701644575e-38,)
(33.033477783203125,)
(1.408765983841204e-38,)
(0.0,)
(9.839021882302715e-36,)
(-1.1925119585221935e-23,)
(0.0,)
(1.9816933148201242e-21,)
(4.0218751556765575e+23,)
(0.0,)
(98320384.0,)
(-1.894110546575914e-13,)

外部循环的原因是我想看看我是否可以通过将其偏移最多11个字节来理解数据(因为我想知道是否可能在11字节的中间开始轮询设备部分),但无论数据是无意义的。

有没有人对我如何理解数据有任何建议?

500长度的示例字节字符串是:

b'\xaaUA\xd4,\xc0\xbbL\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd5\x15\xed\xbbM\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd0p\x84\xbbN\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcd\xb3)\xbbO\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xc4\xb74\xbbP\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xca\x118\xbbQ\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcf(A\xbbR\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd6f\x0f\xbbS\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd5\x8f\x97\xbbT\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd0)\xb3\xbbU\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcd-\xd9\xbbV\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcf\x1f\\\xbbW\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd6\xbf\xf9\xbbX\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd90\xed\xbbY\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xddp\x15\xbbZ\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd7\x91c\xbb[\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd4$\xad\xbb\\\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcf\x88\xa9\xbb]\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcf\xa9\x18\xbb^\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xce\xae{\xbb_\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcc\x89+\xbb`\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd0\x08\x83\xbba\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd4\xdb\xb5\xbbb\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd95a\xbbc\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd70\xa8\xbbd\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd3#`\xbbe\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcd\xa4]\xbbf\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcd\xa0L\xbbg\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcd\xe5\xd7\xbbh\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xce\xd5\xec\xbbi\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcd;#\xbbj\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcd'

ADDENDUM:抱歉,我不清楚。它开始工作正常,但然后失败。例如,如果我使用上面的字节字符串,我们从良好的数据开始:

(26.5218505859375,)

但这很快就会进入:

(1.408765983841204e-38,)
(0.0,)
(-16140921856.0,)
(-1.1925119585221935e-23,)
(0.0,)
(-1.0772448149509728e-05,)
(4.021874795388587e+23,)
(0.0,)

ADDENDUM:下面标记的答案很好,但是在过渡期间我使用正则表达式提出了我自己的解决方案,这似乎完全正常:

class PLD():
    def __init__(self, device='COM5'):

        self.device = device        # self.device = '/dev/cu.usbserial-DM003616' #osx
        self.sample_rate = 1/0.0256
        self.ser = serial.Serial(device, 115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE, rtscts=False, dsrdtr=False)

    def get_data(self,n=500):
        regexp = '\\xaa.+?\\xbb'
        floats = []
        serial_data = self.ser.read(n)
        for match in re.findall(regexp, serial_data):
            serial_data = match[2:6]
            try:
                datum = struct.unpack('!f', serial_data)[0]
                floats.append(datum)
            except struct.error:
                floats.append(0)
        return floats

2 个答案:

答案 0 :(得分:1)

问题在于你依赖于永不丢失部分传输或遭受任何腐败,这两者都是有缺陷的假设。 你需要对头字节实现等待/检查,理想情况下对于页脚字节是相同的:

#!python3
import struct

class FakeSerial():
    def __init__(self):
        self.data = b'\xaaUA\xd4,\xc0\xbbL\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd5\x15\xed\xbbM\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd0p\x84\xbbN\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcd\xb3)\xbbO\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xc4\xb74\xbbP\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xca\x118\xbbQ\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcf(A\xbbR\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd6f\x0f\xbbS\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd5\x8f\x97\xbbT\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd0)\xb3\xbbU\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcd-\xd9\xbbV\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcf\x1f\\\xbbW\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd6\xbf\xf9\xbbX\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd90\xed\xbbY\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xddp\x15\xbbZ\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd7\x91c\xbb[\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd4$\xad\xbb\\\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcf\x88\xa9\xbb]\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcf\xa9\x18\xbb^\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xce\xae{\xbb_\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcc\x89+\xbb`\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd0\x08\x83\xbba\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd4\xdb\xb5\xbbb\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd95a\xbbc\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd70\xa8\xbbd\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xd3#`\xbbe\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcd\xa4]\xbbf\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcd\xa0L\xbbg\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcd\xe5\xd7\xbbh\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xce\xd5\xec\xbbi\x00\x00\x00\x00\x00\x00\x99f\xaaUA\xcd;#\xbbj\x00\x00\x00\x00\x00\x00\x99f'
        self.index = 0

    def read(self, num=1):
        data = self.data[self.index : self.index+num]
        self.index += num
        if self.index > len(self.data):
            self.index = 0
        return data

s = FakeSerial()

while True:
    if s.read() == b'\xaa': # wait for header 1 because of loop
        if s.read() == b'\x55': # check  header 1 followed immediately by header 2
            data = s.read(4) # get the data
            print(struct.unpack('!f',data)) # unpack it

            # choose one of these methods, not both
            # 1
            padding = s.read(10) # this should read the tag, count, reserved and footer bytes

            # 2
            # this instead loops waiting for footer bytes
#           while True: 
#               if s.read() == b'\x99': # footer 1
#                   if s.read() == b'\x66': # footer 2
#                       break

我创建了一个假的序列类,所以我可以写一个更接近你实际需要使用它的例子,所以你可以忽略那一点,但请注意我从你的示例代码的末尾删除了几个字节,因为它是数据框不完整。

这个输出是:

(26.5218505859375,)
(26.635705947875977,)
(26.05493927001953,)
(25.712480545043945,)
(24.589454650878906,)
(25.258407592773438,)
(25.894655227661133,)
(26.799833297729492,)
(26.695112228393555,)
(26.020360946655273,)
(25.64738655090332,)
(25.89031219482422,)
(26.84373664855957,)
(27.148889541625977,)
(27.67972755432129,)
(26.94598960876465,)
(26.517908096313477,)
(25.941728591918945,)
(25.957565307617188,)
(25.835195541381836,)
(25.56697654724121,)
(26.0041561126709,)
(26.60727882385254,)
(27.151063919067383,)
(26.898757934570312,)
(26.39227294921875,)
(25.70525550842285,)
(25.703269958496094,)
(25.737226486206055,)
(25.854454040527344,)
(25.65387535095215,)

答案 1 :(得分:0)

这些数据看起来是否合适?

by=b'\x41\xd4\x2c\xc0'
print(list(by))
print(struct.unpack('!f',by))

输出:

[65, 212, 44, 192]
(26.5218505859375,)

我查看了你的数据并根据你提供的格式信息,第一个数据包似乎编码了26.521的浮点数......

此外,他们提供的样本数据似乎正确解码:

by=b'\xc0\x59\x99\x99'
print(list(by))
print(struct.unpack('!f',by))

输出:

[192, 89, 153, 153]
(-3.3999998569488525,)

一般来说,你需要编写一些软件来依次读取每个字节,当你找到一个0xaa字节时,也要读取接下来的15个字节并检查所有常量字节是否在正确的位置:([0xaa,0x55​​] ] .... [0xbb]。[0,0,0,0,0,0,0x99,0x66])然后你可以将字节2..5传递给unpack()