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

1 投票
2 回答
2832 浏览
提问于 2025-05-10 15:33

我正在尝试让我的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 个回答

1

我想我找到了问题所在。你的 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))

1

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

撰写回答