2017-02-08 19 views
1

Я тестирую этот простой код arduino в python, но он работает в серийном Arduino, а не в python. Пользователь определяет количество миганий на светодиоде. Это работает на серийном мониторе arduino. Но когда я использую его в python, он не работает. может ли кто-нибудь помочь? СпасибоArduino Sketch работает с Serial Monitor, но не с pyserial

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; 
+0

как вы знаете, он не работает? ожидаемый выход и фактический выход? что вы пробовали? – WhatsThePoint

+2

Ваш код 'python' ничего не делает, и * действительно ничего не происходит *: кажется, работает нормально. * Возможно, вам не нужен вызов 'blinkLED()' где-то в вашем скрипте. –

+0

В оболочке python я вызываю эту функцию. BlinkLED ('10 '), заставит ее мигать 10 раз. –

ответ

0

Я думаю, что вы питон скрипт вызывает 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.

+0

Спасибо за ответ. Я добавил время ожидания (time.sleep (2)) перед вызовом функции blinkLED() Когда я вызываю функцию blinkLED ('10 '), ожидаемый вывод должен мигать светодиодом 10 раз, но ничего не происходит. Я передаю значение '10 'как строка, но на стороне arduino она преобразует ее в целое число. Но в серийном мониторе IDE arduino он отлично работает. –

+1

Как обычно, мы поймем с помощью трассировки. Вы можете инициализировать с помощью 'val = 2', чтобы вы увидели LED мигает, когда arduino входит в основной цикл, даже если ему не удалось выполнить серийный номер. Вы можете добавить 'val = 4;' inside 'installContact()', перед 'val = Serial.parseInt();'; и в python вы отправляете 'blinkLED ('10') '. Таким образом, вы узнаете, как работает код кс. –

1

Во-первых, я буду считать, что где-то в вашем коде вы зовите

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() должен там делать, так как в соответствии с documentation это «Ожидает передачи o выполнить последовательные данные для завершения «, но вы ничего не отправляете на выходе Serial.

Во-вторых, когда вы находитесь на линии 2: на первой итерации цикла, то возможны два случая:

  • А. что-то доступно на Serial входе, поэтому Serial.available() > 0, вы не войти в и вы не читаете val
  • B. ничего не имеется на Serial ввода, поэтому Serial.available() == 0, и вы вводите петлю. В настоящее время существует два подсектора:
    • B.1. Если ничего не поступило на Serial ввода, вы продолжаете читать 0 навсегда и остаетесь в этом петле
    • B.2. если что-то поступает на вход Serial, есть 3 суб-дела:
      • B.2.I. входные данные поступают сразу после выполнения Serial.parseInt(), поэтому на следующей итерации цикла Serial.available() <= 0 ложна и выхода из цикла, не читая ваши val (то есть, вы в конечном итоге в случае А.)
      • В.2 .II. входные данные поступают правильно, когда вы выполняете Serial.parseInt(), и вы успешно разобрали все входные байты в val. Однако в пределах ввода Serial ничего не остается, поэтому условие Serial.available() <= 0 сохраняется, и вы остаетесь застрявшим в петле
      • B.2.III. входные данные поступают правильно, когда вы выполняете Serial.parseInt(), и вы успешно разобрали некоторые входные байты в val. Еще несколько байтов, которые не относятся значение Int(например \r, \n, \t, пространство, буквенные символы, ...) игнорируются Serial.parseInt() и остаются в Serial входного буфера. Поэтому на следующем цикле итерация Serial.available() <= 0 ошибочна, и вы выходите из цикла.

Когда вы звоните blinkLED('10') вы в конечном итоге в одном из следующих случаев: А., B.2.I. или B.2.II.. Это объясняет, почему вы не видите мигания: либо вы все еще застряли в цикле, либо вы прошли мимо него, не прочитав ничего, и у вас все еще есть val == 0.

Дело B.2.III. - единственная ситуация, в которой вы в конечном итоге получаете рабочий эскиз. Это то, что происходит, когда вы используете Arduinoсерийный монитор, поскольку последний посылает дополнительный \n(или \r\n? Я не помню ..) по умолчанию при нажатии enter на клавиатуре.

Так что я думаю, что это объясняет, почему ваша эскиза работы при использовании серийного монитора, но не тогда, когда вы используете питона код. Быстрый тест будет изменить blinkLED(x) следующим образом:

def blinkLED(x): 
    ser.write(x) 
    ser.write('\n') 
    ser.flushOutput() 
    return 

Примечания: тот факт, что при использовании монитора последовательного порта работает на несколько тестов, или даже pyserial может работать с этим исправлением, не означает, что ваш эскиз теперь правильный и что он всегда будет работать. Фактически, код может все еще сбой, например. если Serial.available > 0 слишком скоро, то вы все равно не входите в тело петли и разбираете val.


@ArnoBozo предложил изменить establishContact() следующим образом:

1: void establishContact() { 
2: while (Serial.available() > 0){ 
3:  val = Serial.parseInt(); 
4:  Serial.flush(); 
5: } 
6: } 

Я думаю, что эта конструкция недостатки, а также, потому что снова у вас есть нет гарантии, что к тому времени, вы проверяете Serial.available() > 0 номер телефона: python еще не отправили данные (или его отправка). Если это не так, то корпус просто не выполнен, и вы никогда не разбираете val. Конечно, вы можете попробовать сыграть с delay(), но это делает весь эскиз довольно хрупкий.


Последнее наблюдение: если вы посмотрите на documentation из Serial.parseInt(), вы обнаружите, что:

  • Синтаксический останавливается, когда никакие символы не будут считаны в течение настраиваемого времени ожидания, или считывается незначащая цифра;
  • Если действительные цифры не были прочитаны при тайм-ауте (см. Серий.setTimeout()), возвращается 0;

Если проверить documentation из 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.

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