Arduino Sketch适用于串行监视器,但不适用于pyserial [英] Arduino Sketch works with Serial Monitor but not with 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, thereforeSerial.available() > 0
, you don't enter the loop and you don't readval
- B. nothing is available on
Serial
input, thereforeSerial.available() == 0
, and you enter the loop. Now there are two sub-cases:- B.1. if nothing arrives on
Serial
input, you keep reading0
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 iterationSerial.available() <= 0
is false and you exit the loop without reading yourval
(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 intoval
. However, nothing remains within theSerial
input, so the conditionSerial.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 intoval
. A few more bytes that do not pertain an Int value (e.g.\r
,\n
,\t
, space, alphabetic symbols, ...) are ignored bySerial.parseInt()
and remain in theSerial
input buffer. Therefore at the next loop iterationSerial.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 haveval == 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 pressenter
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. ifSerial.available > 0
too soon then you still don't enter the loop body and parseval
.@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
thepython
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 parseval
. Sure, you can try playing withdelay()
, 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 thetimeout
"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 from0
until when it gets one. Again, you should send an invalid digit after your number (e.g.\n
) because otherwiseSerial.parseInt()
won't return sincetimeout
is now equal to0
.(请注意,我没有测试此代码,如果我误解了库文档的某些部分,它可能也行不通。)
这篇关于Arduino Sketch适用于串行监视器,但不适用于pyserial的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- B.2.I. the input data arrives right after you execute
- B.1. if nothing arrives on
- B.2.I。输入数据在您执行
- B.1。如果没有到达