我有一个Arduino连接到我的计算机上运行的环路,发送通过串行端口的值返回给计算机每100毫秒。

我想打一个Python脚本,它将从串口只每隔几秒钟读,所以我希望它只是看到从阿尔杜伊诺发送的最后一件事。

如何在Pyserial做到这一点?

下面是我尝试了代码简化版,工作。它顺序地读取的行。

import serial
import time

ser = serial.Serial('com4',9600,timeout=1)
while 1:
    time.sleep(10)
    print ser.readline() #How do I get the most recent line sent from the device?
有帮助吗?

解决方案

也许我误解你的问题,但因为它是一个串口线,你必须阅读一切从Arduino的顺序发送的 - 它会在Arduino的,直到你读它被缓存起来。

如果你想有一个状态显示器,显示发送最新的东西 - 用它包含在你的问题的代码线程(减去睡眠),并保持阅读从阿尔杜伊诺最新行的最后一个完整系列的

更新: mtasic的示例代码是相当不错的,但如果Arduino的已派出一个局部线时inWaiting()被调用时,你会得到一个截断线。相反,你想要做的是把最后的完全的行成last_received,并保持局部线buffer,以便它可以追加到下次一轮循环。是这样的:

def receiving(ser):
    global last_received

    buffer_string = ''
    while True:
        buffer_string = buffer_string + ser.read(ser.inWaiting())
        if '\n' in buffer_string:
            lines = buffer_string.split('\n') # Guaranteed to have at least 2 entries
            last_received = lines[-2]
            #If the Arduino sends lots of empty lines, you'll lose the
            #last filled line, so you could make the above statement conditional
            #like so: if lines[-2]: last_received = lines[-2]
            buffer_string = lines[-1]

关于使用readline()的:这是什么Pyserial文档有说(略编辑的清晰度和附带一提改成readlines()):

  

使用 “的ReadLine” 时要小心。做   打开时指定超时   串行端口,否则可能会阻止   永远如果没有换行符是   接收。还要注意的是“readlines方法()”   仅适用于超时。它   取决于具有超时而   解释,由于EOF(文件结束)。

这似乎是很有道理的我!

其他提示

from serial import *
from threading import Thread

last_received = ''

def receiving(ser):
    global last_received
    buffer = ''

    while True:
        # last_received = ser.readline()
        buffer += ser.read(ser.inWaiting())
        if '\n' in buffer:
            last_received, buffer = buffer.split('\n')[-2:]

if __name__ ==  '__main__':
    ser = Serial(
        port=None,
        baudrate=9600,
        bytesize=EIGHTBITS,
        parity=PARITY_NONE,
        stopbits=STOPBITS_ONE,
        timeout=0.1,
        xonxoff=0,
        rtscts=0,
        interCharTimeout=None
    )

    Thread(target=receiving, args=(ser,)).start()

,同时等待字符这些解决方案将占着CPU。

您应该做的至少一个阻塞调用来读取(1)

while True:
    if '\n' in buffer: 
        pass # skip if a line already in buffer
    else:
        buffer += ser.read(1)  # this will block until one more char or timeout
    buffer += ser.read(ser.inWaiting()) # get remaining buffered chars

...和之前做的分裂的事情。

可以使用ser.flushInput()冲洗出当前在缓冲区中的所有串行数据。

清理掉旧的数据后,您可以在用户ser.readline()从串行设备获得的最新数据。

我觉得比其他提出的解决方案的简单一点就在这里。为我工作,希望它是适合你的。

这个方法,可以分开地控制用于收集所有的数据对每一行的超时,和不同的超时等待额外行。

# get the last line from serial port
lines = serial_com()
lines[-1]              

def serial_com():
    '''Serial communications: get a response'''

    # open serial port
    try:
        serial_port = serial.Serial(com_port, baudrate=115200, timeout=1)
    except serial.SerialException as e:
        print("could not open serial port '{}': {}".format(com_port, e))

    # read response from serial port
    lines = []
    while True:
        line = serial_port.readline()
        lines.append(line.decode('utf-8').rstrip())

        # wait for new data after each line
        timeout = time.time() + 0.1
        while not serial_port.inWaiting() and timeout > time.time():
            pass
        if not serial_port.inWaiting():
            break 

    #close the serial port
    serial_port.close()   
    return lines

您将需要一个循环读取一切发送,最后调用的ReadLine()阻塞,直到超时。所以:

def readLastLine(ser):
    last_data=''
    while True:
        data=ser.readline()
        if data!='':
            last_data=data
        else:
            return last_data

轻微修改mtasic&维奈Sajip的代码:

虽然我发现这个代码非常有助于我类似的应用程序,我需要的所有的距离会定期发送信息的串行设备回来的线。

我选择弹出所述第一元件断开的顶部,记录它,然后再加入剩余的元素作为新的缓冲液,并从那里继续。

我意识到,这是不会什么格雷格要求,但我认为这是值得分享的一个方面说明。

def receiving(ser):
    global last_received

    buffer = ''
    while True:
        buffer = buffer + ser.read(ser.inWaiting())
        if '\n' in buffer:
            lines = buffer.split('\n')
            last_received = lines.pop(0)

            buffer = '\n'.join(lines)

使用无限循环内部.inWaiting()可能会有问题。它可以霸占了这取决于实现整个 CPU 。相反,我会建议使用数据的具体尺寸被读取。因此,在这种情况下,以下应例如进行:

ser.read(1024)

<强>太多并发症

什么是由换行或通过其它数组操作分裂字节对象的原因吗? 我写的最简单的方法,这将解决您的问题:

import serial
s = serial.Serial(31)
s.write(bytes("ATI\r\n", "utf-8"));
while True:
    last = ''
    for byte in s.read(s.inWaiting()): last += chr(byte)
    if len(last) > 0:
        # Do whatever you want with last
        print (bytes(last, "utf-8"))
        last = ''

下面是一个使用一个封装器,可以读取无需100%的CPU最近线的示例

class ReadLine:
    """
    pyserial object wrapper for reading line
    source: https://github.com/pyserial/pyserial/issues/216
    """
    def __init__(self, s):
        self.buf = bytearray()
        self.s = s

    def readline(self):
        i = self.buf.find(b"\n")
        if i >= 0:
            r = self.buf[:i + 1]
            self.buf = self.buf[i + 1:]
            return r
        while True:
            i = max(1, min(2048, self.s.in_waiting))
            data = self.s.read(i)
            i = data.find(b"\n")
            if i >= 0:
                r = self.buf + data[:i + 1]
                self.buf[0:] = data[i + 1:]
                return r
            else:
                self.buf.extend(data)

s = serial.Serial('/dev/ttyS0')
device = ReadLine(s)
while True:
    print(device.readline())
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top