Arduino摇杆驱动Pygame圆形对象移动问题排查
问题概述
需求:通过Arduino输出的摇杆坐标控制Pygame中的圆形对象,测试X轴值达到1023时使圆形右移。
遇到两个问题:
- 运行main.py后仅打印几次Arduino摇杆坐标就停止,需按键才恢复;
- 摇杆X轴值为1023时,圆形未右移。
具体疑问:
- 为何X轴值为1023时圆形不移动(按键时会打印ballpos[0]且短暂继续循环,此时X轴数据为1023)?
- 如何在Pygame事件循环中持续读取Arduino摇杆数据?
附Arduino代码(JSPy.ino)
//input pins //analog int JSx = A0; int JSy = A1; //digital int JSpin = 9; //read JS position values int JSxVal; int JSyVal; int JSVal; // delay(ms) int dt = 500; void setup() { // put your setup code here, to run once: pinMode(JSx,INPUT); pinMode(JSy,INPUT); digitalWrite(JSpin,HIGH); Serial.begin(9600); } void loop() { // put your main code here, to run repeatedly: JSxVal = analogRead(JSx); JSyVal = analogRead(JSy); JSVal = digitalRead(JSpin); delay(dt); //JSx coor Serial.print(JSxVal); Serial.print(" "); //JSy coor Serial.println(JSyVal); }
附Python代码(main.py)
import serial import time import pygame as pg # default port is 9600 baud rate so didnt have to set arduinoData = serial.Serial("com3") time.sleep(1) # pygame settings #screen bgSize =screenW,screenH = 500,600 screen = pg.display.set_mode((bgSize)) ballx,bally = 250,300 ballPos=(ballx,bally) GRAY = (112,112,112) BLUE = (0,0,255) run =True while run: for event in pg.event.get(): while(arduinoData.inWaiting()==0): pass dataPacket = arduinoData.readline() # convert from binary to string dataPacket = dataPacket.decode(encoding='utf-8') # make list of string numbers of coordinates dataPacket = dataPacket.split() # turn coordinates into int in the list dataPacket = [eval(i) for i in dataPacket] if event.type == pg.QUIT: run=False if event.type == pg.KEYDOWN: if event.key == pg.K_ESCAPE: run= False if dataPacket[0] == 1023: ballx+=1 print(f"x pos = {ballPos[0]}") screen.fill(BLUE) print(f" JS - x - {dataPacket[0]}") pg.draw.circle(screen, GRAY,ballPos,15,4) pg.display.update()
问题解答
疑问1:X轴值1023时圆形不移动的原因
- 你把摇杆数据的判断逻辑放在了
pg.KEYDOWN事件分支内,只有触发按键事件时才会检查X轴数值,即便摇杆X轴到1023,无按键操作这段代码就不会执行。 ballPos是元组(不可变类型),你修改了ballx但没有更新ballPos,绘制时始终用初始坐标,所以圆形位置不会变化。
疑问2:如何持续读取Arduino摇杆数据
当前代码把串口读取逻辑放在Pygame事件循环内部,只有有事件触发时才会读取一次数据;且while(arduinoData.inWaiting()==0): pass是阻塞式等待,会让程序卡在等待串口数据的状态,只有事件(比如按键)触发才能继续。正确做法是把串口读取放在主循环顶层,与事件循环并行,同时改用非阻塞式判断。
修正后的代码
Arduino代码(无需修改)
保留原代码即可。
修正后的Python代码(main.py)
import serial import time import pygame as pg # 明确指定串口波特率,避免参数不匹配 arduinoData = serial.Serial("com3", 9600) time.sleep(1) # pygame初始化 pg.init() # screen设置 bgSize = screenW, screenH = 500, 600 screen = pg.display.set_mode(bgSize) # 用列表存储圆形位置,方便修改 ballPos = [250, 300] GRAY = (112,112,112) BLUE = (0,0,255) run = True while run: # 处理Pygame事件 for event in pg.event.get(): if event.type == pg.QUIT: run = False if event.type == pg.KEYDOWN: if event.key == pg.K_ESCAPE: run = False # 非阻塞式读取串口数据 if arduinoData.inWaiting() > 0: try: # 读取并处理串口数据 dataPacket = arduinoData.readline().decode('utf-8').strip() dataPacket = dataPacket.split() if len(dataPacket) == 2: js_x = int(dataPacket[0]) print(f"JS - x - {js_x}") # 检测X轴值并移动圆形 if js_x == 1023: ballPos[0] += 1 print(f"x pos = {ballPos[0]}") except: # 处理数据解析错误,避免程序崩溃 pass # 绘制画面 screen.fill(BLUE) pg.draw.circle(screen, GRAY, ballPos, 15, 4) pg.display.update() # 程序结束后清理资源 arduinoData.close() pg.quit()
关键修改点
- 将串口读取逻辑移到主循环顶层,脱离事件循环,实现持续读取
- 用
if arduinoData.inWaiting() > 0替代阻塞式while循环,避免程序卡顿 - 把
ballPos从元组改为列表,修改后直接生效 - 将摇杆X轴的判断逻辑移到串口数据读取分支,不再依赖按键事件
- 添加异常处理,避免串口数据解析错误导致程序崩溃
- 明确指定串口波特率,消除潜在参数不匹配问题
内容的提问来源于stack exchange,提问作者mooseturd
相关产品推荐
相关产品推荐

