Arduino Sketch适用于串行监视器,但不适用于pyserial [英] Arduino Sketch works with Serial Monitor but not with pyserial

查看:229
本文介绍了Arduino Sketch适用于串行监视器,但不适用于pyserial的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在python中测试这个简单的arduino代码,但它在arduino序列中工作,而不是在python中。
用户定义指示灯上的闪烁次数。
这适用于arduino串行监视器。但是当我在python中使用它时它不起作用。有人可以帮忙吗?
谢谢

I am testing this simple arduino code in python but it works in arduino serial not in python. User defines the number of blinks on the led. This works on arduino serial monitor. But when I use it in python it does not work. can anyone help? Thank you

Arduino代码:

Arduino code:

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;


推荐答案

首先,我假设代码中的某处你打电话

First, I'll assume that somewhere in your code you do call

blinkLED('10')

否则整个讨论毫无意义。

otherwise this entire discussion is pointless.

在这方面,我会改变你的函数 blinkLED(x)如下:

On this regard, I'd change your function blinkLED(x) as follows:

def blinkLED(x):
    ser.write(x)
    ser.flushOutput()
    return






其次,我对此代码并不完全相信:


Second, I am not fully convinced by this code:

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

首先,我不是完全确定你认为 Serial.flush()应该在那里做什么,因为根据文档等待传出的串行数据传输完成,但你没有发送任何东西序列输出。

First of all, I am not exactly sure what you think that Serial.flush() is supposed to do there, since according to the documentation it "Waits for the transmission of outgoing serial data to complete", but you are not sending anything on Serial output.

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

