2018-06-10 17:23:11 +00:00
//flash as Wemos D1 R2 & mini
2018-04-08 16:20:11 +00:00
# include <Adafruit_NeoPixel.h>
# ifdef __AVR__
# include <avr/power.h>
# endif
# include <vector>
# include "wagon.h"
# define PIN D2
2018-05-06 16:14:11 +00:00
# define NUMPIXELS 600
2018-04-08 16:20:11 +00:00
Adafruit_NeoPixel strip = Adafruit_NeoPixel ( NUMPIXELS , PIN , NEO_GRB + NEO_KHZ800 ) ;
long lastPixelUpdate = 0 ;
2018-05-06 16:14:11 +00:00
# define PIXELUPDATETIME 20
2018-04-08 16:20:11 +00:00
long lastRoutineUpdate = 0 ;
2018-05-06 16:14:11 +00:00
# define ROUTINEUPDATETIME 20
2018-05-06 19:41:33 +00:00
long lastCheckspawn = 0 ;
# define CHECKSPAWNDELAY 4000 //delay in ms to check random spawn
2018-05-11 22:24:02 +00:00
# define SPAWNCHANCE 20 //1 out of x times wagon will spawn
2018-05-06 19:41:33 +00:00
# define SPAWNCHANCEDOUBLE 5 //change of spawning a two trains simultaneously
2018-04-08 16:20:11 +00:00
2018-05-16 18:48:55 +00:00
# define BRIGHTNESS_RUN 200
# define BRIGHTNESS_DEBUG 150
2018-04-08 16:20:11 +00:00
long loopmillis = 0 ;
uint8_t height [ NUMPIXELS ] ;
2018-05-06 16:14:11 +00:00
uint8_t heightraw [ NUMPIXELS ] ; //uninterpolated values
# define MAXHEIGHT 254
2018-04-08 16:20:11 +00:00
std : : vector < Wagon > wagon_arr ;
uint8_t maxid = 0 ;
2018-05-06 19:41:33 +00:00
bool configmode = false ;
2018-05-06 16:14:11 +00:00
int selectedpixel = - 1 ; //-1 = none
2018-05-06 19:41:33 +00:00
uint8_t wagoncount = 0 ;
//define config
//#define RESPAWNWAGON
# define MAXWAGONS 5 //maximum number of wagons
2018-05-06 16:14:11 +00:00
2018-04-08 16:20:11 +00:00
void setup ( ) {
Serial . begin ( 115200 ) ;
2018-04-10 19:17:45 +00:00
strip . begin ( ) ;
2018-05-16 18:48:55 +00:00
strip . setBrightness ( BRIGHTNESS_RUN ) ; //150
2018-04-10 19:17:45 +00:00
strip . show ( ) ; // Initialize all pixels to 'off'
Serial . println ( " Started " ) ;
2018-05-06 16:14:11 +00:00
resetHeightmap ( ) ;
2018-05-06 19:41:33 +00:00
//fixed heightmap
2018-06-10 17:23:11 +00:00
heightraw [ 0 ] = 254 ;
heightraw [ 20 ] = 253 ;
heightraw [ 40 ] = 254 ;
heightraw [ 67 ] = 241 ;
heightraw [ 79 ] = 240 ;
heightraw [ 90 ] = 237 ;
heightraw [ 130 ] = 218 ;
heightraw [ 144 ] = 217 ;
heightraw [ 159 ] = 218 ;
heightraw [ 196 ] = 232 ;
heightraw [ 228 ] = 197 ;
heightraw [ 236 ] = 191 ;
heightraw [ 245 ] = 197 ;
heightraw [ 275 ] = 235 ;
heightraw [ 300 ] = 210 ;
heightraw [ 345 ] = 178 ;
heightraw [ 362 ] = 176 ;
heightraw [ 369 ] = 176 ;
heightraw [ 381 ] = 169 ;
heightraw [ 421 ] = 112 ;
heightraw [ 460 ] = 80 ;
heightraw [ 474 ] = 78 ;
heightraw [ 489 ] = 80 ;
heightraw [ 524 ] = 112 ;
heightraw [ 534 ] = 121 ;
heightraw [ 542 ] = 122 ;
heightraw [ 561 ] = 123 ;
heightraw [ 580 ] = 145 ;
heightraw [ 599 ] = 172 ;
2018-05-24 23:10:06 +00:00
2018-05-16 18:48:55 +00:00
2018-05-06 19:41:33 +00:00
2018-05-06 16:14:11 +00:00
2018-04-10 19:17:45 +00:00
2018-05-06 16:14:11 +00:00
interpolateHeightValues ( ) ;
/*
Serial . println ( ) ;
for ( int i = 0 ; i < NUMPIXELS ; i + + ) {
Serial . print ( i ) ;
Serial . print ( " : " ) ;
Serial . println ( height [ i ] ) ;
} */
//previewHeightmap(2000);
2018-05-06 19:41:33 +00:00
//spawnWagon();
2018-05-19 18:37:06 +00:00
spawnWagon ( ) ;
2018-05-06 16:14:11 +00:00
}
void resetHeightmap ( ) {
for ( int i = 0 ; i < NUMPIXELS ; i + + ) {
heightraw [ i ] = 255 ; //255 means value need to be interpolated
}
heightraw [ 0 ] = 0 ;
heightraw [ NUMPIXELS - 1 ] = 0 ;
}
2018-04-10 19:17:45 +00:00
2018-05-06 19:41:33 +00:00
void printHeightmapRaw ( ) {
Serial . println ( ) ;
for ( int i = 0 ; i < NUMPIXELS ; i + + ) {
if ( heightraw [ i ] ! = 255 ) {
Serial . print ( " heightraw[ " ) ;
Serial . print ( i ) ;
Serial . print ( " ]= " ) ;
Serial . print ( heightraw [ i ] ) ;
Serial . println ( " ; " ) ;
2018-05-16 18:48:55 +00:00
delay ( 10 ) ;
2018-05-06 19:41:33 +00:00
}
}
}
2018-05-06 16:14:11 +00:00
void interpolateHeightValues ( ) {
for ( int i = 0 ; i < NUMPIXELS ; i + + ) { //copy heightraw to height
height [ i ] = heightraw [ i ] ;
}
2018-04-10 19:17:45 +00:00
//interpolate every part with height value 255
for ( int interpolateStartpos = 0 ; interpolateStartpos < NUMPIXELS - 1 ; interpolateStartpos + + ) {
if ( height [ interpolateStartpos ] = = 255 ) { //interpolation part starts
int interpolateEndpos = interpolateStartpos + 1 ;
while ( interpolateEndpos < NUMPIXELS & & height [ interpolateEndpos ] = = 255 ) {
interpolateEndpos + + ;
}
interpolateEndpos - - ;
//interpolateStartpos index of first 255 value
//interpolateEndpos index of last 255 value
uint8_t interpolateStartvalue = height [ interpolateStartpos - 1 ] ;
uint8_t interpolateEndvalue = height [ interpolateEndpos + 1 ] ;
int interpolateLength = interpolateEndpos - interpolateStartpos + 1 ; //one 255 element -> 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 ;
}
2018-04-08 16:20:11 +00:00
}
}
2018-04-10 19:17:45 +00:00
void previewHeightmap ( int waittime ) {
2018-04-08 16:20:11 +00:00
for ( int i = 0 ; i < NUMPIXELS ; i + + ) {
//uint32_t c=Wheel(height[i]*255/45);
2018-04-10 19:17:45 +00:00
uint8_t b = height [ i ] * 255.0 / MAXHEIGHT ;
2018-05-06 16:14:11 +00:00
//uint32_t c=strip.Color(255-b,b,0);
uint32_t c = Wheel ( b / 1.2 ) ;
2018-04-10 19:17:45 +00:00
if ( height [ i ] = = 255 ) {
c = strip . Color ( 0 , 0 , 0 ) ;
}
2018-04-08 16:20:11 +00:00
strip . setPixelColor ( i , c ) ;
}
2018-05-06 16:14:11 +00:00
if ( waittime > 0 ) {
strip . show ( ) ;
delay ( waittime ) ;
}
2018-04-08 16:20:11 +00:00
}
void spawnWagon ( ) {
2018-04-08 17:47:34 +00:00
//Wagon tmpr = Wagon(maxid++,NUMPIXELS,&strip, height, 35, 6, 0.5,0); //spawn new wagon
2018-05-16 18:48:55 +00:00
// pos, wagonlength, startvel, startacc, trainmass, wagoncolor
2018-05-06 19:41:33 +00:00
//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
2018-05-24 23:10:06 +00:00
int _randomlength = random ( 3 , 40 ) ; //Zelt: 3-> minimum vel 10, 40 -> minium vel 30
2018-05-16 18:48:55 +00:00
// pos, wagonlength, startvel , startacc, trainmass, wagoncolor
2018-06-10 17:23:11 +00:00
//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
2018-07-10 21:18:48 +00:00
Wagon tmpr = Wagon ( maxid + + , NUMPIXELS , & strip , height , NUMPIXELS + _randomlength , _randomlength , - random ( map ( _randomlength , 3 , 40 , 10 , 20 ) , map ( _randomlength , 3 , 40 , 22 , 60 ) ) / 10.0 , 0 , 2.0 , Wheel ( ( uint8_t ) random ( 0 , 255 ) ) ) ; //spawn new wagon
2018-04-08 17:47:34 +00:00
2018-06-10 17:59:01 +00:00
//special spawns
if ( random ( 0 , 50 ) = = 0 ) {
tmpr . setType ( 1 ) ; //make rainbow
tmpr . setLength ( _randomlength * random ( 1 , 3 ) ) ;
}
2018-04-08 16:20:11 +00:00
wagon_arr . push_back ( tmpr ) ;
Serial . println ( " Spawned Wagon " ) ;
}
2018-05-06 16:14:11 +00:00
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 " ) ;
}
2018-04-08 17:47:34 +00:00
2018-04-08 16:20:11 +00:00
void loop ( ) {
loopmillis = millis ( ) ;
2018-05-06 16:14:11 +00:00
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 ) ;
2018-05-06 19:41:33 +00:00
2018-05-06 16:14:11 +00:00
if ( serialstring . equals ( " run " ) ) {
2018-05-16 18:48:55 +00:00
strip . setBrightness ( BRIGHTNESS_RUN ) ;
2018-05-06 16:14:11 +00:00
configmode = false ;
} else if ( serialstring . equals ( " debug " ) ) {
2018-05-16 18:48:55 +00:00
strip . setBrightness ( BRIGHTNESS_DEBUG ) ;
2018-05-06 16:14:11 +00:00
configmode = true ;
2018-05-06 19:41:33 +00:00
} else if ( serialstring . equals ( " print " ) ) {
printHeightmapRaw ( ) ;
2018-05-06 16:14:11 +00:00
} 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 ,
2018-07-10 21:18:48 +00:00
float spawnmass = rest . substring ( 0 , rest . indexOf ( ' , ' ) ) . toInt ( ) / 1000.0 ; //part to next , //mass in gramm
2018-05-06 16:14:11 +00:00
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 < NUMPIXELS & & pixelvalue > = 0 & & pixelvalue < = 255 ) {
heightraw [ pixelnumber ] = pixelvalue ;
} else {
Serial . println ( " Error: Value out of range! " ) ;
}
interpolateHeightValues ( ) ;
Serial . println ( ) ;
for ( int i = 0 ; i < NUMPIXELS ; i + + ) {
Serial . print ( i ) ;
Serial . print ( " : " ) ;
Serial . print ( height [ i ] ) ;
Serial . print ( " ( " ) ;
Serial . print ( heightraw [ i ] ) ;
Serial . println ( " ) " ) ;
}
previewHeightmap ( 0 ) ; //show heightmap
strip . show ( ) ;
} else if ( serialstring . startsWith ( " px= " ) ) {
String pixelnumberstring = serialstring . substring ( serialstring . indexOf ( ' = ' ) + 1 ) ; //part between = and ,
int pixelnumber = pixelnumberstring . toInt ( ) ;
Serial . print ( " show pixel " ) ;
Serial . print ( pixelnumber ) ;
if ( pixelnumber < NUMPIXELS ) {
selectedpixel = pixelnumber ;
} else {
Serial . println ( " Error: Value too high! " ) ;
}
}
}
}
void loop_configmode ( ) {
if ( lastPixelUpdate + PIXELUPDATETIME < loopmillis ) {
lastPixelUpdate = loopmillis ;
previewHeightmap ( 0 ) ;
2018-05-06 19:41:33 +00:00
if ( selectedpixel > = 0 ) {
2018-05-06 16:14:11 +00:00
uint32_t c = strip . Color ( 255 , 255 , 255 ) ;
strip . setPixelColor ( selectedpixel , c ) ;
2018-05-06 19:41:33 +00:00
if ( selectedpixel > = 1 ) {
2018-05-06 16:14:11 +00:00
uint32_t c = strip . Color ( 0 , 0 , 0 ) ;
strip . setPixelColor ( selectedpixel - 1 , c ) ;
}
if ( selectedpixel < NUMPIXELS - 1 ) {
uint32_t c = strip . Color ( 0 , 0 , 0 ) ;
strip . setPixelColor ( selectedpixel + 1 , c ) ;
}
}
strip . show ( ) ;
}
}
void loop_achterbahn ( ) {
2018-04-08 16:20:11 +00:00
//######################### Update LED Output
if ( lastPixelUpdate + PIXELUPDATETIME < loopmillis ) {
lastPixelUpdate = loopmillis ;
for ( int i = 0 ; i < NUMPIXELS ; i + + ) { //all black
uint32_t c = strip . Color ( 0 , 0 , 0 ) ;
strip . setPixelColor ( i , c ) ;
}
for ( std : : vector < Wagon > : : iterator it = wagon_arr . begin ( ) ; it ! = wagon_arr . end ( ) ; + + it ) //all wagons
{
Wagon & w = * it ;
w . updateGraphics ( ) ;
}
strip . show ( ) ;
}
if ( lastRoutineUpdate + ROUTINEUPDATETIME < loopmillis - ROUTINEUPDATETIME ) {
2018-05-06 16:14:11 +00:00
Serial . println ( " Behind! " ) ;
2018-04-08 16:20:11 +00:00
}
//######################### Update Physics
if ( lastRoutineUpdate + ROUTINEUPDATETIME < loopmillis ) {
lastRoutineUpdate = loopmillis ;
2018-05-06 19:41:33 +00:00
wagoncount = 0 ;
2018-04-08 16:20:11 +00:00
for ( std : : vector < Wagon > : : iterator it = wagon_arr . begin ( ) ; it ! = wagon_arr . end ( ) ; + + it ) //all wagons
{
2018-05-06 19:41:33 +00:00
2018-04-08 16:20:11 +00:00
Wagon & w = * it ;
w . updatePhysics ( ROUTINEUPDATETIME ) ;
if ( ! w . alive ( ) )
{
it = wagon_arr . erase ( it ) ; // After erasing, it is now pointing the next element.
- - it ;
2018-05-06 19:41:33 +00:00
# ifdef RESPAWNWAGON
spawnWagon ( ) ; //spawn new one
# endif
} else { //wagon is alive
wagoncount + + ;
}
}
}
//Check spawning
if ( lastCheckspawn + CHECKSPAWNDELAY < loopmillis ) {
lastCheckspawn = loopmillis ;
Serial . print ( " Checking Spawning, wagons " ) ;
Serial . println ( wagoncount ) ;
if ( random ( 0 , SPAWNCHANCE ) = = 0 & & wagoncount < MAXWAGONS ) { //by chance, exclusive SPAWNCHANCE
spawnWagon ( ) ;
if ( random ( 0 , SPAWNCHANCEDOUBLE ) = = 0 ) {
spawnWagon ( ) ;
2018-04-08 16:20:11 +00:00
}
2018-05-16 20:52:45 +00:00
} //else{
//Serial.println("no spawn");
//}
2018-05-06 19:41:33 +00:00
2018-04-08 16:20:11 +00:00
}
}
2018-05-06 16:14:11 +00:00
void removeAllWagons ( ) {
for ( std : : vector < Wagon > : : 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 ;
}
}
2018-04-08 16:20:11 +00:00
// 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 ) ;
}