2

It's worth mentioning up-front that while I have a background in CS, the number of Python scripts I've written in could likely be counted on the number of toes on a sloth's paw. That said, I started playing with PySerial to read from a USB barcode scanner. One problem I'm having is the timeout. If I set it too low, I miss scans. If I set it too high, the processor utilization is huge. Of course, this is mentioned in the documentation for PySerial:

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. readlines() depends on having a timeout and interprets that as EOF (end of file). It raises an exception if the port is not opened correctly.

Right. So, here's my simple code:

#!/usr/bin/env python

import serial
ser = serial.Serial('/dev/ttyACM0', rtscts=True, dsrdtr=True, timeout=0.05)
ser.baudrate = 115200

while True:
    s = ser.readline()
    if s:
        print(s)

How do I appropriately read from a serial device without risking missed scans? Sure, the odds are incredibly low with that small of a timeout, but I'm wanting to use this for production purposes at my business, so let's assume that this is mission-critical. What's the proper way to approach this problem (again, assuming that my understanding of Python is nil)?

Thanks, everyone!

EDIT: Possible solution?

I came up with the following that doesn't use a timeout and simply reads a single character at a time until it reaches a newline. It seems like this is pretty light on processor utilization (which was the whole issue I was having). Of course, I need to account for other newline possibilities from different scanners, but is there any reason why this wouldn't work?

#!/usr/bin/env python

import serial
ser = serial.Serial('/dev/ttyACM0', rtscts=True, dsrdtr=True)
ser.baudrate = 115200

string = ""

while 1:
    char = ser.read(1)
    string += char
    if char == '\r':
        print(string)
        string = ""

2 Answers 2

1

From what I know about barcode scanners, you can configure them so that they only trigger scanning when you send them a specific write command over serial, you can use that to your advantage.

ser = serial.Serial('/dev/ttyUSBx',timeout=y)
ser.write('<trigger scan>')
value = ser.readline()
ser.close()

For continuous reading, the best way of doing it is to keep reading bytes in a timeout loop like

time_start = datetime.datetime.now()
time_end = time_start + datetime.timedelta(seconds=timeout)

output = []
while datetime.datetime.now() < time_end:
        output.append(ser.read(100))

Sign up to request clarification or add additional context in comments.

2 Comments

I didn't take my scanner home with me over the weekend, so I only now got around to testing your suggestion. However, that's not really what I want to do - that's basically programmatically clicking the trigger button on the scanner via Python instead of physically pushing the button. I want to still allow users to click the button as usual and read the output with PySerial without PySerial missing anything due to the timeout. Does that make sense?
It would be great if you could accept the answer if it helped you @ArthurSommers :)
0

My experience with setting timeout to a high value is the opposite of your assertion. A high timeout ensures that python is not checking the serial buffer every 1/20,000th of a second. That's the point of a serial buffer, to store input until it is read. The timeout is in thousandths of seconds, so 0.05 * 1/1000 = 1/20,000 or 20,000 checks per second. I set it to 10 seconds below. (a minimum of 6 checks per minute) Of course, if python encounters a new line sooner then the readline() does not timeout.

#!/usr/bin/env python

import serial
ser = serial.Serial('/dev/ttyACM0', rtscts=True, dsrdtr=True, timeout=10000)
ser.baudrate = 115200

while True:
    s = ser.readline()
    if s:
        print(s)

However, if your UART has no buffer and discards anything past one character, you could lose input. This depends on your hardware and setup. If the bar code fits in the buffer, you should not encounter any problems.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.