如何让通过串口发送的Python数据等待Arduino完成当前任务?
我正在尝试让我的Arduino微控制器和Mac电脑进行通信,并且已经建立了一个可以正常工作的串口连接。我的电脑正在向Arduino发送数据,而Arduino在准备好接收新数据时会发送一个'1'
。
我创建了一个if-else
语句(下面是Python脚本),这个语句要么向Arduino发送一行新数据,要么等待Arduino准备好接收新数据。
问题是,在Python脚本的第一部分,ser.read()
总是返回'1'
,这意味着脚本发送数据的速度比Arduino连接的步进电机反应的速度要快。
在Arduino的脚本中,你可以看到我在serialEvent()
函数的第一行发送了状态信息,这在我看来应该让Arduino完成它的工作,然后再接收新的“任务”。但是,不知道为什么,这并没有成功。有没有人能帮我解决这个问题?
Python脚本
import os
import time
import serial
# Name of csv file with drawing coordinates
csvFile = "scaled_coordinates.csv"
# Create serial connection
ser = serial.Serial(port='/dev/tty.usbserial-A9005bDh', baudrate=9600)
wd = os.getcwd()
myFile = open(wd + "/coordinates/" + csvFile)
state = '1'
while True: # Exits when there is no more lines to read
if state == '0': # Wait for Arduino to be ready
state = ser.read()
elif state == '1': # Send one more line to Arduino
line = myFile.readline()
if not line:
break
print line
ser.write(line)
#time.sleep(1)
state = '0' # Wait for Arduino before reading next line
myFile.close
Arduino loop
函数
void loop() {
serialEvent(); // Call the serial function
if (coord_complete) {
// Steps to move from currrent to new point
target1 = steps(x_current, y_current, x_new, y_new, 1);
target2 = steps(x_current, y_current, x_new, y_new, 2);
// Start moving
stepper1.move(target1);
stepper2.move(target2);
// Update current position
x_current = x_new;
y_current = y_new;
// Reset variables
x_complete = false;
y_complete = false;
coord_complete = false;
}
// Stay in while loop until steppermotors is done
while ((stepper1.distanceToGo() != 0) && (stepper2.distanceToGo() != 0)) {
stepper1.run();
stepper2.run();
}
}
Arduino serialEvent
函数
void serialEvent() {
Serial.write('1'); // Tell Python that Arduino is ready for one more line
while (Serial.available() && coord_complete == false) {
char ch = Serial.read(); // Get new character
Serial.print(ch);
// If digit; add it to coord_string
if (isDigit(ch)) {
coord_string[index++] = ch;
// Else if ch is ","; then rename to x_new
} else if (ch == ',') {
coord_string[index++] = NULL; // Finish coord_string
x_new = atoi(coord_string); // Convert to integer
x_complete = true; // Change x_complete to true
index = 0; // Reset index
memset(coord_string, 0, sizeof(coord_string)); // Reset coord_string
// Else if ch is a new line; then rename as y_new
} else if (ch == ';') {
//Serial.write('0');
coord_string[index++] = NULL;
y_new = atoi(coord_string);
y_complete = true;
index = 0;
memset(coord_string, 0, sizeof(coord_string));
}
// Ends while-loop when true
coord_complete = x_complete * y_complete;
}
}
编辑
当前的Python代码如下:
import os
import time
import serial
# Name of csv file with drawing coordinates
csvGraphic = "Scaled_coordinates.csv"
# Create serial connection
ser = serial.Serial(port='/dev/tty.usbserial-A9005bDh', baudrate=9600)
wd = os.getcwd()
myFile = open(wd + "/graphics/" + csvGraphic)
state = '1'
while True: # Exits when there is no more lines to read
print "state", state
if state == '0': # Wait for Arduino to be ready
state = str(ser.read())
elif state == '1': # Send one more line to Arduino
line = myFile.readline()
if not line:
ser.close()
break
print line
ser.write(line)
state = '0' # Wait for Arduino before reading next line
ser.close()
myFile.close
下面是Python的输出。代码一次性执行,没有等待Arduino。看起来state = str(ser.read())
这一行读取的是某种串口缓冲区中的数据。我猜解决办法是清空这个缓冲区,但我不知道该怎么做。
state 1
239,275;
state 0
state 1
1100,275;
state 0
state 1
300,400;
state 0
state 1
200,400;
state 0
state 1
200,300;
state 0
state 1
[Finished in 0.1s]
相关文章:
- 暂无相关问题
2 个回答
我想我找到了问题所在。你的 SerialEvent()
在每次 loop
开始时都会被调用。它的第一件事就是 write('1')
,这意味着每次执行 loop
时,它都会告诉你的 Python 代码准备好接收新的指令(即使没有给出任何指令!),这就导致缓冲区里充满了很多 '1',而你是一个一个地读取这些 '1'。
试试这个:
void SerialEvent(){
if((stepper1.distanceToGo() == 0) && (stepper2.distanceToGo() == 0)){
Serial.write('1');
}
//Rest of the function
另外,我觉得在你的循环结束时,你想要的是
while((stepper1.distanceToGo() != 0) || (stepper2.distanceToGo() != 0))
而不是 while((stepper1.distanceToGo() != 0) && (stepper2.distanceToGo() != 0))
感谢Mr. E,我找到了一个解决办法。简单来说,在我读取或写入新数据之前,需要先清空串口缓冲区(在Python中用flushInput()
和flushOutput()
,在Arduino中用flush()
)。另外,在Python和Arduino的代码中还需要加一点小延迟,这样才能让它正常工作。
Python
import os
import time
import serial
# Name of csv file with drawing coordinates
fileName = "coordinates.csv"
# Create serial connection
ser = serial.Serial(port='/dev/tty.usbserial-A9005bDh', baudrate=9600)
wd = os.getcwd()
myFile = open(wd + "/graphics/" + fileName)
#num_lines = sum(1 for line in myFile)
state = '0'
idx = 0
while True: # Exits when there is no more lines to read
#print "state", state
while state == '0': # Wait for Arduino to be ready
ser.flushInput() # Clear input buffer
state = str(ser.read())
if state == '1': # Send one more line to Arduino
line = myFile.readline()
if not line:
break
print "Coordinate", idx
print line
ser.flushOutput() # Clear output buffer
ser.write(line)
time.sleep(0.1)
idx = idx + 1
state = '0' # Set waiting flag – make Arduino wait for next line
ser.close()
myFile.close
Arduino serialEvent
函数
void serialEvent() {
if ((stepper1.distanceToGo() == 0) && (stepper2.distanceToGo() == 0)) {
Serial.write('1'); // Tell Python that Arduino is ready for one more line
delay(10);
Serial.flush(); // clear buffer
}
while (Serial.available() && coord_complete == false) {
char ch = Serial.read(); // Get new character
Serial.flush();
// If digit; add it to coord_string
if (isDigit(ch)) {
coord_string[index++] = ch;
// Else if ch is ","; then rename to x_new
} else if (ch == ',') {
coord_string[index++] = NULL; // Finish coord_string
x_new = atoi(coord_string); // Convert to integer
x_complete = true; // Change x_complete to true
index = 0; // Reset index
memset(coord_string, 0, sizeof(coord_string)); // Reset coord_string
// Else if ch is a new line; then rename as y_new
} else if (ch == ';') {
//Serial.write('0');
coord_string[index++] = NULL;
y_new = atoi(coord_string);
y_complete = true;
index = 0;
memset(coord_string, 0, sizeof(coord_string));
}
// Ends while-loop when true
coord_complete = x_complete * y_complete;
}
}