Подождите автоматического сброса 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)
надеюсь, что это поможет вам