倒数计时器不起作用

埃姆斯

目标是:如果有运动,则记录开始,并且计数器(x)每1秒开始递减,但是同时如果有其他运动,则计数器重新开始x(例如:5秒)。

实际上这是行不通的,更具体地说,如果在录制过程中有运动,计数器不会重置,因此每个视频的时长为5秒。

from picamera import PiCamera
from time import sleep                                          
camera = PiCamera()
sensor = MotionSensor(7)
camera.hflip = True                                     

name = "video.h264"
x = 5 #seconds of record

def countdown(count):
    while (count >= 0):
        print (count)
        count -= 1
        sleep(1)
        if sensor.when_motion == True:
           count = x

def registra_video():
    print ("recording started")
    #camera.start_preview()
    camera.start_recording(name)
    countdown(x)

def stop_video():
    camera.stop_recording()
    #camera.stop_preview()
    print ("recording stopped")

print("Waiting...")
sensor.when_motion = registra_video
sensor.when_no_motion = stop_video
pause()

附言:我知道我必须执行一个功能,以不同的方式命名每个视频,但是我随后会做。

疯狂物理学家

介绍

首先,我非常确定使用多线程方法可以最好地解决此问题,原因有两个。首先,事件处理程序通常旨在作为小的代码片段,这些代码片段可以在单个线程中非常快速地运行。其次,您的特定代码以我将在下面描述的方式阻止自己。

当前行为

在提出解决方案之前,让我们看一下您的代码以了解为什么它不起作用。

您有一个运动传感器,当它检测到运动的开始和结束时会输出事件。无论您的代码在做什么,这些事件都会发生。正如您正确指出的那样,MotionSensor对象when_motion每次进入活动状态(即,检测到新动作时)都将调用同样,when_no_motion只要运动停止,它就会调用调用这些方法的方式是将事件添加到队列中,并在专用线程中一对一处理。无法排队的事件(因为队列已满)将被丢弃并且从不处理。默认情况下,队列长度为1,这意味着丢弃在等待处理另一个事件时发生的所有事件。

考虑到所有这些,让我们看看收到新的运动事件时会发生什么。首先,事件将排队。然后,它将导致registra_video几乎立即被调用。registra_video不管发生了什么其他事件,它都会阻塞五秒钟。完成后,另一个事件将从队列中弹出并进行处理。如果下一个事件是在五秒钟的等待期间发生的定格动画事件,则相机将通过关闭stop_video唯一的办法stop_video如果传感器连续五秒以上连续检测到运动,则不会被调用。如果队列长度大于一个,则在阻塞时间内可能会发生另一个事件,并且仍然会对其进行处理。假设这是另一个在五秒钟内发生的开始动作事件。它将重新启动摄像机并创建另一个五秒钟的视频,但是增加队列长度不会改变第一个视频的长度恰好为五秒钟的事实。

希望到现在为止,您已经了解了为什么在事件处理程序中等待视频的整个持续时间并不是一个好主意。它可以防止您对以下事件及时作出反应。在您的特定情况下,您无法在计时器仍在运行时重新启动计时器,因为在计时器阻止事件处理线程时,不允许任何其他代码运行。

设计

所以这是一个可能的解决方案:

  1. 当检测到新动作(when_motion被调用)时,请启动相机(如果尚未运行)。
  2. 当检测到定格动作(when_no_motion被调用)时,您有两个选择:
    1. 如果倒计时没有运行,请启动倒计时。我不建议在中开始倒数计时when_motion,因为该动议将一直进行到when_no_motion被调用为止
    2. 如果倒计时已经在运行,请重新启动。

计时器将在后台线程中运行,这不会干扰事件处理线程。“计时器”线程可以只设置开始时间,休眠五秒钟,然后再次检查开始时间。如果从唤醒开始时间到开始时间超过五秒钟,则会关闭相机。如果开始时间被另一个when_motion调用重置,则该线程将重新进入睡眠状态new_start_time + five seconds - current_time如果定时器在另一个定时器到期之前when_motion过期,请关闭相机电源。

一些线程概念

让我们研究一下使已设计的解决方案有效所需的一些构建基块。

首先,您将更改值并从至少两个不同的线程读取它们我所指的值是相机的状态(开或关),它将告诉您计时器何时到期并且需要重新开始运动,以及倒计时的开始时间。

当事件处理线程获得新的调用when_motion并决定重新启动相机时,您不想在设置“ camera is off”标志但没有完成关闭计时器线程中的相机时遇到麻烦当您将其关闭时。为了避免这种情况,请使用locks

锁是一个对象,它将使线程等待获取它。因此,您可以将整个关闭照相机的操作锁定为一个单元,直到完成为止,然后再允许事件处理线程检查该标志的值。

