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

树莓派Python Pygame项目添加ESC键全局退出功能故障求解

问题根因
  • 内层循环未绑定全局运行状态:按下ESC修改running = False后,内层while GPIO.input(switches[0]) == GPIO.LOW循环没有校验running状态,程序始终卡在内层循环中,无法响应退出逻辑
  • 帧率控制失效:clock.tick(120)仅在主循环外执行了一次,没有在每次循环迭代中调用,既没有实现120fps的控速效果,也会拖慢pygame事件队列的处理效率
  • 阻塞调用拖慢输入响应:time.sleep(0.01)是阻塞式调用,休眠期间pygame无法处理新的输入事件,高频率运行下会出现按键事件丢失、响应延迟的问题
修复方案

核心修改点

  1. 所有循环判断条件增加running状态校验,确保全局退出标记触发后可以跳出所有层级的循环
  2. 将clock.tick(120)移到循环内部,替换time.sleep()作为帧率控制方式,避免阻塞事件处理
  3. 高帧率场景下,对于ESC这类全局响应按键,可直接使用pygame.key.get_pressed()扫描键盘状态,响应速度比遍历事件队列更快

修改后的完整代码

# Importing all libraries
import RPi.GPIO as GPIO
import sys, time, atexit, pygame

# Setup GPIO and Pygame
GPIO.setmode(GPIO.BCM)
pygame.init()

# Define Tuples and Variables
leds = (16,17,22,9,5)
switches = (19,4,27,10,11)
button_pressed = False
taskcomplete = False

# Pygame visual variables
screen = pygame.display.set_mode( (1024,240) )
counterfont = pygame.font.Font('DSEG14Modern-Regular.ttf', 70)

# Set Pygame refresh rate variable = clock 
clock = pygame.time.Clock()
FPS = 120

# Clock variables
sec_val = 0
sec = 0
mins = 0
hours = 0

# Status variables
paused  = False
running = True

# Start the clock
start_time = pygame.time.get_ticks() 

# Defining Functions

# Function that renders segment display on screen 
def time_convert(sec):
    sec = sec % 60
    sec_val = ("Timer: {0}".format(round((sec), 2)))
    counting_text = counterfont.render(str(sec_val), 3, (134,145,255))
    counting_rect = counting_text.get_rect(left = screen.get_rect().left)
    screen.fill( (0,0,0) )
    screen.blit(counting_text, (300,40))
    pygame.display.update()
    
# Stopwatch function to compute for a SS:MS based stopwatch
def stop_Watch():
    end_time = time.time()
    time_lapsed = end_time - start_time
    sec_val = time_convert(time_lapsed)

# Press Button 1 to start the game
def but_3():
    # 所有子函数中的循环都要增加running判断
    while running and GPIO.input(switches[2]) == GPIO.LOW:
        GPIO.output(leds[2],True)
        # 统一用clock.tick控速
        clock.tick(FPS)
        stop_Watch()
    GPIO.output(leds[2],False)
    print(" Button 3 is pressed! Exit")

start_time = time.time()

def buttonPress(channel):
    # This function gets called every time a button is pressed, if the button pressed is the same as the button
    # that is illuminated, then we set the "correct_button" variable to True,
    # otherwise we set the "incorrect_button" variable to True.
    # We need to set some variables to global so that this function can change their value.
    button_pressed = True

def exit():
    # This function gets called when we exit our script, using Ctrl+C
    print("GPIO Clean Up!")
    GPIO.cleanup()
    pygame.quit()
    sys.exit()


# This tells our script to use the "exit()" without this, our "exit()" function would never be called.
atexit.register(exit)

#Loop through the leds to set them up
for led in leds:
    # Set the led to be an ouput
    GPIO.setup(led, GPIO.OUT)
    # Turn the led off
    GPIO.output(led,False)

# Loop through the switches to set them up
for switch in switches:
    # Set the switch to be an input
    GPIO.setup(switch, GPIO.IN)
    # Add rising edge detection
    GPIO.add_event_detect(switch, GPIO.RISING, bouncetime=300)
    # Add the function "buttonPress" to be called when switch is pressed.
    GPIO.add_event_callback(switch, buttonPress)


# Main sequence code
# Start timer
start_time = time.time()

# Main loop
while running:
    # 全局ESC扫描,优先级最高
    keys = pygame.key.get_pressed()
    if keys[pygame.K_ESCAPE]:
        print("escape pressed")
        running = False
        break
    # 处理窗口退出事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
            break
    # Press Button 1 to start the game
    # 内层循环增加running判断
    while running and GPIO.input(switches[0]) == GPIO.LOW:
        # 内层循环也要同步检测全局事件和按键
        keys = pygame.key.get_pressed()
        if keys[pygame.K_ESCAPE]:
            print("escape pressed")
            running = False
            break
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
                break

        GPIO.output(leds[0],True)
        # 用clock.tick替代sleep,控制帧率120
        clock.tick(FPS)
        stop_Watch()
    GPIO.output(leds[0],False)
    print(" Button 1 is pressed! Exit")
    running = False
exit()
高帧率场景全局按键通用实现规范
  • 全局按键检测优先级最高,放在所有业务逻辑之前执行
  • 高频响应按键优先用pygame.key.get_pressed()状态扫描,事件队列检测适合处理单次触发的低频输入(比如空格跳跃、回车确认)
  • 所有循环逻辑必须绑定全局运行状态,避免出现业务逻辑嵌套循环导致退出标记失效的问题
  • 移除所有阻塞式休眠调用,统一用游戏引擎自带的帧率控制接口控速

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 17:15:03