使用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); } } }
问题原因
- 数据格式不匹配:Python仅发送单个字符"0"或"1",但Arduino代码用
readStringUntil('\n')等待换行符作为字符串结束标志,导致Arduino无法完成字符串读取,判断逻辑永远不触发。 - 串口初始化时机:Arduino在串口连接后会自动重启,Python直接发送数据可能在Arduino初始化完成前就开始发送,造成初始数据丢失。
- 冗余发送: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
相关产品推荐
相关产品推荐

