{"id":459,"date":"2021-01-27T18:29:59","date_gmt":"2021-01-27T17:29:59","guid":{"rendered":"https:\/\/followthescore.org\/schueler-labor\/?p=459"},"modified":"2021-02-22T14:30:45","modified_gmt":"2021-02-22T13:30:45","slug":"verkehrsampel-v3","status":"publish","type":"post","link":"https:\/\/followthescore.org\/schueler-labor\/verkehrsampel-v3\/","title":{"rendered":"Verkehrsampel V3"},"content":{"rendered":"\n<div class=\"wp-block-file\"><a href=\"https:\/\/followthescore.org\/schueler-labor\/wp-content\/uploads\/2021\/02\/TrafficLights_V3-1.zip\">TrafficLights_V3-1<\/a><a href=\"https:\/\/followthescore.org\/schueler-labor\/wp-content\/uploads\/2021\/02\/TrafficLights_V3-1.zip\" class=\"wp-block-file__button\" download>Die vollst\u00e4ndige Version herunterladen<\/a><\/div>\n\n\n\n<p>Das war ein schweres St\u00fcck Arbeit. Ganz ohne Hilfe ist es auch nicht gegangen. Aber jetzt sind wir stolze Besitzer von drei Dateien, die zusammen die beiden Ampeln steuern. Perfekt, oder?<\/p>\n\n\n\n<p>D\u00fcrfen wir vorstellen? Die Header Datei des <code>TrafficLight<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#ifndef TRAFFIC_LIGHT_H\n#define TRAFFIC_LIGHT_H\n\n#include &lt;Adafruit_NeoPixel.h&gt;\n\nclass TrafficLight {\n\n    \/\/ A traffic light with adjustable brightness.\n\t\/\/ The traffic light consists of three lamps.\n\t\/\/ Each lamp consists of one or more LED pixels.\n\n    \/\/ symbolic constants for the different STATES of a traffic light\n\t#define TL_OFF\t\t\t\t\t0\t\t\/\/ all lights are off\n    #define TL_STOP                \t1       \/\/ red lamp on\n    #define TL_ALERT               \t2       \/\/ simultaneously red and yellow on\n    #define TL_GO                  \t3       \/\/ green lamp on\n    #define TL_HALT                \t4       \/\/ yellow lamp on\n\n    \/\/ symbolic constants for the lamp color index\n    #define TL_RED_LAMP     0\n    #define TL_YELLOW_LAMP  1\n    #define TL_GREEN_LAMP   2\n\n    public:\n\n        TrafficLight();\n\t\t\n\t\t\/\/ when creating a new TrafficLight we need a name, a reference to the LED strip,\t\n        \/\/ the LED positions (per lamp) and the number of LEDs per lamp\n        TrafficLight(String name, Adafruit_NeoPixel *strip, const int *ledPos, int pixPerLamp);\n\n        \/*\n         * We have several layers of functions, from TOP to BOTTOM:\n         *   (7) setGreenTime, addSensor, setBrightness : configuration\n         *   (6) performCycle        \t: walk through all states in the correct sequence\n         *   (5) off,stop,alert,go,halt : change state of TrafficLight switching appropriate lamp(s)\n         *   (4) ..On, ..Off, clear    \t: switch a certain lamp (x) ON or OFF, clear all lamps\n         *   (3) lampOn, lampOff       \t: switch a lamp on\/off using its defined color\n         *   (2) setColor            \t: assign a color to an arbitrary lamp, changing all of its LEDs\n         *   (1) showFor, showForMin \t: transfer LED settings to the strip and wait  for the appropriate time\n         *\/\n\n        \n        void addSensor(int sensorPin);\n        void setGreenTime(int time);\t\t\/\/ in msec\n        void setBrightness(byte brightness);\t\/\/ 0=off, 255 is maximum\n\n        void performCycle();\n        \n\t\tvoid off();\n        void stop();\n        void alert();\n        void go();\n        void halt();\n                \n        void redOn();\n        void redOff();\n        void yellowOn();\n        void yellowOff();\n        void greenOn();\n        void greenOff();\n\t\tvoid clear();\n\n        void lampOn(int lampNr);\t\t\t\/\/ from top to bottom, 0=red, 1=yellow, 2=green\n        void lampOff(int lampNr);\n\n        void showFor(int time);\t\t\t\t\/\/ in msec\n        bool showForMin(int time, int pct);\t\/\/ show for &#039;time&#039; or shorter, but at least &#039;pct&#039; percent of &#039;time&#039;\n\t\tvoid show();\t\t\t\t\t\t\/\/ just show and return\n\n    private:\n\n\n        void setColor(int lampNr, uint32_t color);\t\/\/ we use the lower 24 bits as RRGGBB color\n\t\n\t    \/\/ message logging to the serial port with time stamp\n        int64_t startedAt;\n        void debug(String message);\n        \n\t\tString name;\n\t\tAdafruit_NeoPixel *strip;\n        int times&#x5B;TL_HALT+1];  \t\t\t\t\/\/ specific times per STATE in msec\n        int ledPos&#x5B;TL_GREEN_LAMP+1];\t\t\/\/ first LED of each lamp\n        int pixPerLamp;     \t\t\t\t\/\/ number of pixels per lamp\n        int sensorPin;      \t\t\t\t\/\/ optional pin for traffic detection sensor\n        uint32_t colors&#x5B;TL_GREEN_LAMP+1];\t\/\/ the three base colors; brightness may be adjusted separately\n};\n\n#endif\n<\/pre><\/div>\n\n\n<p><strong><em>Hey, das sieht gut aus (diesmal ganz ehrlich!). Sch\u00f6n, dass ihr erkannt habt, dass man den Begriff der <code>lamp<\/code> ben\u00f6tigt. Das war der entscheidende Erkenntnisschritt! Man sieht gut, dass die h\u00f6heren Funktionen f\u00fcr den Zustandswechsel nur Lampen kennen und nicht wissen, ob es LEDs sind oder z.B. Gl\u00fchbirnen! So soll es sein. Erst auf einer niedrigeren Ebene der Funktionen ist der Zusammenhang zwischen Lampen und LEDs bekannt.<br>Prima, dass ihr das &#8222;Verriegelungsprinzip gegen Mehrfach-Inklusion&#8220; eingebaut habt. Sicher habt ihr auch im Internet nachgelesen, wozu das gut ist. Zeigt mal das Hauptprogramm!<\/em><\/strong><\/p>\n\n\n\n<p>Wir dachten, dass jetzt eigentlich die Implementierung der <code>TrafficLight<\/code> Klasse an der Reihe w\u00e4re?<\/p>\n\n\n\n<p><strong>Das sehe ich anders. \u00dcberlegt doch einmal, wie ihr es mit der Neopixel-Bibliothek gemacht habt! Ich wette, ihr habt kein Interesse an dem Quellcode der Bibliothek gehabt &#8211; falls ihr \u00fcberhaupt wisst, wo er innerhalb der Arduino IDE zu finden ist \ud83d\ude09<\/strong><\/p>\n\n\n\n<p>Ist das jetzt wirklich wahr? Das war echt anstrengend! Wenn man etwas gut hin bekommen hat, dann finden die anderen es unwichtig?? F\u00fcr uns ist es WICHTIG! Manche Sachen waren au\u00dferdem echt schwer zu programmieren &#8230;<\/p>\n\n\n\n<p><strong><em>Sorry, aber ihr m\u00fcsst lernen, damit zu leben. Das Vertrauen der Benutzer eurer Klasse sollte euch strahlen lassen. Die haben n\u00e4mlich eine andere Perspektive: Sie freuen sich, dass sie die Innereien eurer Klasse gerade NICHT verstehen m\u00fcssen. Sie haben ihre eigenen Probleme zu l\u00f6sen und wollen sich auf ihrer (h\u00f6heren) Abstraktionsebene bewegen. Deswegen ist ein gut entworfenes Interface ja so wichtig. Also zeigt endlich das Hauptprogramm her!<\/em><\/strong><\/p>\n\n\n\n<p>Wenn es denn sein muss, hier ist <code>TrafficLights_V3.ino<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n\/\/  Two traffic lights, using the standard pattern (R,R+Y,G,Y).\n\/\/\n\/\/  The GREEN TIME for each traffic light can be configured\n\/\/  A sensor signal shortens the GREEN TIME for the crossing line  \n\/\/  This might be improved (e.g. mutual blocking of sensors)\n\/\/  special light sequences are used to switch the whole system ON and OFF\n\/\/\n\/\/ version 3\n\n\n#include &quot;TrafficLight.h&quot;\n\n\n\/\/ setup the LED strip\n\/\/ ===================\n\nint numberOfPixels      = 16;\nint stripPin            = 26;\nAdafruit_NeoPixel strip = Adafruit_NeoPixel(numberOfPixels,stripPin);\n\n\n\/\/ declare the two traffic lights\n\/\/ ==============================\n\nTrafficLight tlA, tlB;\n\n\n\/\/ setup\n\/\/ =====\n\nvoid setup() {\n\t\n\t\/\/ setup serial line for debugging\n    Serial.begin(115200);\n    delay(100);\n\n\t\/\/ define two traffic lights\n\n    Serial.println(&quot;Traffic Lights starting (initially OFF) ..&quot;);\n\n    tlA = TrafficLight( &quot;Hasengasse&quot;, \t&amp;strip, (const int&#x5B;]) { 9,8,7}, 1 );\n    tlA.setBrightness(20);\n    tlA.setGreenTime(5000);\n\n    tlB = TrafficLight( &quot;Fuchsweg&quot;,\t\t&amp;strip, (const int&#x5B;]) { 4,3,2}, 1);\n    tlB.setBrightness(2);\n    tlB.setGreenTime(10000);\n    tlB.addSensor(27);\n\n}\n\n\/\/ functions to handle all traffic lights in the same way\n\/\/ ======================================================\n\nvoid allOff() {\n\ttlA.off();\n\ttlB.off();\n}\nvoid allClear() {\n\ttlA.clear();\n\ttlB.clear();\n}\nvoid allSetLamp(int lamp) {\n\tallClear();\n\ttlA.lampOn(lamp);\n\ttlA.show();\n\ttlB.lampOn(lamp);\n\ttlB.show();\n}\nvoid allBlink(int cycles) {\n\tallOff();\n\tfor (int n=0;n&lt;cycles;n++) {\n\t\tallSetLamp(TL_YELLOW_LAMP);\n\t\tdelay(800);\n\t\tallOff();\n\t\tdelay(800);\n\t}\n}\n\n\n\/\/ start up sequence : yellow blink -- steady yellow -- red\n\/\/ ========================================================\n\nvoid startUp() {\n\n\t\/\/ blink all traffic lights two times\n\tallBlink(2);\n\n\t\/\/ steady yellow\n\tallSetLamp(TL_YELLOW_LAMP);\n\tdelay(2000);\n\n\t\/\/ all red for some time\n\tallSetLamp(TL_RED_LAMP);\n\tdelay(2000);\n}\n\n\/\/ standardCycle\n\/\/ =============\nvoid standardCycle() {\n\ttlA.performCycle();\n\ttlB.performCycle();\n}\n\n\/\/ shut down sequence : yellow blink -- off\n\/\/ ========================================\n\nvoid shutDown() {\n\t\n\t\/\/ blink\n\tallBlink(2);\n\n\t\/\/ switch OFF\n\tallOff();\n}\n\n\n\/\/ loop\n\/\/ ====\n\nvoid loop() {\n\n\t\/\/ begin of day\n\tSerial.println(&quot;WAKING UP&quot;);\n\tstartUp();\n\n\t\/\/ during the day (simulate two full cycles)\n\tSerial.println(&quot;STARTING DAYLIGHT CYCLES&quot;);\n\tfor (int n=0;n&lt;2;n++) {\n\t\tstandardCycle();\n\t}\n\n\t\/\/ go asleep at night\n\tSerial.println(&quot;GOING ASLEEP&quot;);\n\tshutDown();\n\tdelay(5000);\n\t\n}\n<\/pre><\/div>\n\n\n<p>Wir haben viele kleine Funktionen entworfen, damit es m\u00f6glichst gut lesbar ist. Unsere Etagen sehen so aus<\/p>\n\n\n\n<ul><li>setup und loop<\/li><li>wakeup, standardCycle, shutDown<\/li><li>allClear, allOff, allSetLamp, allBlink<\/li><\/ul>\n\n\n\n<p><strong><em>Das ist recht gut gelungen! Ich hab da allerdings noch einen kleinen Vorschlag: Ihr k\u00f6nntet die unteren beiden Schichten in eine eigene, neue Klasse packen. Ich w\u00fcsste sogar einen guten Namen daf\u00fcr&#8230;<\/em><\/strong><\/p>\n\n\n\n<p><code>Ampelsteuerung<\/code> vielleicht? Ach so, auf Englisch &#8230; <code>TrafficLightControl<\/code>?<\/p>\n\n\n\n<p><strong><em>Nein, ich hab an <code>TrafficLightSystem<\/code> gedacht. Ich habe n\u00e4mlich im Kopf, dass vielleicht noch Fahrbahn-Sensoren dazu kommen, Fu\u00dfg\u00e4ngerampeln mit nur zwei Lampen und mit einem Signalknopf. All das zusammen gibt ein &#8222;System&#8220;. Klar muss das System &#8222;gesteuert&#8220; werden, damit die Lichter schalten. Aber Klassen benennt man eigentlich eher ungern nach ihren T\u00e4tigkeiten &#8211; so wie man einen Menschen zwar manchmal z.B. als Schwimmer bezeichnet &#8211; aber das erfasst sein Wesen eben nur zum Teil. Eine Klasse ist zuerst einmal ein Etwas, das aus bestimmten Teilen besteht, die Zust\u00e4nde haben k\u00f6nnen (Also: Das TraficLight besteht aus Lampen, die bestimmte Farben zeigen). Die Aktionen (Methoden) der Klasse benutzen die Teile, ver\u00e4ndern Zust\u00e4nde, kurz sie beeinflussen das &#8222;System&#8220;. Auch wenn es eine klar definierte Hauptt\u00e4tigkeit wie &#8222;Schalten&#8220; gibt, benennt man ein Klasse nicht so gern nach der Hauptt\u00e4tigkeit.<\/em><\/strong><\/p>\n\n\n\n<p>Ja, das leuchtet ein. Wenn man zum Beispiel die Fahrbahnsensoren zur Verkehrsz\u00e4hlung benutzen w\u00fcrde, dann h\u00e4tte das ja gar nicht mehr unbedingt etwas mit der Ampel-Schalt-Funktion zu tun. Die Ampelanlage (= der deutsche Begriff f\u00fcr <code>TrafficLightSystem<\/code>) k\u00f6nnte ja sogar nachts z\u00e4hlen, wenn sie abgeschaltet ist!<\/p>\n\n\n\n<p><strong><em>Habt ihr noch genug Energie f\u00fcr einen weiteren Umbau? Die Aufgabe des Hauptprogramms ist es dann nur noch, das System zu konfigurieren und die Betriebszeiten vorzugeben &#8211; also ziemlich genau das, was in <code>setup<\/code> und <code>loop<\/code> jetzt bereits steckt. Ihr seht, das eigentliche Hauptprogramm driftet immer weiter nach oben weg und die Arbeit wird auf den tieferen Ebenen erledigt &#8211; ganz wie im echten Leben&#8230;<\/em><\/strong><\/p>\n\n\n\n<p><strong><em>F\u00fchrt bitte noch eine Fu\u00dfg\u00e4ngerampel ein; ihre Gr\u00fcnphase soll deutlich k\u00fcrzer sein als die der Autos. Schaut euch mal eine echte Ampelanlage an! Das Gr\u00fcnsignal f\u00fcr die Fu\u00dfg\u00e4nger kommt meist ein klein wenig vor den Autos, die in die gleiche Richtung fahren. Das soll verhindern, dass abbiegende Autos den Omis noch eben mal schnell vor die F\u00fc\u00dfe fahren.<\/em><\/strong><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Das war ein schweres St\u00fcck Arbeit. Ganz ohne Hilfe ist es auch nicht gegangen. Aber jetzt sind wir stolze Besitzer von drei Dateien, die zusammen die beiden Ampeln steuern. Perfekt, oder? D\u00fcrfen wir vorstellen? Die Header Datei des TrafficLight: Hey, das sieht gut aus (diesmal ganz ehrlich!). Sch\u00f6n, dass ihr erkannt habt, dass man den&hellip; <a class=\"more-link\" href=\"https:\/\/followthescore.org\/schueler-labor\/verkehrsampel-v3\/\"><span class=\"screen-reader-text\">Verkehrsampel V3<\/span> weiterlesen<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/posts\/459"}],"collection":[{"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/comments?post=459"}],"version-history":[{"count":9,"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/posts\/459\/revisions"}],"predecessor-version":[{"id":492,"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/posts\/459\/revisions\/492"}],"wp:attachment":[{"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/media?parent=459"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/categories?post=459"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/followthescore.org\/schueler-labor\/wp-json\/wp\/v2\/tags?post=459"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}