2

我有一个覆盆子 PI 2。使用继电器板,我用于开关序列(如交通灯)。我使用了一个名为“webiopi”的工具,它可以在网站上创建按钮。单击按钮时,将启动以下 python 脚本的功能。

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

这里提出了一种类似的问题Exiting a continuous loop in python via webiopi但这是针对单个事件的,该解决方案在我的情况下不起作用。

问题是。如何让这个脚本查看在循环运行时单击的按钮(也可以是 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
4

2 回答 2

2

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

下面的示例设置了一个在 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()

主要方法启动消息传递和图片进程,然后设置它自己的小无限循环,该循环不再执行任何操作,每秒显示消息“Tick”。拍照进程设置一个单独的无限循环,定时看钟拍照。Message 进程监视图片进程(同样是一个无限循环),当它检测到已拍摄图片时,它将事实输出到屏幕。

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

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

于 2016-04-05T14:51:57.773 回答
1

如果按钮是问题末尾提到的 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() 您甚至不必等待睡眠间隔完成。

于 2016-04-09T01:06:11.143 回答