Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
| ws2122:game_of_light [2022/04/10 19:37] – [Code] laraw | ws2122:game_of_light [2022/04/10 20:34] (aktuell) – [Ergebnis] laraw | ||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| + | ====Hintergrund==== | ||
| + | **Was ist Conways Game of Life?** \\ | ||
| + | [[https:// | ||
| + | \\ | ||
| + | **Regeln**\\ | ||
| + | Das Feld ist aufgeteilt in einzelne, quadratische Zellen, die einfach so nebeneinander angeordnet sind, dass jede Zelle 8 Nachbarn hat (wie auf einem Karo-Papier). | ||
| + | Jede Zelle kann entweder lebendig oder tot sein, dieser Status hängt vom Anfangszustand und dem Zustand der 8 Nachbarn ab, die die Zelle " | ||
| + | * Zellen mit weniger als 2 Nachbarn sterben (an " | ||
| + | * Zellen mit genau 2 Nachbarn ändern ihren Status nicht | ||
| + | * Zellen mit genau 3 Nachbarn werden lebendig | ||
| + | * Zellen mit mehr als 3 Nachbarn sterben (an " | ||
| + | Durch diese Regeln gibt es bestimmte Muster, die statisch sind, wie z.B. | ||
| + | {{ws2122: | ||
| + | und Muster, die periodisch wiederkehren, | ||
| + | {{ws2122: | ||
| + | Daraus lassen sich faszinierende, | ||
| + | |||
| + | <!-- wie viel noch zu stabilen Zuständen und Mustern? --> | ||
| + | ====Vision==== | ||
| + | Im Rahmen unseres Projektes möchten wir die Funktionsweise von Conway' | ||
| + | Um ein intuitives Verständnis der Thematik zu fördern, wollen wir ein manuell verstellbares und programmierbares Display bauen. | ||
| + | |||
| + | ====Ziele==== | ||
| + | * Feld aus $3\times3$ Einzelzellen bauen | ||
| + | * Interaktivität durch Hall-Sonde & Magnet am " | ||
| + | * Aufbau soll cell-based sein: Jede Zelle sieht nur ihre Nachbarn, es gibt also kein großes Programm im Hintergrund, | ||
| + | * modulare Aufbauweise: | ||
| + | * das Projekt soll vollständig dokumentiert und open-source sein | ||
| + | * Nebenziel: Erweiterung der Installation zur Visualisierung komplexerer Strukturen durch nebenstehenden PC | ||
| + | * Traumziel: wenn Zeit und Resourcen da sind auf ein ca. 20$\times$20 Feld erweitern | ||
| + | |||
| + | ====Arbeitsablauf==== | ||
| + | ===Anfangsüberlegungen=== | ||
| + | **Zellform**: | ||
| + | **lebendig/ | ||
| + | **Welcher Sensor?**: Um die Interaktivität zu gewährleisten, | ||
| + | ===Zelldesign=== | ||
| + | {{ : | ||
| + | Jede Zelle besteht aus einem 3D-gedruckten Zellkörper <!-- Link -->, der so gestaltet ist, dass man die Zellen einfach ineinander schieben kann und somit ein solides Feld erhält. darin müssen die Hall-Sonde, eine LED, ein Arduino Nano und einiges an Kabeln Platz finden, deswegen haben wir die Zellkörper 7cm tief gedruckt. \\ | ||
| + | Die LED und die Hall-Sonde werden im ebenfalls 3D-gedruckten Deckel befestigt (s. Bild rechts), damit das Licht von außen gut sichtbar ist und alle Zellen einheitlich leuchten und ebenso einheitlich auf den Magneten reagieren. Außerdem gibt es Aussparungen für die Steckverbindungen der Kabel, die die Kommunikation der Zellen ermöglicht, | ||
| + | Abgedeckt ist die 3d-gedruckte Deckelrahmenkonstruktion mit milchigem Acrylglas, das mit dem Laser-Cutter geschnitten wurde. | ||
| + | Die Rückseite ist mit einem ebenfalls 3D-gedruckten Deckel verschlossen, | ||
| + | Die 3D-gedruckten Teile wurden mit einem SLA-Drucker gedruckt, da dieser an sich genauer drucken kann als ein FDM-Drucker. Dadurch, dass die Teile nach dem Drucken aber gehärtet werden müssen, besteht bei unseren recht dünnen Wänden eine Neigung zum Neigen. Deswegen drucken wir die Teile doch lieber mit einem FDM-Drucker. | ||
| + | ===Software=== | ||
| + | Jede Zelle trägt das gleiche kleine Programm in sich, dass im Prinzip nur die Anzahl der lebendigen Nachbarn zählen und danach entscheiden muss, wie ihr Lebensstatus sein soll. Das größte Problem hierbei ist die Taktung, denn alle Zellen müssen zunächst den Status ihrer Nachbarn auslesen, bevor sie ihren eigenen ändern, ansonsten würde es zu Fehlern kommen. Recht leicht lösbar wäre diese Herausforderung, | ||
| + | Unsere erste Idee war, die Zellen im Schachbrettmuster auslesen zu lassen, also in zwei Gruppen (angeordnet wie schwarze und weiße Felder auf einem Schachbrett), | ||
| + | Die zweite und auch verwendete Idee ist, die Arduinos in acht Schritten in einer Art " | ||
| + | Für diese Umsetzung ist eine zentrale Taktung notwendig, damit wirklich alle Zellen genau gleichzeitig das gleiche tun. | ||
| + | Dafür kam die Idee auf, einen zentralen Taktgeber-Arduino zu verwenden, der über die analog-Pins die verschiedenen Schritte über unterschiedlich hohe Spannung angeben sollte. Das erwies sich in der Umsetzung als komplizierter als gedacht und auch als komplizierter als nötig. Es reicht nämlich völlig, einen Taktgeber zu haben, der die ganze Zeit Impulse an alle Zellen-Arduinos schickt und diese dann zählen zu lassen.\\ | ||
| + | \\ | ||
| + | Möchte man mit dem Magneten den Lebensstatus der Zellen ändern, also eine neue Startkonfiguration setzen, so muss dieser Prozess unterbrochen werden. Dafür gibt es einen einfachen Kippschalter, | ||
| + | In dem manuellen Modus kann man außerdem über einen Druckknopf einzeln die Generationen durchgehen, was nützlich zum erklären der grundsätzlichen Regeln ist.\\ | ||
| + | Der [[https:// | ||
| + | - Möglichkeit, | ||
| + | - Nachbarn zählen (nach " | ||
| + | - je nach Anzahl der Nachbarn über eigenen Lebensstatus entscheiden | ||
| + | Für Details und Code des Taktgebers siehe den __ordentlich__[[https:// | ||
| + | \\ | ||
| + | **Tipp:** Speist man mehreren verbundenen Arduinos nur über eine Verbindung zum Laptop, so kann es passieren, dass die Stromstärke zu gering ist und merkwürdiges, | ||
| + | ====Ergebnis==== | ||
| + | Die fertige Zelle sieht am Ende wie folgt aus: \\ | ||
| + | {{ : | ||
| + | |||
| + | Im Idealfall sollten deutlich kürzere Kabel verwendet werden, die dann an den Arduino gelötet werden, damit die Zellkörper nicht so vollgestopft werden. Darauf haben wir bis jetzt allerdings verzichtet, damit alle Materialien wiederverwendet werden können.\\ | ||
| + | \\ | ||
| + | {{ : | ||
| + | \\ | ||
| + | |||
| + | |||
| + | Ein komplettes 3x3 Feld konnten wir noch nicht testen, da dafür noch Materialien fehlen, aber ein Test auf einem Steckbrett hat gezeigt, dass alles grundsätzlich funktioniert, | ||
| + | |||
| + | {{ : | ||
| + | <!-- Bilder und Videos einfügen --> | ||
| + | |||
| + | ====Materialien==== | ||
| + | ^ Algemein benötigte Materialien: | ||
| + | | Beliebiger Arduino (auch für Stromversorgung verantwortlich) | ||
| + | | Kippschalter | ||
| + | | Druckknopf | ||
| + | |||
| + | ^ Benötigte Materialien pro Zelle: | ||
| + | | Arduino nano | 1 | | ||
| + | | LEDs | 1 | | ||
| + | | Halleffekt-Sensoren | ||
| + | |**Kabel: | ||
| + | | male-male (Kommunikation) | ||
| + | |Kommunikations anschlüsse (x-female)|8 | ||
| + | | Kabel für interne Elektronik | ||
| + | | Strom Kabel | 2 | | ||
| + | | Takt Kabel | 1 | | ||
| + | |||
| + | |||
| + | ====Code==== | ||
| + | Jeder Arduino nano, der in eine Zelle verbaut ist, benötigt folgenden Code: | ||
| + | <file php CellGenome.ino> | ||
| + | #define LED 11 // | ||
| + | #define sensorPIN A4 //pin zur Senor-Auswerung | ||
| + | #define sensorVALUE analogRead(A4) | ||
| + | #define stepPIN A5 //pin zur koordinierung. Gesteuert durch externe Logik | ||
| + | |||
| + | #define readPIN (stepSTATE+3)%8+2 | ||
| + | #define writePIN stepSTATE+1 | ||
| + | |||
| + | #define stepINPUT digitalRead(A5) | ||
| + | int stepSTATE = 0; //extern angegebener Counter für den Lese/ | ||
| + | boolean stepTOGGLE = false; | ||
| + | int jobSTATE = 0; // | ||
| + | |||
| + | boolean liveSTATE = false; | ||
| + | int liveNEIGHBOUR = 0; //Anzahl der " | ||
| + | |||
| + | const int threshold = 450; //Grenzwert ab dem der Sensor anschlagen soll | ||
| + | boolean sensorTOGGLE = false; | ||
| + | |||
| + | void setup() { | ||
| + | // | ||
| + | pinMode(LED, | ||
| + | pinMode(sensorPIN, | ||
| + | pinMode(stepPIN, | ||
| + | pinMode(12, OUTPUT); | ||
| + | pinMode(12, LOW); | ||
| + | } | ||
| + | |||
| + | void loop() { | ||
| + | digitalWrite(LED, | ||
| + | |||
| + | | ||
| + | | ||
| + | if(stepTOGGLE == false && stepINPUT == true){ | ||
| + | stepTOGGLE = true; //wird vermerkt das ein impuls eingeht | ||
| + | stepSTATE += 1; //und eine Generation hochgegangen | ||
| + | } | ||
| + | if(stepTOGGLE == true && stepINPUT == false){ | ||
| + | stepTOGGLE = false; | ||
| + | } | ||
| + | | ||
| + | if (stepSTATE == 0){ // | ||
| + | if (sensorVALUE <= threshold && sensorTOGGLE == false){ | ||
| + | sensorTOGGLE = true; // | ||
| + | liveSTATE = !liveSTATE; | ||
| + | Serial.println(sensorVALUE); | ||
| + | } | ||
| + | if (sensorVALUE > threshold){ | ||
| + | sensorTOGGLE = false; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | | ||
| + | if (stepSTATE > 0 && stepSTATE < 9 && jobSTATE == stepSTATE - 1){ // | ||
| + | if (stepSTATE == 1){ //wird erst gecheckt ob dies der erste schritt ist | ||
| + | liveNEIGHBOUR = 0; //ist dies der fall wird der Nachbar counter auf null gesetzt | ||
| + | } | ||
| + | pinMode(writePIN, | ||
| + | digitalWrite(writePIN, | ||
| + | pinMode(readPIN, | ||
| + | digitalWrite(readPIN, | ||
| + | pinMode(readPIN, | ||
| + | liveNEIGHBOUR += digitalRead(readPIN); | ||
| + | jobSTATE++; | ||
| + | Serial.print(liveNEIGHBOUR); | ||
| + | Serial.print(" | ||
| + | Serial.print(readPIN); | ||
| + | Serial.println(" | ||
| + | } | ||
| + | |||
| + | else if (stepSTATE ==9 && jobSTATE == stepSTATE - 1){ // | ||
| + | if (liveSTATE == false && liveNEIGHBOUR == 3){ //tote Zelle mit genau drei Lebenden Nachbarn | ||
| + | liveSTATE = true; // | ||
| + | } | ||
| + | else if (liveSTATE == true && liveNEIGHBOUR < 2){ // | ||
| + | liveSTATE = false; | ||
| + | } | ||
| + | else if (liveSTATE == true && liveNEIGHBOUR > 3){ // | ||
| + | liveSTATE = false; | ||
| + | } | ||
| + | | ||
| + | Serial.println(); | ||
| + | Serial.print(" | ||
| + | Serial.println(liveNEIGHBOUR); | ||
| + | Serial.println(); | ||
| + | jobSTATE = 0; //Fertig mit allen Jobs, | ||
| + | stepSTATE = 0; // | ||
| + | } | ||
| + | |||
| + | } | ||
| + | </ | ||
| + | |||
| + | Der Taktgebende Arduino wird mit folgendem Code bespielt: | ||
| + | <file php controllpanell.ino> | ||
| + | #define button 8 //Der druckknopf für's schritweise fortschreiten der Genarationen wird an diesen Pin angeschlossen | ||
| + | #define Switch 7 //Der Kippschalter, | ||
| + | #define PulseOut A5 // | ||
| + | #define Delay 5 // | ||
| + | |||
| + | boolean stepTOGGLE = false; | ||
| + | |||
| + | void setup() { | ||
| + | Serial.begin(9600); | ||
| + | pinMode(PulseOut, | ||
| + | pinMode(button, | ||
| + | pinMode(7, INPUT); | ||
| + | } | ||
| + | |||
| + | void loop() { | ||
| + | if(digitalRead(Switch)== true){ | ||
| + | for (int i = 1; i <= 9; i++ ){ // | ||
| + | digitalWrite(PulseOut, | ||
| + | delay(Delay); | ||
| + | digitalWrite(PulseOut, | ||
| + | delay(Delay); | ||
| + | } | ||
| + | } | ||
| + | | ||
| + | else{ //ist der schalter nicht umgelegt | ||
| + | if(stepTOGGLE == false && button == true){ | ||
| + | stepTOGGLE = true; | ||
| + | for (int i = 1; i <= 9; i++ ){ //und 8 impulse mit entsprechender länge und entsprechenden Pausen abgegeben. | ||
| + | Serial.println(i); | ||
| + | digitalWrite(PulseOut, | ||
| + | delay(Delay); | ||
| + | digitalWrite(PulseOut, | ||
| + | delay(Delay); | ||
| + | } | ||
| + | } | ||
| + | | ||
| + | if(stepTOGGLE == true && button == false){ | ||
| + | stepTOGGLE = false; | ||
| + | } | ||
| + | } | ||
| + | | ||
| + | </ | ||
| + | ====Verbesserungsideen==== | ||
| + | * Kabel anders lösen (großer Kabelsalat) | ||
| + | * nicht jede Zelle mit einem Nano, sondern eigenen Chips designen | ||
| + | * Taktung eleganter lösen (z.B. mit interrupt-Funktion der Nanos) | ||