Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python on Raspberry Pi user input inside infinite loop misses inputs when hit with many

I have a very basic parrot script written in Python that simply prompts for a user input and prints it back inside an infinite loop. The Raspberry Pi has a USB barcode scanner attached for the input.

while True:
    barcode = raw_input("Scan barcode: ")
    print "Barcode scanned: " + barcode

When you scan at a "normal" speed it works reliably and the command output looks like this:

Scan barcode: 9780465031467
Barcode scanned: 9780465031467
Scan barcode: 9780007505142
Barcode scanned: 9780007505142

But when you really hammer it with many scans in close succession it is possible to make it miss inputs and the command output looks like this:

Scan barcode: 9780141049113
Barcode scanned: 9780141049113
Scan barcode: 9780465031467
Barcode scanned: 9780465031467
Scan barcode: 9780007505142
9780571273188
Barcode scanned: 9780571273188

Notice how 9780007505142 was input but never printed back. It got lost in the confusion.

See a video demonstration of my test at: https://youtu.be/kdsfdKFhC1M

My question: Is this an inevitability of using a low powered device like a Pi? Will it always be true that a user with a barcode scanner will be able to out-run the hardware's ability to keep up?

like image 612
Martin Joiner Avatar asked Oct 20 '16 14:10

Martin Joiner


1 Answers

You should probably read from stdin directly using code similar to the following:

import os
import sys
import select

stdin_fd = sys.stdin.fileno()
try:
    while True:
        sys.stdout.write("Scan barcode: ")
        sys.stdout.flush()
        r_list = [stdin_fd]
        w_list = list()
        x_list = list()
        r_list, w_list, x_list = select.select(r_list, w_list, x_list)
        if stdin_fd in r_list:
            result = os.read(stdin_fd, 1024)
            result = result.rstrip()
            result = [line.rstrip() for line in result.split('\n')]
            for line in result:
                print "Barcode scanned: %s" % line
except KeyboardInterrupt:
    print "Keyboard interrupt"

This code should handle the case that multiple lines are read at once. The read buffer size is arbitrary and you might have to change it depending on how much data you need to handle.

like image 116
David Cullen Avatar answered Nov 01 '22 10:11

David Cullen