python - 如何从串行数据中减少 'readline()' 所花费的时间

标签 python python-3.x performance serial-port

我正在尝试创建一个函数来从传感器获取陀螺仪组件 X、Y、Z。

功能如下:

def bimu_get_gyroscope_raw():
    #ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=15)
    ser = serial.Serial('/dev/tty.usbserial-00002014', 115200, timeout=15)
    ser_io = io.TextIOWrapper(io.BufferedRWPair(ser, ser, 1),  
                               newline = '\r',
                               line_buffering = True)
    try:
        ser.isOpen()
        print('serial is open')
    except:
        print('error_1')
        exit()
    #--------------------
    i = 0
    gyro_dict = dict()
    if (ser.isOpen()):
        ser.flushInput()
        # write the function to get 
        while (i==0):
            try:
                print('serial is open_1')
                line = ser_io.readline()
                print('serial is open_2')
                print(line)
            except serial.SerialException as err:
                print("Error ocurred while reading data: {}".format(err))
            if not line.endswith('\r'):
                print("Attempt to read from serial port timed out ... Exiting.")
                break  # terminate the loop and let the program exit
            if line.startswith('S,'):
                i += 1
                line = line.split(',')
                print(line)
                if len(line)==12: 
                    gyro_dict = {'x':float(line[1]), 'y': float(line[2]), 'z': float(line[3]) }
    else:
        print('Cannot open serial port')
    return gyro_dict

我得到以下输出:
raw = bimu_get_gyroscope_raw()
print(raw)

serial is open
serial is open_1
-43,-122,-2833,83,65
serial is open_2
serial is open_1
S,2,0,0,-20,19,1014,-146,184,-158,168,99
serial is open_2
['S', '2', '0', '0', '-20', '19', '1014', '-146', '184', '-158', '168', '99\r']
{'z': 0.0, 'y': 0.0, 'x': 2.0}

我遇到的问题是,在我第一次调用 line = ser_io.readline() 之间使用指针式计时器在屏幕上书写大约需要 2.25 秒 serial is open_2 .
如果函数需要再次调用ser_io.readline()没有延迟和线路serial is open_1serial is open_2几乎同时出现。

我想第一次调用 readline()对端口或数据缓冲区进行内部操作,一旦完成,就会导致对 readline() 的连续调用跑得更快。

有什么办法可以解决这个问题并使函数始终快速运行。

编辑

我用 time 测试了时间python模块并修改了readline部分,如下所示:
     while (i<=5):
        try:
            print('before readline')
            start_time = time.time()
            line = ser_io.readline()
            #print(line)
            print("--- %s seconds ---" % (time.time() - start_time))
            #print(line)
            print('after readline')
        except serial.SerialException as err:
            print("Error ocurred while reading data: {}".format(err))
        if not line.endswith('\r'):
            print("Attempt to read from serial port timed out ... Exiting.")
            break  # terminate the loop and let the program exit
        if line.startswith('S,'):
            i += 1
            line = line.split(',')
            print(line)
            if len(line)==12: 
                gyro_dict = {'x':float(line[1]), 'y': float(line[2]), 'z': float(line[3]) }

结果如下:
    serial is open
before readline
--- 2.1859400272369385 seconds ---
after readline
before readline
--- 5.9604644775390625e-06 seconds ---
after readline
['S', '0', '0', '0', '380', '0', '-902', '-497', '-228', '200', '63', '103\r']
before readline
--- 2.86102294921875e-06 seconds ---
after readline
before readline
--- 3.814697265625e-06 seconds ---
after readline
['S', '-1', '0', '1', '375', '-8', '-918', '-497', '-223', '194', '64', '108\r']
before readline
--- 3.0994415283203125e-06 seconds ---
after readline
['S', '1', '0', '2', '380', '-10', '-909', '-500', '-223', '200', '65', '113\r']
before readline
--- 2.1457672119140625e-06 seconds ---
after readline
before readline
--- 1.9073486328125e-06 seconds ---
after readline
['S', '0', '0', '0', '379', '-1', '-914', '-500', '-220', '197', '66', '69\r']
before readline
--- 2.1457672119140625e-06 seconds ---
after readline
['S', '0', '0', '-1', '374', '-5', '-902', '-500', '-225', '1\r']
before readline
--- 3.0994415283203125e-06 seconds ---
after readline
['S', '1', '1', '1', '376', '-2', '-915', '-500', '-223', '192', '37', '75\r']

