Wie mache ich eine Ausschaltverzögerung

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo Zusammen

    Ich habe das Problem, dass ich von einem Blinkkontakt ein Signal erhalte (0,5sec. an/0,5sec. aus), das ich erfassen möchte.

    Wenn das Signal eine Minute ansteht, möchte ich nicht 60 einzelne Signale sondern ein einzelnes. Deshalb möchte ich die Zeit, in der das Signal ausgeschaltet ist (0.5sec.) softwaremässig mit einer Ausschaltverzögerung überbrücken.

    Nun ist die Frage, wie so eine Ausschaltverzögerung in Python funktioniert..?

    Kann mir das jemand erklären/zeigen?

    Mit einem time.sleep() funktioniert es leider nicht, denn dieser Befehl verzögert ja nur die Fortsetzung des Programms, aber ich möchte ja etwas anderes erreichen.

    Liebe Grüsse

    Bern

  • Für so etwas brauchst du einen Timer. Den du bei jedem Signal zurück setzt, so dass er nur feuert, wenn er nach zb einer Sekunde abgelaufen ist. Wie genau so ein Timer zu realisieren ist, hängt von dem konkreten Programm ab. Ob du zb GUI Toolkits benutzt, etc.

  • Kann man natürlich mit Software lösen. Am einfachsten vielleicht, indem man den Zeitabstand zwischen zwei Signalen misst. Ist er kleiner als 2 Sekunden, dann ist es immer noch das gleiche Blinksignal. Ist er größer, muss man einen neuen Impuls erfassen.

    Du kannst auch ein RC-Glied zur Glättung des Signals verwenden.
    Ein Widerstand mit 20 KOhm und ein Kondensator mit 100 nF ergibt eine Zeitkonstante von 2 Sekunden. Wenn und so lange es Blinkt, wird die Spannung am Kondensator auf high-Level gehen und nicht mehr unter die Schaltschwelle sinken. Wenn das Blinken länger als ein paar Sekunden aufhört, sinkt die Spannung und der GPIO registriert das Abschalten des Signals.

    Oh, man kann hier unliebsame Nutzer blockieren. Wie praktisch!

  • Du könntest gpiozero.DigitalInputDevice nutzen, um bei einer positiven und negativen Flanke etwas zu machen.

    Vorher musst du natürlich mit pip gpiozero installieren.

    Code
    sudo pip3 install gpiozero
    # als root, auch wenn es nicht gerade der beste weg ist
  • Hallo Leute

    Danke für die Antworten.

    @__deets__

    Mein Programm läuft über ein Nextion-Display. Also nicht ein klassiches GUI wie z.B. Tkinter.

    Meinst du so etwas (von https://stackoverflow.com/):

    @Gnom

    Die Softwarelösung ist eine gute Idee, aber ich muss schauen, wie und ob ich das in das Programm einbinden kann.

    Die Hardwarelösung ist auch eine super Idee. Aber ich habe vergessen zu schreiben, dass es 120 Eingänge sind. Deshalb würde das wahrscheinlich teuer werden. Aber ich werde das noch ausrechnen und mich dann entscheiden.

    @DeaD_EyE

    Leider geht das nicht, denn es sind 120Eingänge, die über Schieberegister zusammengefasst sind => sorry hatte ich vergessen zu schreiben. Aber Danke trotzdem vielmals.

    Gruss Bern

  • 120 Eingänge? Na dann auf jeden Fall in Software!
    Wie realisierst du 120 Inputs? Benutzt du Portexpander?
    Auf allen Eingängen kommt, wenn sie denn aktiv sind, dieses Blinksignal? Wie oft rechnest du mit aktiven Signalen? Hast du ein wildes Blinken oder kommt das nur sporadisch wenn zum Beispiel ein Fehler auftritt?
    Wie willst du die Signale erfassen - per polling, also regelmäßig alle 120 abfragen (erscheint mir unsinnig) oder mit Interrupts?

    Vielleicht kannst du uns den Hintergrund der ganzen Sache etwas beschreiben...

    Oh, man kann hier unliebsame Nutzer blockieren. Wie praktisch!

  • Leider geht das nicht, denn es sind 120Eingänge, die über Schieberegister zusammengefasst sind => sorry hatte ich vergessen zu schreiben. Aber Danke trotzdem vielmals.

    120 Threads für 120 Signale wären etwas viel.

    Wie liest du das Schieberegister aus und welche Hardware verwendest du?

  • Bern93 hmjanein. Das ist zwar auch ein Timer, aber hier eher nicht geeignet. Wenn du eine Hauptschleife hast, dann kannst du in der auch periodisch vorgehen:

    Der Timer haelt nach, wann zuletzt Aktivitaet auf dem Kanal vorgelegen hat, und nur wenn die laenger als 2 Sekunden zurueck liegt, liefert er ein positives Ereignis.

  • Ups, hab ich übersehen...
    Also bleibt nur Polling. Auch gut - Schieberegister sind schnell genug.

    Ich nehme an, die Blinksignale sind nicht synchronisiert... also muss man mit allem rechnen sozusagen.

    Ich würde in einer schleife oder ggf. mit Timerinterrupt alle 500 ms die Schieberegister auslesen. Dann jedes der 120 Bits testen. Wenn es HIGH ist, setzt du eine Variable für den entsprechende Eingang auf sagen wir mal 5. Wenn es LOW ist, zählst du ihn eins runter (Minimum 0, nicht negativ). Wenn der Wert der Variablen größer als 0 ist, hast du ein aktives Signal (oder zumindest vor 2500 ms noch gehabt). Wenn der Wert 0 ist, wurde in fünf Messungen kein Signal gemessen, das Blinken ist also aus.

    Hängt aber alles doch noch ein wenig davon ab, wo dein Signal her kommt und was es signalisiert, welche Schaltintervalle zu erwarten sind usw...

    Oh, man kann hier unliebsame Nutzer blockieren. Wie praktisch!

  • Gnom

    120 Eingänge? Na dann auf jeden Fall in Software!

    Es würde ein bisschen viel Arbeit geben aber das Material wäre nicht so teuer. Aber Software ist die bessere Lösung.

    Ich benutze 15 Schieberegister in Serie mit je 8 Eingängen, pro Eingang gibt es noch einen Optokoppler, da jeder Eingang ein 24VDC Signal ist (siehe Schmema im Anhang). Das funktioniert auch soweit gut. Das Blinksignal wird über ein Blinkrelais gemacht (500ms ein und 500ms aus). Die Signale, die ich abfrage sind Alarme, deshalb auch das Blinksignal. Die Alarme, die ich erfassen möchte, werden parallel auch auf einem Schaltpult angezeigt und auf dem hat jede Pumpe, Ventilator, etc eine Betriebslampe, die leuchtet wenn das Teil läuft. Wenn es eine Störung hat dann blinkt die Betriebslampe.

    Im Voraus zu sagen wie viele aktive Signale es gibt ist fast unmöglich, denn es gibt Wochen, da kommt vielleicht ein Alarm und dann gibts Tage da gibt es eine Menge Alarme, je nachdem wie gut die Anlage läuft.

    Ich habe es versucht, aber ich schaffte es nicht die Schieberegister auszulesen. Deshalb habe ich ein vorgefertigtes Programm aus dem Internet geholt und dieses mit meinem Programmcode erweitert... Daher muss ich sagen, dass ich nicht das komplette Programm verstehe. Aber die Alarme werden dauernd abgefragt, denn es gibt auch Alarme, die nur kurz anstehen

    @DeaD_EyE

    Ich habe es versucht, aber ich schaffte es nicht die Schieberegister auszulesen. Deshalb habe ich ein vorgefertigtes Programm aus dem Internet geholt und dieses mit meinem Programmcode erweitert... Wenn du willst, kann ich das Programm hochladen aber es ist sehr gross (weit über 1000 Zeilen).

    Ich hänge noch eine Schemaseite an, da sieht, man wie das Ganze aufgebaut ist. Diese eine Seite muss man mal 15 rechnen, damit man die komplette Hardware sieht.

    Die Schieberegister sind SN74HC165N, die Optokoppler ILQ1 und einen Raspberry Zero habe ich. Der ist zwar ein bisschen langsam aber das reicht dafür

    @__deets__

    Ich werde versuchen den Code von dir in meinen Code zu integrieren. Mal schauen ob ich es schaffe :daumendreh2:

    Danke euch allen. Ich werde noch prüfen, ob ich das Blinksignal nicht eliminieren kann, denn das würde eine Menge leichter machen.

  • Wenn ich das richtig verstehe, sind die Fehler wohl eher "länger"... Du schirebst "Alarme, die nur kurz anstehen". Was heißt denn kurz genau? Ein paar Sekunden? 5 Minuten? Ab welcher Störungsdauer wird es relevant?

    Naja, ein konstantes Signal wäre einfacher. Wie gesagt, mit einem RC-Glied kriegst du das hin. Würde die Sache schon vereinfachen. Ändert aber nichts dran, dass du die Signale in relativ kurzen Zyklen abfragen musst.

    Was hängt denn dann hinten dran? Willst du die Fehler loggen oder Mails verschicken und was läuft noch alles auf dem Pi?
    Vielleicht solltest du das eigentliche Checken der Eingänge über einen µC machen und die Ereignisse dann an den Pi weiter geben. Ein µC kann die auch puffern, bis der Pi ggf. Zeit hat, sie auszulesen und zu verarbeiten.

    Der Code mit der Zählmethode ist eigentlich nicht so schwierig. Jedes Bit einlesen. Wenns 1 ist, die Variable auf 5 setzen und Alarm auslösen, wenns 0 ist, die variable eins runterzählen. Wenn null erreicht ist, Alarm löschen. Wenn du alle Bits einmal gelesen hast, 250 ms Pause und dann von vorne..

    Oh, man kann hier unliebsame Nutzer blockieren. Wie praktisch!

  • Ja genau es kann sein, dass ein Alarm mehrere Stunden ansteht. Ich möchte eigentlich alle Alarme aufzeichnen auch die ganz kurzen, denn deshalb machen wir das eigentlich, denn die Alarme quittieren sich selber und wenn dann ein Problem nur kurz ansteht, haben wir auch schon gesucht, weil auch der kurze Alarm das ganze System herunterfahren lässt. Kurzer Alarm =ca. 3-6 Sekunden.

    Ja vielleicht werde ich den Blinkimpuls los. das ist nämlich schon sehr mühselig. Also ohne Blinkimpuls habe ich ein funktionierendes Programm. Ich wollte das alles eigentlich einbauen und merkte erst kurz vor dem Einbau, dass es ja ein Blinkimpuls ist und nicht ein konstantes Signal.

    Es läuft nur das eine Programm auf dem RPI. Ich habe eine Nextion Display, das eine eigene Logik hat und nur die Kommunikation dem RPI und dem Nextion passen muss. Also ist der RPI-Zero nicht überlastet.

    Aha ja nun weiss ich was du meinst. Ja das wäre sicher auch eine machbare Lösung :) Danke

  • Also, da würde ich die Softwarelösung mit dem Pi machen - das sollte bei den Anforderungen ohne Probleme gehen. Mit der Zählmethode werden auch kurze Alarme (ein einziges Blinken) erkannt. Probier halt mal, was entsprechendes zu programmieren und gib mal Rückmeldung, ob es klappt.

    Oh, man kann hier unliebsame Nutzer blockieren. Wie praktisch!

  • So nun hatte ich einmal Zeit mich damit zu befassen.

    Gnom Ich habe diesen Weg gewählt:

    Laut meinen Nachforschungen im Internet sollte das eigentlich funktionieren.

    Leider werden keine 10 Sekunden gewartet, sondern der self.sp-Wert wird innerhalb von einem Bruchteil einer Sekunde schrittweise von 5 auf null gesetzt. Ich habe die Zeit extra gross gewählt, dass ich deutlich sehen sollte wie sich das verhält => wird später tiefer gewählt.

    Kann mir jemand erklären, was ich falsch mache?

  • Keine callback anzugeben, sondern die Funktion direkt aufzurufen. Der 99%-Fehler bei threads.

    Nachtrag: ich hatte ja schon oben ausgeführt - Threads sind nicht die Antwort.

  • Hallo @__deets__

    Nachtrag: ich hatte ja schon oben ausgeführt - Threads sind nicht die Antwort.

    ja das habe ich nach dem posten des Beitrags auch gesehen...

    Ich dachte mir nur dass das doch die einfachste Lösung wäre.

    Denn leider weiss ich nicht, wie ich deinen geteilten Code vom 17.Juli in mein Programm einbinden soll, schon nur weil ich ihn nicht verstehe.

  • Denn leider weiss ich nicht, wie ich deinen geteilten Code vom 17.Juli in mein Programm einbinden soll, schon nur weil ich ihn nicht verstehe.

    Das lässt sich ja ändern:

    1. PyCharm oder vergleichbare IDE installieren
    2. @__deets__ Code im Forum kopieren und in PyCharm o.ä. einfügen
    3. Breakpoint in Zeile 43 setzen
    4. Klick auf Debug
    5. Zeile für Zeile mit dem entsprechenden Button durchschalten und dabei beobachten im Debug Fenster wie sich die Variablen verändern
    6. Bei Unklarheiten Suchmaschine bemühen; z.B bei time.monotonic()
    7. Bei weiteren Unklarheiten hier nachfragen

    Aber nicht einfach ignorieren nur weil du was nicht verstehst =O

  • Hallo Hofei

    Das lässt sich ja ändern:

    1. PyCharm oder vergleichbare IDE installieren
    2. @__deets__ Code im Forum kopieren und in PyCharm o.ä. einfügen
    3. Breakpoint in Zeile 43 setzen
    4. Klick auf Debug
    5. Zeile für Zeile mit dem entsprechenden Button durchschalten und dabei beobachten im Debug Fenster wie sich die Variablen verändern
    6. Bei Unklarheiten Suchmaschine bemühen; z.B bei time.monotonic()
    7. Bei weiteren Unklarheiten hier nachfragen

    Aber nicht einfach ignorieren nur weil du was nicht verstehst =O

    Ja das stimmt das hätte ich tun sollen. Ich habe dann die Antwort von Gnom besser verstanden, daher habe ich mich an seine Idee gehalten. Aber ich versuche nun mit dem Debugger das Programm nachzuvollziehen.

  • Ich glaube nun begreife ich das Programm im Grossen und Ganzen.

    Noch zwei Fragen habe ich:

    Zeile 8:

    Code
    return bool(int(elapsed * 2) % 2)

    Diese Zeile verstehe ich nicht komplett. Wird da die Variable "elapsed" *2 gerechnet und dann geschaut, wie häufig 2 in die elapsed*2 Variable passt und den Rest ausgegeben( => also 1 oder 0) und dann diese Integer Variable in eine Boolean umgewandelt? Oder was passiert da?

    Wenn meine Annahme stimmt, benötige ich für mein Programm die Zeilen 3-8 gar nicht oder? Diese sind hier nur, damit man eine Änderung im unteren Teil des Codes hat. In diesem Falle müsste ich einen Alarm mit io_value verknüpfen => Wenn der Alarm da ist dann io_value True und wenn der Alarm nicht da ist dann io_value False. Dies müsste ich mit allen 120 Alarmen machen.

    Stimmt das?

Jetzt mitmachen!

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