Alle GPIO gleichzeitig lesen

  • Hallo Freaks

    Alles Einfache ist erst mal schwer.

    Ich möchte folgendes Problem lösen.

    39 Kontakte sollen auf Änderung abgefragt werden, wobei maximal auch zwei nebeneinanderliegende Kontakte gleichzeitig aktiv sein können.

    Die aktiven Kontakte sollen dann zwischengespeichert werden, zur späteren Auswertung. Das Ganze 20mal hintereinander, ale 20 bis 40 Millisekunden.

    Das sind also 77 mögliche Ereignisse, die ich als Logic mit 14 Eingängen unterscheiden kann. Soweit so gut.

    Ich kann 14 GPIO als Input declarieren und in 2 Schleifen abfragen

    Lauf 2 (20mal)

    [Lauf 2 (14mal)]

    GPIO.add_event_detect([lauf2], GPIO.FALLING, callback = isr[lauf1,lauf2], bouncetime = 0)


    aber ich befürchte das wird zu langsam, deshalb frage ich lieber erstmal, bevor ich anfange in Python zu coden.

    Das letzte mal das ich was programmiert habe ist schon 10 Jahre her, damals in Profan; Muß also so wie so ganz unten anfangen.

    Leider finde ich keine Zusammenstellung der möglichen Befehle für die RPi.GPIO und Python.


    Also sind meine primären Fragen:

    Wo finde ich den Befehlsumfang von RPi,GPIO und Python ?


    Sicherlich gibt es ähnliche Projekte mit dieser Problematik:

    Warten auf ein event an einem beliebigen Port, dann

    Ausgabe welche Ports sich geändert haben

    sowas in der Art würde mir schon reichen.


    oder : Eine günstigere Bibliotkek ? wegen der Geschwindigkeit ?


    oder: Besser auf Arduino umsteigen ? ( Fände ich nicht so toll, das RASPBERRY Konzept gefällt mir gut.)


    Nicht lachen, Wertet mich einfach als Einsteiger.

    Walter :helpnew:

  • Tool Tip:

    gpio-library:http://abyz.me.uk/rpi/pigpio/index.html

    Einmal editiert, zuletzt von root ()

  • Wie wichtig ist dir die Geschwindigkeit?


    Generell ist es mit RPi.GPIO durch aus möglich alle GPIO's via Interrupt zeitnah und (nahezu) in Echtzeit zu erfassen, solange in der Interrupt-Callback nichts wildes gemacht wird, denn es wird nur ein einziger Thread für die Callback ausgeführt und wenn diese blockiert wird (wegen einer Verarbeitung oder umfangreichere Ausgabe etc.) können weitere Flankenwechsel derweil verpasst werden.


    Wenn es dir nur um die Erfassung der Flankenwechsel geht und dein Vorhaben nicht wirklich Zeitkritisch ist könntest du zB sowas verwenden:


    Ansonsten wäre es wirklich besser einen µC wie den Arduino zu verwenden, wo kein Betriebssystem ausbremst.



    //EDIT: Noch ein paar Anmerkungen zum obigen Code:

    Die Erfassung eines Flankenwechsels erfolgt unmittelbar und sofort. Die Ausgabe hinkt etwas hinterher (durch das time.sleep(0.5)), was aber in keinster Weise die Erfassung beeinflusst. Das sleep ist nur dazu dar dass die jeweilige while nicht extrem schnell rotiert und 100% CPU Auslastung verursacht. Bei Bedarf kann man die Blockade auch auf zB 0.01 reduzieren aber viel niedriger sollte es nicht sein.

    Man kann für jeden GPIO-Pin eine GPIO.add_event_detect() Zeile setzen, oder bei nur einer Zeile eine List angeben.

    Zusätzlich wird für Rising und Falling ein eigenes Queue erzeugt und jeweils in einem separaten Thread abgefragt, wo dann auch die Verarbeitung/Ausgabe unabhängig erfolgt.

    Beim Flankenwechsel wird dessen exakter Zeitpunkt ins Queue mit eingefügt.

    Die while in der main() Funktion dient nur dazu dass das Script nicht weiter verarbeitet und beendet wird. Könnte man auch durch signal.pause() ersetzen, oder andere Sachen behandeln wie zB eine GUI initialisieren usw...

  • Danke meigrafd, Du hast dir ja richtig viel Arbeit/ Mühe gemacht !


    Wie beschrieben ist mit Ereignissen von 20 bis 40 Millisekunden Abstand zu rechnen. Ob das schon "zeitkritisch" ist, bin ich nicht sicher.

    Gehört queue bereits zur Bibliothek von Python3 oder muss das nachträglich installiert werden?

    time.sleep(5) sind das Millisekunden ?


    Taster = 25

    1. GPIO.setup(Taster, GPIO.IN)
    2. GPIO.add_event_detect(Taster, GPIO.BOTH, callback=partial(interrupt_event, queueFalling, queueRising), bouncetime=200)

    Wird hier NUR GPIO 25 angesprochen ( was mir nichts bringt) oder 25 GPIO Ports ?? (Das wäre prima)

    Wie klein kann die bouncetime gesetzt werden (da Events im Abstand von 20 mS zu erwarten sind würde 200mS bouncetime Events als Tastenprellen ignorieren richtig )?

    Auch bei dir, ähnlich wie bei root, verstehe ich noch nicht WO die Event Daten abgelegt werden ?

    Wie gesagt das Projekt als Kurzfassung : 20 mal hintereinander im Event-Abstand von 20bis40 MilliSekunden 14 Ports auslesen und den Zustand (hight,low) sowie den Zeitstempel zwischenspeichern. (Das sehe ich bisher nirgendwo, auch nicht in Tutoriels und Beispielen)

    Die Auswertung/Verarbeitung der 20x 14 I/O Zustände und des Zeitstempel erfolgt erst NACH Event 20.


    Danke root

    Das sieht mir schon ganz gut aus, ist aber sehr irritierend. z.B. Zeile 4 GPIO 32 - 53 ???

    Der RASPi hat 40 Pins belegt mit 26 GPIO Ports . Was also ist dann GPIO 32 - 53 ???


    1. se as:uint32_t gpioRead_Bits_0_31(void)
    2. Returns the current level of GPIO 0-31.

    Das sieht gut aus; aber: Wo wird das Value der GPIO 0-31 abgelegt, damit ich darauf zugreifen kann ???


    Hoffe ich mache euch nicht zu viel Mühe, und danke für euer Verständnis meiner Unfähigkeit.

    ICH LERNE, aber langsam.

    Lefty

  • Es wäre ganz interessant, zu erfahren, welchen Hintergrund deine Signale haben... also, wo die her kommen...


    Ansonsten, wenn es wirklich zeitkritisch ist und du nicht riskieren willst, irgendwelche Signale zu verpassen, weil der Pi gerade was vermeintlich wichtigeres zu tun hat, nimm einen Mikrocontroller, der unbeeindruckt von aller Unbill der Welt diese Kontakte überwacht und bei Signalen den Pi informiert.

    Ansonsten hatten wir schon gelegentlich ähnliche Aufgabenstellungen - da bietet sich auch immer ein Schieberegister an. Das spart das Handling von 30 GPIOs und lässt sich schnell und einfach abfragen.

  • linusg Danke habs gelesen. Leider sehe ich nicht wie klein Time.sleep sein darf. würde time.sleep(0.0005) funktionieren?

    Warum willst du das derart klein setzen? Wie gesagt beeinträchtigt das die Erfassung in keinster Weise sondern betrifft nur die Ausgabe.

    Wird hier NUR GPIO 25 angesprochen ( was mir nichts bringt) oder 25 GPIO Ports ?? (Das wäre prima)

    Nein nur ein Pin. Wie ich bereits sagte kannst du da auch eine List angeben.

    Wie klein kann die bouncetime gesetzt werden (da Events im Abstand von 20 mS zu erwarten sind würde 200mS bouncetime Events als Tastenprellen ignorieren richtig )?

    Gegenfrage: Weißt du wofür bouncetime ist? Wenn du die Auswirkungen kennst und das ganze Hardwareseitig entprellen kannst, sollte sich diese Frage in Luft auflösen ;)

    Auch bei dir, ähnlich wie bei root, verstehe ich noch nicht WO die Event Daten abgelegt werden ?

    Im Queue. Es gibt ein Queue für steigende Flanken und ein weiteres für fallende Flanken. Beide werden unabhängig von einander verarbeitet, kann man aber auch zusammenfügen - alles ist möglich :fies:

    Die Auswertung/Verarbeitung der 20x 14 I/O Zustände und des Zeitstempel erfolgt erst NACH Event 20.

    Dann musst du noch einen (bzw zwei) Zähler einbauen.


    Das dein Input in 40ms Impulsen erfolgt haben wir soweit mitgekriegt, aber das "Wozu" fehlt noch - was letztlich darüber entscheiden würde ob dein Vorhaben zeitkritisch wäre...

  • Lefty beliebig klein. Nur leidet irgendwann die Genauigkeit, denke ich, weil das Programm ja nicht permanent im Vordergrund läuft, sondern vom Scheduler Zeit zugewiesen bekommt. Unter Umständen wird das Programm also bei einer zu kleinen sleeptime länger "zwangsschlafengelegt".

    Die Genauigkeit reicht meistens aus, aber ein bisschen Ungenauigkeit gibt's natürlich immer :angel:



    Edit: auf einem flotten Rechner, unter Windows wohlgemerkt:


  • OT:


    Ich messe mit - sofern nötig - ``timeit`` die Laufzeit einer Funktion oder eines Programms. Aber die Laufzeit ist von zu vielen Faktoren abhängig, so dass es eh nicht genau sein wird. Auch mit der Systemzeit ``time`` kann es nicht genau sein.


    Python
    1. import timeit
    2. import time
    3. start_time = timeit.default_timer()
    4. time.sleep(1)
    5. print timeit.default_timer() - start_time
    6. >>0.999662626665
  • ok hängt euch nicht an der sleeptime auf, ich werde die Kontakte hardware-entprellen, und kann dann auf sleeptime ganz verzichten.

    Da ihr mich fragt " WOZU DAS GANZE???" will ich die Problematik einmal deutlich beschreiben :

    Vorabinfo zum Problem:

    Ich bin aktiver Sport Bowling Spieler

    Als Sportbowler besitzen wir natürlich mehrere Bälle mit unterschiedlichen Rotationseigenschaften, um sich den Öl-Verhältnissen der Bowlingbahn anpassen zu können.

    Da die Bahn 1 Meter breit aber 20 Meter lang ist, bekommt man beim Beobachten/Vergleichen des Balllauf besonders im unteren drittel der Bahn Probleme. (geht nur gefühlt) Aber nur da ist wichtig zu wissen "was macht der Ball da"?

    (1te drittel auf der Bahn: viel Öl, 2tes weniger,3tes KEIN ÖL! und dadurch komplette Änderung des Balllauf)


    Projekt zur Problemlösung

    Ich platziere auf den letzten 7 Meter über der Bahn im Abstand von ca. 30cm eine Leiste mit 39 Kontakten, also 20 Stück. Die Höhe ist so eingestellt das beim Durchlaufen des Ball 2 Kontakte gleichzeitig betätigt sein können, also 77 mögliche Ereignisse. Das reicht aus. Um diese 77 Events eindeutig zu erfassen brauche ich 14 Ports [Bei 77 Kontakten käme ich natürlich mit 8 Ports aus, wird dann aber zu teuer, weil wenn alles klappt eventuell auch 40 Leisten da sind.

    Der RASPi soll jetzt erfassen welcher Kontakt an Leiste 1 durchrollt wurde und wann, und sich das merken. Dann warten auf den Kontakt der nächsten Leiste, wieder merken(mit Zeit) usw. bis zur letzten Leiste.

    Nach der Datenaufnahme sollen diese Punkte grafisch als Kurve dargestellt werden, Mit den Zeitstempeln möchte ich dann ebenfalls wissen wie schnell der Ball in einzelnen Bereichen der Bahn war.

    Diesen Daten wären sehr hilfreich um zu sehen und zu belegen wo die Unterschiede der Bälle und auch Abwurftechnik liegen.

    DER TRAUM EINES JEDEN BOWLER!!!


    Ich habe schon 5 Hardware-Leisten gebaut, und über den Kontakten LEDs eingesetzt (per Elko eine Leuchtdauer von4 Sekunden. Jetzt schreibe ich also nach dem Wurf schnell auf welche LED bei den Leisten leuchtet, und sehe schon mal den Balllauf im Groben (mehr als 5 Leisten wird da aber Stress) und LaufZeit fehlt mir .

    Im Anhang habe ich euch mal eine Zeichnung (.PDF) und Logic (.ods) eingefügt


    Jetzt bin ich aber echt gespannt !

    Dateien

    • Projekt.pdf

      (207,04 kB, 38 Mal heruntergeladen, zuletzt: )
    • Schranke.ods

      (18,09 kB, 18 Mal heruntergeladen, zuletzt: )
  • Ähm, hab ich das jetzt richtig verstanden? Du willst 780 Kontakte Abfragen, um den exakten zeitlichen und örtlichen Verlauf des Wurfs zu bestimmen?


    Hast du mal drüber nachgedacht, das mit Laserlichstschranken und/oder Ultraschallsensoren zu machen? Ich glaube, der Aufwand wäre ungleich geringer.


    Den Laserstrahl lässt du im "Zickzack" alle 30 cm die Bahn queren. Und mit 20 Ultraschallsensoren kannst du den Abstand der Kugel vom Bahnrand messen, immer dann, wenn die Lichtschranke unterbrochen wird.




    Du könntest auch (je) drei Laserstrahlen nehmen, zwei parallel und einen diagonal dazu. Die beiden parallelen geben die Durchgangszeit vor, der dritte sagt dir die seitliche Position des Balls. Je nach Zeitpunkt der Unterbrechung der drei Strahlen kannst du die Geschwindigkeit und Position ermitteln.

    Bei 10 m/s und einem Strahlabstand von 1 cm ist der Zeitabstand zwischen den beiden Lichtschranken 0,8 ms. Um die seitliche Position auf 1 cm genau zu bestimmen, muss man 1/100 dieser Zeit erfassen. Für einen Mikrocontroller wäre das kein Problem. Und Lasermodule kosten in China 25 Ct.




    Also zum Beispiel: Zeit von L1 zu L2 = 920 µs / Zeit von L1 zu L3 = 355 µs

    -> Geschwindigkeit = 0,01 / 0,000920 = 10,87 m/s = 39,13 Km/h

    -> Position = 355/920 * 100 = 38,6 also 38,6 cm vom linken Bahnrand entfernt - oder 11,4 cm links von der Mitte.

  • ok hängt euch nicht an der sleeptime auf, ich werde die Kontakte hardware-entprellen, und kann dann auf sleeptime ganz verzichten.

    Nochmal: Das erfassen eines Flankenwechsels hat nichts mit den time.sleep() zu tun.


    Selbst wenn du die sleeptimers auf 60 Sekunden stellst verpasst du keinen einzigen Flankenwechsel und wirst trotzdem über _alle_ exakten Zeiten informiert.

    Das erfassen der Flankenwechsel erfolgt unabhängig im Hintergrund in einem eigenen Thread. Das Script selbst ist ebenfalls ein Thread und die beiden Ausgabeprozeduren sind jeweils ebenfalls Threads. Es laufen also insg. 4 Threads. Wird einer blockiert laufen trotzdem noch drei ungehindert weiter.


    Worauf es bei Dir nur an kommt ist eine exakte Zählung der Impulse. Die Auswertung wie viele Impulse es in einer bestimmten Zeit waren kann auch später erfolgen. Genau dafür kannst du meinen Code verwenden - ohne irgendwelche "sleeptimer" raus zu werfen.


    Die time.sleep() in meinem Script dienen nur der CPU Entlastung. Nimmst du die raus rotiert die while dermaßen schnell dass die CPU zu 100% ausgelastet wird - und dann läufst du Gefahr Flankenwechsel zu verpassen. Es wäre also fatal auf "sleeptime" ganz zu verzichten.

    Man könnte den Code auch so anpassen dass die while derweil blockiert wird bis ein Eintrag im Queue erfolgt, also "if not queue.empty():" weglassen, dann wäre der "sleeptime" nahezu überflüssig - natürlich weiterhin mit der CPU-Auslastungs-Einschränkung.


    Verstehst du's jetzt?

  • Gnom

    Danke für dein Mitdenken. Diese Idee mit den Lichtschranken habe ich schon mal versucht, bringt aber Probleme.

    Der mechanische Aufwand (Positionieren der Lichtschranke und Reflektoren) ist zu aufwändig/zeitintensiv (eine feste Installation ist nicht erlaubt).

    meigrafd

    time.sleep habe ich jetzt verstanden DANKE!

    Ich werde mich demnächst mit deinem Code beschäftigen und testen. Dauert ein wenig, weil ich die Hardware noch entsprechend umbauen muss; gebe dann aber sicher ein Feedback.

    Lefty

  • Gnom

    2 mal denken ist immer gut. Dein 2ter Lösungsvorschlag mit 3 Laser auf 3 Fotozellen (pro Station) im Abstand von 1cm; Das Ganze als "Modul, so das keine Justage etc nötig ist, wäre praktikabel.

    Der Kostenaufwand ist sicher deutlich geringer, und auch die Fehleranfälligkeit (Kontakte) geht gegen 0.

    Also wäre dann im RASPi zu tun:
    Stationen = (Anzahl der Stationen)

    Schleife 1 bis Stationen

    3 GPIO als Event erkennen , nur die TIME 1>3 (für Geschwindigkeitsrechnung) und 1>2 (für Positionsrechnung) erfassen und im RAM speichern; 300 yS Zeit !! Du meinst der RASPi ist schnell genug dazu?

    Zusammenfassen der Daten (n Stationen x 2 TIME), Speichern in Datenbank aud USB-Stick, grafische Darstellung usw. kann danach erfolgen, das ist nicht zeitproblematisch.


    Auf Grund der deutlich geringeren Kosten und des geringeren Hardware-Aufwand werde ich die erste Idee in den Hinterkopf verschieben (nicht böse sein meigrafd) und eine Station zum Test bauen.

    Danke an Alle

    Lefty

  • Wenn der Pi nicht schnell genug ist (was wahrscheinlich ist, denn er wird immer mal von Aufgaben des Betriebssystems bei der Arbeit gestört), kannst du jedes Modul (oder mehrere oder alle) mit einem Mikrocontroller steuern und die Daten dann an den Pi senden - per Kabel oder per WLAN oder was auch immer. Ein Arduino Mega hat 54 GPIOs - du brauchst für 20 Leisten 60 GPIOs, wenn du nicht trickst und irgendwie mit weniger Photosensoren auskommst.

    Jedes Modul mit einem eigenen kleinen Mikrocontroller auszurüsten, wäre auch kein Problem. Macht die Sache noch leichter modular zu handeln. Vielleicht wäre ein ESP8266/ESP12 hier eine gute Lösung (eingebautes WLAN). Funkverbindung hätte den Vorteil, dass du den Pi gleich vorne an die Bahn stellen und die Ergebnisse in Echtzeit anzeigen kannst.


    Ich hätte noch eine weitere Idee, falls du doch die Leisten mit den Kontakten bauen willst... Um dir die vielen GPIOs und das komplizierte Auswerten zu sparen, könntest du die Kontakte auf 100 in Reihe geschaltete Widerstände schalten lassen. Also je nachdem, welcher Kontakt getroffen wurde, ändert sich der Widerstand. Mit einem AD-Wandler könntest du den dann messen... (ginge auch mit zwei Reihen, um Doppelkontakte zu erfassen, wie du es vorgesehen hattest.) Fraglich ist nur, ob sich der Widerstand schnell genug einstellt und lange genug halbwegs stabil ist, um ihn hinreichend genau zu messen.



  • Werde die erste Idee erst mal versuchen. Da dem Laser die Strecke ziemlich egal ist kann ich die Strecke an beiden Seiten der Bahn ca. 20cm überstehen lassen und den Abstand der Laser auf 5cm erhöhen. Dadurch wären die Events zeitlich weiter auseinander, was für den RASPi vielleicht reicht.

    Wenn ich einen Arduino Uno benutze hat dieser ja schon USB; dann brauch ich wahrscheinlich den RASPi garnicht und brauche ja nur die 2 Time pro Station dem PC senden und dort weiter verarbeiten.

    Alleine schon wegen der entfallenen Justage der Stationen auf der Bahn und dem baulichem Aufwand beim Herstellen/Einsetzen der Kontakte habe ich mich momentan in deine Laser-Idee verliebt.

    Aber auch deine zweite Idee mit den Widerständen ist mir vorstellbar zumal hier nur 1EIN analoger Eingang benötigt würde.

    Bleibt mir also als Version im Hinterkopf, falls Laser nicht funktioniert.

    Lefty