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(),您甚至不必等待睡眠间隔结束。
我有一个 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(),您甚至不必等待睡眠间隔结束。