Second, when you are at line 2: at the first loop iteration, there are two possible cases:


  • A。 串行输入,因此 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 为false并且您在不读取 val 的情况下退出循环(也就是说,最终结果是 A。

      • B.2.II。输入数据在您执行 Serial时就会到达。 parseInt()并且您成功地将所有输入字节解析为 val 。但是, Serial 输入中没有任何内容,因此条件 Serial.available()< = 0 仍然存在且你仍然陷入困境

      • B.2.III。当你执行 Serial.parseInt()<时,输入数据就会到达/ code>并且您成功地将一些输入字节解析为 val 。还有一些与Int值无关的字节 (例如 \ r \ n \t ,空格,字母符号,......) Serial.parseInt忽略( )并保留在 Serial 输入缓冲区中。因此,在下一个循环迭代 Serial.available()< = 0 为false并退出循环。

      • A. something is available on Serial input, therefore Serial.available() > 0, you don't enter the loop and you don't read val
      • B. nothing is available on Serial input, therefore Serial.available() == 0, and you enter the loop. Now there are two sub-cases:
        • B.1. if nothing arrives on Serial input, you keep reading 0 forever, and remain stuck in that loop
        • B.2. if something arrives on Serial input, there are 3 sub-cases:
          • B.2.I. the input data arrives right after you execute Serial.parseInt(), so at the next loop iteration Serial.available() <= 0 is false and you exit the loop without reading your val (that is, you end up in case A.)
          • B.2.II. the input data arrives right when you execute Serial.parseInt() and you successfully parse all of the input bytes into val. However, nothing remains within the Serial input, so the condition Serial.available() <= 0 still holds and you remain stuck in the loop
          • B.2.III. the input data arrives right when you execute Serial.parseInt() and you successfully parse some of the input bytes into val. A few more bytes that do not pertain an Int value (e.g. \r, \n, \t, space, alphabetic symbols, ...) are ignored by Serial.parseInt() and remain in the Serial input buffer. Therefore at the next loop iteration Serial.available() <= 0 is false and you exit the loop.

          致电时 blinkLED('10')您最终遇到以下情况之一: A。 B.2.I。 B.2.II。。这就解释了为什么你没有看到任何闪烁:要么你仍然被困在循环中,要么你没有阅读任何东西就已经过去了,你仍然有 val == 0

          When you call blinkLED('10') you end up in one of the following cases: A., B.2.I. or B.2.II.. This explains why you don't see any blinking: either you are still stuck in the loop, or you got past it without reading anything and you still have val == 0.

          案例 B.2.III。是唯一可以使用草图的情况。当您使用 Arduino 串行监视器时会发生这种情况,因为后者会发送额外的 \ n (或 \\\\ n ?我不记得..)默认情况下按输入在你的键盘上。

          Case B.2.III. is the only situation in which you end up with a working sketch. This is what happens when you use the Arduino serial monitor, since the latter sends an additional \n (or \r\n? I don't remember..) by default when you press enter on your keyboard.

          所以我认为这解释了为什么你的草图在你使用串口监视器时工作,但不是在使用 python 代码时。快速测试将修改 blinkLED(x),如下所示:

          So I think this explains why your sketch works when you use the serial monitor, but not when you use the python code. A quick test would be to modify blinkLED(x) as follows:

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

          注意:使用串行监视器的情况适用于一些测试,或甚至 pyserial 可能适用于此修复,并不意味着您的草图现在正确并且它始终可以正常工作。事实上,代码可能仍然失败,例如如果 Serial.available> 0 过早你仍然没有进入循环体并解析 val

          Note: the fact that using the serial monitor works on a few tests, or that even pyserial might work with this fix, doesn't mean that your sketch is now correct and that it is always going to work. In fact, the code might still fail, e.g. if Serial.available > 0 too soon then you still don't enter the loop body and parse val.

          @ArnoBozo建议更改 establishContact(),如下所示:

          @ArnoBozo proposed changing establishContact() as follows:

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

          我认为这个设计是有缺陷的,因为当你检查 Serial.available()>时,你还有无保证 0 python 对应方已发送数据(或已收到)。如果不是这种情况,则不会执行循环体并且您永远不会解析 val 。当然,您可以尝试使用 delay(),但这会使整个草图非常脆弱。

          I think that this design is flawed as well, because again you have no guarantee that by the time you check Serial.available() > 0 the python counterpart has already sent the data (or that it was received). If this is not the case, the loop body is simply not executed and you never parse val. Sure, you can try playing with delay(), but that makes the entire sketch quite fragile.

          最后观察:如果你看一下 Serial.parseInt()的noreferrer>文档,您会发现:

          A final observation: if you look at the documentation of Serial.parseInt(), you find that:



          • 如果没有为可配置的超时值读取字符,或者读取非数字,则解析停止;

          • 如果没有有效数字在超时(参见Serial.setTimeout())发生时读取,返回0;

          如果您查看 Serial.setTimeout的文档( )你发现超时 默认为1000毫秒。再一次,以重复自己和出现迂腐为代价,除非严格必要,否则不应该依赖通信协议中的超时延迟(例如启发式决定是时候分配免费资源与不再参与通信的外部实体进行通信了。

          If you check the documentation of Serial.setTimeout() you find out that the timeout "defaults to 1000 milliseconds". Again, at the cost of repeating myself and appearing pedantic, one should not rely on timeouts and delays in a communication protocol unless strictly necessary (e.g. to heuristically decide that it is time to free resources allocated to communicate with an external entity that is no longer participating to the communication).

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

          Thus, my advice is to either scratch Serial.parseInt() and write your own parser, or use it in a more robust way wrt. the goal you have in mind:

          Serial.setTimeout(0);            // disables timeout
          while (val == 0) {               // discard any 'garbage' input
              val = Serial.parseInt();     // keeps trying to read an Int
          }
          

          这种方法相当残酷 (但YOLO) Arduino 不会停止尝试解析与<$不同的 int c $ c> 0 直到获得一个。同样,您应该在您的号码之后发送无效数字(例如 \ n ,否则 Serial.parseInt() 将不会返回,因为 timeout 现在等于 0

          This approach is rather brutal (but YOLO): Arduino won't stop trying to parse an int different from 0 until when it gets one. Again, you should send an invalid digit after your number (e.g. \n) because otherwise Serial.parseInt() won't return since timeout is now equal to 0.

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

          这篇关于Arduino Sketch适用于串行监视器,但不适用于pyserial的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