4

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

Ashesh Shrestha
  • 328
  • 4
  • 15
  • 1
    Sometimes your python code gets called in the middle of a transmission. You should never assume that the complete transmission has arrived. Use the in_waiting to find out how many characters have arrived and wait for the whole message before you read it. Or wait to read the whole message before you print it. – Delta_G Apr 12 '20 at 04:32
  • @Delta_G beginner here. What do you mean by code gets called in the middle of transmission? It is just a small code where is no other functions or external inputs AFAIK. I added little code to check if serial read contains world (of Hello world) else to reread and add to the statement. Line break seems to have been solved. – Ashesh Shrestha Apr 12 '20 at 05:58
  • Your python code has a while loop. So it keeps running that code in the while loop over and over and over. If the ser.readline() line gets run in the middle of the transmission then it will read what has been received so far. It has no way to know that there is more coming. It's like if your friend is writing you a note and you grab it from them and read it before they're done writing it. There's nothing that you're doing wrong, you just need to realize that it takes time to send the message, it doesn't just magically all appear together. – Delta_G Apr 12 '20 at 16:23
  • @Delta_G thank you for your explanation. Your answer makes sense that ser.readline() grabs what is available when I call it. Now that I know the issue, I will search for fix. Thank you. – Ashesh Shrestha Apr 12 '20 at 16:40

1 Answers1

3

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)
Ashesh Shrestha
  • 328
  • 4
  • 15
  • Helped me!. Searched everywhere, used in_waiting but the data is dynamic, you are the only one that is able to suit my usecase – Wing Shum Mar 17 '21 at 13:58