PySerial не разговаривает с Arduino

Я написал некоторый код для имитации некоторого оборудования, с которым я работаю, и загрузил его на плату Arduino. Этот код работает. Я знаю это, потому что получаю ожидаемый ответ от HyperTerminal.

Однако, когда я пытаюсь подключиться с помощью PySerial, соединение не завершается ошибкой, но я не получаю ответа на отправляемые команды.

Почему это может быть?

Код Python

import serial

def main():
    sp = serial.Serial()
    sp.port = 'COM4'
    sp.baudrate = 19200
    sp.parity = serial.PARITY_NONE
    sp.bytesize = serial.EIGHTBITS
    sp.stopbits = serial.STOPBITS_ONE
    sp.timeout = 0.5
    sp.xonxoff = False
    sp.rtscts = False
    sp.dsrdtr = False

    sp.open()

    sp.write("GV\r\n".encode('ascii'))
    value = sp.readline()
    print value
    sp.write("GI\r\n".encode('ascii'))
    value = sp.readline()
    print value

    sp.close()
 
if __name__ == "__main__":
    main()

NB: код на Arduino отправляет обратно \r\n в конце ответа на команду.

Конфигурация гипертерминала:

Конфигурация COM4 в HyperTerminal

Редактировать

Я обнаружил, что если увеличить время ожидания до 10 секунд и добавить sp.readline() перед отправкой чего-либо, то я получаю ответы на обе команды.

Как долго обычно длится аппаратное рукопожатие между PySerial и портами Arduino или USB RS-232?


person Matt Ellen    schedule 16.11.2011    source источник
comment
Один небольшой комментарий по поводу отправки команд в REPL (командный процессор), как это делается здесь. Я заметил, что команды, которые вы отправляете, завершаются с помощью \r\n. Хотя обычные текстовые строки обычно заканчиваются \r\n, команды Sent обычно заканчиваются только одним символом \r, так как их вводил бы пользователь-человек. Если отправляется \n, это может быть интерпретировано как начало следующей команды и потенциально может привести к зависанию или вызвать другие ложные нежелательные результаты.   -  person RufusVS    schedule 22.10.2018


Ответы (5)


Не могу проверить это, но может случиться так, что вы попытаетесь прочитать до того, как там появятся какие-либо данные, поэтому вы не получите ответа.

Чтобы проверить это, вы можете попробовать и опросить, пока не появятся данные

value = None
while not value:
   value = sp.readline()
print value

Изменить

Arduino перезагрузится, когда вы откроете последовательное соединение, любые данные, записанные во время загрузки, скорее всего, попадут в рай. Вы можете использовать сон в течение 2 секунд (не удалось найти точное время, которое требуется, вероятно, все равно будет варьироваться), прежде чем выполнять какие-либо операции чтения/записи.

В качестве альтернативы вы можете писать на него, пока не получите ответ, после того, как вы получите ответ, вы начнете делать «настоящую работу».

person ib.lundgren    schedule 16.11.2011
comment
К сожалению, readline возвращает пустую строку по истечении времени ожидания. Это не работает для меня. Я попытался дождаться непустой строки, но это привело к бесконечному циклу. - person Matt Ellen; 16.11.2011
comment
Очень плохо, вы пробовали базовый тест Arduino, который просто спамит Serial.println, чтобы увидеть, можете ли вы вообще получить какой-либо вывод? - person ib.lundgren; 16.11.2011
comment
Да, я могу получить выход. Первоначально я мог получить его только через HyperTerminal, но я обнаружил, что проблема заключается в задержке между подключением и возможностью отправки/получения данных. Я обновил вопрос. Спасибо за вашу помощь. - person Matt Ellen; 16.11.2011

На данный момент я использую обходной путь. Я установил timeout на 1,5 секунды и вставил вызов readline перед первой записью.

Итак, теперь код Python выглядит так:

import serial

