fix height error and implement hadr25 tree

This commit is contained in:
interfisch 2025-07-18 22:53:12 +02:00
parent 0a24dae76c
commit 7e437daf75
13 changed files with 195 additions and 53 deletions

View file

@ -166,7 +166,7 @@ void setup() {
//myPort = new Serial(this, "COM3", 115200); //myPort = new Serial(this, "COM3", 115200);
myPort = new Serial(this, "/dev/ttyUSB0", 115200); myPort = new Serial(this, "/dev/ttyACM0", 115200);
} }
void Set() { void Set() {

64
src/espnow.cpp Normal file
View file

@ -0,0 +1,64 @@
#ifdef DEACTIVATED
#include "espnow.h"
//Mac Adress Receiver: 24:58:7c:cd:a8:c4
// Create a struct_message
struct_message espnowdata;
void readMacAddress(){
uint8_t baseMac[6];
esp_err_t ret = esp_wifi_get_mac(WIFI_IF_STA, baseMac);
if (ret == ESP_OK) {
Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
baseMac[0], baseMac[1], baseMac[2],
baseMac[3], baseMac[4], baseMac[5]);
} else {
Serial.println("Failed to read MAC address");
}
}
void initESPNOW() {
WiFi.mode(WIFI_STA);
WiFi.begin();
Serial.print("[DEFAULT] ESP32 Board MAC Address: ");
readMacAddress();
// Init ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Once ESPNow is successfully Init, we will register for recv CB to
// get recv packer info
esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
}
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
memcpy(&espnowdata, incomingData, sizeof(espnowdata));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print(" Command: ");
Serial.println(espnowdata.cmd);
statuspixel.setPixelColor(0, statuspixel.Color((millis()%3==0)*255,(millis()%3==1)*255,(millis()%3==2)*255)); //change status led when packet arrives
statuspixel.show();
processCommand(&espnowdata);
Serial.println();
}
#endif

45
src/espnow.h Normal file
View file

@ -0,0 +1,45 @@
#ifdef DEACTIVATED //deactivated to compile again without espnow
#ifndef espnow_h
#define espnow_h
#include <WiFi.h>
#include <esp_wifi.h>
#include <esp_now.h>
#include <Adafruit_NeoPixel.h>
extern Adafruit_NeoPixel statuspixel;
extern void processCommand(struct_message espnowdata);
void readMacAddress();
void initESPNOW();
// Must match the receiver structure
enum command { findled, setheight, resetheightmap, saveheightmap };
/*
findled: a=lednum, b=unused
setheight: a=lednum,b=height
resetheightmap: a=23, b=42
saveheightmap: a=24, b=43
*/
typedef struct struct_message {
command cmd;
int a;
int b;
} struct_message;
// callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len);
#endif
#endif

View file

