Arduino Sketch适用于串行监视器,但不适用于pyserial

时间:2017-02-08 13:03:16

标签: python interface arduino pyserial

我在python中测试这个简单的arduino代码,但它在arduino序列中工作,而不是在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;

2 个答案:

答案 0 :(得分: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&#34;等待传出的传出要完成的串行数据&#34; ,但您没有在Serial输出上发送任何内容。

其次,当您在第一次循环迭代时处于行2:时,有两种可能的情况:

  • A。 Serial输入提供了某些内容,因此Serial.available() > 0,您无法进入循环而您无法阅读{{1} }}
  • B。 val输入无效,因此Serial,您进入循环。现在有两个子案例:
    • B.1。如果Serial.available() == 0输入上没有任何内容,您将继续阅读Serial,并继续停留在该循环中
    • B.2。如果有0次输入的内容,则有3个子案例:
      • B.2.I。输入数据在您执行Serial后立即到达,因此在下一个循环迭代Serial.parseInt()为false并且您退出循环而不读取您的Serial.available() <= 0(也就是说,最终结果是 A。
      • B.2.II。当您执行val并且您成功将所有输入字节解析为{{1}时,输入数据就会到达}。但是,Serial.parseInt()输入中没有任何内容,因此条件val仍然存在且您仍处于循环中
      • B.2.III。当您执行Serial并且您成功将某些输入字节解析为{{1}时,输入数据就会到达}。还有一些与Int值无关的字节 (例如Serial.available() <= 0Serial.parseInt()val,空格,字母符号,......) \r忽略并保留在\n输入缓冲区中。因此,在下一个循环迭代\t为false并退出循环。

当您致电Serial.parseInt()时,您会遇到下列情况之一: A。 B.2.I。 B.物2.ii。即可。这就解释了为什么你没有看到任何眨眼:要么你仍然被困在循环中,要么你没有阅读任何内容就已经过去了,你仍然有Serial

案例 B.2.III。是您最终使用草图的唯一情况。当您使用 Arduino 串行监视器时会发生这种情况,因为后者发送了额外的Serial.available() <= 0 (或blinkLED('10')?我不知道#39;记住..)默认情况下按键盘上的val == 0

所以我认为这解释了为什么草图在您使用串行监视器时有效,而在您使用 python 代码时则无法解释。快速测试是修改\n,如下所示:

\r\n

注意:使用串行监视器可以在一些测试中使用,或者即使enter也可以使用此修复,这并不意味着您的草图现在是正确的,并且它总是会起作用。事实上,代码可能仍然失败,例如如果blinkLED(x)太快,那么您仍然无法进入循环体并解析def blinkLED(x): ser.write(x) ser.write('\n') ser.flushOutput() return

@ArnoBozo建议如下更改pyserial

Serial.available > 0

我认为此设计有缺陷,因为当您检查val establishContact()时,您再次无保证对方已经发送了数据(或收到的数据)。如果不是这种情况,则不会执行循环体并且您永远不会解析1: void establishContact() { 2: while (Serial.available() > 0){ 3: val = Serial.parseInt(); 4: Serial.flush(); 5: } 6: } 。当然,您可以尝试使用Serial.available() > 0,但这会使整个草图非常脆弱。

最后观察:如果你查看python的{​​{3}},就会发现:

  
      
  • 如果没有为可配置的超时值读取任何字符,或者读取非数字,则解析停止;
  •   
  • 如果超时(参见Serial.setTimeout())没有读取有效数字,则返回0;
  •   

如果您检查val的{​​{3}},则会发现delay() &#34;默认为1000毫秒&#34; 。再次,以重复自己和出现迂腐为代价,除非严格必要,否则不应该依赖通信协议中的超时延迟(例如启发式决定是时候分配免费资源与不再参与通信的外部实体进行通信了。

因此,我的建议是 scratch Serial.parseInt()并编写自己的解析器,或以更健壮的方式使用它。你想到的目标:

Serial.setTimeout()

这种方法相当野蛮 (但是YOLO) Arduino 不会再试图解析timeoutSerial.parseInt()不同,直到获得一个。同样,您应该在您的号码(例如Serial.setTimeout(0); // disables timeout while (val == 0) { // discard any 'garbage' input val = Serial.parseInt(); // keeps trying to read an Int } 之后发送一个无效数字,因为否则int因为0现在等于{{}}而不会返回{1}}。

(请注意,我没有测试此代码,如果我误解了库文档的某些部分,它可能也行不通。)

答案 1 :(得分:0)

我认为你的python脚本在某处调用了blinkLED(),并且在你的arduino上的establishContact()收到了消息。

但你应该写Serial.available() > 0(在传入缓冲区中等待读取的字节数。)

您可以删除以下行:

while (!Serial) { }  // DOES NOT wait for serial port to connect (USB)

确实Serial对象在编译时被实例化并立即返回(除了一个板:Leonardo?)。

你没有在这里使用的

Serial.flush()空的传出缓冲区;它对传入的缓冲区没有任何作用。

在你的python脚本中打开到arduino的串口时,这肯定会重置arduino板;这将持续不到2秒。所以:

  • python可以等到那个arduino发给你一个问候消息。
  • 或python可以在发送blinkLED()消息之前等待2秒。

如果你打开你的arduino IDE串口显示器,它会重置你的arduino板,但你不能在电路板准备好之前输入并发送信息,所以你没有看到问题。

该错误代码会发生什么:

while (Serial.available() <= 0){
   val = Serial.parseInt();  }

如果没有数据在序列上等待,它将进入while循环。然后Serial.parseInt()将等待传入数据超时1秒。如果什么都没有,它将返回0。