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

直线加速赛练习树计时系统右侧车道反应时间测量异常求助

直线加速赛练习树计时系统右侧车道反应时间测量异常求助

我正在开发一个直线加速赛的练习计时系统,大部分功能都正常,但右侧车道的反应时间总是测不准:

  • 如果先松开左侧按钮,右侧能显示正确的反应时间
  • 如果先松开右侧按钮,两侧的时间会显示成一样的,而且必须等左侧按钮松开后才会有结果

我的代码如下:

from gpiozero import LED, Button
from time import *
import lcddriver

def measure_reaction_time():      
    # Left lane reaction time        
    left_reaction_time = left_time - start_time
        # Turns on the red light if under 0.001
    if left_reaction_time < 0.001:  
        red.off()
        green.on()
        print(f"Left False start! You jumped the gun! {left_reaction_time:.3f}")
        lcd.lcd_display_string("LEFT RED LIGHT!!!", 1)
    # Turns on the green light if over 0.001 
    if left_reaction_time > 0.001:
        green.off()
        print(f"Left reaction time: {left_reaction_time:.3f}")
        lcd.lcd_display_string("Left lane reaction", 1)
        lcd.lcd_display_string(f"{left_reaction_time:.3f}", 2)  
    # Right lane reaction time    
    right_reaction_time = right_time - start_time 
    # Turns on the red light if under 0.001
    if right_reaction_time <  0.001:
        red.off()
        green.on()
        print(f"Right false start! You jumped the gun! {right_reaction_time:.3f}")
        lcd.lcd_display_string("RIGHT RED LIGHT!!!", 3)
    # Turns on the green light if over 0.001
    if right_reaction_time > 0.001:
        green.off()
        print(f"Right reaction time: {right_reaction_time:.3f}")
        lcd.lcd_display_string("Right lane reaction", 3)
        lcd.lcd_display_string(f"{right_reaction_time:.3f}", 4)
try:
    while True:        
        lcd = lcddriver.lcd()
        # Displays this message to the LCD
        lcd.lcd_display_string(" GET READY!!!", 2)
        # Wait for both buttons to be pressed
        left.wait_for_press()
        right.wait_for_press()
        # Sets the lights to off when both buttons are pressed
        reset_lights()
        # Clear the lcd screen
        lcd.lcd_clear()
        # Drop the tree
        light_sequence()
        sleep(.100)
        # Start timer after the tree comes down
        start_time = time()        
        # Waits for left button to be released to get the RT
        left.wait_for_release()    
        left_time = time()     
        # Waits for right button to be released to get the RT
        right.wait_for_release()
        right_time = time()
        # Measures reaction times
        measure_reaction_time() 
        # Wait before the next race
        sleep(5)
        reset_lights()
except KeyboardInterrupt:
    print("\nExiting...")
    lcd.lcd_clear()
finally:
    reset_lights()

问题分析

兄弟,你的核心问题出在按钮释放的阻塞等待逻辑上!你现在是先调用left.wait_for_release(),程序会卡在这一行直到左侧按钮松开,之后才会去执行right.wait_for_release()。这就导致:

  • 如果右侧先松开,程序根本不会立刻记录右侧的释放时间,而是一直等左侧松开,此时记录的right_time其实是左侧松开的时间,自然和left_time完全一致
  • 只有左侧先松开时,程序才会正常走到右侧的等待逻辑,这时候右侧的时间才是准确的

解决方案:用异步回调替代阻塞等待

我们可以利用gpiozero提供的when_released回调函数,异步监听两个按钮的释放事件,这样两个按钮的操作不会互相阻塞。修改后的代码如下:

from gpiozero import LED, Button
from time import time, sleep
import lcddriver

# 全局变量存储释放时间,每次比赛前重置
left_release_time = None
right_release_time = None

# 左侧按钮释放时的回调
def on_left_release():
    global left_release_time
    left_release_time = time()

# 右侧按钮释放时的回调
def on_right_release():
    global right_release_time
    right_release_time = time()

def measure_reaction_time(start_time):      
    # 计算左侧反应时间
    left_reaction_time = left_release_time - start_time
    if left_reaction_time < 0.001:  
        red.off()
        green.on()
        print(f"Left False start! You jumped the gun! {left_reaction_time:.3f}")
        lcd.lcd_display_string("LEFT RED LIGHT!!!", 1)
    elif left_reaction_time > 0.001:
        green.off()
        print(f"Left reaction time: {left_reaction_time:.3f}")
        lcd.lcd_display_string("Left lane reaction", 1)
        lcd.lcd_display_string(f"{left_reaction_time:.3f}", 2)  
    
    # 计算右侧反应时间
    right_reaction_time = right_release_time - start_time 
    if right_reaction_time < 0.001:
        red.off()
        green.on()
        print(f"Right false start! You jumped the gun! {right_reaction_time:.3f}")
        lcd.lcd_display_string("RIGHT RED LIGHT!!!", 3)
    elif right_reaction_time > 0.001:
        green.off()
        print(f"Right reaction time: {right_reaction_time:.3f}")
        lcd.lcd_display_string("Right lane reaction", 3)
        lcd.lcd_display_string(f"{right_reaction_time:.3f}", 4)

try:
    # 初始化硬件(请替换成你实际使用的GPIO引脚)
    left = Button(2)
    right = Button(3)
    red = LED(4)
    green = LED(5)
    
    # 绑定按钮释放回调
    left.when_released = on_left_release
    right.when_released = on_right_release
    
    lcd = lcddriver.lcd()
    
    while True:        
        # 重置释放时间变量,确保每次比赛都是新的计时
        left_release_time = None
        right_release_time = None
        
        lcd.lcd_clear()
        lcd.lcd_display_string(" GET READY!!!", 2)
        
        # 等待两个按钮都被按下
        left.wait_for_press()
        right.wait_for_press()
        
        # 重置灯光
        reset_lights()
        lcd.lcd_clear()
        # 执行灯光序列
        light_sequence()
        sleep(0.100)
        # 记录开始时间
        start_time = time()        
        
        # 等待两个按钮都被释放(避免占用过多CPU,用短睡眠循环等待)
        while left_release_time is None or right_release_time is None:
            sleep(0.01)
        
        # 计算并显示反应时间
        measure_reaction_time(start_time) 
        # 等待5秒后开始下一轮
        sleep(5)
        reset_lights()
except KeyboardInterrupt:
    print("\nExiting...")
    lcd.lcd_clear()
finally:
    reset_lights()

修改要点说明

  1. 异步回调监听释放事件:通过when_released绑定回调函数,两个按钮的释放会各自触发时间记录,不再互相阻塞
  2. 重置时间变量:每次循环开始时把left_release_time和right_release_time设为None,避免上一轮的时间影响下一轮
  3. 等待双按钮释放:用一个循环等待两个时间都被记录完成,再进行反应时间计算
  4. 优化条件判断:把原来的两个独立if改成elif,避免时间刚好等于0.001时同时触发两个逻辑(虽然概率极低,但更严谨)

备注:内容来源于stack exchange,提问作者mudeki

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 08:28:10