2016-04-05 28 views
1

Ich habe eine Himbeere PI 2. Mit einem Relais-Board, was ich für eine Schaltsequenz (wie eine Ampel) zu verwenden. Ich benutze ein Tool namens "Webiopi", was Schaltflächen auf einer Website erstellen. Wenn auf die Schaltfläche geklickt wird, wird die Funktion des folgenden Python-Skripts gestartet.Raspberry Pi Python eine Schleife Sequenz anhalten, wenn Taste gedrückt

Was ich will, ist aus der Schleife zu brechen (oder zu pausieren), wenn eine andere Taste geklickt wird. Solange diese Schleife läuft, sieht das Tool jedoch nicht auf der Webseite

Eine ähnliche Frage wird hier gestellt Exiting a continuous loop in python via webiopi aber das ist für ein einzelnes Ereignis und die Lösung funktioniert nicht in meinem Fall.

Frage ist. Wie kann ich dieses Skript Blick auf eine Schaltfläche, was geklickt wird (kann auch ein GPIO-Schalter sein), während die Schleife

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 

Antwort

1

Wird die Taste das ist GPIO-Schalter, wie Sie am Ende der Frage erwähnt, anstelle die Webseite Taste, dann können Sie die Verwendung einer eingebauten GPIO-Interrupt-Funktion, die speichert Ihre Computer die resouces konstanten Polling machen:

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 

Weil Sie diese verwenden aus einer Schleife zu brechen, wollen Sie diese Schleife zu einem einzigen Prozess zu verkürzen.

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 

Durch das Einfädeln Ereignis mit() wait() und .set() statt der Standardzeit.sleep() müssen Sie nicht einmal auf fo warten r das Schlafintervall zu beenden.

+0

Das ist eine großartige Möglichkeit, dieses Problem zu lösen Paul. Vielen Dank für diesen Vorschlag. Ich werde das versuchen und die endgültige Lösung hier machen. – Richard

1

läuft Wenn eine Echtzeit-Ereignisüberwachung wie Sensoren oder Ihre Schaltfläche, um Ihre beste Lösung Sie richten einen separaten Thread oder Prozess ein, der nur eine Endlosschleife enthält, die die Ressource überwacht und eine Markierung setzt, wenn etwas Interessantes passiert.

Im folgenden Beispiel wird ein Prozess eingerichtet, der automatisch ein Bild auf dem RPI erstellt. jede Minute.

#!/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() 

Die wichtigste Methode startet die Messaging- und Bildprozesse und setzt dann seine eigene kleine Endlosschleife, die mehr tut nichts, dass die Meldung „Tick“ jede Sekunde angezeigt werden soll. Der Bildprozess richtet eine separate Endlosschleife ein, beobachtet die Uhr und nimmt periodisch ein Bild auf. Der Nachrichtenprozess überwacht den Bildprozess (wiederum eine Endlosschleife) und wenn er feststellt, dass ein Bild aufgenommen wurde, gibt er die Tatsache an den Bildschirm aus.

Der wichtige Teil dieses für Ihren Zweck ist die Nachrichtenwarteschlange. Die Prozesswarteschlange ermöglicht es den Bild- und Nachrichtenprozessen, zu kommunizieren.

Und weil die Aufgabe in verschiedenen Prozessen stattfindet, ist es nicht wichtig, wenn ein Prozess pausiert, da die anderen immer aktiv sind. Wenn Sie einen Button-Monitor-Prozess einrichten, können Sie die Nachrichtenwarteschlange auf diese Tatsache überprüfen und Ihr Hauptprogramm anhalten, wenn Sie auf die Schaltfläche klicken. Diese Pause im Hauptprogramm würde den Knopfprozess nicht beeinflussen, der dann die Tatsache aufgreifen könnte, dass die Taste erneut gedrückt wird.

+0

Vielen Dank für das Senden dieser gut dokumentierten Antwort. Ich werde mit Ihrer Eingabe arbeiten und werde meine endgültige Lösung veröffentlichen, wenn Sie fertig sind – Richard

+0

Geben Sie mir den Scheck für die Antwort würde geschätzt werden. :-) – codingCat