除了基本线程和代码锁之外,我将避免使用其他任何东西。

代码

这是一个示例,说明如何修改代码以使其与我一直在抱怨的广告素材概念有关。我已尽可能地保留了总体结构,但请记住,全局变量通常不是一个好主意。我使用它们是为了避免不得不解释类的麻烦。实际上,我已经花了尽可能多的精力来介绍一般性的想法,如果您不熟悉线程,这将使您花费足够的时间来处理:

from picamera import PiCamera
from time import sleep
from datetime import datetime
from threading import Thread, RLock

camera = PiCamera()
sensor = MotionSensor(7)
camera.hflip = True                                     

video_prefix = "video"
video_ext = ".h264"

record_time = 5

# This is the time from which we measure 5 seconds.
start_time = None

# This tells you if the camera is on. The camera can be on
# even when start_time is None if there is movement in progress.
camera_on = False

# This is the lock that will be used to access start_time and camera_on.
# Again, bad idea to use globals for this, but it should work fine
# regardless.
thread_lock = RLock()

def registra_video():
    global camera_on, start_time
    with thread_lock:
        if not camera_on:
            print ("recording started")
            camera.start_recording('{}.{:%Y%m%d_%H%M%S}.{}'.format(video_prefix, datetime.now(), video_ext))
            camera_on = True
        # Clear the start_time because it needs to be reset to
        # x seconds after the movement stops
        start_time = None

def stop_video():
    global camera_on
    with thread_lock:
        if camera_on:
            camera.stop_recording()
            camera_on = False
            print ("recording stopped")

def motion_stopped():
    global start_time
    with thread_lock:
        # Ignore this function if it gets called before the camera is on somehow
        if camera_on:
            now = datetime.now()
            if start_time is None:
                print('Starting {} second count-down'.format(record_time))
                Thread(target=timer).start()
            else:
                print('Recording to be extended by {:.1f} seconds'.format((now - start_time).total_seconds()))
            start_time = now

def timer():
    duration = record_time
    while True:
        # Notice that the sleep happens outside the lock. This allows
        # other threads to modify the locked data as much as they need to.
        sleep(duration)
        with thread_lock:
            if start_time is None:
                print('Timer expired during motion.')
                break
            else:
                elapsed = datetime.now() - start_time
                if elapsed.total_seconds() >= record_time:
                    print('Timer expired. Stopping video.')
                    stop_video() # This here is why I am using RLock instead of plain Lock. I will leave it up to the reader to figure out the details.
                    break
                else:
                    # Compute how much longer to wait to make it five seconds
                    duration = record_time - elapsed
                    print('Timer expired, but sleeping for another {}'.format(duration))

print("Waiting...")
sensor.when_motion = registra_video
sensor.when_no_motion = motion_stopped
pause()

作为额外的奖励,我添加了一个片段,它将在您的视频名称后附加一个日期时间。您可以在此处此处阅读有关字符串格式的所有信息第二个链接是一个很好的快速参考。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

倒数计时器不起作用

来自分类Dev

倒数计时器onTick方法不起作用

来自分类Dev

Javascript倒数计时器在Safari或IE上不起作用

来自分类Dev

Uncaught SyntaxError:意外的令牌<结果导致jQuery倒数计时器不起作用

来自分类Dev

我正在尝试创建一个倒数计时器,但是它不起作用

来自分类Dev

创建即将到来的页面时,倒数计时器不起作用

来自分类Dev

重置倒数计时器不起作用+ Java Swing游戏中的JDialog / JOptionPane

来自分类Dev

JS 倒数计时器(天:分钟:小时:秒)不起作用

来自分类Dev

JavaScript计时器不起作用

来自分类Dev

角度计时器不起作用

来自分类Dev

秒表(计时器)不起作用

来自分类Dev

角度计时器不起作用

来自分类Dev

计时器不起作用

来自分类Dev

我找不到在React中暂停倒数计时器的方法(Clear Interval似乎不起作用)

来自分类Dev

C#计时器不起作用?

来自分类Dev

C#计时器不起作用

来自分类Dev

Android SDK计时器不起作用

来自分类Dev

快速无效计时器不起作用

来自分类Dev

计时器间隔不起作用的Javascript

来自分类Dev

计时器onReceive在NavigationView中不起作用

来自分类Dev

每年计时器不起作用

来自分类Dev

子线程中的计时器不起作用

来自分类Dev

计时器在Android Eclipse中不起作用

来自分类Dev

角度计时器在我的应用中不起作用

来自分类Dev

NSTimer [计时器无效]不起作用

来自分类Dev

为什么我的Java计时器不起作用?

来自分类Dev

Esper 模式计时器:interval() 不起作用

来自分类Dev

我的反应组件计时器不起作用

来自分类Dev

JAVAFX,倒数计时不起作用