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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 23:24:23