"Notaus" Schalter um laufende Funktion abzubrechen

  • Schönen Guten Abend,

    Ich arbeite momentan an einer Linearführung die per Schrittmotor und Riemen auf Knopfdruck nach vorne bis zu einem Induktiven Näherungssensor(INS) fährt und danach wieder auf Anfang(auch bis zu einem INS) zurück fährt. Das ganze hat auch noch ein UI das primär aber mit dieser "Achse" nichts zu tun hat. Die Fahrt bis zum Ende und zurück auf Anfang funktioniert einwandfrei. Was ich nun aber gerne noch einbauen möchte ist eine Art Notaus Schalter mit dem man die Fahrt abbrechen kann und der Wagen der Linearführung langsam zurück zum Anfang fährt.

    Momentan ist es so das ich per PWM bis zum hintern INS fahre und dann die nächste Funktion startet die wieder zum Anfang fährt. Da es mehrere Funktionen sind habe ich diese in einer Liste die nacheinander abgearbeitet wird:

    Hat jemand eine Idee wie ich das Ganze am besten realisieren könnte? Einfach den Strom für den Motor kappen möchte ich nicht, da die Software ja dann noch wartet bis der INS am Ende auf den Wagen wartet. Eine Idee von mir wäre noch vor jedem neu generierten PWM Signal ein If Statement einzufügen das checkt ob der Notaus Taster betätigt wurde. Das glaube ich aber, selbst wenn es halbwegs funktioniert nicht die richtige Lösung.

    Ich hoffe jemand kann mir helfen oder mich in die richtige Richtung leiten :)

  • "Notaus" Schalter um laufende Funktion abzubrechen? Schau mal ob du hier fündig wirst!

  • Hallo,

    wie definierst du denn Not-Aus? Ein klassischer Not-Aus sollte doch in der Tat die Anlage stromlos schalten.

    Ansonsten ist das mit der if-Abfrage schon der richtige Weg. Wobei man wohl eher an das Event des Tastendrucks eine Callback-Funktionen binden würde, die ein threading.Event Objekt auf True setzt. Und dieses Objekt würdest du in deiner Funktionen abfragen, statt permanent den Taster.

    Gruß, noisefloor

  • Der “interrupt” reicht hier nicht. Schließlich gibt es Wartezeiten bis zu einer Sekunde. Und den ganzen Code so umzustricken, das jede einzelne Anweisung prüft, ob der Fehlerfall vorliegt, wird ein ziemlicher Klumpatsch.

    Es gibt aus meiner Sicht drei Wege:

    - der Einsatz eines Zustandsautomaten, denn der kommt damit klar, aus einer Schleife getrieben zu werden, und den kann man dann mit dem Notaus umschalten.

    - der Einsatz von asyncio, denn damit wird das warten nicht zur “Falle”, sondern man bekommt einen cancelbaren task.

    - einen groben Hammer: das Skript wird von einem anderen Skript gestartet. Das äußere überwacht das Notaus, und bei Auslösung wird das Kindskript abgeschossen & wieder neu gestartet. Und der Rücklauf sollte ja eh beim Start einmal stattfinden.

  • Deshalb habe ich Notaus in "" geschrieben. Der Taster/Notaus soll nur die aufgerufene Funktion A2Fahrt(): direkt beenden und den Wagen an der Linearführung langsam wieder zum Anfang zurück fahren lassen. Auf die Idee mit der If Abfrage kam ich weil ich etwas ähnliches mal gemacht habe. Dort war es aber eine for schleife die ein paar hundert mal wiederholt wurde und nach jedem Durchlauf getestet hat ob ein Taster betätigt wurde bzw ein GPIO einen Input bekommen hat.

    Also Interrupts und Threading übersteigen momentan noch meine Fähigkeiten.. Aber das ist ja schonmal eine Richtung in die ich gehen kann.

    der Einsatz von asyncio, denn damit wird das warten nicht zur “Falle”, sondern man bekommt einen cancelbaren task.

    Hört sich auf jeden Fall interessant an.

    Wartezeiten bis zu einer Sekunde

    Was ja bei der Lösung mit der If Abfrage heißen würde das man über diese Sekunde hinaus den Taster betätigen muss damit es im time.sleep nicht untergeht.

  • Nein, das heißt es nicht. Da haben die Vorreiter mit dem Hinweis auf „Interrupts“ schon recht gehabt: damit bekommst du das mit, ohne das dein Hauptprogramm in dem Moment anfragen muss. Aber natürlich wird der Effekt dann trotzdem verzögert erreicht.

  • Also ich habe mal folgendes probiert:

    Code
    def A2Fahrt():
    
        try:
          while True:
              GUIsperren
              A2Fahrt1()
              A2Fahrt2()
              GUIentsperren()
        except KeyboardInterrupt:
            print("abbruch")

    Das ist dann aber eine Endlosschleife bis ich Strg+C drücke. Wie gesagt Interrupts sind noch komplettes Neuland für mich.

  • Das sind auch keine interrupts, sondern ein thread, in dem eine Rückrufaktion ausgeführt wird. Darin kannst du zb eine Variable setzen. Nur hilft das nur bedingt, denn das Hauptprogramm läuft nebenher weiter. Du musst das also mit Prüfungen garnieren, ob jetzt gerade abgebrochen werden soll. Was ziemlich ätzend und fehleranfällig ist. Besser sind die genannten Alternativen.

  • Mal noch ein gänzlich anderer Gedanke...

    Wieso nicht die Marlin-Software (ist für 3d-Drucker gedacht) auf einem ATMega2560 benutzen? Inkl. Display und 6 Motortreibern nebst diversen Endschaltern ist da alles dabei. Zudem werden die Motoren bei einer Fahrt auf den Endschalter (hier z.B. als Notaus verwendet) nicht stromlos geschaltet sondern aktiv in Ihrer Position gehalten. Je nach Anlagenauslegung ist der sicherste Zustand nicht unbedingt immer der stromlose (ein eufgrund fehlenden Stromes "absinkender" Roboterarm von 100kg schmerzt auf dem Fuß...) - wenngleich das wohl meistens der Fall ist.

  • schnasseldag ich dachte auch schon an etwas ähnliches: LinuxCNC. Damit betreiben Kumpels schon seit Jahren ihre Portalfräse, und so etwas sollte damit auch möglich sein. Python scripting inklusive! Ob’s das auch auf dem PI gibt, muss ich mal schauen.

    Edit: Auf dem PI4 läufts gut: http://erste.de/linuxCNC_raspberry_PI4.html

    Einmal editiert, zuletzt von MistyFlower59469 (18. Juli 2020 um 09:57)

  • Hallo,

    hier mal ein sehr simples Beispiel, wie man über ein Event eine laufende Funktion stoppen kann:

    Gruß, noisefloor

  • @__deets__: Da haben Deine Kumpel sich aber ein schönes Projekt gesucht - Hut ab. Vor allem haben sie das OS erst mal in ein für Steuerungen brauchbares per RT-Patch verwandelt. :) Es gibt hier ja jede Menge von "Steuerungsprojekten", die mit dem "Linux von der Stange" sicherlich gut machbar sind, bei einer ruckfreien und synchronen Steuerung von Antrieben ist da aber (im Userspace) Schluß. Auch beim Funken von Bitsequenzen, so sie nicht per DMA o.ä. durchgeführt werden... Man liest das ja zuweilen...

    Mein o.g. Gedanke der Trennung der Steuerungsaufgabe von der Applikation lag hauptsächlich in den folgenden Dingen:

    • man schiebt die Echtzeitanforderung auf den Arduino (ohne OS),
    • besitzt mittels der G-Befehle ein komfortables Positioniersystem mit Beschleunigungen, Geschwindigkeiten, Endschaltern... und
    • kann den Arduino bequem seriell vom Pi aus steuern und hält sich den Pi damit offen für alle Art anderer Software.

    Günstig zu haben ist die Arduino basierte Hardware obendrein. Ich habe mir als "Ersatz" für meinen HC7 3D-Drucker vor einigen Jahren eine Marlin-FW parametriert, die ich im Notfall einsetzen werde. Arduino 2560, Treibershield und LCD-Display haben so an die 30€ in der Bucht gekostet. Billiger und schneller kann man eine Fahrablaufsteuerung kaum bekommen...

    Gruß in den Norden!

    schnasseldag

  • schnasseldag die Kumpels sind ja nur Nutzer. Selbst gemacht ist da nix. Und ich hab’s installiert ;) Aber mit einem ~10 Jahre alten PC fährt die Fräse absolut stabil, und man kann währenddessen zb mit Firefox Surfen etc. Das ist schon gute Technik. Vor allem aber hat das natürlich auch schon Vorkehrungen für kalibrationsfahrten etc. an Bord, wie sie hier auch notwendig sind. Und die harten Echtzeit Funktionen sind sehr einfach via Python ansprechbar - also eine komfortable Teilung. Wenn das System auf dem PI gut läuft.

    Ich persönlich würde auch PREEMPT_RT einsetzten, und ggf einen uC. Ich nutze gerne den Parallax Propeller, weil der mit seinen 8 Kernen eine unerhörte zeitliche Stabilität erreicht. Fast jitter-frei.

    Im konkreten Fall hier scheint der TE ja aber an sich zufrieden mit der Leistung des Systems. Da ist nur die Programmierung etwas im Weg.

  • Der “interrupt” reicht hier nicht. Schließlich gibt es Wartezeiten bis zu einer Sekunde. Und den ganzen Code so umzustricken, das jede einzelne Anweisung prüft, ob der Fehlerfall vorliegt, wird ein ziemlicher Klumpatsch.

    Das ist einfach Falsch.

    Wer einen Interrupt so programmiert, hat das System nicht verstanden.

    Das ganze mittels Zeitschleifen zu machen, ist .... (BASIC, Anfängerkurs)

    Computer ..... grrrrrr

  • Das ist einfach Falsch.

    Wer einen Interrupt so programmiert, hat das System nicht verstanden.

    Das ganze mittels Zeitschleifen zu machen, ist .... (BASIC, Anfängerkurs)

    Ich bin mir nicht sicher, ob jemand, der etwas beständig Interrupt nennt, obwohl es keiner ist, das wirklich besser versteht. Aber ich lasse mich da gerne eines besseren belehren. Wie macht man es denn besser? Konkret?

  • Unter "Not-Aus" Not-Halt verstehe ich das hier:


    Sehr einfach mit einem Relais zu realisieren.

    Wenn man den Not-Halt betätigt, werden zwei Öffner geöffnet, das Relais fällt ab und die Schließer des Relais trennen die Verbindung zum PWM- und Enable-Eingang. Man bekommt auch Relais für 5V.

    Du kannst mal einfach testen, was passiert, wenn du den Enable- und/oder PWM-Eingang des Antriebs entfernst. Normalerweise müsste er dann sofort den Antrieb stoppen. Ich nutze immer nur die ganz teuren aus der Industrie.

  • Ich bin mir nicht sicher, ob jemand, der etwas beständig Interrupt nennt, obwohl es keiner ist, das wirklich besser versteht.

    https://www.raspberrypi.org/documentation/…/gpio/README.md

    Aber ich lasse mich da gerne eines besseren belehren. Wie macht man es denn besser? Konkret?

    Gerne, sogar mit Beispielen.

    http://www.netzmafia.de/skripten/hardw…i_GPIO_int.html

    Hast du wirklich verstanden, was ein Interrupt ist?

    Computer ..... grrrrrr

  • beim 808* war das ein Input-Pin am Prozessor. Durch einen Interrupt-Signal wird das aktuelle Programm unterbrochen und in eine Intrrupt-Serviceroutine ausgeführt und, nach deren Ende, das unterbrochene Programm fortgesetzt. Interupt-Serviceroutinen müssen kurz sein, damit sie sich nicht gegenseitig behindern.

    Interrupts können maskiert (gesperrt) werden. Interrupt-Serviceroutinen können, müssen aber nicht unterbrechbar sein.

    (Das ist eine vereinfachte Darstellung)

  • Rasp-Berlin das der PI Interrupts kennt, wie nahezu jede andere CPU, ist irrelevant. Denn wie auch alle anderen Features dieser Art (DMA, Hardware fuer I2C, SPI, etc) ist das registrieren von IRQ-Handlern ausschliesslich dem Kernel vorbehalten. Kein User-Space-Programm kann daran etwas aendern.

    Und entsprechend wird hier auch nichts unterbrochen. Der einzige Weg, der dem Userspace dazu offensteht, waere Signale (SIGINT, SIGUSR1, etc). Nur koennen die nicht von GPIOs ausgeloes werden.

    Stattdessen gibt es einen zweiten Thread, und DER liefert die Ereignisse an das Programm. Wie man hier sieht: https://sourceforge.net/p/raspberry-gp…ent_gpio.c#l339

    Und damit wird eben genau nix hier 'unterbrochen'. Sondern passiert parallel. Womit also die Frage beantwortet werden muss, wie man denn aus einem Thread auf einen anderen Einwirkt. Ich habe dazu antworten gegeben. Du nicht. Aber das kann man ja nachholen:


    Hier. Bau mal ein, was deiner Meinung nach notwendig ist, um diese 10 Sekunden Wartezeit zu unterbrechen. So, wie ein Interrupt es taete, wenn wir denn einen haetten. Ich warte hochgespannt.

    Abfragen innerhalb der while-Schleife, und das verringern der Wartezeit, sind selbstverstaendlich verboten. Denn wer das macht hat "das System nicht verstanden".

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!