Arduino Sketch работает с Serial Monitor, но не с pyserial
Я тестирую этот простой код arduino в python, но он работает в arduino serial, а не в python. Пользователь определяет количество миганий на светодиоде. Это работает на серийном мониторе arduino. Но когда я использую его в python, он не работает. может ли кто-нибудь помочь? спасибо
Код Arduino:
int ledPin = 13; // select the pin for the LED int val = 0; // variable to store the data from the serial port void setup() { pinMode(ledPin,OUTPUT); // declare the LED's pin as output Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect (USB) } establishContact(); } void establishContact(){ while (Serial.available() <= 0){ val = Serial.parseInt(); Serial.flush(); // Serial.println("Est"); } } void loop () { if (val>0) { for(int i=0; i<val; i++) { digitalWrite(ledPin,HIGH); delay(150); digitalWrite(ledPin, LOW); delay(150); } val=0; } }
Код Python:
import serial import time ser = serial.Serial('/dev/tty.usbmodem1421', baudrate=9600,timeout =None) def blinkLED(x): ser.write(x) return;
- Поиск приложения GUI для ввода команд Linux
- Оберните несколько C-источников (файлы .c), чтобы использовать их функции в Python, используя SWIG
- В компиляции SWIG: В заголовочном файле в интерфейсе не удается разрешить другие файлы заголовков.
- Почему pylint продолжает говорить, что мой класс R0923 – «интерфейс не реализован»
- Настроить тип параметра функции в Python?
Во-первых, я буду предполагать, что где-то в коде, который вы вызываете
blinkLED('10')
иначе вся эта дискуссия бессмысленна.
В связи с этим я изменил бы функцию blinkLED(x)
следующим образом:
def blinkLED(x): ser.write(x) ser.flushOutput() return
Во-вторых, я не полностью убежден в этом коде:
1: void establishContact() { 2: while (Serial.available() <= 0){ 3: val = Serial.parseInt(); 4: Serial.flush(); 5: } 6: }
Прежде всего, я не совсем уверен, что вы думаете, что Serial.flush()
должен там делать, поскольку согласно документации он «ожидает завершения передачи последовательных данных» , но вы ничего не отправляете Serial
выход.
Во-вторых, когда вы находитесь в строке 2:
на первой итерации цикла возможны два случая:
- A. что-то доступно на
Serial
входе, поэтомуSerial.available() > 0
, вы не вводите цикл, и вы не читаетеval
- B.
Serial.available() == 0
ничего доступного наSerial
входе, поэтомуSerial.available() == 0
, и вы вводите цикл. Теперь есть два подсектора:- B.1. если ничего не поступит на
Serial
вход, вы всегда будете читать0
и остаетесь в этом цикле - БИ 2. если что-то прибывает на
Serial
вход, есть 3 поддиапазона:- B.2.I. входные данные поступают сразу после выполнения
Serial.parseInt()
, поэтому на следующем итерации циклаSerial.available() <= 0
является ложным, и вы выходите из цикла, не читая свойval
(то есть, вы заканчиваете в случае A. ) - B.2.II. входные данные поступают правильно, когда вы выполняете
Serial.parseInt()
и вы успешно разбираете все входные байты вval
. Тем не менее, вSerial.available() <= 0
входе ничего не остается, поэтому условиеSerial.available() <= 0
все еще сохраняется, и вы остаетесь в цикле - B.2.III. входные данные поступают правильно, когда вы выполняете
Serial.parseInt()
и вы успешно разбираете некоторые входные байты вval
. Еще несколько байтов, которые не имеют значения Int (например,\r
,\n
,\t
, пробел, буквенные символы, …) , игнорируютсяSerial.parseInt()
и остаются в буфереSerial
ввода. Поэтому на следующем цикле итерацияSerial.available() <= 0
является ложной, и вы выходите из цикла.
- B.2.I. входные данные поступают сразу после выполнения
- B.1. если ничего не поступит на
Когда вы вызываете blinkLED('10')
вы blinkLED('10')
в одном из следующих случаев: A. , B.2.I. или B.2.II. , Это объясняет, почему вы не видите мигания: либо вы все еще застреваете в цикле, либо вы прошли мимо него, ничего не читая, и у вас все еще есть val == 0
.
Случай B.2.III. это единственная ситуация, в которой вы получаете рабочий эскиз . Это происходит, когда вы используете серийный монитор Arduino , поскольку последний отправляет дополнительный \n
(или \r\n
? Я не помню ..) по умолчанию, когда вы нажимаете enter
на своей клавиатуре.
Поэтому я думаю, что это объясняет, почему ваш эскиз работает, когда вы используете последовательный монитор , но не тогда, когда вы используете код python . Быстрое испытание было бы изменить blinkLED(x)
следующим образом:
def blinkLED(x): ser.write(x) ser.write('\n') ser.flushOutput() return
Обратите внимание: тот факт, что использование последовательного монитора работает на нескольких тестах или что даже pyserial
может работать с этим исправлением, не означает, что ваш эскиз теперь правильный и что он всегда будет работать. Фактически, код может по-прежнему не работать, например, если Serial.available > 0
слишком скоро, вы все равно не входите в тело цикла и parse val
.
@ArnoBozo предложил изменить installContact establishContact()
следующим образом:
1: void establishContact() { 2: while (Serial.available() > 0){ 3: val = Serial.parseInt(); 4: Serial.flush(); 5: } 6: }
Я думаю, что этот дизайн также ошибочен , потому что опять же у вас нет гарантии, что к моменту проверки Serial.available() > 0
копия python
уже отправила данные (или что она была получена) . Если это не так, тело цикла просто не выполняется, и вы никогда не разбираете val
. Конечно, вы можете попробовать играть с delay()
, но это делает весь эскиз довольно хрупким.
Окончательное замечание: если вы посмотрите документацию Serial.parseInt()
, вы обнаружите, что:
- Парсинг останавливается, если никакие символы не были прочитаны для настраиваемого значения тайм-аута, или считывается не цифра;
- Если действительные цифры не были прочитаны, когда тайм-аут (см. Serial.setTimeout ()), возвращается 0;
Если вы проверите документацию Serial.setTimeout()
вы обнаружите, что timeout
«по умолчанию составляет 1000 миллисекунд» . Опять же, за счет повторения себя и появления педантизма, не следует полагаться на тайм-ауты и задержки в протоколе связи, если это строго необходимо (например, чтобы эвристически решить, что пришло время освободить ресурсы, выделенные для связи с внешним объектом, который больше не является участвуя в сообщении).
Таким образом, мой совет – либо поцарапать Serial.parseInt()
написать собственный синтаксический анализатор, либо использовать его более надежным способом. цель, которую вы имеете в виду:
Serial.setTimeout(0); // disables timeout while (val == 0) { // discard any 'garbage' input val = Serial.parseInt(); // keeps trying to read an Int }
Этот подход довольно жестокий (но YOLO) : Arduino не перестанет пытаться анализировать int
отличное от 0
пока он не получит его. Опять же, вы должны отправить недопустимую цифру после своего номера (например, \n
), потому что иначе Serial.parseInt()
не будет возвращаться, так как timeout
теперь равен 0
.
(обратите внимание, что я не тестировал этот код, он также может не работать, если я неверно истолковал некоторые части документации библиотеки.)
Я думаю, что скрипт python вызывает blinkLED()
где-то, и сообщение получено в blinkLED()
establishContact()
на вашем arduino.
Но вы должны были написать Serial.available() > 0
(сколько байтов ожидает чтения в входящем буфере).
Вы можете удалить следующие строки:
while (!Serial) { } // DOES NOT wait for serial port to connect (USB)
Действительно, серийный объект инстанцируется во время компиляции и сразу возвращается (за исключением одной платы: Леонардо?).
Serial.flush()
пустой исходящий буфер, который вы здесь не используете; он ничего не делает на входящем буфере.
В вашем скрипте python, когда вы открываете последовательный порт для arduino, это, безусловно, сбросит плату arduino; который будет длиться менее 2 секунд. Так:
- python может подождать, когда arduino отправит вам посылку привет.
- или python может ждать 2 секунды, прежде чем отправлять сообщение
blinkLED()
.
Если вы откроете серийный монитор Arduino IDE, он сбрасывает плату arduino, но вы не можете вводить и отправлять сообщения до того, как плата готова, поэтому вы не видите проблему.
Что происходит с этим прослушиваемым кодом:
while (Serial.available() <= 0){ val = Serial.parseInt(); }
Он входит в цикл while, если нет данных, ожидающих серийный номер. Затем Serial.parseInt()
будет ждать тайм-аута 1 с для входящих данных. Если ничего не произойдет, оно вернет 0.
- cx_Oracle с несколькими версиями клиента Oracle
- OpenCV и Python – Как накладывать изображения, задавая координаты?
- Отзывчивая запись PyAudio
- Как документировать и тестировать интерфейсы, необходимые для формальных параметров в Python 2?
- Как закончить вход sys.stdin.readlines ()?
- Что такое хороший способ реализовать что-то похожее на интерфейс в Python?
- «Иногда», получая InterfaceError на PostgreSQL с Peewee ORM
- Рекурсивные определения классов в Python
- Проблемы с просмотром PDF-файлов
- Взаимодействие с кривой на графике Matplotlib
- Простой сетевой обмен сообщениями python