Raspberry Pi Python 按下按钮时暂停循环序列

Raspberry Pi Python pause a loop sequence, when button pushed

我有一个 raspberry PI 2. 有了继电器板,我用它来实现开关序列(比如交通灯)。 我使用一个名为 "webiopi" 的工具来创建网站上的按钮。单击该按钮后,下面的 python 脚本的功能将启动。

我想要的是在单击另一个按钮时跳出循环(或暂停循环)。但是,只要这个循环是运行,工具就不要看网页

此处提出了一种类似的问题 但这是针对单个事件的,解决方案不适用于我的情况。

问题是。我怎样才能让这个脚本在循环为 运行

时查看单击的按钮(也可以是 gpio 开关)
GPIO_nek=11 
GPIO_schouder=12
GPIO_rug1=8
GPIO_ONOFF=18
interval1 = 2
interval2 = 4
for x in range(0, 20):
    GPIO.digitalWrite(GPIO_nek, GPIO.LOW)
    time.sleep(interval1)
    GPIO.digitalWrite(GPIO_schouder, GPIO.LOW)
    time.sleep(interval1)
    GPIO.digitalWrite(GPIO_nek, GPIO.HIGH)
    time.sleep(interval1)
    GPIO.digitalWrite(GPIO_rug1, GPIO.LOW)
    time.sleep(interval2)
    GPIO.digitalWrite(GPIO_schouder, GPIO.HIGH)
    if (GPIO.digitalRead(GPIO_ONOFF) == GPIO.LOW):
        GPIO.digitalWrite(GPIO_ONOFF, GPIO.HIGH)
        break

当监控实时事件(例如传感器或您的按钮)时,您最好的解决方案是设置一个单独的线程或进程,它只包含一个无限循环,用于监视资源并在有趣的事情发生时设置一个标志。

下面的示例设置了一个在 RPI aprox 上自动拍照的过程。每分钟。

#!/usr/bin/python
#Threading Prototype - Running a background thread that will take
#  pictures at the appropriate time
#------------------------------------------------------------------

from multiprocessing import Queue
from multiprocessing import Process
from time import sleep
from datetime import datetime
from datetime import timedelta
from subprocess import call 


#Doing the work ---------------------------------------------------

#Global Variables ---
messages = Queue()
start_time = datetime.now()

#Returns number of Milliseconds since start of program
def milliSinceStart():
    global start_time
    dt = datetime.now() - start_time
    ms = (dt.days * 24 * 60 * 60 + dt.seconds) * 1000 + dt.microseconds / 1000.0
    return ms

#Process Methods --------------------------------------------------
def processMessages():
    print "Message Processor Launched"
    while True:
        print messages.get()  #should halt until message in queue
        sleep(0.1) #sleep for a tick just to avoid a run away process

def processPicutres():
    print "Picture Taker Launched"
    pictureCycleStart = milliSinceStart()
    index = 0

    while True:
        if milliSinceStart() - pictureCycleStart > 10000: #once a minute
            a = "blip" + str(index) + ".jpg"
            b = "raspistill -n -t 100 -o " + a
            messages.put("Click")
            call ([b], shell=True)
            messages.put("picture taken - " + b)
            index = index + 1

            pictureCycleStart = milliSinceStart()


        sleep(0.1) #wait a tick -- don't hog processor time




def main():
    print "MultiProcessing Prototype"

    print "Launching message process"
    Process(target=processMessages).start()
    print "Back from launch"

    print "Launching picture taking process"
    Process(target=processPicutres).start()
    print "Back from launch"


    cycleStart = milliSinceStart()
    index = 0
    while True:
        if milliSinceStart() - cycleStart > 1000:
            messages.put("Tick " + str(index))
            cycleStart = milliSinceStart()
            index = index + 1


if __name__ == "__main__":
      main()

main 方法启动 Messaging 和 Picture 进程,然后设置自己的小无限循环,仅每秒显示消息 "Tick"。图片进程设置一个单独的无限循环,观察时钟并周期性地拍照。 Message 进程监视图片进程(同样是一个无限循环),当它检测到图片已被拍摄时,它会将事实输出到屏幕。

对于您的目的而言,重要的部分是消息队列。进程队列允许图片和消息进程进行通信。

并且因为任务发生在不同的进程中,所以一个进程是否暂停并不重要,因为其他进程始终处于活动状态。如果您设置了一个按钮监视器进程,您可以检查消息队列以了解这一事实,并在按下按钮时停止您的主程序。主程序中的这个暂停不会影响按钮进程,然后可以在再次按下按钮的事实中恢复。

如果按钮是你在问题末尾提到的GPIO开关,而不是网页按钮,那么你可以利用内置的GPIO中断功能,为你的计算机节省不断轮询的资源:

import RPi.GPIO as GPIO
from threading import Event  # We'll use it like time.sleep, but we can interrupt it.
GPIO_nek=11 
GPIO_schouder=12
GPIO_rug1=8
GPIO_ONOFF=18
interval1 = 2
interval2 = 4
GPIO.setup(GPIO_ONOFF, GPIO.IN, pull_up_down=GPIO.PUD_UP)

done = False  # loop control
timer = Event()
def quit_loop():  # Called by inbuilt threaded interrupt
    global done
    done = True
    timer.set()  # Interrupt the waiting

GPIO.add_event_detect(GPIO_ONOFF, GPIO.FALLING, callback=quit_loop, bouncetime=300) # Setup interrupt to call quit_loop

因为您要使用它来打破循环,所以您想将该循环缩短为单个进程:

tasks = [
(GPIO_nek, GPIO.LOW, interval1),
(GPIO_schouder, GPIO.LOW, interval1),
(GPIO_nek, GPIO.HIGH, interval1),
(GPIO_rug1, GPIO.LOW, interval2),
(GPIO_schouder, GPIO.HIGH, 0) ]

for pin, level, interval in tasks * 20:  # Above you ran it 20 times, this notation keeps it in a single loop to break our o
    if not done:
        GPIO.digitalWrite(pin, level)
        timer.wait(interval)
    else:
        timer.clear()
        break

通过使用线程 Event().wait() 和 .set() 而不是标准 time.sleep(),您甚至不必等待睡眠间隔结束。