You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Arduino处理串口输入存在1-2秒延迟,如何提升响应速度?

问题解决思路与优化方案

一、代码层面的核心优化(优先解决,成本最低)

Python端优化

  1. 添加串口结束符,避免Arduino阻塞
    你的Python代码发送坐标时未添加结束符,但Arduino用readStringUntil('\r')等待回车符,这会导致Arduino持续阻塞等待超时,是延迟和无响应的核心原因之一。修改发送逻辑:
    coord = f'{x} {y}\r'  # 追加\r作为结束符,匹配Arduino的读取逻辑
    arduinoData.write(coord.encode())
    arduinoData.flush()  # 确保数据立即发送,避免缓冲区堆积
    
  2. 仅发送坐标变化超过阈值的数据
    无需固定每30帧发送一次,记录上一次发送的x值,当当前x与上次的差值超过设定阈值(比如5)时再发送,大幅减少不必要的串口负载:
    last_x = -1
    threshold = 5
    while True:
        # 人脸检测逻辑...
        for (x, y, w, h) in faces:
            cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
            if abs(x - last_x) > threshold:
                coord = f'{x} {y}\r'
                arduinoData.write(coord.encode())
                arduinoData.flush()
                last_x = x
    
  3. 改用二进制传输(可选,进一步提升效率)
    字符串传输字节占用多,改用二进制打包整数能压缩数据量,传输和处理速度更快:
    import struct
    # 发送时用小端模式打包两个16位整数
    data = struct.pack('<hh', x, y)
    arduinoData.write(data)
    

Arduino端优化

  1. 替换String类为C风格字符数组,提升运行效率
    String类在Arduino上易产生内存碎片,且处理速度慢,改用字符数组处理串口数据:
    #include <Servo.h>
    Servo myservo;
    int gLED = 2;
    int rLED = 3;
    char buffer[10];  // 存储串口接收的字符
    int bufferIndex = 0;
    int last_servo_us = 1450;  // 记录上次舵机位置,避免重复指令
    
    void setup() {
      Serial.begin(115200);
      pinMode(rLED, OUTPUT);
      pinMode(gLED, OUTPUT);
      myservo.attach(8);
      myservo.writeMicroseconds(last_servo_us);
    }
    
    void loop() {
      while (Serial.available() > 0) {
        char c = Serial.read();
        if (c == '\r') {  // 收到结束符,开始处理数据
          buffer[bufferIndex] = '\0';  // 添加字符串结束标记
          // 分割x坐标字符串
          char* x_str = strtok(buffer, " ");
          if (x_str != NULL) {
            int pos1 = atoi(x_str);
            int target_us = last_servo_us;
            // 判断目标舵机位置
            if (pos1 > 300) {
              digitalWrite(gLED, HIGH);
              digitalWrite(rLED, LOW);
              target_us = 1400;
            } else if (pos1 < 240) {
              digitalWrite(rLED, HIGH);
              digitalWrite(gLED, LOW);
              target_us = 1510;
            } else {
              digitalWrite(gLED, LOW);
              digitalWrite(rLED, LOW);
              target_us = 1450;
            }
            // 仅当位置变化时发送舵机指令
            if (target_us != last_servo_us) {
              myservo.writeMicroseconds(target_us);
              last_servo_us = target_us;
            }
          }
          bufferIndex = 0;  // 重置缓冲区索引
        } else if (bufferIndex < sizeof(buffer)-1) {
          buffer[bufferIndex++] = c;  // 存储字符到缓冲区
        }
      }
    }
    
  2. 避免冗余的舵机指令
    记录上次的舵机微秒值,仅当目标位置变化时才调用writeMicroseconds,减少舵机的无效操作,节省处理时间。
  3. 设置串口超时(可选)
    若担心未收到结束符导致阻塞,可添加Serial.setTimeout(10)设置10毫秒超时,避免Arduino长时间卡住。

二、通信协议选择

  • 串口通信(优先保留):优化后的串口通信完全能满足需求,115200波特率下,即使每秒发送30次坐标(每次仅几个字节),负载也极低,无需更换协议。
  • I2C协议:适合短距离(≤1米)板间通信,速度略快于串口,但需要额外接线,普通PC还需USB转I2C适配器,不如串口便捷。若Python运行在树莓派这类带I2C接口的设备上可尝试,但优化串口后基本无需更换。
  • SPI协议:速度更快,但硬件接线复杂,不适合新手快速解决问题。

内容的提问来源于stack exchange,提问作者Liam McMillen-Meyers

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 05:51:18