该函数第一次迭代需要两秒多,其余迭代非常快。

最佳答案

我有几个建议给你。我编写使用串行端口的 Windows 应用程序并使用不同的方法 - 我假设所有操作系统的原理都是相同的。我首先在程序开始时创建并打开端口,然后将其保持打开状态。在程序存在之前关闭端口是一个很好的做法,但这并不是真正必要的,因为之后操作系统会清理。

但是每次调用该函数时,您的代码都会创建并初始化端口。完成后,您没有明确关闭它;也许您可以摆脱这种情况,因为端口对象会被垃圾收集。在您尝试再次打开它之前,您相信串行库会在操作系统级别正确关闭端口。在任何情况下,如果创建端口对象有开销,为什么不产生一次并完成它呢?

您根本不需要创建 TextIOWrapper,更不用说双向的了。您想知道这是否是您的性能问题的原因,那么为什么不摆脱它呢?串行端口库具有您需要的所有功能:查看 read_until功能。

我认为你应该从这样的框架开始。我无法运行和测试这个程序,所以它只是一个示意图。我已经删除了所有错误处理代码。一个小问题是串行端口对字节进行操作,您必须将其转换为字符串。

ser = serial.Serial('/dev/tty.usbserial-00002014', 115200, timeout=15)
def bimu_get_gyroscope_raw():
    while True:
        ser.flushInput()
        b = ser.read_until('\r')
        s = str(b, encoding='latin1')  # convert to str
        if a.startswith('S,'):
            line = s.split(',')
            if len(line)==12: 
                return dict(x = float(line[1]),
                            y = float(line[2]),
                            z = float(line[3]))

我做了ser一个全局的,但您也可以将它作为参数传递给函数。

请记住串行端口在现代操作系统上的工作方式。您永远不会直接从硬件读取字符 - 操作系统正在为您执行此操作,并将字符放在输入缓冲区中。当您从端口“读取”时,您实际上是在从缓冲区中检索任何字符,或者等待它们的到来。您所观察到的 - 长时间的延迟,随后是快速连续的数据行 - 可以解释为陀螺仪硬件在几秒钟内什么都不做,然后产生超过一条线长的数据突发。我不知道你的陀螺仪是如何工作的,所以我不能说真的是这样。

PySerial 实现实际上是一组操作系统调用的包装器。 Python 开销非常小,其中大部分是错误处理代码。我相信您将能够使用 Python 每秒接收数千个字符——我一直都这样做。在现代 PC 上,三秒几乎是永恒的。必须有另一种解释。暂时不要认为 Python 是您的瓶颈。

通过查看屏幕并单击秒表来计时事件是笨拙的。查看 Python 时间包。您可以简单地在每个打印语句中打印 time.time() 的值并收起您的计时器。

您可以独立测试实现的数据收集部分。只需去掉解析数据的逻辑,并永远停留在 while 循环中。打印数据以及每个接收行的时间戳。如果您有另一个与串行端口通信的仪器,您可以将仪器的性能与软件的性能隔离开来。

最后,什么事件导致陀螺仪进行数据传输?它是只是定期广播其数据的仪器之一,还是您必须向它发送一些命令来请求数据?如果前者和广播每三秒一次,谜团就解开了;同样,如果是后者并且响应的延迟为三秒。我可以想象可能会出现这样的情况,因为仪器必须读取一些传感器并将结果转换为字符串。你没有向我们展示整个程序或告诉我们仪器是如何工作的,所以这只是猜测。

关于python - 如何从串行数据中减少 'readline()' 所花费的时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60286728/

相关文章:

python-3.x - 我想知道如何使用断言来保证列表列表中的所有元素都具有相同的长度

python - 我们可以在spyder中直接使用One Hot Encoding而不使用标签编码来处理分类数据吗

python - 在 Python 中以一定角度(旋转)绘制文本

javascript - jQuery:$.on 应该如何工作?

python - 如何在Python中使用xpath打印特定标签中的所有文本?

python - 多文件 C Python 扩展组织问题

python - 在Python中,比较多列的行差异

python - 运行带有3GB RAM的python代码并使PC崩溃

python - 在 Cython 中优化字符串

r - 数据表中的.EACHI?