Python pySerial на Raspberry Pi Zero W: обнаружение отключенного последовательного устройства

В моем проекте есть Raspberry Pi Zero W, связанный с Arduino Pro Micro через последовательные линии TX/RX (через преобразователь логических уровней 5–3,3 В). При включении питания Arduino начинает посылать команду «ты здесь» по последовательному порту, пока Pi не завершит загрузку и не запустит программу Python, которая прослушивает последовательный порт, и ответит «да». Затем Arduino продолжает отправлять регулярные обновления с данными датчиков.

По какой-то еще непонятной причине Arduino может отключиться и перезагрузиться, в то время как Pi все еще работает. И по какой-то причине соединение на стороне Python разрывается таким образом, что не возникает исключения, если connection.in_waiting читается.

import serial
import time
ser = serial.Serial('/dev/serial0')
ser.baudrate = 9600
cmd = b''
while True:
  time.sleep(1)
  print(ser.is_open)
  while ser.in_waiting:
    ch = ser.read()
    if ch == b'\n':
      print('New command:', cmd)
      cmd = b''
      ser.write(b'OK\n')
      continue
    else:
      cmd = cmd + ch

Я тестировал этот простой код, но в моих тестах, если я отключу Arduino и снова подключу его, ser.is_open никогда не будет False, а старое соединение прекрасно работает и с повторно подключенным Arduino. Так что, к сожалению, я не могу точно воспроизвести сценарий потери соединения, когда данные перестают поступать после отключения. Однако для дальнейшего исследования я хотел бы добавить некоторый код мониторинга, который будет регистрировать инциденты последовательного отключения в файле. Но есть ли способ? Если connection.is_open всегда истинно, даже если Arduino не подключен, то как определить, что соединения нет?


person Passiday    schedule 07.09.2019    source источник
comment
Вы пробовали установить тайм-аут? Без тайм-аута read() будет блокироваться до тех пор, пока не будет прочитано запрошенное количество байтов (по умолчанию 1).   -  person bromosapien    schedule 10.09.2019
comment
@bromosapien ser.read() следует сразу за while ser.in_waiting:. Есть ли причина, по которой read() будет блокироваться в таких условиях?   -  person Passiday    schedule 10.09.2019


Ответы (1)


Порт остается открытым, если есть разъединение, так что ваш код примера будет непрерывно зацикливаться.

import serial

def connect(port):
    return serial.Serial(port, baudrate=9600, timeout=1)

ser = connect('/dev/serial0')
buf = bytearray()
while True:
    i = buf.find(b'\n')
    if i >= 0:
        buf = buf[i + 1:]
        ser.write('OK\n')

    num_bytes = max(1, min(1024, ser.in_waiting))
    data = ser.read(num_bytes)
    if data:
        buf.extend(data)
    else:
        # no data to read aka disconnection has occurred
        ser = connect('/dev/serial0')
        if ser.isOpen():
            continue
        else:
            # could not reconnect
            break
person bdoubleu    schedule 11.09.2019
comment
Вы должны установить тайм-аут с помощью этого метода, потому что минимальное количество байтов для чтения равно 1, и без тайм-аута .read() будет зависать, ожидая получения байтов, которые не отправляются. - person bdoubleu; 11.09.2019
comment
Почему отсутствие данных означает, что произошло отключение? Другой конец может просто ничего не отправлять. - person Passiday; 14.10.2019