def main():
    sp = serial.Serial()
    sp.port = 'COM4'
    sp.baudrate = 19200
    sp.parity = serial.PARITY_NONE
    sp.bytesize = serial.EIGHTBITS
    sp.stopbits = serial.STOPBITS_ONE
    sp.timeout = 1.5 #1.5 to give the hardware handshake time to happen
    sp.xonxoff = False
    sp.rtscts = False
    sp.dsrdtr = False

    sp.open()

    sp.readline() #to give the hardware handshake time to happen

    sp.write("GV\r\n".encode('ascii'))
    value = sp.readline()
    print value
    sp.write("GI\r\n".encode('ascii'))
    value = sp.readline()
    print value

    sp.close()

if __name__ == "__main__":
    main()
person Matt Ellen    schedule 16.11.2011
comment
Я не понимал, зачем это нужно, но добавление readline() перед write сработало и для меня. - person wizofwor; 12.05.2015
comment
@wizofwor как таковой не требуется, это просто удобный способ заставить программное обеспечение ждать готовности оборудования. - person Matt Ellen; 26.06.2015

Недавно я также столкнулся с этой проблемой, и вот мое решение:

import serial

ser = serial.Serial(4, timeout=2)
ser.setRTS(True)
ser.setRTS(False)
while 1:
    line = ser.readline()
    print(line)
ser.close

Оказывается, это успешно перезагрузит плату Arduino.

person Memphis    schedule 04.07.2012

Добавьте задержку после открытия порта, когда Arduino сбрасывается и загрузчик начинает прослушивать новую прошивку. Если в этот момент что-то отправляется, MCU остается в загрузчике. Задержка приводит к тайм-ауту загрузчика.

sp.open()
time.sleep(2) # 2 seconds or possibly a bit less
sp.write("blahblah")
person nvd    schedule 16.08.2016

Вы можете легко и надежно подключаться и взаимодействовать между платами Python и Arduino с помощью совместимых библиотек SerialTransfer.h и pySerialTransfer. Эти библиотеки автоматически пакетируют и анализируют последовательные пакеты, используя маркеры начала/конца, циклическую проверку избыточности, последовательное заполнение служебных байтов и динамическую длину полезной нагрузки.

SerialTransfer.h устанавливается через диспетчер библиотек Arduino IDE, а pySerialTransfer устанавливается через pip.

Пример Python:

from pySerialTransfer import pySerialTransfer as txfer

if __name__ == '__main__':
    try:
        link = txfer.SerialTransfer('COM13')

        link.txBuff[0] = 'h'
        link.txBuff[1] = 'i'
        link.txBuff[2] = '\n'

        link.send(3)

        while not link.available():
            if link.status < 0:
                print('ERROR: {}'.format(link.status))

        print('Response received:')

        response = ''
        for index in range(link.bytesRead):
            response += chr(link.rxBuff[index])

        print(response)
        link.close()

    except KeyboardInterrupt:
        link.close()

Пример Arduino:

#include "SerialTransfer.h"
#include <SoftwareSerial.h>


SoftwareSerial mySerial(2, 3); // RX, TX
SerialTransfer myTransfer;


void setup()
{
  Serial.begin(115200);
  mySerial.begin(9600);
  myTransfer.begin(mySerial);
}

void loop()
{
  myTransfer.txBuff[0] = 'h';
  myTransfer.txBuff[1] = 'i';
  myTransfer.txBuff[2] = '\n';

  myTransfer.sendData(3);
  delay(100);

  if(myTransfer.available())
  {
    Serial.println("New Data");
    for(byte i = 0; i < myTransfer.bytesRead; i++)
      Serial.write(myTransfer.rxBuff[i]);
    Serial.println();
  }
  else if(myTransfer.status < 0)
  {
    Serial.print("ERROR: ");
    Serial.println(myTransfer.status);
  }
}
person P_B    schedule 10.02.2020