Ashesh Shrestha
Ashesh Shrestha

Reputation: 388

readline() in pySerial sometimes captures incomplete values being streamed from Arduino serial port

Every one second, Arduino prints (in serial) 'current time in milliseconds and Hello world'. On serial monitor, the output looks fine.

But in pySerial, sometimes there is line break at the middle of string.

313113   Hel
lo world
314114   Hello world
315114   Hello world

My python code is as:

import serial
import time
ser = serial.Serial(port='COM4',
                    baudrate=115200,
                    timeout=0)

while True:
   str = ser.readline()         # read complete line
   str = str.decode()           # decode byte str into Unicode
   str = str.rstrip()           

   if str != "":
      print(str)
   time.sleep(0.01)

What am I doing wrong?

My configuration:

Python 3.7
pySerial 3.4
Board Arduino Mega

Upvotes: 5

Views: 6650

Answers (1)

Ashesh Shrestha
Ashesh Shrestha

Reputation: 388

The problem definitely seems to be caused by very fast reads where the data is read when the serial output from the Arduino hasn't finished sending full data.

Now with this fix, the pySerial will be able to receive the complete data and no data is missed. The main benefit is that it can be used for any type of data length and the sleep time is quite low.

I have fixed this issue with code below.

# This code receives data from serial device and makes sure 
# that full data is received.

# In this case, the serial data always terminates with \n.
# If data received during a single read is incomplete, it re-reads
# and appends the data till the complete data is achieved.

import serial
import time
ser = serial.Serial(port='COM4',
                    baudrate=115200,
                    timeout=0)

print("connected to: " + ser.portstr)

while True:                             # runs this loop forever
    time.sleep(.001)                    # delay of 1ms
    val = ser.readline()                # read complete line from serial output
    while not '\\n'in str(val):         # check if full data is received. 
        # This loop is entered only if serial read value doesn't contain \n
        # which indicates end of a sentence. 
        # str(val) - val is byte where string operation to check `\\n` 
        # can't be performed
        time.sleep(.001)                # delay of 1ms 
        temp = ser.readline()           # check for serial output.
        if not not temp.decode():       # if temp is not empty.
            val = (val.decode()+temp.decode()).encode()
            # requrired to decode, sum, then encode because
            # long values might require multiple passes
    val = val.decode()                  # decoding from bytes
    val = val.strip()                   # stripping leading and trailing spaces.
    print(val)

Upvotes: 4

Related Questions