直线加速赛练习树计时系统右侧车道反应时间测量异常求助
直线加速赛练习树计时系统右侧车道反应时间测量异常求助
我正在开发一个直线加速赛的练习计时系统,大部分功能都正常,但右侧车道的反应时间总是测不准:
- 如果先松开左侧按钮,右侧能显示正确的反应时间
- 如果先松开右侧按钮,两侧的时间会显示成一样的,而且必须等左侧按钮松开后才会有结果
我的代码如下:
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()
修改要点说明
- 异步回调监听释放事件:通过
when_released绑定回调函数,两个按钮的释放会各自触发时间记录,不再互相阻塞 - 重置时间变量:每次循环开始时把
left_release_time和right_release_time设为None,避免上一轮的时间影响下一轮 - 等待双按钮释放:用一个循环等待两个时间都被记录完成,再进行反应时间计算
- 优化条件判断:把原来的两个独立
if改成elif,避免时间刚好等于0.001时同时触发两个逻辑(虽然概率极低,但更严谨)
备注:内容来源于stack exchange,提问作者mudeki
相关产品推荐
相关产品推荐

