Verkehrsampel V1

Der erste Entwurf unseres Programms ist fertig. Wir sind ein wenig stolz, weil der Code so schön lesbar und so gut kommentiert ist. Das Ein- und Ausschalten der Anlage fehlt noch, aber es funktioniert schon prima! Und in Englisch ist es auch noch!

// Two traffic lights, using the standard pattern (R,R+Y,G,Y).
// GREEN time is shared 50:50 between the two lights

// version 1

#include <Adafruit_NeoPixel.h>

// we use a single strip of 14 LEDs
// traffic light A =  RED( 1, 2), YELLOW( 3, 4), GREEN( 5, 6)
// traffic light B =  RED(11,12), YELLOW( 9,10), GREEN( 7, 8)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(14,26);
 
void setup() {
    Serial.begin(115200);
    delay(100);

    Serial.println("all dark");
    strip.fill(0);
}
 
void loop() {

    // all red
    Serial.println("* = R");
    strip.setPixelColor( 1, 20, 0, 0);  // tlA = RED
    strip.setPixelColor( 2, 20, 0, 0);
    strip.setPixelColor(11, 20, 0, 0);  // tlB = RED
    strip.setPixelColor(12, 20, 0, 0);
    strip.show();
    delay(500);

    Serial.println("A = R+Y");
    strip.setPixelColor( 3, 20,20, 0);  // tlA = RED + YELLOW
    strip.setPixelColor( 4, 20,20, 0);
    strip.show();
    delay(1000);

    Serial.println("A = G");
    strip.setPixelColor( 1,  0, 0, 0);  // tlA = no red
    strip.setPixelColor( 2,  0, 0, 0);
    strip.setPixelColor( 3,  0, 0, 0);  // tlA = no yellow
    strip.setPixelColor( 4,  0, 0, 0);
    strip.setPixelColor( 5,  0,20, 0);  // tlA = GREEN
    strip.setPixelColor( 6,  0,20, 0);
    strip.show();
    delay(10000);

    Serial.println("A = Y");
    strip.setPixelColor( 5,  0, 0, 0);  // tlA = no green
    strip.setPixelColor( 6,  0, 0, 0);
    strip.setPixelColor( 3, 20,20, 0);  // tlA = YELLOW
    strip.setPixelColor( 4, 20,20, 0);
    strip.show();
    delay(2000);

    // all red
    Serial.println("* = R");
    strip.setPixelColor( 3,  0, 0, 0);  // tlA = no yellow
    strip.setPixelColor( 4,  0, 0, 0);
    strip.setPixelColor( 1, 20, 0, 0);  // tlA = RED
    strip.setPixelColor( 2, 20, 0, 0);
    strip.show();
    delay(500);

    Serial.println("B = R+Y");
    strip.setPixelColor( 9, 20,20, 0);  // tlB = RED + YELLOW
    strip.setPixelColor(10, 20,20, 0);
    strip.show();
    delay(1000);

    Serial.println("B = G");
    strip.setPixelColor(11,  0, 0, 0);  // tlB = no red
    strip.setPixelColor(12,  0, 0, 0);
    strip.setPixelColor( 9,  0, 0, 0);  // tlB = no yellow
    strip.setPixelColor(10,  0, 0, 0);
    strip.setPixelColor( 7,  0,20, 0);  // tlB = GREEN
    strip.setPixelColor( 8,  0,20, 0);
    strip.show();
    delay(10000);

    Serial.println("B = Y");
    strip.setPixelColor( 7,  0, 0, 0);  // tlB = no green
    strip.setPixelColor( 8,  0, 0, 0);
    strip.setPixelColor( 9, 20,20, 0);  // tlB = YELLOW
    strip.setPixelColor(10, 20,20, 0);
    strip.show();
    delay(2000);

    strip.setPixelColor( 9,  0, 0, 0);  // tlB = no yellow
    strip.setPixelColor(10,  0, 0, 0);
    
}

Als wir das Programm unserem Lehrer zeigen, lobt er uns, denn er hat gelernt, dass Lob die Motivation fördert.

Innerlich denkt er sich allerdings: Wie kann ich euch jetzt schonend beibringen, dass dieses wundervolle Programm ein komplette Katastrophe ist?

Er versucht es mit der Methode von Aristoteles: Er stellt ein paar unverfängliche Fragen und bringt uns ins Nachdenken:

Ich sehe, ihr habt die Helligkeit recht dunkel eingestellt. Für den Test ist das prima. An wievielen Stellen müsst ihr euer Programm eigentlich ändern, wenn die Ampel später richtig schön hell leuchten soll?

