Подождите автоматического сброса Arduino с помощью pySerial

Я пытаюсь читать строки с платы Arduino с очень простым кодом (ради демонстрации проблемы) на Linux.

Python-кода:

# arduino.py
import serial
arduino = serial.Serial('/dev/ttyACM0')

with arduino:
    while True:
        print(arduino.readline())

Arduino код:

// simpleWrite.ino
long ii = 0;

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
}

void loop() {
  Serial.println(ii);
  ii++;
}

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

Это типичный выход:

$ python arduino.py 
b'09rn'
b'540rn'
b'541rn'
b'542rn'
b'543rn'
b'544rn'
b'545rn'
b'546rn'
b'547rn'
b'548rn'
b'549rn'
b'550rn'
b'551rn'
b'552rn'
b'553rn'
b'554rn'
b'555rn'
b'556rn'
b'557rn'
b'55xfe0rn'  # <---- Here the board restarted
b'1rn'
b'2rn'
b'3rn'
b'4rn'
b'5rn'
b'6rn'
b'7rn'
b'8rn'
b'9rn'
b'10rn'

однако я вижу последовательный монитор Arduino IDE не имеет этой проблемы и правильно показывает задержку (при перезапуске), а затем печатает все строки, начиная с первой.

есть ли способ эмулировать это поведение в Python с помощью pySerial? то есть, отбрасывая все выходные перед перезагрузкой и ничего больше? Возможно, через какие-то низкоуровневые функции?

Я попытался посмотреть на соответствующий исходный код Arduino, но я не знаю Java и не помощь.

Примечание: конечно, я мог бы поспать, скажем, три секунды, отбросить все и начать оттуда, но я, вероятно, отбросил бы некоторые из первых строк тоже.

редактировать: по-видимому, эта проблема не существует в Windows, и принятое решение не было необходимым.

3 ответов


переключатель монитора Arduino IDE является назначенным DTR-контактом порта при подключении. Где это переключение вызывает сброс на Arduino. Отмечая, что DTR переключается после того, как монитор открыл последовательный порт и готов к приему данных. В вашем случае приведенный ниже пример должен сделать то же самое.

Import serial

arduino = serial.Serial('/dev/ttyS0',
                     baudrate=9600,
                     bytesize=serial.EIGHTBITS,
                     parity=serial.PARITY_NONE,
                     stopbits=serial.STOPBITS_ONE,
                     timeout=1,
                     xonxoff=0,
                     rtscts=0
                     )
# Toggle DTR to reset Arduino
arduino.setDTR(False)
sleep(1)
# toss any data already received, see
# http://pyserial.sourceforge.net/pyserial_api.html#serial.Serial.flushInput
arduino.flushInput()
arduino.setDTR(True)

with arduino:
    while True:
        print(arduino.readline())

Я бы также добавил комплимент DTR для Arduino с AVR с использованием встроенного USB, такого как Leonoardo, Esplora и тому подобное. Метод Setup() должен иметь после этого, чтобы дождаться USB, который будет открыт хостом.

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
}

это не будет иметь никакого эффекта для FTDI на основе UNO и таких.


Я понимаю, что это старый вопрос, но, надеюсь, это может быть полезно кому-то еще с той же проблемой.

у меня была проблема, когда, если бы я использовал любые бодраты, кроме 9600, последовательное соединение в python просто получало бы тарабарщину все время, даже если Serial.begin(...) правильно установлен на arduino и соответствует значению, используемому в коде python. Я читал в интернете, что загрузчик или сторожевой пес может занять секунду для загрузки (когда плата включена), и он может отправить материал над серийным на некотором специфическом baudrate (для программирования обломока по возможности). Я предполагаю, что это то, что портит последовательную связь в python.

вот фрагмент кода, который дает мне надежные результаты:

import serial
from time import sleep
arduino = serial.Serial('/dev/ttyACM0') # dummy connection to receive all the watchdog gibberish (unplug + replug) and properly reset the arduino
with arduino: # the reset part is actually optional but the sleep is nice to have either way.
  arduino.setDTR(False)
  sleep(1)
  arduino.flushInput()
  arduino.setDTR(True)

# reopen the serial, but this time with proper baudrate. This is the correct and working connection.
arduino = serial.Serial('/dev/ttyACM0',baudrate=57600)

with arduino:
    while True:
        print(arduino.readline())

код, используемый на стороне arduino для тестирования, так прост:

void setup() {
  Serial.begin(57600);
  Serial.println("setup");
}

void loop() {
  Serial.println("hello");
  delay(200);
}

вам нужно установить var, попробуйте:

unsigned long ii = 0;

но обратите внимание ,что это 32-битный var, и когда он заполнен, вызовите переполнение и перезагрузку. для меня работа. Как предложил @Kobi K добавить минимальное время задержки, для загрузки реальных данных на 9600 boud каждый символ имеет длительность 2 мс,

    void loop() {

      Serial.println(ii);
      delay(20);
      ii++;
    }

и в python вам нужно объявить Pyserial следующим образом:

arduino=serial.Serial('/dev/ttyACM0',9600,timeout=0.0001)

надеюсь, что это поможет вам