如何让Python(通过串口)发送的数据等待Arduino完成当前任务?

How to make data sent by Python (via serial connection) wait for Arduino to finish current task?

我尝试让我的 Arduino 微控制器和我的 Mac 一起通话,并创建了一个功能性串行连接。我的电脑正在向我的 Arduino 发送数据,当我的 Arduino 准备好接收新数据时,我的 Arduino 正在发送 '1'

我创建了一个 if-else 语句(下面的 Python 脚本),它要么向 Arduino 发送一行新数据,要么等待 Arduino 准备好接收新行数据。

问题是 Python 脚本第一部分中的 ser.read() 总是 returns '1',这意味着脚本正在更快地发送各个数据行比 Arduino 连接的步进电机可能做出反应。

在 Arduino 脚本中,您可以看到我在 serialEvent() 函数的第一行发送了状态状态,在我的世界中,这应该让 Arduino 在新的 "task" 来了。但是,由于某种原因它不起作用。有人可以帮我吗?

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]

我想我找到了。您的 SerialEvent()loop 的开头被调用。它做的第一件事是 write('1') 意味着每次执行 loop 时它会告诉您的 python 代码它已准备好接受新指令(即使没有给出指令!)并用 lot 填充缓冲区你一个一个读的'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))

感谢 E 先生,我找到了解决方案。基本上我需要在读取或写入之前清除串行缓冲区(flushInput()flushOutput() in Python 和 flush() in Arduino)Python 和 Arduino 之间的新数据.此外,Python 和 Arduino 代码中的一个小延迟是必要的,以使其工作。

Pyhton

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;
  }
}