Тайм-аут PySerial, загрузка процессора и сканирование штрих-кода

#python #barcode #barcode-scanner #pyserial

#python #штрих-код #сканер штрих-кода #pyserial

Вопрос:

Сразу стоит упомянуть, что, хотя у меня есть опыт работы в CS, количество написанных мной скриптов на Python, скорее всего, можно пересчитать по количеству пальцев на лапе ленивца. Тем не менее, я начал играть с PySerial для чтения со сканера штрих-кодов USB. Одна из проблем, с которой я сталкиваюсь, — это тайм-аут. Если я установлю его слишком низким, я пропущу сканирование. Если я установлю его слишком высоким, загрузка процессора будет огромной. Конечно, это упоминается в документации для PySerial:

Будьте осторожны при использовании readline(). Обязательно указывайте тайм-аут при открытии последовательного порта, иначе он может заблокироваться навсегда, если не будет получен символ новой строки. Также обратите внимание, что readlines () работает только с таймаутом. readlines () зависит от наличия тайм-аута и интерпретирует его как EOF (конец файла). Если порт открыт неправильно, возникает исключение.

Правильно. Итак, вот мой простой код:

 #!/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)
  

Как мне правильно считывать с последовательного устройства, не рискуя пропустить сканирование? Конечно, шансы невероятно малы при таком малом таймауте, но я хочу использовать это для производственных целей в моем бизнесе, поэтому давайте предположим, что это критически важно. Как правильно подойти к этой проблеме (опять же, предполагая, что мое понимание Python равно нулю)?

Спасибо всем!

РЕДАКТИРОВАТЬ: Возможное решение?

Я придумал следующее, которое не использует тайм-аут и просто считывает по одному символу за раз, пока он не достигнет новой строки. Похоже, что это довольно мало влияет на загрузку процессора (в чем и заключалась вся проблема, с которой я столкнулся). Конечно, мне нужно учитывать другие возможности перевода строки из разных сканеров, но есть ли какая-либо причина, по которой это не сработает?

 #!/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 = ""
  

Ответ №1:

Из того, что я знаю о сканерах штрих-кодов, вы можете настроить их так, чтобы они запускали сканирование только тогда, когда вы отправляете им определенную команду записи через serial, вы можете использовать это в своих интересах.

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

Для непрерывного чтения лучший способ сделать это — продолжать считывать байты в цикле ожидания, например

 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))

  

Комментарии:

1. Я не взял свой сканер с собой домой на выходные, поэтому только сейчас нашел время протестировать ваше предложение. Однако это не совсем то, что я хочу сделать — это в основном программное нажатие кнопки запуска на сканере через Python вместо физического нажатия кнопки. Я хочу по-прежнему разрешать пользователям нажимать кнопку как обычно и читать выходные данные с помощью PySerial, не пропуская ничего из-за тайм-аута. Имеет ли это смысл?

2. Было бы здорово, если бы вы могли принять ответ, если это помогло вам @ArthurSommers 🙂

Ответ №2:

Мой опыт установки таймаута на высокое значение противоположен вашему утверждению. Высокий тайм-аут гарантирует, что python не проверяет последовательный буфер каждые 1/20 000 долю секунды. В этом смысл последовательного буфера — хранить входные данные до тех пор, пока они не будут прочитаны. Время ожидания измеряется тысячными долями секунды, поэтому 0,05 * 1/1000 = 1/20 000 или 20 000 проверок в секунду. Я установил его на 10 секунд ниже. (минимум 6 проверок в минуту) Конечно, если python обнаруживает новую строку раньше, то readline () не прерывает работу.

 #!/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)
  

Однако, если ваш UART не имеет буфера и отбрасывает что-либо, кроме одного символа, вы можете потерять ввод. Это зависит от вашего оборудования и настроек. Если штрих-код помещается в буфер, у вас не должно возникнуть никаких проблем.