@ -1,7 +1,7 @@
#include "fx_flash.h" #include "fx_flash.h"
#include "effect.h" #include "effect.h"
FX_Flash::FX_Flash(int numpixels,Adafruit_NeoPixel *strip,uint8_t *height,uint32_t flashcolor) FX_Flash::FX_Flash(int numpixels,Adafruit_NeoPixel *strip,uint16_t *height,uint32_t flashcolor)
{ {
_numpixels=numpixels; _numpixels=numpixels;
_strip=strip; _strip=strip;

View file

@ -7,7 +7,7 @@
class FX_Flash : public Effect class FX_Flash : public Effect
{ {
public: public:
FX_Flash(int numpixels,Adafruit_NeoPixel *strip,uint8_t *height,uint32_t flashcolor); FX_Flash(int numpixels,Adafruit_NeoPixel *strip,uint16_t *height,uint32_t flashcolor);
FX_Flash(); FX_Flash();
void updateRoutine(float updatedelayms); void updateRoutine(float updatedelayms);
void updateGraphics(); void updateGraphics();
@ -20,7 +20,7 @@ class FX_Flash : public Effect
long _starttime; long _starttime;
uint8_t _brightness; uint8_t _brightness;
long _flashtime; long _flashtime;
uint8_t *_height; uint16_t *_height;
}; };
#endif #endif

View file

@ -1,7 +1,7 @@
#include "fx_scanner.h" #include "fx_scanner.h"
#include "effect.h" #include "effect.h"
FX_Scanner::FX_Scanner(int numpixels,Adafruit_NeoPixel *strip,uint8_t *height,int startpos,float scannervel,uint32_t scannercolor) FX_Scanner::FX_Scanner(int numpixels,Adafruit_NeoPixel *strip,uint16_t *height,int startpos,float scannervel,uint32_t scannercolor)
{ {
_numpixels=numpixels; _numpixels=numpixels;
_pos = startpos; _pos = startpos;

View file

@ -7,7 +7,7 @@
class FX_Scanner : public Effect class FX_Scanner : public Effect
{ {
public: public:
FX_Scanner(int numpixels,Adafruit_NeoPixel *strip,uint8_t *height,int startpos,float scannervel,uint32_t scannercolor); FX_Scanner(int numpixels,Adafruit_NeoPixel *strip,uint16_t *height,int startpos,float scannervel,uint32_t scannercolor);
FX_Scanner(); FX_Scanner();
void updateRoutine(float updatedelayms); void updateRoutine(float updatedelayms);
void updateGraphics(); void updateGraphics();
@ -18,7 +18,7 @@ class FX_Scanner : public Effect
Adafruit_NeoPixel *_strip; Adafruit_NeoPixel *_strip;
float _pos; float _pos;
float _vel; float _vel;
uint8_t *_height; uint16_t *_height;
uint32_t _scannercolor; uint32_t _scannercolor;
}; };

View file

@ -1,7 +1,7 @@
#include "fx_shootingstar.h" #include "fx_shootingstar.h"
#include "effect.h" #include "effect.h"
FX_ShootingStar::FX_ShootingStar(int numpixels,Adafruit_NeoPixel *strip,uint8_t *height) FX_ShootingStar::FX_ShootingStar(int numpixels,Adafruit_NeoPixel *strip,uint16_t *height)
{ {
_numpixels=numpixels; _numpixels=numpixels;
_strip=strip; _strip=strip;

View file

@ -7,7 +7,7 @@
class FX_ShootingStar : public Effect class FX_ShootingStar : public Effect
{ {
public: public:
FX_ShootingStar(int numpixels,Adafruit_NeoPixel *strip,uint8_t *height); FX_ShootingStar(int numpixels,Adafruit_NeoPixel *strip,uint16_t *height);
FX_ShootingStar(); FX_ShootingStar();
void updateRoutine(float updatedelayms); void updateRoutine(float updatedelayms);
void updateGraphics(); void updateGraphics();
@ -19,7 +19,7 @@ class FX_ShootingStar : public Effect
long _starttime; long _starttime;
uint8_t _brightness; uint8_t _brightness;
long _duration; long _duration;
uint8_t *_height; uint16_t *_height;
int _pos; int _pos;
float _vel; float _vel;
}; };

View file

@ -1,5 +1,7 @@
#include <Arduino.h> #include <Arduino.h>
//#include "espnow.h" //TODO
#include <Adafruit_NeoPixel.h> #include <Adafruit_NeoPixel.h>
#ifdef __AVR__ #ifdef __AVR__
@ -36,7 +38,6 @@ void saveHeightmapRaw();
#ifdef PIN_NEOPIXEL #ifdef PIN_NEOPIXEL
#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel statuspixel(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel statuspixel(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
#endif #endif
@ -68,9 +69,9 @@ unsigned long last_ldrread=0;
long loopmillis=0; long loopmillis=0;
uint8_t height[NUMPIXELS]; uint16_t height[NUMPIXELS];
uint8_t heightraw[NUMPIXELS]; //uninterpolated values uint16_t heightraw[NUMPIXELS]; //uninterpolated values
#define MAXHEIGHT 254 #define MAXHEIGHT 350
std::vector <Wagon> wagon_arr; std::vector <Wagon> wagon_arr;
uint8_t maxid=0; uint8_t maxid=0;
@ -108,6 +109,8 @@ long last_changePersistancemode=0;
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
//initESPNOW(); //todo, deactivated to compile
#ifdef PIN_LDR #ifdef PIN_LDR
pinMode(PIN_LDR, INPUT); pinMode(PIN_LDR, INPUT);
#endif #endif
@ -156,19 +159,40 @@ void setup() {
resetHeightmap(); resetHeightmap();
loadHeightmapRaw(); //loadHeightmapRaw();
heightraw[0]=0;
heightraw[50]=96;
heightraw[64]=103;
heightraw[87]=100;
heightraw[107]=120;
heightraw[155]=199;
heightraw[185]=220;
heightraw[238]=184;
heightraw[269]=209;
heightraw[290]=187;
heightraw[318]=120;
heightraw[358]=187;
heightraw[385]=135;
heightraw[408]=114;
heightraw[464]=203;
heightraw[494]=240;
heightraw[502]=243;
heightraw[506]=240;
heightraw[550]=203;
heightraw[574]=188;
heightraw[599]=199;
interpolateHeightValues(); interpolateHeightValues();
/*
Serial.println(); Serial.println();
for (int i=0;i<NUMPIXELS;i++){ for (int i=0;i<NUMPIXELS;i++){
Serial.print(i); Serial.print(i);
Serial.print(": "); Serial.print(": ");
Serial.println(height[i]); Serial.println(height[i]);
}*/ }
@ -180,10 +204,10 @@ void setup() {
} }
#define NEEDS_INTERPOLATION 65535
void resetHeightmap(){ void resetHeightmap(){
for (int i=0;i<NUMPIXELS;i++){ for (int i=0;i<NUMPIXELS;i++){
heightraw[i]=255; //255 means value need to be interpolated heightraw[i]=NEEDS_INTERPOLATION;
} }
heightraw[0]=0; heightraw[0]=0;
heightraw[NUMPIXELS-1]=0; heightraw[NUMPIXELS-1]=0;
@ -192,7 +216,7 @@ void resetHeightmap(){
void printHeightmapRaw() { void printHeightmapRaw() {
Serial.println(); Serial.println();
for (int i=0;i<NUMPIXELS;i++){ for (int i=0;i<NUMPIXELS;i++){
if (heightraw[i]!=255){ if (heightraw[i]!=NEEDS_INTERPOLATION){
Serial.print("heightraw["); Serial.print("heightraw[");
Serial.print(i); Serial.print(i);
Serial.print("]="); Serial.print("]=");
@ -209,18 +233,18 @@ void interpolateHeightValues(){
} }
//interpolate every part with height value 255 //interpolate every part with height value 255
for (int interpolateStartpos=0;interpolateStartpos<NUMPIXELS-1;interpolateStartpos++){ for (int interpolateStartpos=0;interpolateStartpos<NUMPIXELS-1;interpolateStartpos++){
if (height[interpolateStartpos]==255){ //interpolation part starts if (height[interpolateStartpos]==NEEDS_INTERPOLATION){ //interpolation part starts
int interpolateEndpos=interpolateStartpos+1; int interpolateEndpos=interpolateStartpos+1;
while (interpolateEndpos<NUMPIXELS && height[interpolateEndpos]==255){ while (interpolateEndpos<NUMPIXELS && height[interpolateEndpos]==NEEDS_INTERPOLATION){
interpolateEndpos++; interpolateEndpos++;
} }
interpolateEndpos--; interpolateEndpos--;
//interpolateStartpos index of first 255 value //interpolateStartpos index of first NEEDS_INTERPOLATION value
//interpolateEndpos index of last 255 value //interpolateEndpos index of last NEEDS_INTERPOLATION value
uint8_t interpolateStartvalue=height[interpolateStartpos-1]; uint8_t interpolateStartvalue=height[interpolateStartpos-1];
uint8_t interpolateEndvalue=height[interpolateEndpos+1]; uint8_t interpolateEndvalue=height[interpolateEndpos+1];
int interpolateLength=interpolateEndpos-interpolateStartpos+1; //one 255 element -> length 1 int interpolateLength=interpolateEndpos-interpolateStartpos+1; //one NEEDS_INTERPOLATION element -> length 1
float interpolateStep= ((int)(interpolateEndvalue)-(int)(interpolateStartvalue))*1.0 /(interpolateLength+1); float interpolateStep= ((int)(interpolateEndvalue)-(int)(interpolateStartvalue))*1.0 /(interpolateLength+1);
Serial.println(); Serial.println();
Serial.print("interpolateStep="); Serial.print("interpolateStep=");
@ -267,10 +291,11 @@ void interpolateHeightValues(){
void previewHeightmap(int waittime){ void previewHeightmap(int waittime){
for (int i=0;i<NUMPIXELS;i++){ for (int i=0;i<NUMPIXELS;i++){
//uint32_t c=Wheel(height[i]*255/45); //uint32_t c=Wheel(height[i]*255/45);
uint8_t b=height[i]*255.0/MAXHEIGHT; //uint8_t b=height[i]*255.0/MAXHEIGHT;
uint8_t b=height[i];
//uint32_t c=strip.Color(255-b,b,0); //uint32_t c=strip.Color(255-b,b,0);
uint32_t c=Wheel(b/1.2); uint32_t c=Wheel(b/1.2);
if (height[i]==255){ if (height[i]==NEEDS_INTERPOLATION){
c=strip.Color(0,0,0); c=strip.Color(0,0,0);
} }
strip.setPixelColor(i,c); strip.setPixelColor(i,c);
@ -304,24 +329,26 @@ void spawnWagon(){
// pos, wagonlength, startvel , startacc, trainmass, wagoncolor // 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 //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; //start at beginning of strip int side_startpos=0; //0=start at beginning of strip
int side_multi=1; //start in forward direction int side_multi=1; //1=start in forward direction
/*if (random(0,2)==0){ //spawn from other side
side_startpos=NUMPIXELS+_randomlength;
side_multi=-1;
}*/
#ifdef REVERSE_DIRECTION
//Force start from end of strip //Force start from end of strip
side_startpos=NUMPIXELS+_randomlength; //start at end of strip side_startpos=NUMPIXELS+_randomlength; //start at end of strip
side_multi=-1; //start in backward direction side_multi=-1; //start in backward direction
#endif
#ifdef RANDOM_DIRECTION
if (random(0,2)==0){ //spawn from other side
side_startpos=NUMPIXELS+_randomlength;
side_multi=-1;
}
#endif
//Wagon tmpr = Wagon(maxid++,NUMPIXELS,&strip, height, side_startpos, _randomlength, side_multi*random(map(_randomlength,3,30,0,40)/10.0, map(_randomlength,3,30, 5,60))/10.0 , 0 , random(3.0,7.0) , Wheel((uint8_t)random(0,255))); //spawn new wagon //Wagon tmpr = Wagon(maxid++,NUMPIXELS,&strip, height, side_startpos, _randomlength, side_multi*random(map(_randomlength,3,30,0,40)/10.0, map(_randomlength,3,30, 5,60))/10.0 , 0 , random(3.0,7.0) , Wheel((uint8_t)random(0,255))); //spawn new wagon
//Wagon tmpr = Wagon(maxid++,NUMPIXELS,&strip, height, side_startpos, _randomlength, side_multi*random(map(_randomlength,3,30,30,100)/10.0, map(_randomlength,3,30, 5,60))/10.0 , 0 , 1.8 , Wheel((uint8_t)random(0,255))); //spawn new wagon //Wagon tmpr = Wagon(maxid++,NUMPIXELS,&strip, height, side_startpos, _randomlength, side_multi*random(map(_randomlength,3,40,30,80)/10.0, map(_randomlength,3,40, 5,60))/10.0 , 0 , 1.8 , Wheel((uint8_t)random(0,255))); //spawn new wagon
Wagon tmpr = Wagon(maxid++,NUMPIXELS,&strip, height, side_startpos, _randomlength, side_multi*random(0,random(10,60))/10.0 , 0 , random(2,5)/10.0 , Wheel((uint8_t)random(0,255))); //spawn new wagon . start from near standstill Wagon tmpr = Wagon(maxid++,NUMPIXELS,&strip, height, side_startpos, _randomlength, side_multi*random(20,70)/10.0 , 0 , map(_randomlength,3,40,2.0,1.0) , Wheel((uint8_t)random(0,255))); //spawn new wagon
//Mass: the lighter the faster is changes speed //Mass: the heavier the faster is changes speed
@ -372,7 +399,11 @@ void loop() {
} }
/*
void processCommand(struct_message espnowdata) { //espnow data from remote
espnowdata.cmd //TODO
}
*/
void checkSerial(){ void checkSerial(){
static String serialstring_temp=""; static String serialstring_temp="";
@ -394,8 +425,6 @@ void checkSerial(){
if (serialstring.length()>0) { if (serialstring.length()>0) {
Serial.println("String:"+serialstring); Serial.println("String:"+serialstring);
if (serialstring.equals("run")){ if (serialstring.equals("run")){
strip.setBrightness(BRIGHTNESS_RUN); strip.setBrightness(BRIGHTNESS_RUN);
configmode=false; configmode=false;
@ -648,7 +677,8 @@ void loop_achterbahn(){
//Check spawning //Check spawning
#define AUTOSPAWN
#ifdef AUTOSPAWN
if (lastCheckspawn+CHECKSPAWNDELAY<loopmillis) { if (lastCheckspawn+CHECKSPAWNDELAY<loopmillis) {
lastCheckspawn=loopmillis; lastCheckspawn=loopmillis;
Serial.print("Checking Spawning, wagons "); Serial.print("Checking Spawning, wagons ");
@ -660,6 +690,7 @@ void loop_achterbahn(){
} }
} }
} }
#endif
//Check Effect Spawning //Check Effect Spawning
@ -708,9 +739,11 @@ uint32_t Wheel(byte WheelPos) {
void loadHeightmapRaw(){ void loadHeightmapRaw(){
int c_eepromaddress=EEPROMSTARTADDRESS_HEIGHTMAP; int c_eepromaddress=EEPROMSTARTADDRESS_HEIGHTMAP;
uint8_t lastvalue=0; uint16_t lastvalue=0;
for (int i=0;i<NUMPIXELS;i++){ for (int i=0;i<NUMPIXELS;i++){
lastvalue = EEPROM.read(c_eepromaddress); lastvalue = EEPROM.read(c_eepromaddress); //lowbyte
c_eepromaddress++;
lastvalue += EEPROM.read(c_eepromaddress)<<8; //highbyte
heightraw[i]=lastvalue; heightraw[i]=lastvalue;
c_eepromaddress++; c_eepromaddress++;
} }
@ -720,9 +753,9 @@ void loadHeightmapRaw(){
void saveHeightmapRaw(){ void saveHeightmapRaw(){
int c_eepromaddress=EEPROMSTARTADDRESS_HEIGHTMAP; int c_eepromaddress=EEPROMSTARTADDRESS_HEIGHTMAP;
for (int i=0;i<NUMPIXELS;i++){ for (int i=0;i<NUMPIXELS;i++){
EEPROM.write(c_eepromaddress, heightraw[i]); //address, value EEPROM.write(c_eepromaddress, (byte)heightraw[i]); //address, value, lowbyte
EEPROM.write(c_eepromaddress, (byte)(heightraw[i]>>8)); //address, value, highbyte
c_eepromaddress++; c_eepromaddress++;
} }
Serial.println("Saved to EEPROM"); Serial.println("Saved to EEPROM");
EEPROM.commit(); //write changes to eeprom. EEPROM.end() will also commit and release the ram copy of eeprom contents EEPROM.commit(); //write changes to eeprom. EEPROM.end() will also commit and release the ram copy of eeprom contents

View file

@ -30,7 +30,7 @@
191,193,194,196,198,200,202,204,206,208,210,212,214,216,218,220, 191,193,194,196,198,200,202,204,206,208,210,212,214,216,218,220,
222,224,227,229,231,233,235,237,239,241,244,246,248,250,252,255}; */ 222,224,227,229,231,233,235,237,239,241,244,246,248,250,252,255}; */
Wagon::Wagon(int id,int numpixels, Adafruit_NeoPixel *strip,uint8_t *height,float pos, float trainlength,float startvel,float startacc, float wagonmass, uint32_t wagoncolor) Wagon::Wagon(int id,int numpixels, Adafruit_NeoPixel *strip,uint16_t *height,float pos, float trainlength,float startvel,float startacc, float wagonmass, uint32_t wagoncolor)
{ {
_id = id; _id = id;
_numpixels=numpixels; _numpixels=numpixels;

View file

@ -7,7 +7,7 @@ class Wagon
{ {
public: public:
int _id; int _id;
Wagon(int id,int numpixels,Adafruit_NeoPixel *strip,uint8_t *height, float pos, float wagonlength, float startvel,float startacc, float wagonmass, uint32_t wagoncolor); Wagon(int id,int numpixels,Adafruit_NeoPixel *strip,uint16_t *height, float pos, float wagonlength, float startvel,float startacc, float wagonmass, uint32_t wagoncolor);
Wagon(); Wagon();
bool operator==(const Wagon &r) const; bool operator==(const Wagon &r) const;
void updatePhysics(float updatedelayms); void updatePhysics(float updatedelayms);
@ -28,7 +28,7 @@ class Wagon
float _acc; float _acc;
float _wagonmass; float _wagonmass;
float _trainlength; float _trainlength;
uint8_t *_height; uint16_t *_height;
long _spawntime; long _spawntime;
float _lastvel; float _lastvel;
float _lastpositivedirchangepos; float _lastpositivedirchangepos;