Python if条件获取耗时 解决Raspberry Pi车速检测start_time未定义问题
问题根因
Name 'start_time' can be undefined警告的触发逻辑非常明确:start_time仅在GPIO.input(prox1) == False的if分支内被赋值,如果程序运行时先检测到prox2触发、或者prox1从未被触发就走到了计算时间差、判断速度的逻辑,start_time根本不存在,直接调用就会抛出变量未定义的运行时错误。
原代码除了这个警告之外,还存在几个会直接导致运行失败的问题:
- 缺失
RPi.GPIO库的导入语句,运行时会直接报GPIO未定义 - 每次触发拍照后就执行
camera.close()关闭摄像头,下一次循环触发拍照时会直接报错 - 没有测量状态校验,可能出现车辆先触发prox2再触发prox1的顺序错误,算出负的时间差/速度
- 主循环内
No Car Detected分支的time.sleep(1)阻塞时间过长,很容易漏掉传感器的触发信号 - 拍照文件名固定为
test1.jpg,多次触发会覆盖之前的图片,也没有指定自定义存储路径 - 速度比较时单位不匹配,直接拿带单位的speed值和无单位的数字60比较会抛单位运算错误
无if内临时声明变量的实现方案
最稳妥的实现是在循环外层提前初始化所有业务变量,加一个测量状态标记位控制触发逻辑,完全避免变量未定义的问题,核心逻辑如下:
- 提前初始化
start_time、stop_time、timer、speed变量为默认值 - 增加布尔标记
is_measuring,标记当前是否已经被prox1触发、处于等待prox2信号的测量状态 - 仅在
is_measuring == False时响应prox1的触发信号:记录开始时间、点亮LED、把标记切为测量中 - 仅在
is_measuring == True时响应prox2的触发信号:记录结束时间、熄灭LED、计算耗时和车速、判断是否触发拍照、完成后把标记切回未测量状态 - 摄像头只在程序启动时初始化一次,程序退出前再统一关闭,不要在循环内反复开关
- 把长阻塞延时换成0.05s的短轮询延时,既不占满CPU,也不会漏掉传感器信号
- 拍照时用时间戳生成文件名,支持指定存储文件夹,避免文件覆盖
修复后的可运行代码如下:
import time import os import RPi.GPIO as GPIO from pint import UnitRegistry from picamera import PiCamera # 单位初始化 ureg = UnitRegistry() # 摄像头初始化 提前创建存储文件夹 SAVE_FOLDER = "/home/pi/vehicle_captures/" os.makedirs(SAVE_FOLDER, exist_ok=True) camera = PiCamera() camera.resolution = (1280, 720) camera.exposure_mode = 'sports' camera.iso = 0 camera.shutter_speed = 7500 time.sleep(2) # 摄像头预热 # GPIO配置 GPIO.setwarnings(False) prox1 = 12 prox2 = 18 led = 16 GPIO.setmode(GPIO.BOARD) GPIO.setup(prox1, GPIO.IN) GPIO.setup(prox2, GPIO.IN) GPIO.setup(led, GPIO.OUT) # 固定参数 提前初始化所有业务变量 避免未定义问题 distance = 50 * ureg.cm SPEED_THRESHOLD = 60 * ureg.cm / ureg.second is_measuring = False start_time = 0 stop_time = 0 timer = 0 * ureg.second speed = 0 * ureg.cm / ureg.second try: while True: # 响应prox1触发:仅在非测量状态下生效 if not is_measuring and GPIO.input(prox1) == False: start_time = time.time() GPIO.output(led, GPIO.HIGH) print('开始测速,等待车辆通过第二个传感器') is_measuring = True time.sleep(0.3) # 传感器防抖 # 响应prox2触发:仅在测量状态下生效 if is_measuring and GPIO.input(prox2) == False: stop_time = time.time() GPIO.output(led, GPIO.LOW) timer = (stop_time - start_time) * ureg.second print(f'通过耗时:{timer.magnitude:.2f}s') speed = distance / timer print(f'测得速度:{speed.to(ureg.cm/ureg.second).magnitude:.2f}cm/s') # 超速判断+拍照 if speed > SPEED_THRESHOLD and timer < 1 * ureg.second: file_name = f"{SAVE_FOLDER}speed_{int(time.time())}.jpg" camera.capture(file_name) print(f'超速,图片已存储至:{file_name}') time.sleep(0.5) # 重置测量状态 准备下一次检测 is_measuring = False time.sleep(0.3) # 传感器防抖 # 短轮询延时 避免阻塞漏检 time.sleep(0.05) except KeyboardInterrupt: print('程序退出,清理资源') camera.close() GPIO.cleanup()
额外说明
- 代码里的
SAVE_FOLDER可以改成你自己想要的存储路径,程序会自动创建不存在的文件夹 - 两个传感器触发后的0.3s延时是硬件防抖,如果你用的传感器误触发多可以适当调大,正常场景0.2-0.5s都合适
- 如果需要换算成km/h之类的常用单位,直接用pint的
to()方法转换就行,比如speed.to(ureg.km/ureg.hour)
内容的提问来源于stack exchange,提问作者Antonius Juan
相关产品推荐
相关产品推荐

