//flash as Wemos D1 R2 & mini #include #include #ifdef __AVR__ #include #endif #include #define EEPROMSTARTADDRESS_HEIGHTMAP 8 #include #include "wagon.h" #include "effect.h" #include "fx_scanner.h" #include "fx_flash.h" void resetHeightmap(); void printHeightmapRaw(); void interpolateHeightValues(); void previewHeightmap(int waittime); void spawnWagon(); void spawnWagon(float pos, float wagonlength,float startvel, float startacc, float mass, uint8_t wheelcolor); void checkSerial(); void loop_configmode(); void loop_achterbahn(); void removeAllWagons(); uint32_t Wheel(byte WheelPos); void loadHeightmapRaw(); void saveHeightmapRaw(); #define PIN D2 #define NUMPIXELS 600 Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); long lastPixelUpdate=0; #define PIXELUPDATETIME 20 long lastRoutineUpdate=0; #define ROUTINEUPDATETIME 20 long lastCheckspawn=0; #define CHECKSPAWNDELAY 4000 //delay in ms to check random spawn #define SPAWNCHANCE 7 //1 out of x times wagon will spawn #define SPAWNCHANCEDOUBLE 5 //change of spawning a two trains simultaneously long lastCheckspawnEffect=0; #define CHECKSPAWNDELAY_EFFECT 10000 //delay in ms to check random effect #define SPAWNCHANCE_EFFECT_SCANNER 1000 //1 out of x times spawn effect #define SPAWNCHANCE_EFFECT_FLASH 1000 //1 out of x times spawn effect #define BRIGHTNESS_RUN 200 #define BRIGHTNESS_DEBUG 150 long loopmillis=0; uint8_t height[NUMPIXELS]; uint8_t heightraw[NUMPIXELS]; //uninterpolated values #define MAXHEIGHT 254 std::vector wagon_arr; uint8_t maxid=0; bool configmode=false; int selectedpixel=-1; //-1 = none uint8_t wagoncount=0; Effect* effect = NULL; //Persistance effects #define PERSMODE_BLACK 0 #define PERSMODE_FADEPERCENT 1 #define NUM_PERSMODE 2 //number of available persistancemodes uint8_t persistancemode=PERSMODE_BLACK; long last_changePersistancemode=0; #define PERSISTANCEMODECHANGE_DELAY 180000 //define config //#define RESPAWNWAGON #define MAXWAGONS 5 //maximum number of wagons void setup() { Serial.begin(115200); EEPROM.begin(4096); //set eeprom size, between 4 and 4096 bytes. strip.begin(); strip.setBrightness(BRIGHTNESS_RUN); //150 strip.show(); // Initialize all pixels to 'off' Serial.println("Started"); resetHeightmap(); //fixed heightmap loadHeightmapRaw(); interpolateHeightValues(); /* Serial.println(); for (int i=0;i length 1 float interpolateStep= ((int)(interpolateEndvalue)-(int)(interpolateStartvalue))*1.0 /(interpolateLength+1); Serial.println(); Serial.print("interpolateStep="); Serial.print("("); Serial.print(interpolateEndvalue); Serial.print("-"); Serial.print(interpolateStartvalue); Serial.print(")/"); Serial.print(interpolateLength+1); Serial.print("="); Serial.println(interpolateStep); int interpolateStepCounter=1; Serial.println(); Serial.print("interpolateStartpos="); Serial.println(interpolateStartpos); Serial.print("interpolateEndpos="); Serial.println(interpolateEndpos); Serial.print("interpolateStartvalue="); Serial.println(interpolateStartvalue); Serial.print("interpolateEndvalue="); Serial.println(interpolateEndvalue); Serial.print("interpolateLength="); Serial.println(interpolateLength); Serial.print("interpolateStep="); Serial.println(interpolateStep,6); for (int setinti=interpolateStartpos;setinti<=interpolateEndpos;setinti++) { //for all coherent elements to interpolate height[setinti]=height[interpolateStartpos-1]+(int)(interpolateStep*interpolateStepCounter); /*Serial.print(height[interpolateStartpos-1]); Serial.print("+("); Serial.print(interpolateStep); Serial.print("*"); Serial.print(interpolateStepCounter); Serial.print(")="); Serial.println(height[setinti]);*/ interpolateStepCounter++; } interpolateStartpos=interpolateEndpos; } } } void previewHeightmap(int waittime){ for (int i=0;i0){ strip.show(); delay(waittime); } } void spawnWagon(){ //Wagon tmpr = Wagon(maxid++,NUMPIXELS,&strip, height, 35, 6, 0.5,0); //spawn new wagon // pos, wagonlength, startvel, startacc, trainmass, wagoncolor //Wagon tmpr = Wagon(maxid++,NUMPIXELS,&strip, height, random(0, 20), random(3,20), random(0.2, 50)/10.0, 0 , random(5,100) , Wheel(random(0,256))); //spawn new wagon int _randomlength=random(3,40); //Zelt: 3-> minimum vel 10, 40 -> minium vel 30 // pos, wagonlength, startvel , startacc, trainmass, wagoncolor //Wagon tmpr = Wagon(maxid++,NUMPIXELS,&strip, height, random(0, 20), _randomlength, random(map(_randomlength,3,40,1,1), map(_randomlength,3,40, 13,40))/10.0 , 0 , 5 , Wheel((uint8_t)random(0,255))); //spawn new wagon int side_startpos=0; int side_multi=1; if (random(0,2)==0){ //spawn from other side side_startpos=NUMPIXELS+_randomlength; side_multi=-1; } Wagon tmpr = Wagon(maxid++,NUMPIXELS,&strip, height, side_startpos, _randomlength, side_multi*random(map(_randomlength,3,20,5,10), map(_randomlength,3,20, 5,40))/10.0 , 0 , 5.0 , Wheel((uint8_t)random(0,255))); //spawn new wagon //special spawns if (random(0,50)==0){ tmpr.setType(1); //make rainbow tmpr.setLength(_randomlength*random(1,3)); } wagon_arr.push_back(tmpr); Serial.println("Spawned Wagon"); } void spawnWagon(float pos, float wagonlength,float startvel, float startacc, float mass, uint8_t wheelcolor){ //Wagon tmpr = Wagon(maxid++,NUMPIXELS,&strip, height, 35, 6, 0.5,0); //spawn new wagon // pos, wagonlength, startvel, startacc, wagonmass, wagoncolor Wagon tmpr = Wagon(maxid++,NUMPIXELS,&strip, height, pos, wagonlength, startvel, startacc , mass , Wheel(wheelcolor)); //spawn new wagon wagon_arr.push_back(tmpr); Serial.println("Spawned Custom Wagon"); } void loop() { loopmillis=millis(); checkSerial(); if (configmode){ loop_configmode(); }else{ loop_achterbahn(); } } void checkSerial(){ static String serialstring_temp=""; String serialstring=""; while(Serial.available()){ if (Serial.available()>0){ char c = Serial.read(); if (c!='\n') { serialstring_temp+=c; Serial.print(c); //echo }else{ Serial.println(""); //new line serialstring=serialstring_temp; serialstring_temp=""; } } } if (serialstring.length()>0) { Serial.println("String:"+serialstring); if (serialstring.equals("run")){ strip.setBrightness(BRIGHTNESS_RUN); configmode=false; }else if (serialstring.equals("debug")){ strip.setBrightness(BRIGHTNESS_DEBUG); configmode=true; }else if (serialstring.equals("print")){ printHeightmapRaw(); }else if (serialstring.equals("save")){ saveHeightmapRaw(); //save to eeprom }else if (serialstring.equals("load")){ loadHeightmapRaw(); //load from eeprom }else if (serialstring.equals("remove")){ removeAllWagons(); }else if (serialstring.equals("clear")){ resetHeightmap(); interpolateHeightValues(); previewHeightmap(0); //show heightmap strip.show(); }else if (serialstring.startsWith("spawn=")){ String rest=serialstring.substring(serialstring.indexOf('=')+1); //part after = int spawnpos=rest.substring(0,rest.indexOf(',')).toInt(); //part to next , rest=rest.substring(rest.indexOf(',')+1); //part after , int spawnlength=rest.substring(0,rest.indexOf(',')).toInt(); //part to next , rest=rest.substring(rest.indexOf(',')+1); //part after , int spawnstartvel=rest.substring(0,rest.indexOf(',')).toInt(); //part to next , rest=rest.substring(rest.indexOf(',')+1); //part after , int spawnstartacc=rest.substring(0,rest.indexOf(',')).toInt(); //part to next , rest=rest.substring(rest.indexOf(',')+1); //part after , float spawnmass=rest.substring(0,rest.indexOf(',')).toInt()/1000.0; //part to next , //mass in gramm rest=rest.substring(rest.indexOf(',')+1); //part after , int spawncolor=rest.substring(0).toInt(); //part to next , Serial.print("spawning "); Serial.print(spawnpos); Serial.print(","); Serial.println(spawnlength); Serial.print(","); Serial.println(spawnstartvel); //startvel will be /10 Serial.print(","); Serial.println(spawnstartacc); //startacc will be /10 Serial.print(","); Serial.println(spawnmass); Serial.print(","); Serial.println(spawncolor); spawnWagon(spawnpos,spawnlength,spawnstartvel/10.0,spawnstartacc/10.0,spawnmass,spawncolor); }else if (serialstring.equals("spawn")){ spawnWagon(); //random }else if (serialstring.startsWith("setpx=")){ String pixelnumberstring=serialstring.substring(serialstring.indexOf('=')+1,serialstring.indexOf(',')); //part between = and , String pixelvaluestring=serialstring.substring(serialstring.indexOf(',')+1); //part after , int pixelnumber=pixelnumberstring.toInt(); int pixelvalue=pixelvaluestring.toInt(); Serial.print("set pixel "); Serial.print(pixelnumber); Serial.print("="); Serial.println(pixelvalue); if (pixelnumber>=0 && pixelnumber=0 && pixelvalue<=255){ heightraw[pixelnumber]=pixelvalue; }else{ Serial.println("Error: Value out of range!"); } interpolateHeightValues(); Serial.println(); for (int i=0;i=0){ uint32_t c=strip.Color(255,255,255); strip.setPixelColor(selectedpixel,c); if (selectedpixel>=1){ uint32_t c=strip.Color(0,0,0); strip.setPixelColor(selectedpixel-1,c); } if (selectedpixel> 16; uint8_t _pxg = _pxcolor >> 8; uint8_t _pxb = _pxcolor; uint32_t c=strip.Color(_pxr*0.99,_pxg*0.99,_pxb*0.99); strip.setPixelColor(i,c); break; } case PERSMODE_BLACK: default: { uint32_t c=strip.Color(0,0,0); strip.setPixelColor(i,c); break; } } } //possible persistancemode change if (millis()>last_changePersistancemode+PERSISTANCEMODECHANGE_DELAY) { if (random(0,10)!=0){ persistancemode = PERSMODE_BLACK; }else{ persistancemode=random(1,NUM_PERSMODE); } last_changePersistancemode = millis(); } //Wagons for (std::vector::iterator it = wagon_arr.begin(); it != wagon_arr.end(); ++it) //all wagons { Wagon & w = *it; w.updateGraphics(); } //Effects if (effect != NULL ){ if (effect->active()){ effect->updateGraphics(); } } strip.show(); } if (lastRoutineUpdate+ROUTINEUPDATETIME::iterator it = wagon_arr.begin(); it != wagon_arr.end(); ++it) //all wagons { Wagon & w = *it; w.updatePhysics(ROUTINEUPDATETIME); if (!w.alive()) { it = wagon_arr.erase(it); // After erasing, it is now pointing the next element. --it; Serial.println("Killed train"); #ifdef RESPAWNWAGON spawnWagon(); //spawn new one #endif }else{ //wagon is alive wagoncount++; } } //Effects if (effect != NULL ){ if (effect->active()){ effect->updateRoutine(ROUTINEUPDATETIME); }else{ //effect not active anymore delete effect; effect=NULL; } } } //Check spawning if (lastCheckspawn+CHECKSPAWNDELAY::iterator it = wagon_arr.begin(); it != wagon_arr.end(); ++it) //all wagons { Wagon & w = *it; w.updatePhysics(ROUTINEUPDATETIME); it = wagon_arr.erase(it); // After erasing, it is now pointing the next element. --it; } } // Input a value 0 to 255 to get a color value. // The colours are a transition r - g - b - back to r. uint32_t Wheel(byte WheelPos) { WheelPos = 255 - WheelPos; if(WheelPos < 85) { return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); } if(WheelPos < 170) { WheelPos -= 85; return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); } WheelPos -= 170; return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); } void loadHeightmapRaw(){ int c_eepromaddress=EEPROMSTARTADDRESS_HEIGHTMAP; uint8_t lastvalue=0; for (int i=0;i