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 scr
Using .inWaiting()
inside an infinite loop may be problematic. It may hog up the entire CPU depending on the implementation. Instead, I would recommend using a specific size of data to be read. So in this case the following should be done for example:
ser.read(1024)
Too much complications
What is the reason to split the bytes object by newline or by other array manipulations? I write the simplest method, which will solve your problem:
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 = ''
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.
Update: 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!
This method allows you to separately control the timeout for gathering all the data for each line, and a different timeout for waiting on additional lines.
# 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