|
[ Home
] [ Seitenende ] [ Teil 1 ] [ Teil 2b ] [ Teil 3 ] |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Roboter-Auto „Joy-Car“ - Teil 2a Vom schillernden
Regenbogen hin zu Stars mit NeoPixel Wir greifen das Programm „joy-car_teil_01_prog_14.py“
aus dem ersten Teil auf und erweitern die „NeoPixel“-Anzeige der Funktion <NeoPixel_anzeigen(anzeigen_ja_nein, Helligkeit_LEDs)> dahingehend, dass wir
dieser über den Parameter <anzahlNeoPixel> mitteilen, wie
viele von den insgesamt 8 bunten RGB-LEDs angezeigt werden
sollen (siehe roter Kasten). Anstelle der Regenbogenfarben mit dem Statement
<strip.show_rainbow(1, 360)> wird nun das 1.
Statement <strip.show_color(neopixel.colors(NeoPixelColors.RED))> verwendet. Später werden wir dann noch sehen,
wie sich Farben im laufenden Programm
jederzeit ändern lassen. - Wie man weiter unten im grünen
Kasten
sieht, wird die erweiterte Anzeige-Funktion
<NeoPixel_anzeigen(anzeigen_ja_nein, Helligkeit_LEDs, anzahlNeoPixel)> in einer sogenannten kopfgesteuerten
„Do … while“-Schleife gleich mehrfach
aufgerufen und ausgeführt, wobei sich jedes Mal die anzuzeigende Anzahl von NeoPixeln um +1 erhöht, sodass sich die NeoPixel-Reihe wie folgt darstellt: [ 0, 1, 2, 3, 4, 5, 6,
7, 8 ]: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_01.py“) Das 2.
Statement <schleifenZaehler += 1> bedeutet, dass der Wert der Variablen <schleifenZaehler> bei jedem Aufruf um den Wert +1 erhöht wird.
Dabei ist das Statement eine Kurzform vom 3.
Statement <schleifenZaehler = schleifenZaehler + 1> Mathematisch wird dabei der Wert der Variablen <schleifenZaehler> bei jedem
Aufruf inkrementiert,
d.h. um +1 erhöht. Ein weiteres, zukünftig 7 anzuwendendes Statement ist das Ermitteln der Anzahl angeschlossener „NeoPixel“-LEDs mit dem 4.
Statement <anzahlNeoPixel = strip.length()> Mit engl. „strip“ ist der „NeoPixel“-LED-Streifen gemeint, der im
vorliegenden Fall aus 4 x 2 LEDs besteht, wobei diese
über einen seriellen Datenbus „I2C“
angesteuert werden (siehe Bild). Dabei
steht die engl. Abkürzung „I2C“ für „Inter-Integrated Circuit“, d.h. Inter-integrierte
Schaltung bzw. integrierter Schaltkreis (für die Datenkommunikation zwischen
[= „Inter“] elektronischen Komponenten). Programmiertechnisch handelt es sich bei „strip“ um eine Instanz- bzw. Objektvariable,
die auf die Klasse <neopixel> zugreift: 5.
Statement <strip : neopixel.Strip = None> Fragen wir zu Abwechselung die KI von ChatGPT: (Zum Vergrößern bitte
auf das Bild klicken!)
NeoPixel
in Form einzelner bunter RGB-LEDs lassen sich aber
nicht nur der Reihe nach einschalten, sondern auch der
Reihe nach ausschalten. Und zwar mittels des 9.
Statements <strip.shift(1)> in der <for … next>-Schleife (siehe pinkfarbener Kasten): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_02.py“)
Wie der Parameter
1 im 10. Statements <strip.shift(1)> bereits nahelegt, lassen sich auch mehrere
NeoPixel als Ganzes
ausschalten: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_03.py“)
Bei dem „Joy-Car“-Roboterauto wurden bekanntlich
bis zu acht farbigen RGB-LEDs verbaut. Und zwar
jeweils in vier Zweiergruppen, davon je zwei Zweiergruppen vorn und zwei Zweiergruppen
hinten. Wenn man die acht farbigen RGB-LEDs der Reihe nach einschaltet, dann wird als Erstes
eine einzelne RGB-LEDs vorn links und als Letztes eine einzelne RGB-LEDs hinten rechts eingeschaltet. Das nächste Programm „joy-car_teil_02_prog_04.py“ soll so programmiert
werden, dass von den acht farbigen RGB-LEDs nur eine einzige
LED übrig bleibt, die
leuchtet. Und zwar die LED Nr. 4 vorn rechts. Zu diesem Zweck soll eine <for … next>-Schleife mit dem Schleifenkopf 11. Statement <for Index in range(1, anzahlNeoPixel + 1):> programmiert werden. Dabei stellt sich gleich
die Frage, weshalb der engl. „range“, d.h. der Bereich des Index bei 1 beginnt und nicht wie üblich bei 0. Wenn man sich das 12.
Statement <strip = neopixel.create(DigitalPin.P0, 8, NeoPixelMode.RGB)> in
der Funktion NeoPixel_anzeigen( anzeigen_ja_nein, Helligkeit_LEDs, anzahlNeoPixel) anschaut, dann fällt auf, dass es im
vorliegenden Fall insgesamt 8 NeoPixel gibt, die sich ansteuern lassen. Und zwar im Bereich [ 1, …, 8 ] und nicht wie sonst üblich im
Bereich [ 0, …, 7 ] = 8 unterschiedliche Werte. Und trotzdem gibt es bei den 8 NeoPixeln im Bereich [ 1, …, 8 ] einen Wert 0 im Gesamtbereich [ 0, 1, …, 8
] = 9 Werte.
Bemühen wir in diesem Zusammenhang wieder die KI von ChatGPD: (Zum Vergrößern bitte
auf das Bild klicken!) Wenden wir uns wieder der <for … next>-Schleife mit dem Schleifenkopf 14. Statement <for Index in range(1, anzahlNeoPixel + 1):> zu. Dazu muss man wissen, dass die Variable <Index> als Schleifenzähler der <for … next>-Schleife stets mit dem Wert Index = 0 beginnt! Da aber die NeoPixel immer von 1 an gezählt werden,
überspringen wir quasi den Wert Index = 0 und starten den „NeoPixel“-Zählbereich erst mit [ 1, …, 8 + 1 ]: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_04.py“)
Obwohl beim „Joy-Car“-Roboterauto bekanntlich bis zu acht
farbige RGB-LEDs verbaut wurden,
bedeutet das nicht zwangsläufig, dass wir bei der „NeoPixel“-Anzeige auch mit diesen acht
LEDs rechnen bzw. diese
auch anzeigen müssen! Im Gegenteil! Da nur die LED Nr. 4 vorn rechts leuchten soll, müssen wir von den vier
vorderen „NeoPixel“-LEDs insgesamt drei
ausschalten! Und zwar rückwärts von der ersten RGB-LED vorn links
(siehe pinkfarbener Kasten). Der
Nachteil vom Programm „joy-car_teil_02_prog_04.hex“
ist noch der, dass man die vier vorderen „NeoPixel“-LEDs
erst einschalten und zum Leuchten bringen muss, bevor man drei von
ihnen ausschalten kann, damit am Ende nur noch
die erste RGB-LED vorn links
leuchtet.
Aber das Problem lässt ähnlich wie beim Versteck
spielen der Kinder lösen: (Zum Vergrößern bitte
auf das Bild klicken!) Kurz und gut, bei der Programmierung der „NeoPixel“-Anzeigen muss man es so machen
wie die Dreijährigen. Zwar kann sich der „Joy-Car“-Roboter nicht die Augen
zuhalten, weil er keine Webcam hat. Aber er kann
seine NeoPixel quasi verstecken,
d.h. sie unsichtbar machen. Wie aber kann sich eine RGB-LED unsichtbar machen? Schwarz ist zwar auch eine Farbe, die aber im
Gegensatz zu anderen Farben praktisch alle Farbspektren des sichtbaren Lichts
absorbiert, quasi verschluckt. Das hat z.B. bei schwarz lackierten Autos zur
Folge, dass sich diese im Sommer am stärksten aufheizen, weil der schwarze
Lack alle Photonenstrahlung der Sonne samt aller Farbspektren absorbiert. Demzufolge wäre eine schwarze LED praktisch unsichtbar. Aber schwarz
leuchtende LEDs gibt es nicht,
auch nicht zu kaufen. Das macht auch nichts, weil man eine schwarz
leuchtende LED einfach nur ausgeschaltet sein lassen muss,
damit sich quasi unsichtbar ist: 15. Statement <strip.show_color(neopixel.colors(NeoPixelColors.BLACK))> Aber eine schwarz leuchtende LED ist nicht wirklich
ausgeschaltet, nur weil sie nicht leuchtet! Eine schwarz leuchtende LED, die kein Licht
ausstrahlt, muss aber wegen der elektronischen Ansteuerung über den seriellen
Datenbus „I2C“ ständig
erreichbar sein, damit man sie z.B. von schwarz
auf rot umschalten kann, sie wieder
sichtbar machen kann! Zeit also, dass wir die Anzeige-Funktion <NeoPixel_anzeigen(anzeigen_ja_nein, Helligkeit_LEDs, anzahlNeoPixel)> um den Parameter <Farbe_LEDs> wie folgt erweitern (siehe roter Kasten): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_05.py“)
Wenn man das obenstehende Programm „joy-car_teil_02_prog_05.hex“
startet, dann wird nach dem Betätigen des Tasters A nur die Laufschrift mit der Ziffer 4
angezeigt, um zu signalisieren, dass nur 4 NeoPixel eingeschaltet sind und „schwarz leuchten“, sodass man
diese nicht sieht: (Zum Vergrößern bitte
auf das Bild klicken!) Sichtbar wird dann abschließend nur die vierte
RGB-LED auf der rechten Seite des „Joy-Car“-Roboterautos, die für drei
Sekunden in strahlendem Grün leuchtet, weil sie
als einzige nicht abgeschaltet wurde (siehe grüner
Kasten)!
Bei dem obenstehende Programm „joy-car_teil_02_prog_05.hex“
ging es darum nur die LED Nr. 4 vorn rechts
leuchten zu lassen, wozu es notwenig wurde, von den vier vorderen „NeoPixel“-LEDs insgesamt drei ausschalten! Und
zwar rückwärts von der ersten RGB-LED vorn links. Beim nächsten Programm, das auf dem vorherigen
aufbaut, geht es darum nur die LED Nr. 3 vorn rechts
leuchten zu lassen. Da aber wegen des Vorgängerprogramms im Moment noch die LED Nr. 4 leuchtet, müssen wir das Programm dahingehend
ändern, dass die Adressierung der aktuellen LED Nr. 4 auf diejenige der LED Nr. 3 geändert wird. Da wir, obwohl die „NeoPixel“-LEDs alle über den
seriellen „I2C“-Steuer- und Datenbus angesteuert werden,
zum Glück nichts mit der Adressierung
der „NeoPixel“-LEDs zu tun haben, nur die Anzeigeposition von LED Nr. 4 auf LED Nr. 3 mittels des 16.
Statements <strip.rotate(-1)> ändern, indem wir bei der Anzeigeposition der LED gerade einmal einen Schritt nach links verschieben
bzw. „rotieren“ (siehe pinkfarbener Kasten): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_06.py“)
Jetzt wo wir wissen, dass die beiden Statements im roten Kasten und im pinkfarbenen
Kasten
in der logischen Abfolge zusammengehören, können wir diese wie folgt
zusammenfassen: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_07.py“) Als nächstes kann man sich daran machen und
die Statements im pinkfarbenen
Kasten
des Tasters A im „Notepad++“-Editor mittels der Tastenfolge <Strg>, <X> ausschneiden und in der Funktion <NeoPixel_anzeigen(anzeigen_ja_nein, Helligkeit_LEDs, anzahlNeoPixel)> mittels der Tastenfolge <Strg>, <V> am Quelltextende der Funktion wieder einfügen (siehe pinkfarbenen
Kasten).
Darüber hinaus muss man auch noch den Funktionskopf um die neuen Parameter wie folgt erweitern (siehe roter Kasten): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_08.py“) Damit das veränderte Programm „joy-car_teil_02_prog_08.hex“
auch tatsächlich funktioniert, muss man im Hauptprogramm noch die neu hinzugekommenen Variablen <ausschalten_NeoPixel = 0> und <verschieben_NeoPixel
= 0>
hinzufügen und in den Funktionen mittels der Angabe <global> zugänglich machen (siehe kleiner
blauer Kasten).
Da die neu hinzugekommenen Variablen mit dem Anzeigeverhalten der 18.
Funktion <NeoPixel_anzeigen(anzeigen_ja_nein, Helligkeit_LEDs, anzahlNeoPixel)> zu tun haben, muss man diese auch im Funktionkopf als Parameter hinzufügen 19.
Funktion <NeoPixel_anzeigen( anzeigen_ja_nein, Helligkeit_LEDs, anzahlNeoPixel, FarbeLEDs, NeoPixel_ausschalten, NeoPixel_verschieben)> (siehe kleiner pinkfarbener
Kasten).
Wie man in der nachfolgende Tabelle der Variablennamen sieht, kommt der Variablenname <anzahlNeoPixel> doppelt vor. Und zwar in der linken
Spalte als globale Variable im Hauptprogramm und in der rechten
Spalte als lokale Variable in der Funktion <NeoPixel_anzeigen()>:
Das nachfolgende Programm „joy-car_teil_02_prog_09.hex“
wurde noch weiter verbessert, wobei die boolesche Variable <anzeigen_ja_nein> nach dem Aufrufen der Funktion <NeoPixel_anzeigen()> den Wert <anzeigen_ja_nein> = False an die aufrufende Funktion <on_button_pressed_a()> zurückliefert (siehe kleiner roter
Kasten).
Die Rückgabe des Wertes <anzeigen_ja_nein> = False an die aufrufende Funktion
<on_button_pressed_a()> ist dem Umstand
geschuldet, damit der Taster A als Wechseltaster arbeiten kann (siehe großer
blauer Kasten):
(Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_09.py“) Als nächstes geht es darum, Klarheit und
Einheitlichkeit bei der Namensvergabe der globalen und lokalen Variablen zu bringen. Und zwar der Gestalt, dass die Namen der globalen
Variablen stets mit dem Verb anfangen, d.h. mit dem was zu tun ist,
gefolgt vom grammatikalischen Objekt auf das sich das Tun,
das was zu bewerkstelligen ist, bezieht (siehe linke Spalte). Bei den Namen
der lokalen Variablen (= Parameter
im Funktionskopf) ist es umgekehrt. Da
wird zuerst das grammatikalische Objekt (= „NeoPixel“) genannt, um das es geht, gefolgt vom Verb, was zu tun ist bzw. zu bewerkstelligen ist
(siehe rechte Spalte):
Selbstverständlich
lässt sich bei der obenstehenden Liste der Variablennamen die Reihenfolge derselben jederzeit verändern. Wenn man aber die Reihenfolge der Variablennamen ändert,
dann muss man tunlichst darauf achten,
dass man die Reihenfolge der Variablennamen auf
beiden Seiten der Liste ändert. Also bei den globalen und lokalen
Variablen gleichermaßen! Das nachfolgende Programm „joy-car_teil_02_prog_10.hex“
beinhaltet nicht nur die vereinheitlichen globalen
und lokalen Variablennamen und deren Reihenfolge, sondern auch noch dahingehend
vereinfacht, indem auf die drei <if>-Abfragen in der Funktion <NeoPixel_anzeigen()> verzichtet wurde
(siehe pinkfarbener Kasten weiter oben): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_10.py“) Bei den bisherigen „Joy-Car“-Programmen bei denen ein paar NeoPixel abgeschaltet oder verschoben
wurden, fällt auf, dass die abzuschaltenden NeoPixel beim Abschalten oder Verschieben stets
kurz aufblitzten, wobei dieses besonders auffiel, wenn die NeoPixel mit maximaler Helligkeit (= 255) leuchten sollten. Beim Programm
„joy-car_teil_02_prog_11.py“
wird dem kurzen Aufblitzen von abgeschalteten
NeoPixeln versucht
entgegenzuwirken, indem vor dem Abschalten von NeoPixeln 1.
die Variable <NeoPixel_Helligkeit> auf den Wert = 0
2.
und die Variable <NeoPixel_Farbe> auf den Wert = schwarz (" NeoPixelColors.BLACK) gesetzt werden (siehe pinkfarbener
Kasten).
Dabei werden die Einstellungen der
Variablen im ersten Schleifendurchlauf der <for … next>-Schleife umgesetzt und beim zweiten
Schleifendurchlauf, nachdem die NeoPixel auf schwarz und dunkel gesetzt wurden, wieder
rückgängig gemacht. Dazu ist es erforderlich, dass die Variableninhalte der Variablen <NeoPixel_Helligkeit> und <NeoPixel_Farbe> zuvor gesichert
wurden (siehe grüner Kasten). (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_11.py“) Auch das obenstehende Programm „joy-car_teil_02_prog_11.hex“
lässt sich noch optimieren im Sinne von vereinfachen. Und zwar indem wir auf
die globalen Variablen in dem Funktionsaufruf der Funktion <NeoPixel_anzeigen()> verzichten: anzeigen_NeoPixel = NeoPixel_anzeigen( anzeigen_NeoPixel, helligkeit_NeoPixel, anzahl_NeoPixel, farbe_NeoPixel, ausschalten_NeoPixel, verschieben_NeoPixel) Wie im richtigen Leben hat die Medaille zwei
Seiten. Einerseits spart man sich einen Großteil der globalen Variablen im Hauptprogramm,
andererseits ist der nachfolgende Funktionsaufruf der Funktion <NeoPixel_anzeigen()> nur mit den reinen Parametern nicht mehr
selbsterklärend, weil man den Parametern
nicht ansieht, worauf sie sich beziehen: anzeigen_NeoPixel = NeoPixel_anzeigen( True, 8,
4,
NeoPixelColors.RED, 0,
0
) Abhilfe schafft man da nur, indem man die
nichtssagenden Parameter
entsprechend kommentiert: anzeigen_NeoPixel = NeoPixel_anzeigen( True, # NeoPixel_anzeigen 8, #
NeoPixel_helligkeit 4, #
NeoPixel_anzahl NeoPixelColors.RED, # NeoPixel_Farbe 0, #
NeoPixel_ausschalten 0) #
NeoPixel_verschieben Im „MakeCode“-Editor von Microsoft oder
einem anderen Editor wie z.B. Notepad++ lassen
sich die Quelltextzeilen selbstverständlich
nicht fett, kursiv, unterstrichen oder farbig formatieren. Der „micro:bit“-Rechner in der Version 2.x verfügt gegenüber seinem Vorgänger des Weiteren u.a. über einen Touch-Sensor, (Zum Vergrößern bitte
auf das Bild klicken!) den als nächstes im Programm „joy-car_teil_02_prog_12.py“
so programmieren, dass dieser bei Berührung
mit dem Finger
die aktuelle Batteriespannung
UBatt von [ 2,7 V, … 3,2 V ] oder von [ 4,5 V … 6
V ]
anzeigt. Welche von den Spannungen angezeigt wird hängt
davon ab, ob das „Joy-Car“-Mainboard zusammen mit dem 6 V Batteriefach eingeschaltet ist oder nicht. Wenn nur der „micro:bit“-Rechner über das angeschlossene
„USB 2.0“-Kabel, das auch der seriellen Datenübertragung dient, an die Stromversorgung des Windows-PCs angeschlossen wird, das „Joy-Car“-Mainboard also ausgeschaltet
ist, dann wird nur die niedrigere Batteriespannung UBatt von [ 2,7 V, … 3,2 V ] des „micro:bit“-Rechners angezeigt. Demzufolge wird die höhere Batteriespannung UBatt von [ 4,5 V … 6 V ] nur angezeigt, wenn das „Joy-Car“-Mainboard zusammen mit dem 6 V Batteriefach eingeschaltet ist. Dazu muss man
wissen, dass z.B. die Beleuchtung
des „Joy-Car“-Roboters nur funktioniert, wenn das „Joy-Car“-Mainboard eingeschaltet ist
(siehe grüner Kasten): (Zum Vergrößern bitte
auf das Bild klicken!) Werfen wir abschließend noch einen Blick auf
den Quellkode des Programms „joy-car_teil_02_prog_12.py“.
Anhand der pinkfarbenen Kästen erkennt man, wie Funktion <NeoPixel_anzeigen()> nebst der Parameter von den anderen Funktionen des Tasters A oder B aufruft: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_12.py“) Tagfahr- und
Standlicht Früher gab es bei den Kraftfahrzeugen in
Deutschland drei Arten von Licht: das Standlicht, das Fahrlicht und das
Fernlicht. Dabei mussten tagsüber bei den Kraftfahrzeugen kein Licht
eingeschaltet werden. Also weder das Standlicht noch das Fahrlicht. Heutzutage, wo neue Fahrzeuge über eine LED-Beleuchtung verfügen, fahren
diese tagsüber mit Tagfahrlicht und bei Regen, Schnee
und nachts mit Fahrlicht (= Abblendlicht).
Während sich das Standlicht auf alle vier
Lampen vorn und hinten bezieht,
bezieht sich das Parklicht jeweils
nur auf zwei Lampen rechts
oder links. An Bahnübergängen z.B. muss das Fahrlicht ausgeschaltet und das Standlicht eingeschaltet bleiben oder eingeschaltet werden. Mit dem Programm
„joy-car_teil_02_prog_13.hex“
programmieren wir zunächst das Tagfahr- und Standlicht. Und zwar als Funktion
<Tagfahr_oder_Standlicht()>. Beim Vergleich des Quellkodes vom Tagfahrlicht mit dem vom Standlicht fällt auf, dass sich der Quellkode vom
Tagfahrlicht beim Standlicht wiederholt. Der Grund dafür ist ganz
einfach, nämlich der, dass beim Tagfahrlicht nur die beiden vorderen
weiß leuchtenden LEDs in Betrieb sind,
während beim Standlicht noch die beiden hinteren
rot leuchtenden LEDs hinzukommen. Interessant dabei ist, dass die Beleuchtung
für das Standlicht rückwärts von hinten
nach vorn vorgenommen wird. Ganz einfach deshalb, weil sich die roten Rückleuchten am Ende der NeoPixel-Kette befinden. Aus diesem Grund werden alle acht
NeoPixel auf rot leuchtend
geschaltet. Dann werden bei den Rückleuchten
jeweils zwei dunkel (= schwarz) geschaltet. Im zweiten Schritt werden dann
beim Tagfahrlicht die vier vorderen NeoPixel von rot auf weiß leuchtend umgeschaltet und
zwei der vorderen NexoPixel werden dunkel (= schwarz) geschaltet (siehe
zweiter grüner Kasten): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_13.py“
) Neu im
obenstehenden Programm ist das ·
Statement <strip.set_pixel_color(0, neopixel.colors(NeoPixelColors.BLACK))> und
folgende mit dem es auf einfache Weise möglich ist, einzelnen NeoPixeln eine einzelne Farbe zuzuweisen, die aber
wiederum erst mit dem Aufruf des ·
Statements <strip.show()> umgesetzt,
d.h. ausgeführt wird!
Wichtig ist
in diesem Zusammenhang noch, dass die Nummerierung der einzelnen NeoPixel mit der Farbgebung auf der linke Seite (= aus der
Fahrersicht) bei der Nummer 0 beginnt: (Zum Vergrößern bitte
auf das Bild klicken!) Wie bereits erläutert, erfolgt die Konfiguration, d.h. das Ein- und Ausschalten als
auch die Farbgebung, der NeoPixel rückwärts,
d.h. von hinten (= Rücklicht) nach vorn (= Frontlicht): 1.
Statement <strip = neopixel.create(DigitalPin.P0, 8, NeoPixelMode.RGB)> 2.
Statement <strip = neopixel.create(DigitalPin.P0, 4, NeoPixelMode.RGB)> Würde man nämlich zuerst das Frontlicht vorn konfigurieren und
anschließend das Rücklicht hinten, dann
würde die Konfiguration der NeoPixel für das Rücklicht wegen der Nummerierung
8 die vorausgegangene Konfiguration der NeoPixel
für das Frontlicht wegen der Nummerierung 4 überschreiben! Wie man im nachfolgenden Quellkode des Programm „joy-car_teil_02_prog_14.hex“
sieht, wurde dieser weiterhin optimiert, weil sich das Standlicht aus dem roten Rücklicht plus dem weißen Tagfahrlicht zusammensetzt (siehe grüne Kästen): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_14.py“)
Das nachfolgende Programm „joy-car_teil_02_prog_15.hex“
unterscheidet sich vom vorherigen nur im Hauptprogramm
durch die umgekehrte Reihenfolge beim Aufruf der Funktionen <Tagfahr_oder_Standlicht()>: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_15.py“)
Können
Dinge zugleich richtig, engl. „True“ und falsch, engl. „False“ sein? Natürlich nicht! Das ist es ja gerade bei der booleschen Algebra: entweder
es ist richtig oder es ist falsch, aber niemals
beides zugleich! Bei den beiden Programmen „joy-car_teil_02_prog_14.py“
und „joy-car_teil_02_prog_15.py“
gibt es quasi eine Wahrheit dazwischen, zwischen richtig und falsch. Wie aber kann das sein
bzw. wie kann es dazu kommen? Ganz einfach! Bei den beiden Programmen kann
man beim Aufruf der Funktion <Tagfahr_oder_Standlicht()> versehentlich die ·
Funktion <Tagfahr_oder_Standlicht(True, True)> oder ·
Funktion <Tagfahr_oder_Standlicht(False, False)> programmieren und auch aufrufen! Niemand
hindert einen daran! Und was
schiefgehen kann, geht erfahrungsgemäß auch irgendwann schief! Und zwar immer
dann, wenn man nicht damit rechnet! Und damit eben nicht das passiert, was
passieren kann, ändern wir das Programm
ab. Und zwar so, dass es im Funktionskopf der Funktion <Tagfahr_oder_Standlicht()> nur noch einen
Parameter <Tagfahrlicht_einschalten> gibt, der wiederum
immer nur einen Wert richtig oder falsch annehmen kann: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_16.py“)
Da das Tagfahrlicht praktisch immer eingeschaltet wird, sobald man den Motor
des Kraftfahrzeugs startet, lässt es sich im vorliegenden Fall mittels des Parameters <Tagfahrlicht_einschalten> = <True> im ·
Funktionsaufruf <Tagfahr_oder_Standlicht(True)> jederzeit aktivieren und einschalten. Wenn
dann einmal das Standlicht z.B. bei
geschlossener Schranke an einem Bahnübergang oder beim Parken in einer unbeleuchteten Straße eingeschaltet
werden muss, dann kann man dies mittels des Parameters <Tagfahrlicht_einschalten> =
<False> im ·
Funktionsaufruf <Tagfahr_oder_Standlicht(False)> jederzeit umschalten. - Damit sich das Tagfahr- oder
Standlicht auch unabhängig vom
Hauptprogramm jederzeit ein- oder ausschalten lässt, wurde das bisherige Programm noch um die nachfolgende ·
Funktion <Tagfahr_Standlicht()> erweitert, (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_16.hex“)
sodass sich das Tagfahr- oder
Standlicht ab sofort jederzeit
mit dem Touch-Sensor ein- oder ausschalten
lässt: (Zum Vergrößern bitte
auf das Bild klicken!) Dabei arbeitet der Touch-Sensor als Wechsel- bzw. Umschalter mit der booleschen Variablen <schalte_Tagfahr_Standlicht> zusammen (siehe im Hauptprogramm). Das ist dann auch der
Grund dafür, weshalb die booleschen Variablen <schalte_Tagfahr_Standlicht> in der Funktion <Tagfahr_Standlicht()> als global deklariert werden
muss (siehe blauer Kasten oben). Das Programm
„joy-car_teil_02_prog_17.hex“
unterscheidet sich vom Vorgängerprogramm nur dahingehend, dass im Hauptprogramm die Funktion <Tagfahr_oder_Standlicht()> vom Tagfahrlicht auf Standlicht umgeschaltet wird, um genau das Ein- und Ausschalten, Umschalten oder Zurückschalten zu testen: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_17.py“
) Bei den bisherigen Programmen verhielt es sich
so, dass wir beim Einschalten des Standlichts in der Funktion <Tagfahr_oder_Standlicht()> zunächst alle acht
NeoPixel in der Farbe Rot
aufleuchten ließen (siehe roter Kasten Nr. 1.)), um dann die zwei
verbleibenden NeoPixel (5 und 6) der Rückleuchte auf schwarz zu setzen, d.h. auszuschalten. Auch bei den Frontlampen wurden zunächst alle vier NeoPixel auf weiß geschaltet (siehe roter Kasten Nr. 2.)), um dann die zwei
verbleibenden NeoPixel (0 und 3) der Frontleuchte auf schwarz zu setzen, d.h. auszuschalten: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_17.hex“
) Doch es geht anders herum! Nämlich dass man
zunächst alle NeoPixel „ausschaltet“, indem
man diese auf die Farbe Schwarz
setzt (siehe roter Kasten). Anschließend werden dann die vier NeoPixel für das Standlicht eingeschaltet (siehe grüner Kasten). Außerdem wird die Funktion <Standlicht(Standlicht_einschalten)> mittels des ·
Statements <return(Standlicht_einschalten)> für den Betrieb als Wechselschalter erweitert
(siehe blauer Kasten),
sodass die Funktion <Standlicht_schalten()> dafür umso
spartanischer, d.h. einfacher ausfällt (siehe pinkfarbener Kasten): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_18.py“)
Im Zusammenhang mit dem Wechselschalter, d.h. der Funktion <Standlicht_schalten()> muss der Anfangszustand eindeutig definiert werden, da dieser
ansonsten nicht funktioniert. Diesbezüglich bietet es sich an, den Anfangszustand im Hauptprogramm festzulegen, indem man praktischerweise alle
NexoPixel „ausschaltet“, indem
man die NeoPixel-Farbe auf Schwarz
setzt (siehe brauner Kasten): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_18.hex“) Wir entwickeln das obenstehende Programm mit
der Funktion <Standlicht(Standlicht_einschalten)> weiter, indem wir die
Statements weiter oben im grünen
Kasten
in einem sogenannten Array
abspeichern: (Vergrößern: auf das
Bild klicken! | Quelle: OpenAI, ChatGPT) Anschaulicher und besser verständlich lässt
sich ein Array beispielsweise anhand
eines Schachspiels
und dessen Schachbretts erklären. Demzufolge
ist ein Schachbrett in horizontale
(= Zeilen) und vertikale (= Spalten) schwarzweiß gefärbte Felder unterteilt. Dabei sind die Zeilen (= waagrecht) mit Ziffern von [ 1, …, 8 ] und die Spalten
(= senkrecht) mit Buchstaben von [ A, … H ] gekennzeichnet. Bei einer
klassischen Eröffnung setzt man den Bauern vom Feld E2 auf das Feld E3,
sodass die Dame und der Läufer freie Bahn zum Ausschwärmen haben. Ein weiteres Beispiel für ein Array ist in der Mathematik die sogenannten Matrizenrechnung
mit den Elementen der ersten
Zeile a11, a12, a13, a14 und der ersten
Spalte a11, a21, a31, a41. Dabei gilt es eine wichtige Regel einzuhalten: Erst
die Zeile, dann die Spalte! Diese Regel gilt auch bei der Programmierung
eines Arrays! Ein weiteres Beispiel ist ein Kreuzworträtsel,
wobei aber nur zwischen 1.)
waagrecht
und 2.) senkrecht - man achte auf die Reihenfolge! -
unterschieden wird. Im roten Kasten wird zunächst das Array
namens <farbe_NeoPixel> mit dem ·
Statement <farbe_NeoPixel = []> deklariert und anschließend initialisiert,
d.h. mit Daten gefüllt. Dabei machen
wir uns bei der Umsetzung das neue ·
Statement <strip.set_pixel_color(1, neopixel.colors(NeoPixelColors.WHITE))> wie folgt zu nutze: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_19.py“) Wie man im blauen Kasten im obenstehenden
Quellkode sieht, wird das Array <farbe_NeoPixel[ ][ ]> in der <for … next>-Schleife mit dem ·
Statement <for i in range(4):> entsprechend angewendet und in die farbig
leuchtenden NeoPixel umgesetzt. Das Speichern
der laufenden Adressnummern (siehe pinkfarbener
Kasten
oben) der NeoPixel als auch die
betreffenden Farben (siehe grüner
Kasten
oben), die zum Leuchten gebracht werden sollen, lassen sich zwar gut im Array <farbe_NeoPixel> speichern, schaffen aber
nicht zwangsläufig eine gut nachvollziehbare und selbsterklärende Struktur. - Spätestens wenn noch ein dritter Parameter für die Helligkeit mit der ein NeoPixel leuchten soll, hinzukommt, wird es mit dem Array <farbe_NeoPixel> unübersichtlich: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_20.py“) Wir entwickeln das obenstehende Programm
weiter, verzichten aber auf das Array <farbe_NeoPixel[ ]> und legen stattdessen
nachfolgende Struktur an, die aus drei
Teilen besteht (siehe hellgrüner und roter Kasten): 1.
Adressierung bzw. Nummernangabe, welche NeoPixel
leuchten sollen 2.
Farbangabe in welcher Farbe die betreffenden NeoPixel
leuchten sollen und 3.
Helligkeitsangabe, wie hell die
betreffenden NeoPixel leuchten sollen. Wichtig bei der Programmierung des Standlichts ist noch, dass man am Anfang der Funktion <Standlicht()> die Helligkeit aller NeoPixel auf einen bestimmten
Wert wie z.B. <strip.set_brightness(8)> oder <strip.set_brightness(0)> setzt (siehe pinkfarbener
Kasten).
Ansonsten
kann es nämlich passieren, dass noch die Helligkeitswerte des Vorgängerprogramms
angezeigt werden, dessen Werte sich noch im „Joy-Car“-Mainboard (siehe Bild) des „Joy-Car“-Roboters befinden! Diesbezüglich sollte man wissen, dass alle
NeoPixel vom „Joy-Car“-Mainboard aus inkl. Stromversorgung
angesteuert werden!
Bezüglich der Programmierung ist noch das ·
Statement <if i in (1, 2)> mit der Bedingung
in
(1, 2)
hinzugekommen, demzufolge der nachfolgende Programmkode nach der <if>-Abfrage nur ausgeführt wird,
wenn der Schleifenzähler i einen der Werte (1, 2) (siehe grüner
Kasten)
oder (4, 7) (siehe pinkfarbener
Kasten)
enthält: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_21.py“) Warnblink-
und Abbiegeblinker Jetzt wo wir bereits das Tagfahrlicht vorn und das Standlicht vorn und hinten als Funktion mittels Wechselschalter zum Ein-
und Ausschalten programmiert haben,
ist es nicht sehr schwer, das Warnlicht rundum zu
programmieren. Dazu muss man nämlich zunächst nur im Hauptprogramm das Standlicht sozusagen im Sekundentakt ein- und ausschalten: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_22.py“) Wie man im obenstehenden Quellkode des roten Kastens sieht, wird das Standlicht (vorn weiß und hinten rot) fortwährend
ein- und ausgeschaltet. Und, wenn man etwas einschaltet, dann sollte man auch unbedingt
wissen, wie man den Flaschengeist, den
man aus der Flasche gelassen hat, dort wieder hineinbekommt, nämlich ausschaltet. Und wie man ferner oben im roten Kasten sieht, befindet sich
in der <do … while>-Schleife mit dem ·
Statement <while schalteStandlicht == True:> noch ein weiteres ·
Statement <input.on_logo_event(TouchButtonEvent.PRESSED, Standlicht_schalten)>
7 mittels dem sich durch mehrfaches Berühren der Touch-Schaltfläche
(= „micro:bit“-Logo) das Standlicht abwechselnd ein- und wieder ausschalten lässt! Demzufolge arbeitet die Touch-Schaltfläche des „micro:bit“-Rechners als Wechselschalter mit dem sich das Standlicht abwechselnd ein-
und wieder ausschalten lässt: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_22.hex“)
Wie man außerdem im Quellkode des grünen
Kastens
sieht, wird zwar die Funktion <Standlicht()> abwechselnd aufgerufen, wobei
es aber tatsächlich um das Umschalten der boolesche
Variablen <schalteStandlicht>
geht, die sich als globale Variable von
jederzeit von überall her umschalten lässt! Wenn wir also als nächstes aus dem blinkenden
Standlicht einen fortwährenden
Orange farbenen Warnblinker programmieren wollen,
dann müssen wir den Quellkode aus dem Hauptprogramm
(siehe im obenstehenden roten Kasten) in die entsprechende Funktion <Warnblinker_blinkt()> auslagern bzw.
kopieren und dabei die Angabe
„Standlicht“
durch „Warnblinker“ ersetzen: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_23.py“)
Wie man im obenstehenden Quellkode sieht
(siehe pinkfarbener Kasten), heißt die Warnblink-Funktion selbst <Warnblinker_NeoPixel()>. Dabei beträgt das Blinkfrequenz zweimal 500 ms = 1 s, sodass das Blinken weder zu hektisch noch zu langsam ist. Wenn man
sich das Programm „joy-car_teil_02_prog_23.hex“
in den „micro:bit“-Rechner lädt, dann startet sich der Warnblinker automatisch und lässt
sich durch Berühren der Touch-Schaltfläche (= „micro:bit“-Logo) jederzeit beliebig oft wieder aus- oder einschalten! Diesbezüglich
stellt sich noch die Frage, um welche spezielle
Funktion es sich dabei handelt, die sich selbst fortwährend
aufruft bis der Strom ausfällt oder bis man diese mittels der globalen
booleschen Variablen <schalteWarnblinker>
ausschaltet.
Bei genauerem Hinsehen ist es nämlich wider
Erwarten nicht die Funktion <Warnblinker_blinkt()> selbst (siehe roter Kasten oben), die „speziell“
ist, sondern deren Funktionsaufruf mit dem ·
Statement <basic.forever(Warnblinker_blinkt)>, der dafür sorgt, das der Warnblinker fortwährend blinkt,
wenn dieser denn eingeschaltet ist (siehe globale
boolesche Variable <schalteWarnblinker> weiter unten): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_23.py“)
Das Funktionsprinzip
des Warnblinkers ist also das, dass
dieser wegen des Funktionsaufrufs mit dem ·
Statement <basic.forever(Warnblinker_blinkt)>, jederzeit blinkbereit ist, vorausgesetzt,
dass die boolesche Variable <schalteWarnblinker> wie zuvor im Hauptprogramm auf „True“ gesetzt wurde! Aber mittels des ·
Statements <input.on_logo_event(TouchButtonEvent.PRESSED, Warnblinker)> 7 lässt sich der Warnblinker auch jederzeit beliebig oft ein- und ausschalten (siehe blauer Kasten oben und unten): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_23.py“)
Ein Fahrzeug verfügt nicht nur über einen Warnblinker, sondern auch über einen Fahrtrichtungsanzeiger. Obwohl es ja
tatsächlich zwei Fahrtrichtungsanzeiger sind. Und zwar einer
nach rechts zum Rechtsabbiegen und ein weiterer zum Linksabbiegen. Dabei sind beide Fahrtrichtungsanzeiger bis auf die Richtungsanzeige programmiertechnisch
identisch, ist das Rechtsabbieger-Programm der Klon (= Kopie) vom Linksabbieger-Programm und umgekehrt. Rechtsabbieger- und Linksabbieger-Programm wiederum sind
programmiertechnisch jeweils eine Seite
vom Warnblinker-Programm! Wenn wir also den Teil des Warnblinker-Programms nehmen, kopieren
und die Bezeichnung „Warnblinker_“ im Quellkode durch die Bezeichnung „Blinker_rechts_“ ersetzen, dann
ist schon ein Großteil der Programmierarbeit erledigt. Das Umbenennen selbst bewerkstelligen wir mit dem sogenannten „Notepad++“-Editor und der Funktion
„Ersetzen“ mit der „Menü“-Reihenfolge: <Suchen>, <Ersetzen> und <Alle
ersetzen>. Ferner müssen wir in der neuen Funktion <Blinker_rechts_NeoPixel()> noch neu festlegen, welche
NeoPixel jeweils auf der rechten
und linken Fahrzeugseite leuchten sollen. Dabei
gilt es zu beachten, dass moderne Kraftfahrzeuge tagsüber mit weißem Tagfahrlicht und bei Dunkelheit vorn mit weißem und hinten mit rotem
Standlicht fahren! Demzufolge muss beim Tagfahrlicht das vordere linke NeoPixel an der Position 1 weiß leuchten (siehe hellblauer Kasten), während das hintere
linke NeoPixel an der Position 4 dunkel bleibt (siehe roter Kasten): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_24.py“)
Wenn man das Programm „joy-car_teil_02_prog_24.hex“
startet, dann stellt man fest, dass das Tagfahrlicht vorn links weiß blinkt. Der Grund dafür ist
aber ganz banal, nämlich der, dass das Blinken
noch dem Blinkmodus des ehemaligen
Warnblinkers bzw. dem Blinken des Rechtsabbieger-Blinkers geschuldet ist. Diesbezüglich stellt sich die Frage, wie man
das Blinken des Tagfahrlichtes abstellen bzw. ausschalten kann! Und zwar durch einen Trick, indem man das Tagfahrlicht auch dann blinken lässt, wenn es quasi
ausgeschaltet ist bzw. der Rechtsabbieger-Blinker ausgeschaltet
ist (siehe grüne Kästen): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_25.py“) Wenn man sich den obenstehenden Quellkode
anschaut, dann fällt auf, dass sich der Programmkode,
der sich auf das linke NeoPixel Nr.
1 mit
dem weißen Tagfahrlicht bezieht, maßgeblich
zusammenfassen und konzentrieren lässt (siehe grüne Kästen oben). Wenn nämlich das linke NeoPixel Nr. 1 mit dem weißen Tagfahrlicht durchgängig, d.h. ohne
Unterbrechung leuchten soll, während sich die orangenen NeoPixel Nr. 2 und Nr. 7
als Blinklicht abwechselnd ein- und ausschalten, dann
lässt sich der Programmkode, der
sich auf das linke NeoPixel Nr. 1
bezieht (siehe grüne Kästen
oben), komplett aus der <if … then … else>-Abfrage <Blinker_rechts_einschalten> wie folgt entfernen: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_26.py“) Wenn man in
der obenstehenden Funktion <Blinker_rechts_NeoPixel()> verschiedene NeoPixel
unterschiedlich konfiguriert, dann werden die entsprechenden Konfigurationen erst mit dem nächsten ·
Statement <strip.show()> umgesetzt
und angewendet! Und zwar unabhängig von der
jeweiligen Reihenfolge der Konfiguration! Trotzdem sollte man es sich angewöhnen, die
unterschiedlichen Konfigurationen der verschiedenen NeoPixel möglichst stets in einer logischen Abfolge vorzunehmen, wie beispielsweise ·
Statement
<strip.set_brightness(helligkeit_weisse_NP)> ·
Statement
<strip.set_pixel_color(linke_NeoPixel, neopixel.colors(weisse_NeoPixel))> . Wir verbessern die obenstehende Funktion <Blinker_rechts_NeoPixel()> dahingehend, indem
wir die unterschiedlichen Beleuchtungssituationen zwischen Tagfahrlicht und Standlicht berücksichtigen (siehe rote Kästen): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_27.py“) Als nächstes bietet es sich an, das obenstehende
Programm um die Funktion des Fahrrichtungsanzeigers für das Linksabbiegen zu erweitern. Zu diesem Zweck ist es
am einfachsten, wenn man sich den obenstehenden Quellkode im Programm rückwärts mit der Maus markiert,
sodass dieser blau
markiert
erscheint. Dann kopiert man sich den blau markierten Programmkode mittels der Tastenkombination <Strg> & <C> in die Zwischenablage von Windows.
Dann starten wir den „Notepad++“-Editor, klicken in der obenstehenden Menüleiste auf <Datei>, <Neu>, sodass sich ein neues, leeres Editorfenster öffnet. In dieses fügen wir den Text
aus der Windows-Zwischenablage mittels der Tastenkombination <Strg> & <V> wieder ein. In der Menüleiste kann man dann mittels der Tastenfolge <Suchen> & <Ersetzen> alle Ausdrücke „rechts“
durch „links“ sowie „rechte“ durch „linke“ ersetzen. Ersetzt
müssen auch die NeoPixel Nr. „(2, 7)“ durch „(1, 4)“ sowie die einzelnen NeoPixel der rechten Seite Nr. „1“ und „4“ durch Nr.
„2“ und „7“ auf der linken Seite (vom Fahrer aus gesehen, siehe nachfolgende rote Kästen): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_28.py“) Damit sich der Fahrtrichtungsanzeiger „nach links abbiegen“ auch einschalten lässt, müssen wir noch die
entsprechenden Funktionsaufrufe mit dem ·
Statement <input.on_logo_event(TouchButtonEvent.PRESSED, Blinker_links)> ·
Statement <basic.forever(Blinker_links_blinkt)> wie folgt programmieren: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_28.hex“) Selbstverständlich lässt der Fahrtrichtungsanzeiger „nach links abbiegen“ auch noch
anschaulicher demonstrieren, indem man z.B. das Standlicht (= rundum) mittels des ·
Statements <schalteStandlicht = True> oder das Tagfahrlicht (= nur vorn) mittels des ·
Statements <schalteTagfahrlicht = True> aktiviert! - Eine „NeoPixel“-LED ist kein
Glühlämpchen Dass eine „NeoPixel“-LED kein Glühlämpchen ist, dürfte klar sein. Allein schon
deswegen, weil eine „NeoPixel“-LED eine digitale Hardware ist, während es sich bei einer Glühlampe um eine analoge Hardware handelt. Demzufolge lässt sich eine analoge Glühlampe sowohl mit Gleich-
als auch mit Wechselspannung betreiben. Dabei ist
aber das Entscheidende, dass sich in einem Stromkreis mit nur einem Schalter
immer nur eine Hardware ein- oder ausschalten lässt. Dabei kann es sich bei der analogen Hardware um nur eine Glühlampe oder auch mehrere, parallel geschaltete
Glühlampen handeln. Früher gab es z.B. in den Wohnzimmern oftmals Deckenlampen mit bis zu fünf
Leuchtmitteln in Form von Kerzen
oder Kugel förmigen Glühlampen, wobei sich diese meistens mittels zweier Wippschalter an der Wand in einer Zweiergruppe und/oder Dreigruppe schalten ließen, sodass sich die Helligkeit von minimal 2 Glühlampen über 3
Glühlampen bis maximal 5 Glühlampen einstellen ließ. Bei Kugel förmigen, kleinen Glühlampen kam man dabei auf insgesamt
5 * 40 Watt Leistung/Glühlampe auf insgesamt = 200 Watt Gesamtleistung,
sodass sich das Wohnzimmer, wenn es sein musste, ziemlich hell ausleuchten
ließ. Würde man bei einer solchen 5-„flammigen“ Deckenleuchte alle analogen Glühlampen, die ja aus Gründen der
Energieverschwendung schon seit Jahren in Europa verboten sind, durch smarte,
farbige LED-Kugellampen ersetzen, dann ließe
sich jede einzelne mittels Smartphone-App (oder Fernbedienung) einzeln
ansteuern, d.h. ein- und ausschalten bzw. sich individuell in den Farben, den Farbtönen und der Helligkeit ändern. Damit aber der Anwender nicht jede smarte
LED-Lampe einzeln steuern und
regeln muss, lassen sich bei der Smarthome-Vernetzung mehrere solche
smarten LED-Lampen zu einem einzigen
Leuchtmittel zusammenfassen, d.h. gruppieren,
sodass die Einstellungen für Farbe und Helligkeit für alle Leuchtmittel gemeinsam, d.h. synchron,
vorgenommen werden. Und jetzt sind wir schon bei den „NeoPixel“-LEDs angekommen. Demzufolge verfügt der „Joy-Car“-Roboter über acht einzelne „NeoPixel“-LEDs, wobei sich jede „NeoPixel“-LED einzeln oder auch in einer Gruppe
steuern und regeln lässt. Dabei ist mit „ansteuern“ die digitale
Adressierung und mit „regeln“ das
Einstellen von Helligkeit, Farbe oder einer Farbkombination von RGB (= Rot, Grün, Blau) gemeint: ·
Statement <neopixel.rgb(100, 35, 0)> ·
Statement <set_pixel_color( n, neopixel.colors(neopixel.rgb(100, 35, 0))) > ·
Statement <neopixel.colors(NeoPixelColors.RED)> ·
Statement <set_pixel_color( n, neopixel.colors(NeoPixelColors.RED))> ·
Statement <strip.show_color(neopixel.colors(NeoPixelColors.RED))> ·
Statement <set_brightness(8)> Bevor man aber Farbeinstellungen usw. vornehmen kann, muss man die „NeoPixel“-LEDs initialisieren: ·
Statement <neopixel.create(DigitalPin.P0,
8, NeoPixelMode.RGB)> Und an dieser Stelle fangen die Probleme mit
den NeoPixeln an. Im vorstehenden Statement werden nämlich insgesamt 8 NeoPixel adressiert, sodass alle nachfolgenden
Statements auf diese 8 NeoPixel angewendet werden. Wenn dann aber nachfolgend
ein ·
Statement <set_pixel_color( 3, neopixel.colors(NeoPixelColors.RED))> auf nur das einzelne NeoPixel Nr. 3 angewendet wird,
bleiben die anderen NeoPixel davon unberührt. Und
das kann im einen oder anderen Fall zu ganz erstaunlichen, unverständlichen
und nicht nachvollziehbaren Effekten führen. Nachfolgend
geht es konkret darum, herauszufinden, weshalb die beiden Programmteile mit den Tastern A und B im Programms „joy-car_teil_02_prog_12.py“
einwandfrei funktionieren, (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_12.py“) während
diese jetzt im Programm „joy-car_teil_02_prog_28.py“
nicht mehr richtig funktionieren! Um das obenstehende Programm „joy-car_teil_02_prog_12.py“
besser verstehen zu können, specken wir dieses ab, indem wir die ·
Funktion <NeoPixel_anzeigen(NeoPixel_anzeigen)> einfacher gestalten und im Funktionskopf nur noch einen Parameter, nämlich die lokale Variable <NeoPixel_anzeigen>) verwenden, die wiederum mit der gleichnamigen Funktion <NeoPixel_anzeigen(NeoPixel_anzeigen)> nichts zu tun hat: (Vergrößern: auf das Bild
klicken! | Programm „joy-car_teil_02_prog_29.py“) Wenn man das obenstehende Programm startet und
auf den Taster A drückt, dann bekommt
man zunächst die Laufschriftanzeige „->a1“ und „->a2“ angezeigt, bevor die Funktion
<NeoPixel_anzeigen(True)> aufgerufen wird. Als nächstes wird dann die Laufschriftanzeige „->n1“, „->n2“ und „->n3“ angezeigt, bevor die grüne „NeoPixel“-LED aufleuchtet. Die grüne „NeoPixel“-LED lässt sich wiederum
durch erneutes Drücken des Tasters A ausschalten. Dabei wird dann die Laufschriftanzeige „->a1“ und „<-a3“ angezeigt (siehe oben). In diesem Zusammenhang stellt sich noch die
Frage, ob der Quellkode im hellblauen
Kasten
gebraucht wird oder nicht (siehe oben)! Wenn man das obenstehende Programm startet und
auf den Taster A drückt, dann wird die
Funktion <NeoPixel_anzeigen(True)> aufgerufen und ausgeführt, sodass die grüne „NeoPixel“-LED aufleuchtet. Anschließend wird das Statement <NeoPixel_anzeigen = False> ausgeführt, das aber
noch zur <if>-Abfrage des Statements <if NeoPixel_anzeigen == True:> gehört, sodass die <if>-Abfrage damit beendet ist und
das Programm im blauen Kasten mittels des Statements <return(NeoPixel_anzeigen)>
wieder an die Stelle des aufrufenden Programmteils <anzeigen_NeoPixel = NeoPixel_anzeigen(True)> zurückkehrt (siehe grüner
Kasten
oben). Demzufolge wird der Programmkode
im hellblauen Kasten oben nicht erreicht, d.h. nicht ausgeführt,
sodass dieser weggelassen werden kann! Das nächste Programm „joy-car_teil_02_prog_30.hex“
basiert auf dem Vorgängerprogramm. Allerdings wurde ein wichtiges Statement
weggelassen, das das Verhalten des Programms maßgeblich beeinflusst. Um herauszufinden,
um welches Statement es sich dabei handelt, muss man das Programm starten und
das entsprechende Verhalten beobachten. Nach dem Programmstart
leuchten sofort die vorderen vier „NeoPixel“-LEDs rot auf. Und
zwar noch bevor der Programmname „Prog_30“ angezeigt wird (siehe roter Kasten). Dabei sorgt das ·
Statement <strip = neopixel.create(DigitalPin.P0,
4, NeoPixelMode.RGB)> dafür, dass die ersten vier „NeoPixel“-LEDs als RGB-farbige LEDs deklariert und nachfolgend initialisiert werden, sodass
diese mit der Helligkeit 8 in Rot
leuchten (siehe roter Kasten): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_30.py“) Wenn man dann als nächstes den Taster A drückt, dann wird an der Position 2 (siehe Bild 20) der vorderen vier
„NeoPixel“-LEDs sofort die „NeoPixel“-LED Nr. 2 von Rot
auf Grün umgeschaltet. Dabei leuchten
die verbleibenden drei „NeoPixel“-LEDs weiterhin in Rot. Der Grund dafür ist der, dass es in der Funktion <NeoPixel_anzeigen(NeoPixel_anzeigen)> kein weiteres ·
Statement <strip = neopixel.create(DigitalPin.P0,
4, NeoPixelMode.RGB)> gibt, sodass die bisherige Deklaration der „NeoPixel“-LEDs weiterhin bestehen bleibt. Mit
Ausnahme der grün leuchtenden „NeoPixel“-LED Nr. 2., denn deren Farbe wurde ja von Rot auf Grün
geändert (siehe hellgrüner Kasten): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_30.py“)
Bei den älteren „Windows“-Betriebssystemen wie z.B. Windows 3.1,
Windows 95 usw. von Microsoft gab es gelegentlich
eine Fehlermeldung beim Einschalten und Hochfahren des Windows-Rechners, die
immer dann auftrat, wenn versehentlich keine Tastatur an den PC
angestöpselt war. Sie lautete sinngemäß: „Es ist keine Tastatur angeschlossen! Drücken Sie bitte [die
Funktionstaste] F1.“ DAUs würden das natürlich sofort machen, auf der
Tastatur die Funktionstaste F1 drücken, dann die Kundenhotline anrufen und
sich beschweren, dass das Ganze nicht funktioniert. Technik affine Computeranwender wissen
natürlich, dass alle herkömmlichen PC-Tastaturen drei Kontrollleuchten in Form
kleiner LEDs haben, nämlich für „Num“ (= numerische
Tastatur zur Zahleneingabe), „Shift“ (=
Umschalttaste für dauerhaftes Schreiben in Großbuchstaben) und „Rollen“ (=
Herauf- oder Herunterscrollen, z.B. im Fenster der „Eingabeaufforderung“ im
Konsolemodus). Beim Einschalten und Hochfahren des PCs leuchten diese drei
LEDs kurz auf, aber eben nur dann, wenn eine entsprechende PC-Tastatur
angeschlossen ist! - Wenn man noch sarkastischer ist, könnte man
dem DAU auch empfehlen sich einen
neuen Rechner zu kaufen, falls weiterhin keine Tastatur an den
Windows-PC angeschlossen ist. Und zwar in Form eines Notebooks, weil
Notebooks bis jetzt immer über eine Tastatur verfügen. Im Gegensatz zu Tablet-PCs,
die nur über eine einblendbare „Touch“-Tastatur
verfügen, die mit den Fingern bedient werden muss. Was aber hat das alles mit dem ·
Statements <strip = neopixel.create(DigitalPin.P0,
4, NeoPixelMode.RGB)> zu tun? Ganz einfach! Das Statement ist so etwas wie eine Art „Eier
legende Woll-Milch-Sau“. Ein Alleskönner, der immer
dann angewendet wird, wenn
nichts mehr geht, wenn keine „NeoPixel“-LEDs
mehr leuchten oder blinken! Obwohl es noch ein weiteres, mächtiges
Werkzeug zu den „NeoPixel“-LEDs gibt. Um das
herauszufinden muss man beim Programm
„joy-car_teil_02_prog_30.hex“
beim Leuchten der grünen „NeoPixel“-LED und der anderen drei rot leuchtenden „NeoPixel“-LEDs nur die Taste B drücken, sodass alle vier leuchtenden „NeoPixel“-LEDs ausgeschaltet werden. Allerdings
leuchtet die grüne „NeoPixel“-LED beim erneuten Drücken der Taste B wieder auf! Aber nur die grüne „NeoPixel“-LED ganz für sich allein! Jetzt wissen wir, dass sich die grüne „NeoPixel“-LED mittels der Taste B
immer wieder ein- oder ausschalten lässt! Aber nicht nur das! Der Grund dafür, weshalb zuvor die
anderen drei rot
leuchtenden „NeoPixel“-LEDs
ausgeschaltet wurden, findet sich im nachfolgenden Programmkode im hellgrünen Kasten: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_30.py“) Fragen wir zu Abwechselung wieder die KI von ChatGPT: (Vergrößern: auf das
Bild klicken! | Quelle: OpenAI, ChatGPT)
Dass die leere „strip“-Liste physisch nicht als Ganzes
gelöscht wird, lässt sich sogar beweisen bzw. zeigen, indem im obenstehenden Programm „joy-car_teil_02_prog_30.hex“
nach dem Programmstart
abwechselnd den Taster A (= 1.), den Taster B (= 2.) und wieder den Taster A (= 3.) betätigt. Hätten nämlich die beiden Statements im obenstehenden hellgrünen Kasten die „strip“-Liste komplett, d.h. auch physisch
gelöscht, dann ließe sich die grüne „NeoPixel“-LED weiter oben im hellgrünen
Kasten
nicht ein weiteres Mal zum Leuchten bringen! In diesem Zusammenhang gibt es noch ein
weiteres, interessantes Phänomen. Starte dazu das Programm „joy-car_teil_02_prog_31.hex“
und finde heraus, weshalb sich die grüne „NeoPixel“-LED jetzt nicht
mehr zum Leuchten bringen lässt. Und zwar egal, welche der Tasten A oder B
man betätigt! Tipp: Der Programmierfehler lässt sich leicht
herausfinden, indem man den Quellkode der beiden Programm „joy-car_teil_02_prog_30.py“
und „joy-car_teil_02_prog_31.py“
miteinander vergleicht. Und zwar den im Hauptprogramm
(siehe roter Kasten
unten). Auch wenn wir wieder eine Menge über das
Programmieren der „NeoPixel“-LEDs gelernt haben, so
haben wir dennoch im Zusammenhang mit dem Programm „joy-car_teil_02_prog_28.py“
oder „joy-car_teil_02_prog_30.py“
noch nicht gelernt, worin sich die Taster A
und B vom Touch-Panel (= Antippen/Berühren des „micro:bit“-Logos – siehe Bild 17) (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_30.py“) nun tatsächlich bzw. maßgeblich unterscheiden!
Dabei gilt es zunächst festzustellen, dass sich alle drei Statements zu den Tastern A und B
sowie zum Touch-Panel (siehe blauer Kasten) im statischen
Hauptprogramm (siehe roter Kasten) befinden! Also nichts von wegen endloser Wiederholung der Programmausführung bei Funktionen usw.: (Zum Vergrößern bitte
auf das Bild klicken!) Aber auf welche der drei Statements zu den Tastern A und B
sowie zum Touch-Panel (siehe blauer Kasten) lässt sich das ·
Statement <basic.forever(Name der Funktion)> denn nun tatsächlich fehlerfrei anwenden? Man höre und staune: nur auf das Touch-Panel, da es sich bei diesem um einen Ereignis
gesteuerten Sensor handelt. Wenn man die anderen beiden Taster A und B
mit in die dynamische Programmierung
bzw. das Ereignis gesteuerte Programmierung einbinden will, dann muss man
deren Statements nebst weiterer Auslöse- und Reaktions-Funktionen innerhalb des
sich endlos wiederholenden Programmblocks
<basic.forever()> platzieren: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_32.py“) Eigentlich verhält es sich so, dass sich die
beiden Taster A und B Ereignis
gesteuert
verhalten und demzufolge verzögerungsfrei und sofort reaktiv
verhalten, sodass sich diese jederzeit betätigen lassen. Demzufolge
wäre es eigentlich nicht erforderlich, diese explizit in die Funktion <on_forever()> aufzunehmen (siehe rosaroter
Kasten).
Später, wenn beide Fahrrichtungsanzeiger, d.h. die beiden Blinker rechts und
links, ordnungsgemäß funktionieren, werden wir deshalb nochmals die Frage
nach der „real time“-Funktion (= Echtzeitverhalten)
der beiden Taster A und B aufgreifen. – Auch wenn das Programm „joy-car_teil_02_prog_32.py“
noch nicht so funktioniert, wie es letztlich funktionieren soll, so bietet es
trotzdem noch einen weiteren Erkenntnisgewinn. Und zwar den einer sogenannten
„Do … while“-Schleife, die es so in Python - im
Gegensatz zu anderen, höheren Programmiersprachen - nicht gibt. Mal sehen was das neue „ChatGPT 4.0“ mit der KI von Open AI in der neuen
„bing“-Suchmaschine von Microsoft dazu heraus findet: (Vergrößern: auf das
Bild klicken! | „Bing“-Suchmaschine mit KI " Chat) Dabei handelt es sich bei der „Do … while“-Schleife um eine fußgesteuerte „Endlos“-Schleife, die so oft „im Kreis“ läuft bis der
Strom ausfällt oder die Abbruchbedingung
<schalteBlinker_rechts = False>
erfüllt ist (siehe roter Kasten): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_32.py“) Obwohl wir
jetzt wissen, wie man eine fußgesteuerte „Do … while“-Schleife
programmiert und den Vorteil zu schätzen wissen, ·
dass diese auf jeden
Fall mindestens einmal durchlaufen wird und sich mittels ·
der Abbruchbedingung <if input.button_is_pressed(Button.A)> jederzeit
beenden lässt, verhält es sich dennoch so, dass diese nicht mit der endlosen Wiederholung in Echtzeit der Funktion <on_forever()> (Zum Vergrößern bitte
auf das Bild klicken!) vergleichbar
ist. Wenn man
nämlich das Programm „joy-car_teil_02_prog_32.hex“
startet und mittels einer die beiden Taster A oder B den Fahrrichtungsanzeiger
(= Blinker) entweder nach links (= Taster B)
oder nach rechts (= Taster A) auslöst, dann
schaltet sich dieser sofort verzögerungsfrei ein und beginnt zu
blinken, weil die beiden Taster A oder B innerhalb der Funktion
<on_forever()> fortwährend abgefragt werden! Anders verhält es sich hingegen, wenn man den Blinker mittels eines der entsprechenden Taster A oder B
wieder ausschalten will, da das Ausschalten nicht direkt,
sondern nur indirekt über die globale, boolesche Variable <schalteBlinker_rechts> oder die globale,
boolesche Variable <schalteBlinker_links> erfolgt! Demzufolge
erfolgt das Ausschalten des Blinkers entweder sofort oder aber nur verzögert
nach längerem Drücken eines der
entsprechenden Taster A oder B, je nachdem in welcher Funktion sich das Programm
gerade befindet. Im ungünstigen Fall kann das dann schon mal einen andauernden
Tastendruck von mehr als einer Sekunde erfordern: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_32.py“) Wenn man später bei dem „Joy-Car“-Roboter die Bewegung,
insbesondere das Abbiegen nach links oder
rechts, programmieren will, dann kann man für den Abbiegevorgang den im „micro:bit“-Rechner integrierten Kompass für die jeweilige Richtungsänderung hinzuziehen und das Setzen des Fahrrichtungsanzeigers (= Blinker) automatisch
veranlassen. Und sobald der „Joy-Car“-Roboter die eingeschlagene
Richtung für ein paar Sekunden beibehält, kann man wiederum den Blinker automatisch ausschalten. Denkbar wäre aber auch, dass der „Joy-Car“-Roboter immer nur dann eine Richtungsänderung nach links oder
rechts vornehmen kann, wenn zuvor der Blinker
entsprechend per Taster A oder B gesetzt wurde. Damit man nicht jedes Mal bei
der geringsten Richtungsänderung den Blinker vorher setzen muss, kann man die Richtungsänderung vom eingeschlagenen
Lenkradeinschlag bzw. Lenkwinkel abhängig machen. Denkbar wäre aber auch, dass sich der Blinker immer erst dann automatisch ein- oder
ausschaltet, wenn die Änderung des Lenkwinkels mehr als 30 Grad beträgt. Demzufolge wäre bei allen Richtungsänderungen nebst Lenkwinkeleinschlag,
dass sich der Blinker je
nach Programmierung auf jeden Fall ohne Zeitverzögerung, d.h. in Echtzeit aktivieren oder deaktivieren
lässt! Das ist dann auch der Grund dafür, weshalb wir die fußgesteuerte „Do … while“-Schleife wieder aus dem
obenstehenden Programm entfernen: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_33.py“) Wie man im obenstehenden Programmkode sieht, wird der Blinkvorgang jetzt nur noch ein einziges Mal
durchgeführt (siehe roter Kasten). Da der Blinkvorgang aber so lange andauern soll bis der Taster A (= rechts blinken aus Fahrersicht) zwecks Ausschaltens ein weiteres Mal
gedrückt wird, muss man sich um das wiederholte Blinken selbst kümmern bzw. dieses in der Funktion <on_forever()> explizit
programmieren. Und zwar für beide Taster A
und B (siehe rote Kästen): (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_33.hex“) Spätestens jetzt dürfte man die Endlosschleife der Funktion <on_forever()> in Echtzeit zu schätzen wissen! Selbstverständlich lässt sich die Standard-Funktion
<on_forever()> auch im logischen
Sinnzusammenhang mit der Blinker-Funktion wie folgt umbenennen: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_34.py“) Wie man im obenstehenden Sourcecode sieht, gehört die umbenannte Funktion <rechts_links_Blinken()> in den Funktionsteil des Programms und nicht in das Hauptprogramm. Schließlich geht es
darum, das Hauptprogramm möglichst kompakt
und übersichtlich zu halten. Das Programm
„joy-car_teil_02_prog_34.hex“
funktioniert bis auf einen Schönheitsfehler einwandfrei. Dabei
handelt es sich bei dem Schönheitsfehler wider Erwarten nicht
um einen herkömmlichen Programmier- oder Syntaxfehler, sondern vielmehr um
einen, teils logischen, Verständnisfehler, der wiederum eher
mit der logischen Abfolge des
Blinkvorganges
an sich zu tun hat. Aber um welchen logischen Verständnis- und Denkfehler handelt es sich dabei
eigentlich? Wie macht sich der Schönheitsfehler überhaupt bemerkbar? Wenn man das obenstehende Programm startet,
dann wird als Erstes das Tagfahrlicht gestartet, sodass die
vorderen NeoPixel-LEDs Nr. 1
und 2 weiß und die hinteren
NeoPixel-LEDs Nr. 4 und 7
rot leuchten. Wenn man dann den Rechts- oder Links-Blinker per Tastendruck
einschaltet, dann müssen dazu die entsprechenden NeoPixel-LEDs Nr. 1 und 4
beim Linksblinken (= Taster B) oder die
NeoPixel-LEDs Nr. 2 und 7
beim Rechtsblinken (= Taster A) aus- und
umgeschaltet werden. Dabei macht sich beim Rechtsblinken (= Taster A) der Schönheitsfehler in der Form
bemerkbar, dass beim Ein- und Ausschalten der orangenen NeoPixel-LED Nr. 2 ein unangenehmes weißes Aufblitzen störend bemerkbar
macht: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_34.hex“) Das unangenehme weiße Aufblitzen (siehe mittleres
Bild) lässt sich aber auch ausschalten, (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_34.hex“) indem man durch Berühren des Touch-Sensors (siehe Bild 17) das Stand- oder Tagfahrlicht einfach deaktiviert, d.h. ausschaltet! Damit wäre bewiesen, dass es zwischen den obenstehenden
Funktionen 1.
Funktion <Blinker_links_blinkt(schalte_Ein_Aus)>, 2.
Funktion <Blinker_rechts_blinkt(schalte_Ein_Aus)> und der 3.
Funktion <Standlicht(schalteStandlicht)> oder auch der 4.
Funktion <Tagfahrlicht(schalteTagfahrlicht)> hinsichtlich des unangenehmen weißen Aufblitzens einen Zusammenhang
gibt! Und zwar den, dass die beiden Funktionen 1.) und 2.)
jeweils die im <else>-Programmteil enthaltenen Funktionsaufrufe 3.) und 4.) aufrufen und diese miteinander
funktional verschachteln. Da das unangenehme und störende weiße Aufblitzen wider Erwarten nicht
beim Linksblinken auftritt, können wir
die Funktion 1.) als Fehlerursache ausschließen. Des Weiteren können wir die Funktionen(!) 3.) und 4.) ebenfalls als Fehlerursache ausschließen, da
weder beim Tagfahrlicht noch beim Standlicht ein weiß leuchtendes Aufblitzen programmiert wurde. Und überhaupt, was bedeutet denn der Vorgang
des Aufblitzens
beim Leuchten des Lichts? Es bedeutet nichts anderes als dass der Lichtstrahl bzw. das Licht
fortwährend unterbrochen wird, so als würde der Lichtstrahl von einer rotierenden Lochkranzscheibe
wie beim analogen Filmprojektor
ständig, d.h. periodisch wiederkehrend, ein-
und ausgeschaltet wird. Und da es bei
den „NeoPixel“-LEDs und deren Leuchtbefehlen keine Statements oder Funktionen zum Aufblitzenlassen der LEDs gibt, kann es sich bei dem weiß
leuchtenden Aufblitzen auch nicht um einen Programmierfehler im Sinne eines
speziellen „NeoPixel“-Befehls handeln. Wenn es aber keinen „NeoPixel“-Befehl zum Aufblitzen, kurzen Aufleuchten oder dem Blinken z.B. für das Links- oder Rechtsabbiegen gibt, wie programmiert man dann das Blinken einer oder mehrerer „NeoPixel“-LEDs? Ganz einfach ähnlich wie bei einer Taschenlampe, d.h.
einer modernen, elektronischen Taschenlampe, die z.B. anstelle eines
herkömmlichen Ein-/Aus-Schiebe- oder eines Drucktasten-Schalters über einen Multifunktionstaster verfügt mit dem sich u.a. die Helligkeit einer oder mehrerer,
weißer LEDs in bis zu drei
Stufen einstellen lässt.
Darüber hinaus sollte diese auch über eine Tasterfunktion zum Morsen, d.h. zum schnellen
Ein- und Ausschalten des Lichts
verfügen, sodass sich mit dieser auch kurze Lichtblitze erzeugen lassen. Wie aber lassen sich solche oder ähnliche Lichtblitze nebst des schnellen
Ein- und Ausschaltens einzelner oder mehrerer „NeoPixel“-LEDs programmieren, obwohl es doch keinen
einzelnen „NeoPixel“-Befehl gibt? Keine Sorge, wir müssen die Lichtblitze nicht explizit
programmieren, da wir diese bereits programmiert haben! Allerdings sind diese
Lichtblitze ziemlich träge und
noch dazu langsam. Demzufolge „blitzen“ die Lichtblitze mit einer langsamen, symmetrischen
Blitzfrequenz
von fBlitz = 1 Hz, d.h. einer
Schwingung pro Sekunde. Dabei gilt: fBlitz = 1 / TBlitz oder TBlitz =
1 / fBlitz = 1 / 1 Hz = 1 / ( 1 Schwingung/s ) = 1 s " T = Periodendauer Wie man
sieht, ist dabei eine (Rechteck-) Schwingung mit n = 1 dimensionslos:
TBlitz = n / fBlitz = 1 / 1 Hz = 1 s Dabei ist die langsame Blitzfrequenz im vorliegenden Fall symmetrisch,
weil die Leuchtdauer des Blitzes (= Einschaltdauer tEin)
zeitlich eben so lang ist wie die Leuchtpause (= Ausschaltdauer tAus). Demzufolge berechnet sich die Leucht- bzw. Impulsdauer t (= griechischer Buchstabe
„Tau“) des Blitzes wie folgt: t =
D * T " D = Tastgrad bzw. Tastverhältnis zwischen Ein- und Ausschaltzeit D = t / T =
500 ms / 1 s = 0,500 s / 1 s = 0,5 " 50 % Wie man unschwer sieht, beträgt das Tastverhältnis D zwischen Ein- und Ausschaltzeit (=t / T ) (Vergrößern: auf das
Bild klicken! | Wikipedia „Rechtecksignal“) tatsächlich 50 % oder 500 ms: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_35.py“) Das symmetrische Tastverhältnis D zwischen Ein- und Ausschaltzeit (=t / T ) von 50 % hat den Vorteil, dass das relativ langsame
Blinken des Fahrtrichtungsanzeigers (= Blinker) im Sekundentakt als angenehm und nicht als aggressiv
empfunden wird. Während also das langsame Blinken des Fahrtrichtungsanzeigers (= Blinker) über ein symmetrische
Tastverhältnis D zwischen Ein- und Ausschaltzeit (=t / T ) von 50 % verfügt, kann man das von dem unangenehmen weißen
Aufblitzen
nicht behaupten. Da aber das störende und unangenehm weiße
Aufblitzen
ebenfalls im Sekundenrhythmus aufblitzt, muss es
zwangsläufig über den Programmkode
mit den Zwangspausen, der damit
verbundenen Periodendauer
T = 1 s
und den Statements <basic.pause(500)> laufen (siehe grünes und rotes Fenster im Bild oben). Allerdings erfolgt das Aufblitzen mit einem wesentlich
kürzeren und vor allem asymmetrischen Tastverhältnis, was ja gerade den Blitzeffekt, ähnlich eines Foto- oder
Gewitterblitzes, ausmacht. Gemäß dem obenstehenden Programmkode muss dabei das
unangenehme und störend weiße Aufblitzen zeitlich nach dem roten Blinken
des Fahrtrichtungsanzeigers für das Rechtsabbiegen erfolgen. Wegen der Trägheit des
menschlichen Auges lässt sich aber die zeitliche Abfolge und Reihenfolge des Blinkvorgangs und des Aufblitzens wider Erwarten nicht
nachvollziehen. Was es aber
an dieser Stelle und in diesem Zusammenhang noch aufzuklären gilt, ist der
Umstand, dass das unangenehme und störend weiße Aufblitzen nur bei der „NeoPixel“-LED Nr. 2 auftritt, obwohl sich
das Tagfahr-
oder Standlicht entsprechend der Programmierung auf beide
„NeoPixel“-LEDs Nr. 1 und Nr. 2 bezieht!
Und genau dieser Umstand ist es, der die erfolgreiche Fehlersuche praktisch unmöglich macht! Was also tun? Um bei der Fehlersuche trotzdem erfolgreich zu sein, muss man
die unterschiedlichen Lichter und Lichteffekte von Tagfahr- und Standlicht sowie vom Rechts- und Linksblinken unterscheidbar
machen, indem man diesen unterschiedliche Farben
zuweist! Demzufolge bekommt das Standlicht nicht mehr die Farbe Weiß zugewiesen, sondern
die Farbe Blau! Außerdem wird das orangefarbene Blinklicht für das Rechtsblinken der „NeoPixel“-LED Nr. 2
in der Funktion <Blinker_rechts_NeoPixel(Blinker_rechts_einschalten)> kurzerhand mit (7, 7)
anstelle von vormals (2, 7) ausgeschaltet: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_35.hex“) Wenn man jetzt das obenstehende Programm
startet, dann stellt man fest, dass jetzt das Standlicht nicht mehr wie zuvor weiß, sondern vielmehr blau leuchtet. Wenn man dann den Taster A drückt, um das Rechtsabbiegen zu signalisieren, dann stellt man ferner fest, dass das Standlicht jetzt plötzlich blau aufblitzt! Und zwar
bei beiden „NeoPixel“-LEDs der Nr. 1 (= links) und Nr. 2 (= rechts) aus Fahrersicht. Dabei verhält es sich ferner so, dass das orangefarbene
Blinklicht für das Rechtsblinken der „NeoPixel“-LED Nr. 2
nicht mehr blinkt, da dieses zuvor abgeschaltet wurde (siehe rote Kästen im Bild oben),
während das hintere orangefarbene Blinklicht für das Rechtsabbiegen der „NeoPixel“-LED Nr. 7 weiterhin wie gehabt,
blinkt. Schaltet man das Rechtsblinken mittels des Tasters A wieder aus, verschwindet das blaue Aufblitzen wieder! Mittels des Touch-Sensors (siehe Bild 17) lässt sich das Stand- oder Tagfahrlicht jederzeit beliebig oft aus-
oder wieder einschalten und auf diese Weise
der Effekt des blauen Aufblitzen verdeutlichen!
Wenn man also etwas sehen will, was man sonst
nicht sieht, weil beide Anzeigen (= Funktion <Standlicht()> und Funktion
<Blinker_rechts_blinkt()> ) ein- und dieselbe „NeoPixel“-LED-Farbe verwenden, dann muss
man für beide Anzeigen unterschiedliche
„NeoPixel“-LED-Farben verwenden und, wenn
das blaue Aufblitzen kürzer als ein
Wimpernschlag ist, dann muss man wegen der Trägheit des menschlichen Auges
zwecks besserer Erkennbarkeit eine der beiden Anzeigen vorübergehend ausschalten/deaktivieren (siehe
roter, abgewinkelter Pfeil im grünen
Kasten
im obenstehenden Screenshot). Aber das alles erklärt noch nicht das blaue Aufblitzen an sich! Was aber bedeutet es praktisch bzw. technisch,
wenn eine „NeoPixel“-LED aufblitzt, d.h. ganz
kurz aufleuchtet? Das ganz kurze Aufleuchten einer „NeoPixel“-LED bedeutet programmiertechnisch, dass die LED ganz kurz ein- und gleich darauf wieder ausgeschaltet wird (siehe Bild 61). Dabei gibt es aber
einen wesentlichen Unterschied bei den beiden Anzeigen. Während das Rechtsblinken der „NeoPixel“-LED Nr. 2
auf der rechten Fahrerseite
im Sekundentakt erfolgt, erfolgt das blaue Aufblitzen im Bereich einiger Millisekunden (= 1/1000 Sekunden)! Aber weshalb? Knackpunkt ist, dass wir es mit zwei Anzeigen (= Funktion
<Standlicht()> und Funktion <Blinker_rechts_blinkt()> ) zu tun haben, die nacheinander
ablaufen, wobei sich das blaue Aufblitzen auf den Vorgang und
die Funktion <Standlicht()> bezieht. Wenn man
also das Programm „joy-car_teil_02_prog_35.hex“
startet, dann wird als erstes das blaue
Standlicht eingeschaltet und anschließend
auf Tastendruck des Tasters A das Blinklicht für das Rechtsabbiegen. Dabei gilt es zu beachten, dass das Standlicht dauerhaft angezeigt wird, gleichzeitig
aber vom Blinklicht unterbrochen
wird! Und die Unterbrechung des Blinklichts ist es schließlich, die das blaue Aufblitzen des Standlichts zur Folge hat! Wenn man also das blaue
Aufblitzen des Standlichts vermeiden will, dann muss man 1.
das Standlicht vor und
während des Blinkens für das Rechtsabbiegen ausschalten oder 2.
das Standlicht mit dem Blinklicht „überschreiben“! Da sich die Fehlersuche nach dem blauen Aufblitzen sehr komplex
gestaltet, gehen wir jetzt sehr stringent vor, indem wir einzelne Funktionen, die mit dem Standlicht und dem Rechtsblinken zu tun haben, nacheinander gegen intakte, funktionierende
Funktionen auswechseln bzw.
„auskommentieren“. Doch zunächst gehen wir auf Nummer sicher und
kommentieren die anfangs übrig gebliebenen Funktionen wie folgt aus: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_36.py“) Da das Auskommentieren des orangefarbenen
Quellkodes im roten Kasten im obenstehenden
Screenshot bezüglich des blauen Aufblitzens ohne Auswirkung
blieb, tauschen wir als nächstes alle Funktionen nebst Funktionsaufrufen aus, die mit dem Standlicht zu tun haben: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_37.py“) Wie man im obenstehenden Quellkode sieht, wird
die globale Variable <schalteStandlicht> bei beiden Funktionen <Standlicht_schalten()> von <True> auf <False> und umgekehrt
umgeschaltet. Weiter nichts. Während bei der alten, auskommentierten orangefarbenen Funktion dem Funktionsaufruf <Standlicht()> lediglich der statische
Wert <True> mit auf den Weg
gegeben wird, wird bei der neuen Funktion
<Standlicht_schalten()> der dynamische
Wert der Variablen <schalteStandlicht> übergeben, der je nachdem entweder <True> oder <False> sein kann. Aber zwischen der alten, auskommentierten
orangefarbenen Funktion und der neuen Funktion <Standlicht_schalten()> gibt es noch einen
weiteren, programmiertechnischen und funktionalen Unterschied. Bei der alten
Funktion wird die Funktion <Standlicht(True)> aufgerufen und wegen
des Rückgabestatements <return(Standlicht_einschalten)> auch definitiv ausgeführt!
Dabei wird der Rückgabewert im Statement <return(Standlicht_einschalten)> an die globale Variable <schalteStandlicht> übergeben. Bei der neuen
Funktion <Standlicht_schalten()> wird die Funktion <Standlicht(schalteStandlicht)> ebenfalls aufgerufen
und ausgeführt, der eventuell geänderte Rückgabewert
im Statement <return(Standlicht_einschalten)> aber nicht an
die globale Variable <schalteStandlicht> übergeben, sodass es
bei dem zugewiesenen Variableninhalt <schalteStandlicht
= False> bleibt.
Wir nehmen diese neue Programmiererkenntnis zum Anlass und ändern
bei dieser Gelegenheit die auch die Funktion
<Tagfahrlicht_schalten()> Da die Funktion
<Standlicht_schalten()> nur in Verbindung mit
dem Touch-Sensor und dem Statement
<input.on_logo_event(TouchButtonEvent.PRESSED, Standlicht_schalten)> gebraucht wird, steht
diese in keinem Zusammenhang mit dem blauen
Aufblitzen der vorderen „NeoPixel“-LEDs. (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_38.py“)
In diesem Zusammenhang muss noch erwähnt
werden, dass sich das Standlicht mit der Funktion <Standlicht(Standlicht_einschalten)>
jeweils im Wechsel ein- und ausschalten lassen soll (siehe
rote Unterstreichung im obenstehenden Programmkode). Demzufolge darf der Statuswechsel von <True> auf <False> nur in der <else>-Bedingung erfolgen (siehe im
obenstehenden Screenshot)! Insgesamt verhält es sich so, dass die Funktion <Standlicht(Standlicht_einschalten)>
keinen Einfluss auf das blaue Aufblitzen der vorderen „NeoPixel“-LEDs hat! - Die neue Funktion <Blinker_rechts()> unterscheidet sich gegenüber der alten
Funktion <Blinker_rechts()> nur dahingehend, dass
sich die Reihenfolge vom Umschalten der
globalen Variablen <schalteBlinker_rechts> von <False> auf <True> ändert: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_39.py“) Dies ist dem Umstand geschuldet, dass das Rechtsblinken mit der Status-Variablen
<schalteBlinker_rechts> im Hauptprogramm mittels des ·
Statements <schalteBlinker_rechts
= False> auf den Anfangsstatus
<False> gesetzt wurde!
Abschließend verhält es sich so, dass die Funktion <Blinker_rechts()> keinen
Einfluss auf das blaue Aufblitzen der vorderen „NeoPixel“-LEDs hat! - Die neue Funktion <Blinker_rechts_blinkt(schalte_Ein_Aus)> unterscheidet sich gegenüber der alten
Funktion <Blinker_rechts_blinkt(schalte_Ein_Aus)> dahingehend, dass auf das wiederholte Aufrufen des Tagfahrlichtes oder des Standlichtes verzichtet wurde (siehe roter Kasten). Und zwar aus dem
einfachen Grund, um unterschiedliche Funktionen nicht miteinander zu vermischen, sondern strikt
voneinander zu trennen! Darüber hinaus macht es wenig Sinn, die „NeoPixel“-LEDs Nr. 2 und 7 auf der rechten Seite des „Joy-Car“-Roboters dunkel zu schalten
(siehe blauer Kasten), wenn diese
Konfiguration gleich darauf von dem aktivierten und wieder eingeschalteten Standlicht (oder Tagfahrlicht) überschrieben wird: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_40.py“) Da es in der <else>-Bedingung nur darum geht, das Rechtsblinken nach dem Einschalten wieder ausschalten zu können, sodass
sich der Taster A als Wechseltaster zum Ein-
und Ausschalten verwendet lässt,
würde man normalerweise die „NeoPixel“-LEDs als Ganzes komplett
ausschalten. Beispielsweise mit dem ·
Statement <JoyCar.light(ToggleSwitch.OFF)> oder mit den Statements ·
Statement <strip.clear()> ·
Statement <strip.show()> Aber genau das verbietet sich im vorliegenden
Fall, weil zwar das Rechtsblinken ausgeschaltet werden
soll, gleichzeitig aber die Anzeigen der „NeoPixel“-LEDs als Ganzes wieder in
den Modus „Standlicht“ (oder „Tagfahrlicht“) zurückfallen soll! Und zwar verzögerungsfrei, ohne
größere Pause und vor allem ohne dass die „NeoPixel“-LEDs in irgendeiner Weise
aufblitzen! Deshalb gehen wir auf Nummer sicher, nehmen die Helligkeit , engl. „brightness“,
aus allen „NeoPixel“-LEDs heraus und wechseln
zusätzlich noch die „NeoPixel“-Farbe auf Schwarz (siehe grüner
Kasten
oben). Wendet man das Programm „joy-car_teil_02_prog_40.hex“
praktisch an, indem man dieses startet, dann stellt man fest, dass auch die neue
Funktion <Blinker_rechts_blinkt(schalte_Ein_Aus)> keinen Einfluss auf das blaue Aufblitzen der vorderen „NeoPixel“-LEDs hat! - Als nächstes knöpfen wir uns die alte Funktion <rechts_links_Blinken()> vor, indem wir diese
wie folgt auskommentieren und durch die neue Funktion <rechts_links_Blinken()> ersetzen. (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_41.py“) Wie man im obenstehenden Quellkode sieht, wird
die globale Variable <schalteBlinker_rechts> bei beiden Funktionen <rechts_links_Blinken()> von <True> auf <False> und umgekehrt
umgeschaltet. Weiter nichts. Während bei der alten, auskommentierten orangefarbenen Funktion dem Funktionsaufruf <rechts_links_Blinken()> lediglich der statische
Wert <True> mit auf den Weg
gegeben wird, wird bei der neuen Funktion
<rechts_links_Blinken()> der dynamische
Wert der Variablen <schalteBlinker_rechts> übergeben, der je
nachdem entweder <True> oder <False> sein kann. Gemäß dem ·
Statement <basic.forever(rechts_links_Blinken)> im Hauptprogramm
ist die Funktion <rechts_links_Blinken()> die einzige im
Programm, die nach dem Programmstart fortwährend,
d.h. endlos bis zum Stromausfall ausgeführt wird. Dabei dient die „Endlos“-Funktion <rechts_links_Blinken()> dazu, die beiden
Taster A und B und den Touch-Sensor mit dem Statement <input.on_logo_event(TouchButtonEvent.PRESSED, Standlicht_schalten)> permanent,
d.h. ununterbrochen aufzurufen und abzufragen, ob diese ggf. betätigt
wurden. Außerdem dient die „Endlos“-Funktion <rechts_links_Blinken()> dazu, dass sich die Funktionen ·
<Blinker_rechts_blinkt(schalteBlinker_rechts)>, ·
<Blinker_links_blinkt(schalteBlinker_links)>, ·
<Warnblinker_blinkt(schalteWarnblinker)> und ·
<Standlicht_schalten()> per Tastendruck bzw. Berühren, engl. „touch“, ähnlich einem einpoligen Wechselschalter
im Flur oder Treppenhaus wechselseitig von <True> auf <False> und umgekehrt hin-
und herschalten lassen, sodass zum Ein-
oder Ausschalten kein zweiter Schalter oder Touch-Sensor benötigt wird! Wendet man das Programm „joy-car_teil_02_prog_41.hex“
praktisch an, indem man dieses startet, dann stellt man fest, dass auch die neue
Funktion <rechts_links_Blinken()> keinen
Einfluss auf das blaue Aufblitzen der vorderen „NeoPixel“-LEDs hat! - So, nun bleibt bezüglich der Fehlersuche nach der Ursache für blaue Aufblitzen nur noch die Funktion <Blinker_rechts_NeoPixel(Blinker_rechts_einschalten)> übrig. Diesbezüglich erinnern wir uns an den
Vorsatz, nur noch Funktionen zu programmieren, die
keine anderweitigen Funktionalitäten wie z.B. das Konfigurieren von
diversen „NeoPixel“-LEDs für das Tagfahrlicht oder Standlicht vorzunehmen! Demzufolge werden alle Programmteile, die mit
dem Konfigurieren diverser „NeoPixel“-LEDs für das Tagfahrlicht oder Standlicht zu tun haben, auskommentiert (siehe organgefarbenen Text): (Vergrößern: auf das Bild
klicken! | Programm „joy-car_teil_02_prog_42.py“) Auch das abschließende Umschalten der booleschen Variablen <Blinker_rechts_einschalten> von <True> auf <False> und umgekehrt, wird
auskommentiert (siehe blauer Kasten), da dieses bereits in der „Endlos“-Funktion <rechts_links_Blinken()> erfolgt. Zu guter
Letzt werden noch ein paar kleine Korrekturen vorgenommen (siehe rote Unterstreichung). Wenn man
das Programm „joy-car_teil_02_prog_42.hex“
startet, dann stellt man fest, dass die
auskommentierten Programmteile keinen Einfluss auf das blaue Aufblitzen der vorderen „NeoPixel“-LEDs haben! - Damit die Funktion
<Blinker_rechts_NeoPixel(Blinker_rechts_einschalten)> (siehe oben) übersichtlicher wird, entfernen
wir alle zuvor auskommentierten,
orangefarbenen Programmzeilen, sodass nur noch der nachfolgende Sourcecode übrig bleibt: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_43.py“) Wir starten
das neue Programm „joy-car_teil_02_prog_43.hex“,
um zu überprüfen, ob dies noch ordnungsgemäß funktioniert und stellen dabei
fest, dass das blaue Aufblitzen der vorderen „NeoPixel“-LEDs noch immer
besteht! Als letzte Maßnahme sozusagen, kommentieren
wir ·
die alte Funktion
<Blinker_rechts_NeoPixel(Blinker_rechts_einschalten)> aus und fügen unterhalb deren Stelle die ·
die neue Funktion
<Blinker_rechts_NeoPixel(Blinker_rechts_einschalten)> wie folgt ein: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_44.py“) Beim Vergleich der alten, auskommentierten Funktion mit der neuen Funktion (siehe im Bild oben),
fällt sofort auf, dass das ·
Statement <strip = neopixel.create(DigitalPin.P0, 8, NeoPixelMode.RGB)> in der neuen Funktion nicht mehr vorkommt (siehe pinkfarbener
Kasten
oben im Bild)! Wenn man
das neue Programm „joy-car_teil_02_prog_44.hex“
startet, dann stellt man nicht nur fest, dass dieses ordnungsgemäß
funktioniert, sondern auch, dass das blaue
Aufblitzen der vorderen „NeoPixel“-LEDs
plötzlich nicht mehr auftritt! Jetzt wo der Fehler,
der das blaue Aufblitzen der vorderen „NeoPixel“-LEDs verursachte, gefunden ist, räumen wir
das Programm „joy-car_teil_02_prog_44.py“
auf, indem wir alle auskommentierten
Programmteile,
die mit dem Standlicht und dem Rechtsblinken zu tun haben, löschen.
Dabei bleiben aber die Programmteile
in den Zeilen 12 bis 65 mit den Funktionen ·
NeoPixel_anzeigen(),
·
on_button_pressed_a(),
·
on_button_pressed_b() weiterhin erhalten, werden also nicht
gelöscht (siehe Programm „joy-car_teil_02_prog_45.py“)!
Im Zusammenhang mit dem fehlerhaften blauen Aufblitzen der vorderen „NeoPixel“-LEDs muss noch erwähnt werden, dass das
ursprüngliche, fehlerhafte ·
Statement <strip = neopixel.create(DigitalPin.P0, 8, NeoPixelMode.RGB)> nur durch das korrekte ·
Statement neopixel.create(DigitalPin.P0,
8, NeoPixelMode.RGB)> hätte ersetzt bzw. eingetastet
werden müssen: (Vergrößern: auf das
Bild klicken! | Programm „joy-car_teil_02_prog_45.py“) Weiter zum [ Teil 2b ] mit der Objekt
orientierten Programmierung (OOP). |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
[
Home ]
[ Seitenanfang ] [Teil 1 ] [ Teil 2b ] [ Teil 3 ] |
|