Einlesen, speichern und ändern einer Choreografie von Tastendrücken

  • Hallo,


    ich bin Anfänger und habe mir ein Projekt für meinen Raspberry Pi vorgenommen.


    Das Projekt:


    Ich möchte einen Motor in einer vorher einstudierten Weise bewegen. Die Ausgangsposition des Motors ist A. Bei Tastendruck (z.B. Maustaste) fährt der Motor auf Position B. Beim Loslassen der Taste fährt der Motor wieder zurück auf Position A. Beim Abspielen der Aufnahme soll sich der Motor exakt(!) wieder in der gleichen Choreografie bewegen. Es darf nicht zu einer Zeitverzögerung /-abweichung kommen. Idealerweise kann ich die Aufnahme anschließend (als Liste?) anzeigen und bearbeiten. Ich programmiere in Python.


    Was fehlt mir noch?


    Das Bewegen des Motors funktioniert schon. Für die Aufnahme habe ich noch keine Lösung.


    Warum schreibe ich hier?

    • Ich finde viel über Keylogger. Diese geben allerdings nur eingegebene Events wieder. Der Zeitverlauf der Events wird dabei nicht berücksichtigt.
    • Modul pygame scheint mir den Zeitverlauf auch nicht zu liefern
    • Einige Module funktionieren offensichtlich nicht unter Linux und habe ich deshalb nicht weiterverfolgt: pyautogui, msvcrt
    • Gibt es eine Möglichkeit die Events zu speichern. Dafür müssten mehrere Werte jeweils abgelegt werden: Key, „up“ oder „down“, Zeitpunkt auf die 1/1000 s genau.

    Welche Ansätze könnten vielleicht weiterhelfen?

    import keyboard

    events = keyboard.record('esc')

    keyboard.play(events)


    Leider spielt es gar nichts ab, nachdem ich esc drücke…Vielleicht mache ich auch etwas falsch?!

    Vielen Dank für Eure Mühen!

    Edited 4 times, last by djust ().

  • Go to Best Answer
  • Hallo djust,


    das wird so nichts werden. Du hat nichts über das Betriebssystem geschrieben, das Du einsetzt. Auch nichts über den Motortyp.


    Das übliche Betriebssystem des RPi ist kein Realtime-OS (RTOS). Dadurch gibt es keine konkrete Aussage über Zeiten und Zeitabstände. Je kleiner die Intervalle umso unpräziser wird das.


    Schreibe zur Veranschaulichung mal ein ganz simples Programm, das nur zwischen zwei Sekundenwechseln einen Zähler hochzählt.


    Beim RPi kommst Du auf Ergebnisse in der Art, das die kleinste Zahl ungefähr bei 50 bis 60 % der höchsten Zahl liegt.


    Wenn Du einen Motor (Getriebemotor) zeitgesteuert auf die gleiche Position wie beim letzten Mal bringen willst, dann kann das aus diesem Grund nur auf 0,5 bis 2mal des Ausgangswertes genau - also untauglich - sein.



    Bei anderen Systemen betragen die Unterschiede Minimum zu Maximum ungefähr maximal 3%. Ist zwar auch nicht der Brüller - aber deutlich reproduzierbarer. Z.B. Asus Tinkerboard mit Linaro-OS.



    Einen Schrittmotor steuert man üblicherweise positionsgenau - aber nicht zeitgesteuert.


    Wenn Du also keine andere Möglichkeit hast, Anfangsposition und eine Zielposition zu "erkennen", dann wirst Du das Ziel nie treffen.


    Ändere Dein Design...

    Z.B. Abfrage der Tasten über einen Mikrocontroller. Mit einem Arduino erreichst Du z.B. eine Zeitauflösung beim Erkennen von Ereignissen von 4 Mikrosekunden.


    Aber auch hier wirst Du feststellen, dass 1000 mal delay(1 Millisekunde) > delay(1 Sekunde) ist. Also nur bedingt brauchbar.


    Z.B. Verwende Schrittmotoren. Bei jedem Ereignis merkst Du Dir die Position. Beim Abspielen der Choreographie brauchst du nur die gemerkten Positionen anzusteuern. Das ist um Größenordnungen genauer und absolut reproduzierbar.


    Zum Aufzeichnen und Wiederabspielen von von Anwendern ausgelösten Ereignissen nutze ich Techniken des Eventmultiplexings (aber nicht Python).



    Beste Grüße


    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    • Icon-Tutorials (IDE: Geany) - GPIO-Library - µController-Programmierung in Icon! - ser. Devices - kein Support per PM / Konversation

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

    Edited 3 times, last by Andreas: Ergänzt ().

  • Vielen Dank für Eure Antworten!


    Ich habe schon befürchtet, dass der Pi für die Anwendung zu unpräzise ist.


    Als Betriebssystem nutze ich Linux. Ich nutze einen günstigen Motor (Longruner SG90 Micro Servo Motor 9G), den ich bei Bedarf auch durch einen hochwertigeren ersetzt hätte. Allerdings wollte ich zuerst die richtige Software programmieren.


    Natürlich hätte ich gerne einen Code präsentiert. Mein erster Code hat den Motor bewegt und mit einer fest hinterlegten Liste habe ich eine grobe Choreografie programmiert. Allerdings zeigte sich hier schon, wie unterschiedlich die Ergebnisse von einem Lauf zum anderen Lauf waren. Meine Hoffnung war, dass ich durch das manuelle Einspielen einer Choreografie das Ergebnis verbessern könnte.


    Mir erschien die Wahl der Methode eine Kernfrage zu sein, um die herum ich dann das weitere Programmieren lerne. Ich habe schon verschiedene Ansätze programmiert, allerdings hat keine der Methoden mich weitergebracht.


    Ich werde die Ideen von Andreas überdenken. Zusammenfassend gesagt, muss ich das ganze Setup ändern: Hardware und sogar die Programmiersprache. Die Alternative ist auch, ein anderes passenderes Projekt zum gegebenen Setup zu wählen.


    Andreas, Du hast mir sehr geholfen. Somit laufe ich nicht weiter in die falsche Richtung 😊.


    Vielen Dank nochmals!






  • Hallo djust,


    dass Du ein Anfänger sein könntest, habe ich schon vermutet.


    An Deiner Stelle würde ich erst mal programmieren lernen. Die zum jeweiligen Programmierskill passenden Projekte ergeben sich dann wie von selbst.


    Wenn Du dann mal so weit bist, Dich Deiner hier vorgestellten Idee wieder anzunähern, dann käme sogar ein Raspberry Pi in Frage, sofern Du ihn als Bare Metal nutzt. Da läuft dann kein Betriebssystem (mit all seinen Unzulänglichkeiten bzgl. Real Time) sondern nur Deine Anwendung. Du nutzt den RPi dann quasi als µController - als sauschneller µController.


    Wenn Bare Metal nicht in Frage kommt, dann könntest Du mit einem ASUS Tinkerboard wahrscheinlich sehr nahe an Deine Wünsche herankommen. Das Tinkerboard lässt sich im Prinzip genauso wie ein Raspberry Pi programmieren. Dessen Standard-Betriebssystem kommt einem Real-Time-OS relativ nahe.


    Aber ums Programmieren (egal welches System) kommst Du nicht herum. Und Du musst natürlich die Hardware einsetzen, die die beste Eignung aufweist. Für Dich ist es wahrscheinlich am sinnvollsten, zuerst zu versuchen herauszufinden, ob Du mit Schrittmotoren weiterkommst. Dann lässt sich der Rest sogar mit recht lausiger Programmierung erreichen.



    Beste Grüße


    Andreas


    .

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    • Icon-Tutorials (IDE: Geany) - GPIO-Library - µController-Programmierung in Icon! - ser. Devices - kein Support per PM / Konversation

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Hallo Andreas,


    meinen Anfänger-Status hatte ich ja gleich zu Beginn offenbart ;)

    Bitte sein so nett und beantworte noch kurz Fragen, die mir wegen Deiner Vorschläge kommen:

    1. Wenn ich mit Python nicht weiterkomme, womit sollte ich dann programmieren?

    2. Das ASUS Tinkerboard empfiehlst Du wegen seines geeigneteren Betriebsystems und der mit einem Betriebsystem einhergehenden einfacheren Handhabung? Ich könnte ja laut Deines Vorschlages den Pi auch als Mikro-Controller verwenden.

    3. Warum empfiehlst Du mir im ersten Schritt die Verwendung eines Schrittmotors? Stellt dies eine eigene Herausforderung dar, weil dieser anders zu programmieren ist? Oder einfach nur wegen deren Präzision. Warum frage ich: Ich möchte die schwierigen Dinge in diesem Projekt gleich zu Anfang angehen. Die Programmierung des Servo-Motors habe ich ja nun schon hinbekommen. Die Schwierigkeit liegt nun offensichtlich in der Programmierung der Zusatzfunktionen (Aufnahme der Choreografie etc.) und das mit Hardware, die Leistungsfähig genug ist. Den Motor müsste ich ja anschießend "nur" noch austauschen.


    Viele Grüße

    djust

  • Wie viel Geld möchtest du ausgeben?


    Für einen Linearantrieb habe ich mal Motoren von henschel-robotics verwendet.

    Der Vorteil ist, dass alles im Motor integriert ist und die Ansteuerung via Ethernet geschieht.

    Die Latenz ist recht gering und die Ansteuerung der Position sehr genau. Habe jetzt keine Werte im Kopf,

    aber es reichte aus um ein Radar-System auf einem Stativ 0.1° genau so positionieren.


    Da kann man sich aussuchen, welches Protokoll man verwendet. XML und ein binäres Protokoll werden unterstützt.

    Gleichzeitig kann man viele von diesen Motoren via CAN-Bus (ist mit dabei) synchronisieren.


    Jedenfalls ist der Unternehmer sehr freundlich und hat für uns die Motoren modifiziert.

    Die neuen Modelle sind Industrie-Tauglich und haben auch entsprechende M12 Stecker.

    Schade, dass ich momentan was anderes mache...

    Jedenfalls ist das mal keine Bastellösung.

    Bastellösungen gehen auch, aber da würde ich dann eher einen Mikrocontroller genauer gesagt Arduino zur Ansteuerung verwenden.

    Dafür gibt es Boards inklusive den Leistungsteil für Schrittmotoren.

    Ein Computer mit einem Betriebssystem hat zu viel um die Ohren, um etwas sehr genau zeitlich aufeinander abstimmen zu können.

    Deswegen verwendet man für Antriebe fast immer dedizierte Hardware, um die CPU zu schonen und Jitter zu vermeiden.

    Selbst in der Industrie wird das so gemacht. Umrichter steuern die Antriebe und SPS steuern die Umrichter.

  • Cool, DeaD_EyE!

    Danke für Deine Erläuterungen. Ich versteht im Moment noch nicht alles. Das werde ich aber mit dem alleswissenden Internet abgleichen. Der Motor sieht gut aus. Allerdings muss ich erst schauen, wie eine Steuerung über Ethernet dann funktioniert. :)

    Aber gut aussehen tut er ja. Die Kosten sind mäßig wichtig. Wenn ich dieses Projekt erfolgreich abgeschlossen habe, wartet das nächste Projekt und der Motor sollte ja so lange halten.

  • So, jetzt habe ich einen ersten Code, den ich vorzeigen kann. Ich habe mal meine Anfängerkommentare drin gelassen. Vielleicht hilft das dem ein oder anderen, meine Gedankengänge nachzuvollziehen. Ich hoffe, den Quellcode im richtigen Format eingegeben zu haben.


    • Best Answer

    djust: Bezüglich der Kommentare: Die sind zwar nützlich um Deine Gedanken nachzuvollziehen, machen das in der Form aber schwerer lesbar weil die zu vielen sehr langen Zeilen führen und die dann entweder rechts ”verschwinden” oder umgebrochen werden und dann sehr irritieren.


    Wie gesagt verstehe ich die Intention hier, aber in normalem Code sollten so wenige Kommentare wie möglich stehen, und stattdessen der Code so lesbar und verständlich sein. Faustregel für Kommentare: Nicht kommentieren *was* der Code macht, denn das steht da bereits als Code, sondern warum der das so macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in der Regel was in der Dokumentation der Programmiersprache und den verwendeten Bibliotheken steht.


    Den Kommentar beim `pygame.init()` finde ich widersprüchlich. Der fängt an mit „pygame muss initialisiert werden“ und endet mit „Keine zwingende Funktion.“


    ``as`` bei Importen ist zum umbenennen gedacht, `GPIO` wird aber gar nicht umbenannt.


    Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst. Daraus folgt auch das man keine globalen Variablen verwendet und das Funktionen und Methoden alles was sie ausser Konstanten benötigen als Argument(e) übergeben bekommen.


    Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).


    `p` ist kein guter Name weil der dem Leser nicht vermittelt was der Bedeutet. Einbuchstabige Namen sind selten gute Namen. Es gibt wenige Ausnahmen wie `i`, `j`, `k` als Indexvariablen oder `x`, `y`, `z` für Koordinaten, weil das übliche und bekannte Namen aus der Mathematik für diese Zwecke sind.


    Statt `time.time()` sollte man `time.monotonic()` für Zeitmessungen verwenden. Ein `float()`-Aufruf ist bei beiden Funktionen unnötig weil die bereits eine Gleitkommazahl liefern.


    Das die Funktionen zum Programmabschluss nicht am Ende stehen, sondern mitten in einer verschachtelten Schleife ist unübersichtlich. Das sollte a) tatsächlich am Programmende stehen und b) sollten die wirklich wichtigen Aufräumarbeiten wie der `cleanup()`-Aufruf auch sichergestellt werden wenn das Programm nicht den normalen Weg nimmt, sondern beispielsweise wegen einer Ausnahme abbricht.


    Die Klammern um die Werte bei ``return`` sind überflüssig.


    Ungetestet:

    “The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in; we're computer professionals. We cause accidents.” — Nathaniel Borenstein

  • __blackjack__: Da hast Du mir ja mal einen klasse Code hingezaubert. Der schnurrt wie eine Katze :) (Zeile 45 hat nur ein f zu viel).

    Deine Anmerkungen sind mir sehr willkommen und sehr hilfreich! Vielen, vielen Dank für Deine Mühen! Toll dass Ihr alle soviel Zeit für meine Idee opfert. So ein überarbeiteter Code ist eine super Hilfe. Ich lerne viel dabei!


    Ich werde den Code nun als Grundlage für die weitere Arbeit nutzen und versuchen, mich an die Regeln zu halten :)


    Als nächstes werde ich die Zeiten beim Drücken der ENTER-Taste abspeichern und versuchen diese wieder auszulesen, um den Motor autonom fahren zu lassen. Bisher habe ich keine Funktion gefunden, die dies direkt unterstützt, aber vielleicht kann ich es mit einer Liste erreichen, die ich dann in eine Datei speichere.

  • Wenn Zeile 45 ein f zu viel hat, dann ist die Python-Version zu alt (<3.6). Oder welches f habe ich da übersehen‽

    “The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in; we're computer professionals. We cause accidents.” — Nathaniel Borenstein

  • Dann ist wie gesagt Dein Python zu alt. Was für ein System hast Du denn da installiert? Und/oder wie lange ist das schon her?

    “The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in; we're computer professionals. We cause accidents.” — Nathaniel Borenstein

  • Mhhh...nach der Fehlermeldung habe ich nur das f gelöscht. Das System (Stand 3.4.2, sollte ich wohl aktualisieren) hatte eine Fehlermeldung herausgegeben. Es funktionierte dann eigentlich ganz gut.

  • djust Wenn Du nur das f entfernst, dann werden die Platzhalter in der Zeichenkette nicht durch die Werte ersetzt. Und 3.4 ist dann wohl schon ein etwas älteres System. Das was ich aktuell habe was am weitesten hinterher hinkt ist ein RPi mit OSMC und das hat ein Python 3.5 als Standard 3er.

    “The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in; we're computer professionals. We cause accidents.” — Nathaniel Borenstein

  • Mir fehlt ja ein bisschen Hintergrund, um besser beurteilen zu können, ob dein Ziel erreichbar ist. Meine Vorredner haben natürlich gute Punkte bezüglich zb der Echtzeitfähigkeit des PI (oder besser von Linux) gebracht, aber ich sehe noch nicht, dass das zwingend notwendig ist. Klar bekommt man unterschiedliche Wartezeiten und einen großen Fehler, wenn man sagt “warte 10ms”, und die dann stumpf aufsummiert. Darum ist aller Code, der etwas mit hoher zeitlicher Güte machen soll, anders geschrieben: man misst die vergangene Zeit, und steuert zb den Motor davon abhängig. Dadurch gleicht sich der “Jitter” oft vollkommen ausreichend aus.


    Und wenn es denn doch die Echtzeit sein soll oder muss, so ist auch das nicht aussichtslos. Runter bis 500uS kommt man mit dem PI, allerdings musst du dann C/C++ bemühen. Oder es reicht ggf PiGPIO zu nutzen, denn das benutzt DMA und ist damit unabhängig vom scheduling jitter.


    Aber wie gesagt: details, was da eigentlich erreicht werden soll, tun IMHO Not.

  • @__deets__: Ja, vielleicht ist der Ansatz, die vergange Zeit zu Messen gut. Vielleicht auch ausreichend. Vermutlich muss ich die Zeitabstände zum Start des Programm speichern und nicht die einzelnen Phasen (Drücken und Nicht-Drücken), weil ich sonst die Fehler aufsummiere.


    Was ist mein Ziel?

    Ich möchte mich dem Thema, wie steuere ich Hardware mit Software/RPi nähern. Dazu habe ich mir dieses kleine Projekt ausgedacht: Ich möchte mit dem Motorarm ein Spiel auf dem Handy spielen, welches verhältnismäßig simpel ist. Bisher habe ich einfach Werte in einer Liste gespeichert und damit die Choreografie definiert. Obwohl ich die Werte identisch lies, war der Erfolg unterschiedlich. Wenn ich es selber Spiele, kann ich Abweichungen korrigieren.


    Da ich aber keine KI programmieren kann :) versuche ich die Choreografie vorher einzuspielen, in der Hoffnung bessere Ergebnisse zu erzielen. Die eingespielte Choreografie muss natürlich möglichst exakt gespeichert und wiedergegeben werden.


    Der Weg ist das Ziel.