Einige aber nicht alle M5-Geräte sind mit einem AXP192 als Powermanagementsystem ausgestattet. Dieses IC biete viele Möglichkeiten zur Überwachung und Steuerung der Stromversorgung. Hier stelle ich ein Blockly Programm vor, dass die interessantesten Daten auf dem Bildschirm ausgibt.
Ich habe das Programm auf einem M5Stick C plus entwickelt. Mit entsprechender Anpassung der grafischen Oberfläche läuft es auch auf einem M5Stick C und einem M5Stack Core2. Nur diese 3 Geräte haben derzeit einen AXP192 als Powermanager.
Das Programm kann dauerhaft auf des Gerät geladen und bei Bedarf gestarte werden.
Das Bild oben zeigt, was alles angezeigt wird. Zur Zeile Ladestrom ist noch eine Erklärung nötig. Für den M5Stick C/plus gibt es diverse Hats mit einem eigenen Akku. Der kat keine eigene Ladeelektronik, sondern wird einfach parallel zum eingebauten Akku geschaltet. Diese Akkus haben eine Kapazität von 700 – 750mAh. Die Voreinstellung für den Ladestrom liegt bei 100mA. Da kann sich jeder selbst ausrechnen wie lange es dauert bis der Akku voll ist. Bei dem eingebauten mit 90mAh dauert es nur eine Stunde.
Deshalb habe ich eine Ladestrom Umschaltung mit Taster B eingebaut. Voreingestellt sind weiterhin 100mA. Ein Druck auf Taster B schaltet den Ladestrom auf 360mA um. Ein weiterer Druck auf Taste B schaltet wieder auf 100mA zurück. Wenn die Ladung abgeschlossen ist oder unterbrochen wird schaltet das Programm automatisch auf 100mA zurück.
Der Ladestrom kann auf vorgegebene Werte zwischen 100mA und 1A eingestellt werden. Das lässt sich auch im Programm ändern. Allerdings sollte man wissen was man tut, wenn man sich daran macht.
Die grafische Oberfläche wurde mit den UI-Simulator in der UIFlow IDE erstellt. Dashalb erscheinen im Programm keine Blöcke zur Positionierung. Der Vorteil ist, dass das Display beim Neuaufbau nicht flackert. Das erledigt die Firmware ohne das man etwas davon wahrnimmt. Mit CLS und dem lcd.print Block aus der Textsammlung gibt es erheblich Flackereffekte.
Wenn daran Änderungen vorgenommen werden sollen, dann müssen die entsprechendn Elemente in diesem Bild verschoben werden.
Nachdem der Fernsteuersender funktioniert ist jetzt der Empfänger dran.
Anforderungen
Die Umsetzung in kleinen Schritten
Das MAC-Adress Problem
Das erste Problem war, dass der M5Stack C mir mit dem Block „get mac adress“ 24:a1:60:53:bc:15 anzeigt. Als Absenderadresse sendet er aber 24:a1:60:53:bc:14.
Der erste Versuch – Kontaktaufnahme
Als die MAC-Adresse angepasst war funktionierte das erste Programm:
Der zweite Versuch – Daten extrahieren – dauert etwas länger
Nun der nächste Versuch. Die Daten hatte ich im Senderprogramm in eine Liste getan. So werden sie auch auf dem vorherigen Bild im Empfänger dargestellt. Diese soll nun entpackt werden, damit ich die einzelnen Werte verwenden kann:
Das Ergebnis verwundert mich dann doch sehr:
Das sieht so aus, als wären die Daten nicht als Liste, sondern als String übertragen worden. Index 0 gibt das letzte Zeichen „]“ aus, Index 1 das erste „[“ und Index 2 das zweite „0“.
Der Versuch den empfangenen String in eine Liste umzuwandeln bleibt auch erfolglos.
Die list() Funktion aus Python habe ich dann versucht:
Erstaunlich ist jedoch, dass die Ausgabe von rx_list leer ist oder ein # enthält (erste Zeile im Display), wärend die daraus extrahierten Werte „richtig“ angezeigt werden:
Allerdings ist damit dem Problem nicht bei zu kommen. Hier macht die typlosigkeit von Python wohl Probleme.
Der Versuch rx-data zu addieren endet mit einer Fehlermeldung (rotes Kreuz auf dem Display) ohne weiter Informationen.
Wenn rx_data aber vorher in ein Integer umgewandelt wird funktioniert die Addition und es wird die 2 im Display angezeigt.
Damit ist klar, der Wert wird immer als String gesendet! Und die Konvertierung in eine Liste funktioniert nicht. Nun ist guter Rat teuer. Mit Stringverarbeitung möchte ich mich hier nur ungern abgeben. Dauert lange und braucht viel RAM.
Das hätte ich viel einfacher haben können:
espnow.send(id=1, data=str(send_data))
So steht es im Micropython Code.
Trotz Brille
Diesen Block habe ich glatt übersehen.
Ins Programm eingefügt:
Und …
Das sieht doch schon besser aus. Die einzelnen Werte sind nun richtig getrennt. Aber die Klammern stören noch und es sind Leerzeichen enthalten.
Wie erwartet führt dieser Versuch zu einer Fehlermeldung, weil nicht numerische Zeichen enthalten sind. Also bleibt nur noch die Klammern und Leerzeichen gezielt zu entfernen.
Die Zeile
espnow.send(id=1, data=str(send_data))
bringt mich auf eine andere Idee. Den Micropython mit dem Ausführen Block ohne str() einbauen. Mal sehen ob’s klappt.
Fehlermeldung: „Type should be bytes or string“. Es wäre auch zu schön gewesen.
Also musste ich mich doch mit der Stringmanipulation beschäfftigen. Allerdings war es dann doch nicht schlimm wie ich befürchtet hatte. Zuerst habe ich die eckigen Klammern aus dem String rx_data entfernt. Dann daraus eine Liste erstellt und bei der Gelegenheit gleich die überflüssigen Leerzeichen entfernt. Schließlich erfolgt noch die Umwandlung in Integer oder Float. Damit habe ich die Daten so wie ich sie haben möchte.
Das Programm dazu sieht so aus:
Und die Anzeige zeigt rx_list immer noch nicht an. Die anderen Ausgaben entsprechen den Erwartungen. X-Wert (int), Y-Wert (int) und Batteriespannung (float).
Der Grund für die fehlend Anzeige von rx_list ist vermutlich, dass der Block „LCD ausgeben“ keine Typumwandlung von list zu String vornimmt. Das baue jetzt mal ins Programm ein.
… das war’s:
Das Ziel dieses Programms ist aber nicht die Werte anzuzeigen, sondern Servos anzusteuern. Also los auf zur nächsten Runde!
Etwas mit den Daten machen.
Die empfangenen Daten sollen 2 M5Stack 360° Servos als Antrieb für ein kleines LEGO-Fahrzeug steuern. Deshalb habe ich zuerst ausprobiert wie die Servoansteuerung funktioniert. Dazu habe ich ein kleines Gestell mit LEGO Steinen gebaut an dem die 360° und 180° Servos befestigt sind.
Das ist mein erstes Programm zum Servotesten:
Zur Servoansteuerung wurden nur die 4 Blöcke „set servos rotate“ hinzugefügt. Wenn man vorher am Servos Hat den kleinen Schalter auf ON stellt klappt’s dann mit den Servos.
Vorher musste ich die empfangen Daten aber noch aufbereiten. Die Servoansteuerung erfolgt mit Ganzzahlwerten zwischen 0 und 180. Bei den Servos ist also 90 die Grundstellung bzw. der Motorstillstand. Das ist ein Anlass die Übertragung von Wertung zwischen -100 und +100, die ich im Moment im Sender implementiert habe zu überdenken. Das hat aber noch Zeit. Zuerst soll alles zuverlässig funktionieren. Dann kann ich an Modifikationen denken.
Der Wert muss dem Servo nur einmal übermittelt werden. Er bleibt dann solange eingestellt bis ein neuer Wert übermittelt wird.
Das erste Testprogramm wertet nur die X-Achse aus und schickt diesen Wert zu allen 4 Servos. Die 180° Servos bewegen sich dabei parallel, die 360° drehen hingegen entgegengesetzt.
XY zu 2X
Die Überschrift dieses Kapitels sieht nach Mathe aus und ist es auch. Vom Sender kommen Werte für die X- und Y-Achse. Wenn aber keine normale Steuerung wie sie im Kfz üblich ist eingesetzt wird, sondern 2 Motoren parallel laufen, dann müssen diese unterschiedlich schnell drehen um eine Kurve zu fahren. Diese Aufgabenstellung gibt es auch in der Fliegerei bei Flugzeugen mit V-Leitwerk.
Nach einigen Überlegungen und Versuchen bin ich zu folgender Lösung gelangt. Die X- und Y-Werte werden für den einen Motor addiert und für den anderen subtrahiert. Dann sind noch einige Anpassungen erforderlich und schon passt es.
Nun noch die detailierteren Erklärungen:
Hauptprogramm
Das Hauptprogramm enthält hier die wesentlichen Teile des Code.
Setup
Im Setupteil wird zuerst das Display eingerichtet. Anschließend mit dem „Add peer“ Block ESP Now eingerichtet. Im zweiten „Add Peer“ Block wird die MAC Adresse des Senders eingetragen, damit der Empfänger Daten zum Sender schicken kann, z.B. Batterie ist schwach. Diese Funktion ist noch nicht implementiert. Die Variable rx_flag signalisiert dem Hauptprogramm wenn neue Daten eingetroffen sind. Deshalb erstmal auf 0 – keine neuen Daten gesetzt. Schließlich wird die RGB-LED auf dem Servos Hat in grün eingeschaltet.
Loop
In der Loop wird zuerst nachgeschaut ob Post (neue Daten) eingetroffen sind. Wenn nicht hat sie nichts zu tun und langweilt sich.
Wenn aber neue Daten vorhanden sind, also rx-flag = 1 ist, wird zuerst die RGB-LED auf rot gesetzt, das signalisiert neue Daten werden bearbeitet.
Die weiteren Abschnitte werden gleich erklärt.
Am Ende des aktiven Abschnittes wird rx-flag wieder auf 0 gesetzt und die RGB-LED wird wieder grün.
Nun zu den übersprungenen Abschnitten.
Stringliste entpacken
In Blockly verschickt ESP Now die Daten immer als String. Die Daten wurden im Sender in eine Liste gepackt. Im String wird die Liste nun incl. „[“ und „]“, Leerzeichen und Kommas dargestellt. Daraus müssen nun die Daten herrausgepult werden.
Die ersten beiden Blöcke entfernen die beiden eckigen Klammern. Aus dem übrig gebliebenen String lässt sich nun eine Liste machen. Deren Elemente sind auch Strings und enthalten noch die Leerzeichen. Diese werden mit den nächsten drei Blöcken entfernt. Gleichzeitig werden die Daten noch in integer bzw. float bei der Batteriespannung umgewandelt. Nun liegen die Daten so vor, dass sie weiterverarbeitet werden können.
XY Mischen
Hier werden die Geschwindigkeitswerte für die beiden Motoren errechnet von -100 … +100 auf 0 … 100 angehoben.
Bereichsanpassung
Nun wird noch die Drehrichtung angepasst und auf den Bereich 0 – 180 skaliert.
Anzeige
Eine Anzeige ist im Empfänger nicht wirklich erforderlich. Ich habe sie für Programmentwicklung benötigt. Diesen Teil kann man entfernen, oder sie den eigenen Bedürfnissen anpassen.
Empfangsroutine
Der Empfang der ESP Now Daten geschieht im Hintergrund. Da braucht man nichts zu programmieren. Allerdings muss bekannt sein, wo die MAC-Adresse des Absenders und die Daten gespeichert werden sollen. Die entsprechenden Variablennamen müssen „Receive“ Block eingetragen werden. Wenn Daten empfangen wurden, wird das darunter eingetragene Programm abgearbeitet (Interrupt Service Routine oder callback genannt). Hier wird nur geprüft, ob die Daten vom zugeordneten Sender kommen und eine Flagge (rx_flag) gehisst, die dem Hauptprogramm mitteilt, das es nun Daten verarbeiten muß.
Bei der MAC-Adresse die zu prüfen ist muss beachtet werden, das diese im 1 kleiner ist als die mit dem entsprechenden Block abgefrage MAC-Adresse.
Notaus
Bei meinen Experimenten ist es häufiger vorgekommen, dass die Servos nicht mehr abgeschaltet werden konnten, weil die Skalierung nicht stimmte. Deshalb habe ich mit der Taste A einen Notaus eingebaut.
Das Programm ist so wie es jetzt ist einsetzbar. Ich werde aber später noch den Rückkanal implementieren, der Statusdaten des Mobils an den Sender schickt.
Drehimpulsgeber sind beliebte und vielseitige Eingabegeräte. Im M5-Universum gibt es leider nur einen für den M5Face. Deshalb habe ich mich drangesetzt und eine Routine für die anderen M5-Geräte entworfen. Diese ermöglicht den Einsatz eines Drehimpulsgebers mit der UIFlow-IDE und Blockly / Micropython.
Als Hardware kommt ein M5Stick C plus und ein Drehimpulsgeber von az-Delivery zum Einsatz. Der Drehimpulsgeber hat 3 Pullup Widerstände auf der Platine.
Der Drehimpulsgeber liefert 3 digitale Signale. Davon liefern zwei die Information über den den aktuellen Zustand des Drehgebers und eines den Zustand des Tasters. Im Ruhezustand liefern alle drei Signale eine 1.
Es gibt im Internet so einige Beschreibungen zum Thema Drehimpulsgeber. Einige davon basieren auf Interrupts, die zwar beim ESP32 vorhanden sind, aber in UIFlow und Blockly nicht zur Verfügung stehen. Deshalb habe ich mich für einen pragmatischen Ansatz entschieden. Ich habe die 2 Bits in eine Zahl umgewandelt und mir angeschaut was passiert. Dabei ist herausgekommen, dass im eingerasteten Zustand die Zahl 3 (0b11) ansteht. Beim Drehen bis zur nächsten Rastung entsteht entweder die Zahlenfolge 201 für vorwärts oder 102 für rückwärts. Dann steht wieder die 3 beim nächsten Rastpunkt an. Es ist also nur wichtig zu wissen welche Zahl nach der 3 kommt. Ein überschaubares Problem.
Nun gibt es aber auch noch einen Taster, der ebenfalls abgefragt werden soll. Dieser liefert im Ruhezustand 1, wenn er gedrückt wird eine 0. Deshalb habe ich eine 3-Bit-Zahl zu Grunde gelegt. Es wird dann fortlaufend der Zustand des Drehimpulgebers eingelesen. Wenn eine 7 (entspricht der 3 im obigen Absatz) eingelesen wird, wird ein Flag gesetzt. Wird eine 5 (1) eingelesen, wird geprüft, ob das Flag gesetzt ist. Wenn nicht wird der Wert ignoriert. Wenn ja, so wird das Flag zurückgesetzt und -1 ausgegeben. Bei einer 6 (2) erfolgt die selbe Prozedur, nur wird dann 1 zurückgegeben. Wenn die Zahl < 4 ist, ist der Taster gedrückt und es wird eine 0 zurückgegeben. Die anderen Werte interessieren dann nicht. Wird eine andere Zahl eingelesen, wird diese ignoriert.
Bei dieser Lösung wird das Programm blockiert, solange keine Eingabe erfolgt. Es können auch keine Tastendücke unterschiedlicher Länge identifiziert werden. Weiterhin findet keine Entprellen der Kontakte statt, so dass es gelegentlich zu falschen Werten kommt. Wenn die Impulse nicht gezählt, sondern als Zahl im Display angezeigt werden ist das zwar nicht schön, aber für Bastler m.E. aktzeptabel. Für den Anfang soll es so genügen. Spätere Verbesserungen sind ja immer möglich.
Zunächst müssen unter Setup die verwendeten Pins initialisiert werden:
Und nun das Programm:
Nach einigem hin und her funktionierte das Programm dann ordnungsgemäß. Anfangs gab das Programm zwar die Werte 1 und -1 korrekt zurück, bei der 0 wurden aber immer viele Nullen ausgegeben. Ich habe lange nach der Ursache gesucht. Schließlich stellte ich fest, dass der nächste und viele weitere Aufrufe von dig_auswerten erfolgten bevor ich den Taster wieder losließ. Deshalb habe ich die Warteschleife für die Tasterauswertung eingebaut. Nun läuft das Programm.
Einen eigenen Block erzeugen
Nun werde ich versuchen einen eigenen Block für diese Funktion zu erzeugen. Eine umfangreiche Beschreibung des Blockmaker werde ich an anderer Stelle machen. Hier nur soviel wie nötig.
Es werden drei Blöcke benötigt:
init_dig – zum Initialisieren der Ports
read_dig – den aktuellen 3-Bit-Wert ermitteln
get_dig – daraus den Rückgabewert erzeugen und zurückgeben
Ich habe mich hier für englische Bezeichnungen entschieden, weil es sich dabei um die internen Bezeichnungen handelt und Englisch in der Programmierung Standard ist. Wobei dig dann in ris (rotary impuls switch) geänder werden müsste. Der Name des Blocks kann in Deutsch erfolgen.
Nachdem ich nun einige Zeit mit dem Blockmaker oder besser mit meinen mangelnden Pythonkenntnissen und einigen Nachlässigkeiten beim Testen zu kämpfen hatte, ist es mir gelungen entsprechende Blöcke zu erstellen.
Da die UIFlow-IDE die Blöcke wie Macros in den Code einfügt, ist der Block read_dig überflüssig geworden. Dessen Code habe ich gleich bei get_dig eingefügt. Die beiden übriggebliebenen Blöcke heissen jetzt init_dig und hole nächsten Impuls. Wie versprochen in deutsch.
Anwendung der Blöcke
init_dig
Wie der Name schon verrät wird mit diesem Block die Verwendung eines Drehimpusgebers initialisiert. In den Feldern pinA und pinB sind die Nummern der Pins anzugeben an denen die Anschlüsse A und B oder wie immer sie heissen mögen des Drehimpulsgebers einzutragen. Die Pinnummer des Tasteranschlusses wird bei pinT eingetragen. Das ist schon alles was zur Vorbereitung des Drehimpulsgeber Einsatzes erforderlich ist.
Hier gibt es aber einige Einschränkungen zu beachten: Es kann nur ein Drehimpulsgeber angeschlossen werden. Der Drehimpulsgeber kann nur direkt an Pins des M5-Gerätes angeschlossen werden. Ein I/O-Expander kann nicht eingesetzt werden. Weiterhin werden die drei Pins intern als Eingang und float initialisiert. Es ist also jeweils ein externen Widerstand gegen +3,3V erforderlich, so wie es bei dem von mir verwendeten Modul der Fall ist. Letzters kann leicht mit dem Blockmaker im Code geändert werden.
Da habe ich wohl schon ein neues Projekt 😉
hole nächsten Impuls
Die Impulse des Drehimpulsgebers werden einzeln geholt. Der Rückgabewert dieses Blocks ist:
1 = ein Schritt vorwärts
-1 = ein Schritt rückwärts
0 = Taster gedrückt (erst wenn Taster losgelassen wurde)
Wobei vorwärts und rückwärts sich auf meinen Testaufbau beziehen und hängt davon ab, welche internen Schalter des Drehimpulsgebers jeweils an pinA und pinB liegen. Wenn die falsche Richtung erscheint kann man:
die Kabel an pinA und pinB vertauschen,
im Blockmaker die Ausgabewerte ändern oder
die Auswertung umstellen auf -1 vorwärts und 1 rückwärts.
Wichtiger Hinweiß
Wenn Du in einem Blockly-Programm eigene Blöcke verwendest und es erneut in die IDE laden willst, so musst Du vorher die eingen Blöcke (das *.m5b-File) in die IDE laden, sonst wird das Blockly-Programm nicht geladen!
Nun viel Spaß beim Basteln.
Download
Geht noch nicht, weil WordPress den Upload der Datei noch blockiert und „WP Extra File Types“ nicht funktioniert. Ich arbeite daran.
wenn kein Blockcode eingetragen ist speichert der Blockeditor nicht. Im Zweifelsfall hilft ein # (Kommentar) Zeichen im Codefeld.
Kontakt
Wenn Jemand sich zu diesem Beitra äußern möchte, mich auf Fehler hinweisen oder Tipps dazu geben möchte, so geht dass über die Emailadresse peter@peters-bastelkiste.de
Die Kommentar- und Diskussionsfunktion ist noch nicht freigeschaltet.
11. Januar 2021 · Kommentare deaktiviert für Herzlich Willkommen auf meiner Website! · Kategorien: Allgemein
Diese Website ist ein rein privates Projekt. Es verfolgt keinerlei kommerzielle Ziele. Deshalb werden von mir auch keine persönlichen Daten gespeichert. Deshalb kann sich auch niemand auf dieser Website anmelden und Kommentare hinterlassen. Der Provider (1blu.de) speichert die Verbindungsdaten für einen begrenzten Zeitraum.
Dieser Blog dient mir dazu meine Projekte zu dokumentieren und meine Erfahrungen damit festzuhalten. Er ist im Internet frei zugänglich, damit auch Andere von meinen Erfahrungen profitieren können. Schließlich muss nicht jeder das Rad selbst erfinden.
Mein Beiträge sind keine Bauanleitungen! Es besteht kein Anspruch darauf, dass die vorgestellten Projekte bei einem Nachbau funktionieren! Sollten dabei Schäden entstehen, so ist dafür der Nachbauer verantwortlich. Schließlich sollte jeder wissen was er tut. Ich schließe jede Haftung aus.
Die Beiträge können nur als Anregung angesehen werden.
Wenn Du mir etwas mitteilen möchtest, so schicke mir unter peter@peters-bastelkiste.de eine Email.
Neueste Kommentare