Betriebsart: Automatik

In unserem Thread für die Automatik sehen wir nun ein interessantes Konzept. Wir „warten“ im Quellcode auf Sensoren, die auslösen. Der Quellcode blockiert an den jeweiligen Stellen und kann über bestimmte Bedingungen, Ereignisse oder threading.Events() fortgesetzt werden.

Die Ablauflogik ist in der run() Funktion, welche durchgehend ausgeführt wird, wenn der Thread läuft. Der Thread wird durch die Eventfunktion def evt_start(self): aus unserem vorherigen Beitrag gestartet.

Für den kapazitiven Sensor „s_metall“ wird zu Beginn des Threads ein Event Registriert, welches unseren „Merker“ self.metall auf True setzt. Dieser wird in der run() Funktion ausgewertet.

class Automatik(Thread):

    """Thread fuer den Automatikbetrieb."""

    def __init__(self, rpi):
        """Instanziiert den Automatik-Thread."""
        super().__init__()
        self.evt_ende = Event()
        self.daemon = True
        self.rpi = rpi
        self.metall = False

    def run(self):
        """Wird durchgehend ausgefuehrt, wenn Anlage im Automatikbetrieb.

        Diese Funktion lauft durchgehend und Regelt die Ablaeufe fuer den
        Automatikbetrieb. Die wait() Funktionen bekommen immer das Exit-Event
        self.evt_ende uebergeben, damit diese beim Beenden vom Automatikbetrieb
        abgebrochen werden. Da dann ein False zurueckgegeben wird, brechen wir
        die Verarbeitung an der Stelle ab. Die while-Schleife wird dann
        verlassen.

        Ungewoehnlich ist evtl. das sich das Programm DAUERHAFT in dieser
        Schleife aufhaelt. Die automatische Prozessbildaktualisierung von
        RevPiModIO synchronisiert im Hinterhund staendig unsere Inputs und
        Outputs. Und ein Blockieren des Programms verhindern wir damit, dass
        diese Funktion als Thread ausgefuehrt wird.

        """
        # Lampe h_start Einschalten
        self.rpi.devices["do02"]["h_start"] = True

        # Automatisch Grundstellung herstellen
        funccatalog.band.grundstellung()
        funccatalog.zylinder.grundstellung()
        self.rpi.devices["do02"]["h_automatik"] = True
        self.rpi.devices["di02"].reg_event(
            "s_metall", self.set_metall, edge=revpimodio.RISING
        )

        while not self.evt_ende.is_set():

            # Warten, bis ein Wuerfel am Sensor s_rutsche erkannt wird
            ec = self.rpi.devices.wait(
                "di02", "s_rutsche", exitevent=self.evt_ende, okvalue=True
            )
            if ec > 0:
                break

            # Zylinder m1 einfahren
            funccatalog.zylinder.set_m1(False)

            # Metallmerker reset
            self.metall = False

            # Warten bis Endlage m1 erreicht ist
            ec = self.rpi.devices.wait(
                "di02", "m_m1_eingefahren", exitevent=self.evt_ende
            )
            if ec > 0:
                break

            # Warten damit Würfel zum Metallsensor rutschen kann
            self.evt_ende.wait(2)

            # Zylinder m1 ausfahren
            funccatalog.zylinder.set_m1(True)

            # Prüfen ob Magazine voll sind
            if self.checkmagazinvoll():
                self.aufhaldefahren()
                continue

            print("motor los")
            funccatalog.band.set_lahm_rechts(True)

            if self.metall:

                # Warten bis Würfel bei Magazin 2 angekommen ist
                ec = self.rpi.devices.wait(
                    "di02", "s_magazin2",
                    exitevent=self.evt_ende,
                    timeout=7000
                )

                print("motor aus")
                funccatalog.band.set_lahm_rechts(False)

                if ec == 1:
                    # exitevent ausgelöst
                    break
                if ec == 2:
                    # timeout überschritten
                    continue

                self.evt_ende.wait(0.5)

                # Zylinder m3 ausfahren und warten auf Endlage
                print("auswerfen")
                funccatalog.zylinder.set_m3(True)
                ec = self.rpi.devices.wait(
                    "di02", "m_m3_ausgefahren", exitevent=self.evt_ende
                )
                if ec > 0:
                    break

                # Magazinzähler Metall erhöhen
                funccatalog.anlage.magazin2 += 1

                # Zylinder m3 einfahren
                funccatalog.zylinder.set_m3(False)

            else:
                print("kunststoff erkannt")

                # Warten bis Würfel bei Magazin 1 angekommen ist
                ec = self.rpi.devices.wait(
                    "di02", "s_magazin1",
                    exitevent=self.evt_ende,
                    timeout=10000
                )

                print("motor aus")
                funccatalog.band.set_lahm_rechts(False)

                if ec == 1:
                    # exitevent ausgelöst
                    break
                if ec == 2:
                    # timeout überschritten
                    continue

                self.evt_ende.wait(0.5)

                # Zylinder m2 ausfahren und warten auf Endlage
                print("auswerfen")
                funccatalog.zylinder.set_m2(True)
                ec = self.rpi.devices.wait(
                    "di02", "m_m2_ausgefahren", exitevent=self.evt_ende
                )
                if ec > 0:
                    break

                # Magazinzähler Kunststoff erhöhen
                funccatalog.anlage.magazin1 += 1

                # Zylinder m2 einfahren
                funccatalog.zylinder.set_m2(False)

        self.rpi.devices["do02"]["h_automatik"] = False
        self.rpi.devices["di02"].unreg_event(
            "s_metall", self.set_metall, edge=revpimodio.RISING
        )

        # Lampe h_start Ausschalten
        self.rpi.devices["do02"]["h_start"] = False

    def aufhaldefahren(self):
        """Faehrt Wuerfel auf die Halde."""
        print("magazin voll - auswerfen")
        funccatalog.band.set_schnell_rechts(True)
        self.evt_ende.wait(4)
        funccatalog.band.set_schnell_rechts(False)

    def checkmagazinvoll(self):
        """Prueft ob eines der Magazine voll ist.
        @return True, wenn eines der Magazine voll ist"""
        return (
            self.metall
            and funccatalog.anlage.magazin2 >= funccatalog.anlage.magazin2max
            or not self.metall
            and funccatalog.anlage.magazin1 >= funccatalog.anlage.magazin1max
        )

    def set_metall(self, ioname, iovalue):
        """Eventfunktion loest aus, wenn Metallsensor gesetzt wird."""
        print("metall erkannt")
        self.metall = True

        # Im Event Prüfen
        if self.checkmagazinvoll():
            # Nur auf Halde fahren, wenn noch nicht gemacht
            if not self.rpi.devices["do01"]["q_schnell_rechts"]:
                self.aufhaldefahren()

    def stop(self):
        """Beendet den Automatikbetrieb."""
        self.evt_ende.set()
        funccatalog.band.grundstellung()
        funccatalog.zylinder.grundstellung()