Na ja, die Zahl 20 kommt ungefähr 20 mal vor (Was für ein netter Zufall;-).
Aber jeder Editor beherrscht doch „Suchen“ und „Ersetzen“. Das ist doch nur ein Handgriff! Ein bisschen dumm ist allerdings, dass die 20 auch den Anfang von 2000 bildet. Die Wartezeit der Gelbphase würde kaputt gehen, wenn wir nicht aufpassen…

Ist euch aufgefallen, dass ihr zum Umschalten einer einzelnen Lampe immer zwei Programmzeilen braucht?

Wir ahnen einen leisen Vorwurf hinter dieser Frage, aber wir antworten tapfer: Ja schon, aber soo schlimm ist das doch wohl nicht. Das war doch von Anfang an die Idee, weil wir doch den Weihnachtsstern als Grundlage nehmen wollten. Und der hat eben zwei LEDs pro Arm.

Stellt euch mal vor, eine verbesserte Hardware bietet euch plötzlich viel mehr LEDs je Lampe an, vielleicht 20 anstatt nur 2. Wie viele Zeilen müßtet ihr denn da noch ins Programm einfügen?

Also den Gefallen tun wir ihm nicht, das auszurechnen. Na gut, dann müssen wir da wohl eine Schleife einbauen, obwohl es doch jetzt wirklich nur zwei LEDs sind. Wenn wir das ordentlich schreiben, dann brauchen wir aber zumindest 3 Zeilen dafür, jedesmal. Da wird das Programm aber auf jeden Fall jetzt erst mal länger! Ein schwacher Versuch der Verteidigung, aber immerhin …

Nicht unbedingt. Wenn jemand eine Bibliothek entwirft, dann überlegt er sich, was die aufrufenden Programme von ihm typischerweise wollen könnten. Kann es sein, dass die Bibliothek bereits eine Funktion bietet, um einen zusammenhängenden Bereich von LEDs mit einer einheitlichen Farbe auszustatten?

Also, wie soll diese komische Funktion denn heißen?

Leute, es gibt nicht nur das Header-File. Seht euch halt auch mal die DOKU an!

Dann legen wir mal los!

HAAALT !!!

Das Wichtigste beim Programmieren ist, ein Problem in unterschiedliche ABSTRAKTIONSEBENEN zu zerlegen. Dafür muss man Begriffe definieren und sich das Zusammenspiel von FUNKTIONEN überlegen. Von ganz weit oben betrachtet könnte man z.B. sagen:


(1) An Straßenkreuzungen benutzt man Lichtsignalanlagen zur Regelung des Verkehrs. Ihre Lichtzeichen (manchmal auch unterstützt durch akustische Signale für Sehbehinderte) repräsentieren jeweils einen ZUSTAND, wie z.B. „Halt, Stehen bleiben“ oder „Freie Fahrt“ oder „Gerade aus fahren ist erlaubt, Linkssabbieger müssen aber noch warten“ oder „Radfahrer können losfahren“.

(2) Man sieht, dass die Ampeln sich an unterschiedliche Adressaten (Autos, Radfahrer, Fußgänger) richten bzw. an Gruppen mit bestimmten Absichten („Linksabbieger“).

(3) Letztlich regeln Ampeln den Verkehr, indem sie eine streng definiert Folge von Zuständen durchlaufen und den jeweiligen Zustand durch eine bestimmte Kombination von Lichtern anzeigen.

(4) Die Zeitdauer der einzelnen Zustände kann fest eingestellt sein; sie kann sich auch abhängig von der Tageszeit ändern oder sogar Sensordaten berücksichtigen, über die fahrende und/oder stehende Fahrzeuge erfasst werden.

Auf den unteren Ebenen des Programms geht es dann darum, die richtigen LEDs mit der richtigen Farbe anzusteuern und das Zeitschema genau einzuhalten.


Diese Ebene dominiert in eurem bisherigen Programm, Nun seht mal zu, dass auch die abstrakteren Ebenen einen Niederschlag in euerem Programmcode finden!

Schlechte Software zeichnet sich dadurch aus, dass man den Wald vor lauter Bäumen nicht sieht, weil man ständig mit den unteren Ebenen konfrontiert wird beim Lesen des Programmcodes. Gute Software repräsentiert die Wirklichkeit durch passende Konzepte, durch natürliche Namensgebung und durch das Aufeinander-Schichten von Funktionen unterschiedlicher Abstraktionsebenen. „Zahlen“ gehören beispielsweise zu den niedrigen Schichten, die oberen Ebeben arbeiten grundsätzlich mit symbolischen Konstanten. Aber das hatten wir ja schon erwähnt…

So, jetzt könnt ihr loslegen!

Herausgekommen ist Version 2 des Programms.

Veröffentlicht am
Kategorisiert in Allgemein