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

使用pySerial实现Python向Arduino持续发数据的问题排查

Python通过pySerial向Arduino持续发送数据控制LED失败问题排查

问题描述

作为pySerial新手,尝试在Python的while循环中持续发送"0"或"1"字符串,通过手势识别控制Arduino板载LED开关,但实际LED未正确响应。原代码如下:

原Python代码

import serial
import time
import cv2
import mediapipe as mp
from cvzone.HandTrackingModule import HandDetector
ser = serial.Serial('COM5', 9600)

# initiate webcam
cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)

x3 = 0
y3 = 0
xgrab = 0
ygrab = 0
grab = 0 
# hand detector
detector = HandDetector(detectionCon=0.8, maxHands=1)

while True:
  success, image = cap.read()
  hands = detector.findHands(image, draw=False)
  if hands:
    lmList = hands[0]['lmList']
    xgrab, ygrab = lmList[4][:2]
    x3, y3 = lmList[3][:2]
    if xgrab < x3:
        grab = 1
    else:
        grab = 0
  else:
      grab = 0
  grab = str(grab)
  ser.write(grab.encode())
  cv2.imshow('Control window', cv2.flip(image,1))
  if cv2.waitKey(5) & 0xFF == 27:
      break
cap.release()

原Arduino代码

String Recstring;
void setup() {

Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
if (Serial.available()){
  Recstring = Serial.readStringUntil('\n');
  if (Recstring == "1"){
    digitalWrite(LED_BUILTIN, HIGH);
  }
  else{
    digitalWrite(LED_BUILTIN, LOW);
  }
  }
}

问题原因

  1. 数据格式不匹配:Python仅发送单个字符"0"或"1",但Arduino代码用readStringUntil('\n')等待换行符作为字符串结束标志,导致Arduino无法完成字符串读取,判断逻辑永远不触发。
  2. 串口初始化时机:Arduino在串口连接后会自动重启,Python直接发送数据可能在Arduino初始化完成前就开始发送,造成初始数据丢失。
  3. 冗余发送:while循环高频重复发送相同值,可能导致串口缓冲区堆积,但核心问题仍是换行符缺失。

解决方案

修改后的Python代码

import serial
import time
import cv2
from cvzone.HandTrackingModule import HandDetector

# 初始化串口,添加延迟等待Arduino重启完成
ser = serial.Serial('COM5', 9600)
time.sleep(2)

# 初始化摄像头
cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)

x3 = 0
y3 = 0
xgrab = 0
ygrab = 0
last_grab = -1  # 记录上一次发送的值,避免重复发送
detector = HandDetector(detectionCon=0.8, maxHands=1)

while True:
    success, image = cap.read()
    hands = detector.findHands(image, draw=False)
    grab = 0
    if hands:
        lmList = hands[0]['lmList']
        xgrab, ygrab = lmList[4][:2]
        x3, y3 = lmList[3][:2]
        grab = 1 if xgrab < x3 else 0
    
    # 仅当值变化时发送,减少串口负载
    if grab != last_grab:
        # 发送带换行符的字符串,匹配Arduino的读取逻辑
        ser.write(f"{grab}\n".encode())
        last_grab = grab

    cv2.imshow('Control window', cv2.flip(image,1))
    if cv2.waitKey(5) & 0xFF == 27:
        break

cap.release()
cv2.destroyAllWindows()  # 关闭显示窗口
ser.close()  # 关闭串口连接

修改后的Arduino代码(两种可选方案)

方案1:保留原字符串读取逻辑

无需修改原Arduino代码,确保Python发送带换行符的数据即可。

方案2:简化为单字符读取(更高效)

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  if (Serial.available() > 0) {
    char received = Serial.read();
    if (received == '1') {
      digitalWrite(LED_BUILTIN, HIGH);
    } else {
      digitalWrite(LED_BUILTIN, LOW);
    }
    // 清空缓冲区,避免残留数据干扰后续读取
    while(Serial.available() > 0) Serial.read();
  }
}

关键修改说明

  • Python端:添加time.sleep(2)等待Arduino重启;发送数据时追加换行符\n;增加last_grab变量,仅在值变化时发送,降低串口冗余数据。
  • Arduino端:若用原字符串读取逻辑,只需匹配Python的换行符格式;若改用单字符读取,逻辑更简洁,无需依赖换行符,同时增加缓冲区清空步骤避免数据残留。

内容的提问来源于stack exchange,提问作者SandNguyen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 22:47:37