I have an Arduino connected to my computer running a loop, sending a value over the serial port back to the computer every 100 ms.
I want to make a Python script that will read from the serial port only every few seconds, so I want it to just see the last thing sent from the Arduino.
How do you do this in Pyserial?
Here's the code I tried which does't work. It reads the lines sequentially.
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?
Perhaps I'm misunderstanding your question, but as it's a serial line, you'll have to read everything sent from the Arduino sequentially - it'll be buffered up in the Arduino until you read it.
If you want to have a status display which shows the latest thing sent - use a thread which incorporates the code in your question (minus the sleep), and keep the last complete line read as the latest line from the Arduino.
mtasic's example code is quite good, but if the Arduino has sent a partial line when
inWaiting() is called, you'll get a truncated line. Instead, what you want to do is to put the last complete line into
last_received, and keep the partial line in
buffer so that it can be appended to the next time round the loop. Something like this:
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]
Regarding use of
readline(): Here's what the Pyserial documentation has to say (slightly edited for clarity and with a mention to readlines()):
Be careful when using "readline". Do specify a timeout when opening the serial port, otherwise it could block forever if no newline character is received. Also note that "readlines()" only works with a timeout. It depends on having a timeout and interprets that as EOF (end of file).
which seems quite reasonable to me!
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()