Dieser Beitrag wurde am 09.11.2022 aktualisiert.
Was soll das sein?
Ein Motortisch ist ein Tisch, der aus einem Motorblock besteht. In meinem Fall aus dem Motor eines Polo 6N, 999cm², 4Zylinder, 50PS, 86Nm. Um den Tisch optisch noch ein bisschen aufzuwerten, habe ich die Zylinder beleuchtet, allerdings nicht nur aus/an. Es beinhaltet einen ESP8266, WLAN-Anbindung und eine Android-App. Doch zuerst muss der Tisch „gebaut“ werden.
Inhaltsverzeichnis
Entstehung des Tisches
Angefangen hat alles bei einer Autoverwertung: Ich habe mir einen Motor ausgewählt und 50€ bezahlt. Dieser war direkt aus dem Polo ausgebaut, die Anbauteile waren schon demontiert. Ich habe mich dann zuhause im Keller an die Demontage des Aggregats gemacht. Der Zahnriemen war schnell ab, die Ölwanne wollte sich nur mit dem Winkelschleifer vom Kurbelgehäuse trennen. Der Zylinderkopf war auch ein ziemlicher Kampf, genauso wie die Ventile aus dem Zylinderkopf zu bekommen. Doch mehrere Stunden und eine riesen Sauerei durch das Restöl,(immer fachgerecht entsorgen!) später war der Motor nackig. Ich habe dann noch alles schön sauber gemacht,(Abwasser nicht die Kanalisation!) und grau lackiert.
Als Füße habe ich die Kolben samt Pleuel verwendet. Gehalten werden die Pleuel durch die Kurbelwelle. Die Glasplatte wird durch 4 Einlassventile gehalten, die in Schraubenlöchern stecken.
Wichtiger Tipp: Wenn ihr den Motortisch nachbauen wollt, achtet darauf, dass es ein Alu-Block ist, sonst ist er sehr schwer.
Hardware
Die Hardware besteht aus einem ESP8266 und 32 WS2812B-LEDs sowie ein bisschen Elektronik für die Spannungsversorgung und Pegelanpassung. Sämtliche Komponenten habe ich auf selber entwickelten Platinen, die in China hergestellt wurden, verlötet.
Auf der Steuerplatine befindet sich ein ESP8266-01. Dieser wird mit 3,3V betrieben und hat keinen integrierten Spannungsregler auf seiner Platine, deswegen habe ich einen LF33CV Spannungsregler für die Versorgungsspannung des ESP verwendet. Dieser benötigt für eine korrekte Funktionsweise laut Datenblatt zwei Kondensatoren zur Glättung und Stabilisation der Spannung.
Der Mosfet „U1“ rechts neben dem ESP dient zur Pegelanpassung der Kommunikation zwischen ESP(3,3V) und WS2812B-LEDs(5V) in einer einfachen Schaltung mit zwei Widerständen.
Diese Art der Pegelanpassung wird oft verwendet und funktioniert zuverlässig, ist allerdings nicht besonders effizient. Aber wir haben es hier ja nicht mit einer batteriebetriebenen Anwendung zutun.
Der Rest der Bauelemente auf der Platine haben den einzigen Zweck, die zwei LEDs auf der Platine, die die Scheinwerfer und die Rückleuchte darstellen sollen, ein- und auszuschalten. Die habe ich nur aus Spaß dort hin gemacht.
Die Platinen, die sich in den Zylindern befinden, sind sehr simpel.
Es sind 8 WS2812B verbau, sowie ein Elektrolytkondensator zur Spannungsstabilisierung. Und wer die WS2812B LEDs kennt, wird jetzt denken: Moment mal, die Anschlüsse sind komplett vertauscht. Ja, sind sie. Also bitte aufpassen, falls man die Platine nachbauen möchte.
Software
Der Softwarepart umfasst zum einen den Arduino-Code und zum anderen die Android-App zum Steuern des Ganzen. Auf die App werde ich hier nicht näher eingehen, da eine Steuerung über web-Interface genauso möglich wäre.
Der Motortisch hat verschiedene Lichtmodi: Man kann jeden Zylinder einzeln in einer beliebigen Farbe leuchten lassen oder den Simulationsmodus verwenden, in dem der Motortisch in einer der ausgewählten Farben die Zündreihenfolge (1-3-4-2) in einer beliebigen Drehzahl simuliert. Außerdem kann man die Helligkeit der LEDs bestimmen.
Arduino-Code
#include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include <ArduinoJson.h> #include <Adafruit_NeoPixel.h> Adafruit_NeoPixel pixels = Adafruit_NeoPixel(32, 2, NEO_GRB + NEO_KHZ800); ESP8266WebServer server; char* ssid = "supersicher"; char* password = "123456789"; boolean Einzelstatezylinder1; boolean Einzelstatezylinder2; boolean Einzelstatezylinder3; boolean Einzelstatezylinder4; int Einzelfarbvaluezyl1; int Einzelfarbvaluezyl2; int Einzelfarbvaluezyl3; int Einzelfarbvaluezyl4; String Presetvalues; int LEDbn; int Rzyl1; int Gzyl1; int Bzyl1; int Rzyl2; int Gzyl2; int Bzyl2; int Rzyl3; int Gzyl3; int Bzyl3; int Rzyl4; int Gzyl4; int Bzyl4; int dimRzyl1; int dimGzyl1; int dimBzyl1; int dimRzyl2; int dimGzyl2; int dimBzyl2; int dimRzyl3; int dimGzyl3; int dimBzyl3; int dimRzyl4; int dimGzyl4; int dimBzyl4; float UproMin; // Umdrehungen pro Minute float Uproms; // Umdrehungen pro Millisekunde float msproU; // Millisekunde pro Umdrehung int Countvalue; // 1/2 Kurbelwellenumdrehung int32_t Zyl_1_flash; int32_t Zyl_2_flash; int32_t Zyl_3_flash; int32_t Zyl_4_flash; int32_t Lasttoggle1; int32_t Lasttoggle2; int32_t Lasttoggle3; int32_t Lasttoggle4; float Flashvalue; boolean ZYL1BOOL; boolean ZYL2BOOL; boolean ZYL3BOOL; boolean ZYL4BOOL; boolean LT1; boolean LT2; boolean LT3; boolean LT4; float RPMV; boolean SIM; int iO = 200; void setup() { /* Rzyl1 = 255; Gzyl1 = 0; Bzyl1 = 0; Rzyl2 = 255; Gzyl2 = 0; Bzyl2 = 0; Rzyl3 = 255; Gzyl3 = 0; Bzyl3 = 0; Rzyl4 = 255; Gzyl4 = 0; Bzyl4 = 0; */ WiFi.begin(ssid, password); Serial.begin(115200); while(WiFi.status()!=WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(""); Serial.print("IP Address: "); Serial.print(WiFi.localIP()); server.on("/SBZYL1", SBZYL1); server.on("/SBZYL2", SBZYL2); server.on("/SBZYL3", SBZYL3); server.on("/SBZYL4", SBZYL4); server.on("/Buttonzyl1", Buttonzyl1); server.on("/Buttonzyl2", Buttonzyl2); server.on("/Buttonzyl3", Buttonzyl3); server.on("/Buttonzyl4", Buttonzyl4); server.on("/Buttonconnect", Buttonconnect); server.on("/setrpm", setrpm); server.on("/StartSim",StartSim); server.on("/SBbn",set_bn); server.begin(); pixels.begin(); Zyl_2_flash = millis(); ZYL1BOOL = true; ZYL2BOOL = false; ZYL3BOOL = false; ZYL4BOOL = false; LEDbn = 100; } void loop() { server.handleClient(); if(SIM)PageSim(); } void set_bn(){ LEDbn = server.arg("pos").toInt(); dimRzyl1=Rzyl1/100*LEDbn; dimGzyl1=Gzyl1/100*LEDbn; dimBzyl1=Bzyl1/100*LEDbn; if(!Einzelstatezylinder1)turnonzyl(1); dimRzyl2=Rzyl2/100*LEDbn; dimGzyl2=Gzyl2/100*LEDbn; dimBzyl2=Bzyl2/100*LEDbn; if(!Einzelstatezylinder2)turnonzyl(2); dimRzyl3=Rzyl3/100*LEDbn; dimGzyl3=Gzyl3/100*LEDbn; dimBzyl3=Bzyl3/100*LEDbn; if(!Einzelstatezylinder3)turnonzyl(3); dimRzyl4=Rzyl4/100*LEDbn; dimGzyl4=Gzyl4/100*LEDbn; dimBzyl4=Bzyl4/100*LEDbn; if(!Einzelstatezylinder4)turnonzyl(4); } void calcbn(){ dimRzyl1=Rzyl1/100*LEDbn; dimGzyl1=Gzyl1/100*LEDbn; dimBzyl1=Bzyl1/100*LEDbn; dimRzyl2=Rzyl2/100*LEDbn; dimGzyl2=Gzyl2/100*LEDbn; dimBzyl2=Bzyl2/100*LEDbn; dimRzyl3=Rzyl3/100*LEDbn; dimGzyl3=Gzyl3/100*LEDbn; dimBzyl3=Bzyl3/100*LEDbn; dimRzyl4=Rzyl4/100*LEDbn; dimGzyl4=Gzyl4/100*LEDbn; dimBzyl4=Bzyl4/100*LEDbn; } void SBZYL1(){ Einzelfarbvaluezyl1 = server.arg("pos").toInt(); Serial.println(Einzelfarbvaluezyl1); Rzyl1 = 0; Gzyl1 = 0; Bzyl1 = 0; if(Einzelfarbvaluezyl1<51) Rzyl1 = map(Einzelfarbvaluezyl1,0,50,255,0); if(Einzelfarbvaluezyl1<50) Gzyl1 = map(Einzelfarbvaluezyl1,0,50,0,255); if(Einzelfarbvaluezyl1>=50)Gzyl1 = map(Einzelfarbvaluezyl1,50,100,255,0); if(Einzelfarbvaluezyl1>49) Bzyl1 = map(Einzelfarbvaluezyl1,50,100,0,255); server.send(iO); if(Einzelstatezylinder1)turnonzyl(1); } void SBZYL2(){ Einzelfarbvaluezyl2 = server.arg("pos").toInt(); Serial.println(Einzelfarbvaluezyl2); Rzyl2 = 0; Gzyl2 = 0; Bzyl2 = 0; if(Einzelfarbvaluezyl2<51) Rzyl2 = map(Einzelfarbvaluezyl2,0,50,255,0); if(Einzelfarbvaluezyl2<50) Gzyl2 = map(Einzelfarbvaluezyl2,0,50,0,255); if(Einzelfarbvaluezyl2>=50)Gzyl2 = map(Einzelfarbvaluezyl2,50,100,255,0); if(Einzelfarbvaluezyl2>49) Bzyl2 = map(Einzelfarbvaluezyl2,50,100,0,255); server.send(iO); if(Einzelstatezylinder2)turnonzyl(2); } void SBZYL3(){ Einzelfarbvaluezyl3 = server.arg("pos").toInt(); Serial.println(Einzelfarbvaluezyl3); Rzyl3 = 0; Gzyl3 = 0; Bzyl3 = 0; if(Einzelfarbvaluezyl3<51) Rzyl3 = map(Einzelfarbvaluezyl3,0,50,255,0); if(Einzelfarbvaluezyl3<50) Gzyl3 = map(Einzelfarbvaluezyl3,0,50,0,255); if(Einzelfarbvaluezyl3>=50)Gzyl3 = map(Einzelfarbvaluezyl3,50,100,255,0); if(Einzelfarbvaluezyl3>49) Bzyl3 = map(Einzelfarbvaluezyl3,50,100,0,255); server.send(iO); if(Einzelstatezylinder3)turnonzyl(3); } void SBZYL4(){ Einzelfarbvaluezyl4 = server.arg("pos").toInt(); Serial.println(Einzelfarbvaluezyl4); Rzyl4 = 0; Gzyl4 = 0; Bzyl4 = 0; if(Einzelfarbvaluezyl4<51) Rzyl4 = map(Einzelfarbvaluezyl4,0,50,255,0); if(Einzelfarbvaluezyl4<50) Gzyl4 = map(Einzelfarbvaluezyl4,0,50,0,255); if(Einzelfarbvaluezyl4>=50)Gzyl4 = map(Einzelfarbvaluezyl4,50,100,255,0); if(Einzelfarbvaluezyl4>49) Bzyl4 = map(Einzelfarbvaluezyl4,50,100,0,255); server.send(iO); if(Einzelstatezylinder4)turnonzyl(4); } void Buttonzyl1(){ Einzelstatezylinder1 = !Einzelstatezylinder1; if(Einzelstatezylinder1)turnonzyl(1); if(!Einzelstatezylinder1)turnoffzyl(1); server.send(iO); } void Buttonzyl2(){ Einzelstatezylinder2 = !Einzelstatezylinder2; if(Einzelstatezylinder2)turnonzyl(2); if(!Einzelstatezylinder2)turnoffzyl(2); server.send(iO); } void Buttonzyl3(){ Einzelstatezylinder3 = !Einzelstatezylinder3; if(Einzelstatezylinder3)turnonzyl(3); if(!Einzelstatezylinder3)turnoffzyl(3); server.send(iO); } void Buttonzyl4(){ Einzelstatezylinder4 = !Einzelstatezylinder4; if(Einzelstatezylinder4)turnonzyl(4); if(!Einzelstatezylinder4)turnoffzyl(4); server.send(iO); } void Buttonconnect(){ String valuezyl1; String valuezyl2; String valuezyl3; String valuezyl4; if(Einzelfarbvaluezyl1 < 100)valuezyl1 = "0" + Einzelfarbvaluezyl1; if(Einzelfarbvaluezyl2 < 100)valuezyl2 = "0" + Einzelfarbvaluezyl2; if(Einzelfarbvaluezyl3 < 100)valuezyl3 = "0" + Einzelfarbvaluezyl3; if(Einzelfarbvaluezyl4 < 100)valuezyl4 = "0" + Einzelfarbvaluezyl4; Presetvalues = Einzelstatezylinder1 + valuezyl1 + Einzelstatezylinder2 + valuezyl2 + Einzelstatezylinder3 + valuezyl3 + Einzelstatezylinder4 + valuezyl4; server.send(iO); Presetvalues = ""; } void setrpm(){ RPMV = map(server.arg("rpm").toInt(),0,100,0,1500); server.send(iO); } void StartSim(){ SIM = !SIM; server.send(iO); } void turnonzyl(int zylnr){ calcbn(); switch(zylnr){ case 1: pixels.setPixelColor(0, pixels.Color(dimRzyl1,dimGzyl1,dimBzyl1)); pixels.setPixelColor(1, pixels.Color(dimRzyl1,dimGzyl1,dimBzyl1)); pixels.setPixelColor(2, pixels.Color(dimRzyl1,dimGzyl1,dimBzyl1)); pixels.setPixelColor(3, pixels.Color(dimRzyl1,dimGzyl1,dimBzyl1)); pixels.setPixelColor(4, pixels.Color(dimRzyl1,dimGzyl1,dimBzyl1)); pixels.setPixelColor(5, pixels.Color(dimRzyl1,dimGzyl1,dimBzyl1)); pixels.setPixelColor(6, pixels.Color(dimRzyl1,dimGzyl1,dimBzyl1)); pixels.setPixelColor(7, pixels.Color(dimRzyl1,dimGzyl1,dimBzyl1)); pixels.show(); break; case 2: pixels.setPixelColor(8, pixels.Color(dimRzyl2,dimGzyl2,dimBzyl2)); pixels.setPixelColor(9, pixels.Color(dimRzyl2,dimGzyl2,dimBzyl2)); pixels.setPixelColor(10, pixels.Color(dimRzyl2,dimGzyl2,dimBzyl2)); pixels.setPixelColor(11, pixels.Color(dimRzyl2,dimGzyl2,dimBzyl2)); pixels.setPixelColor(12, pixels.Color(dimRzyl2,dimGzyl2,dimBzyl2)); pixels.setPixelColor(13, pixels.Color(dimRzyl2,dimGzyl2,dimBzyl2)); pixels.setPixelColor(14, pixels.Color(dimRzyl2,dimGzyl2,dimBzyl2)); pixels.setPixelColor(15, pixels.Color(dimRzyl2,dimGzyl2,dimBzyl2)); pixels.show(); break; case 3: pixels.setPixelColor(16, pixels.Color(dimRzyl3,dimGzyl3,dimBzyl3)); pixels.setPixelColor(17, pixels.Color(dimRzyl3,dimGzyl3,dimBzyl3)); pixels.setPixelColor(18, pixels.Color(dimRzyl3,dimGzyl3,dimBzyl3)); pixels.setPixelColor(19, pixels.Color(dimRzyl3,dimGzyl3,dimBzyl3)); pixels.setPixelColor(20, pixels.Color(dimRzyl3,dimGzyl3,dimBzyl3)); pixels.setPixelColor(21, pixels.Color(dimRzyl3,dimGzyl3,dimBzyl3)); pixels.setPixelColor(22, pixels.Color(dimRzyl3,dimGzyl3,dimBzyl3)); pixels.setPixelColor(23, pixels.Color(dimRzyl3,dimGzyl3,dimBzyl3)); pixels.show(); break; case 4: pixels.setPixelColor(24, pixels.Color(dimRzyl4,dimGzyl4,dimBzyl4)); pixels.setPixelColor(25, pixels.Color(dimRzyl4,dimGzyl4,dimBzyl4)); pixels.setPixelColor(26, pixels.Color(dimRzyl4,dimGzyl4,dimBzyl4)); pixels.setPixelColor(27, pixels.Color(dimRzyl4,dimGzyl4,dimBzyl4)); pixels.setPixelColor(28, pixels.Color(dimRzyl4,dimGzyl4,dimBzyl4)); pixels.setPixelColor(29, pixels.Color(dimRzyl4,dimGzyl4,dimBzyl4)); pixels.setPixelColor(30, pixels.Color(dimRzyl4,dimGzyl4,dimBzyl4)); pixels.setPixelColor(31, pixels.Color(dimRzyl4,dimGzyl4,dimBzyl4)); pixels.show(); break; case 5: break; } } void turnoffzyl(int zylnr){ switch(zylnr){ case 1: pixels.setPixelColor(0, pixels.Color(0,0,0)); pixels.setPixelColor(1, pixels.Color(0,0,0)); pixels.setPixelColor(2, pixels.Color(0,0,0)); pixels.setPixelColor(3, pixels.Color(0,0,0)); pixels.setPixelColor(4, pixels.Color(0,0,0)); pixels.setPixelColor(5, pixels.Color(0,0,0)); pixels.setPixelColor(6, pixels.Color(0,0,0)); pixels.setPixelColor(7, pixels.Color(0,0,0)); pixels.show(); break; case 2: pixels.setPixelColor(8, pixels.Color(0,0,0)); pixels.setPixelColor(9, pixels.Color(0,0,0)); pixels.setPixelColor(10, pixels.Color(0,0,0)); pixels.setPixelColor(11, pixels.Color(0,0,0)); pixels.setPixelColor(12, pixels.Color(0,0,0)); pixels.setPixelColor(13, pixels.Color(0,0,0)); pixels.setPixelColor(14, pixels.Color(0,0,0)); pixels.setPixelColor(15, pixels.Color(0,0,0)); pixels.show(); break; case 3: pixels.setPixelColor(16, pixels.Color(0,0,0)); pixels.setPixelColor(17, pixels.Color(0,0,0)); pixels.setPixelColor(18, pixels.Color(0,0,0)); pixels.setPixelColor(19, pixels.Color(0,0,0)); pixels.setPixelColor(20, pixels.Color(0,0,0)); pixels.setPixelColor(21, pixels.Color(0,0,0)); pixels.setPixelColor(22, pixels.Color(0,0,0)); pixels.setPixelColor(23, pixels.Color(0,0,0)); pixels.show(); break; case 4: pixels.setPixelColor(24, pixels.Color(0,0,0)); pixels.setPixelColor(25, pixels.Color(0,0,0)); pixels.setPixelColor(26, pixels.Color(0,0,0)); pixels.setPixelColor(27, pixels.Color(0,0,0)); pixels.setPixelColor(28, pixels.Color(0,0,0)); pixels.setPixelColor(29, pixels.Color(0,0,0)); pixels.setPixelColor(30, pixels.Color(0,0,0)); pixels.setPixelColor(31, pixels.Color(0,0,0)); pixels.show(); break; case 5: break; } } void Countms() { Uproms = RPMV/60000.0; // Umdrehungen pro Millisekunde berechnen msproU = 1.0/Uproms; // Millisekunde pro Umdrehung berechnen Countvalue = msproU/2.0; // Zählwert berechnen (Millisekunden pro Verbrennung) Flashvalue = Countvalue/2.0; // Länge der Zündung } void PageSim() { Countms(); // *****************************************Zylinder 1************************************* if (millis() - Zyl_2_flash >= Countvalue && ZYL1BOOL == true){ turnonzyl(1); if (LT1 == false){ Lasttoggle1 = millis(); LT1 = true; } if (millis() - Lasttoggle1 >= Flashvalue){ turnoffzyl(1); Zyl_1_flash = millis(); ZYL3BOOL = true; ZYL1BOOL = false; LT1 = false; } } // *****************************************Zylinder 3************************************ Countms(); if (millis() - Zyl_1_flash >= Countvalue && ZYL3BOOL == true){ turnonzyl(3); if (LT3 == false){ Lasttoggle3 = millis(); LT3 = true; } if (millis() - Lasttoggle3 >= Flashvalue){ turnoffzyl(3); Zyl_3_flash = millis(); ZYL4BOOL = true; ZYL3BOOL = false; LT3 = false; } } // ***************************************Zylinder 4************************************** Countms(); if (millis() - Zyl_3_flash >= Countvalue && ZYL4BOOL == true){ turnonzyl(4); if (LT4 == false){ Lasttoggle4 = millis(); LT4 = true; } if (millis() - Lasttoggle4 >= Flashvalue){ turnoffzyl(4); Zyl_4_flash = millis(); ZYL2BOOL = true; ZYL4BOOL = false; LT4 = false; } } // *******************************************Zylinder 2*********************************** Countms(); if (millis() - Zyl_4_flash >= Countvalue && ZYL2BOOL == true){ turnonzyl(2); if (LT2 == false){ Lasttoggle2 = millis(); LT2 = true; } if (millis() - Lasttoggle2 >= Flashvalue){ turnoffzyl(2); Zyl_2_flash = millis(); ZYL1BOOL = true; ZYL2BOOL = false; LT2 = false; } } //bool fadeonzyl(int zylnr, bool rdy){ // bool ran; // if(ran == false){ // int fadeRzyl1 = 0; // int fadeGzyl1 = 0; // int fadeBzyl1 = 0; // ran == true; // } // if(zylnr == 1){ // if(Rzyl1 > fadeRzyl1 && zylnr == 1)fadeRzyl1 = fadeRzyl1 + 1; // if(Gzyl1 > fadeGzyl1 && zylnr == 1)fadeGzyl1 = fadeGzyl1 + 1; // if(Bzyl1 > fadeBzyl1 && zylnr == 1)fadeBzyl1 = fadeBzyl1 + 1; // pixels.setPixelColor(0, pixels.Color(Rzyl1,Gzyl1,Bzyl1)); // pixels.setPixelColor(1, pixels.Color(Rzyl1,Gzyl1,Bzyl1)); // pixels.setPixelColor(2, pixels.Color(Rzyl1,Gzyl1,Bzyl1)); // pixels.setPixelColor(3, pixels.Color(Rzyl1,Gzyl1,Bzyl1)); // pixels.setPixelColor(4, pixels.Color(Rzyl1,Gzyl1,Bzyl1)); // pixels.setPixelColor(5, pixels.Color(Rzyl1,Gzyl1,Bzyl1)); // pixels.setPixelColor(6, pixels.Color(Rzyl1,Gzyl1,Bzyl1)); // pixels.setPixelColor(7, pixels.Color(Rzyl1,Gzyl1,Bzyl1)); // } // if(Rzyl1 == fadeRzyl1 && Gzyl1 == fadeGzyl1 && Bzyl1 == fadeBzyl1){ // rdy = true; // return rdy; // } //} }