FastLED Feuerwerk Simulation

Hallo Community,

Ich habe mir eine Wortuhr gebaut das Funktioniert alles super.
Hatte nun die Idee das mir zum Neujahr ein Feuerwerk angezeigt wird.

Auf GitHub habe ich diesen Code gefunden:

In den Kommentaren wurde eine Funktion auch schon angepasst, dass der Code auf einer ZigZag Matrix mit den WS2812B angetrieben von einem NodeMCU.

Angeschlossen sind die LEDs nach diesem Schema:

1234
.......|
8765

Es sind 10 Reihen mit jeweils 11 LEDs in der Reihe.

Leider blinkt der obige Code nur wild umher und man sieht nicht das es ein Feuerwerk sein soll was auch zum Himmel geschossen wird.

Hat jemand von Euch eine Idee, wie ich anfangen soll das Problem zu lösen?

Vielen, vielen Dank im voraus!

LG,
Björn

MajorW:
Hat jemand von Euch eine Idee, wie ich anfangen soll das Problem zu lösen?

Klar, Fehler suchen.

Oder eine genaue Beschreibung, wie du alles angeschlossen hast und was für ein Netzteil du verwendest.
Und deinen Sketch hier in Code-Tags posten.

Hallo,

das ist der Code den ich nutze. So gefunden auf GitHub habe nur meinen DataPin angepasst.

Angeschlossen ist der WS2812B Stripe am PIN 3 vom NodeMCU (TX) - funktioniert mit der Wordclock perfekt nur mit der Feuerwerk Script nicht. Mit Strom versorgt wird das ganze zur Zeit noch über ein Labornetzteil (5V / 4A sind eingestellt).

Eigentlich sollte das Script wie in einem Youtube Video erst einen Punkt nach oben schießen der dann Explodiert. Es sind auch "Explosionen" zu sehen - allerdings erkennt man nicht das es ein Feuerwerk sein soll..

Ich hoffe ich hab jetzt alle Daten geliefert die Ihr braucht. Würde mich echt freuen wenn mir jemand unter die Arme greifen könnte - komme einfach nicht weiter :(...

#define FASTLED_ESP8266_RAW_PIN_ORDER
#include "FastLED.h"

// FireworksXY
// Quick and dirty 2-D fireworks simulation using FastLED.
//
// Originaly designed an Adafruit 5x8 WS2811 shield, but works fine
// on other XY matricies.
//
// by Mark Kriegsman, July 2013
// (and not updated too much since then, so it's a little stale,
//  but it's a good starting point, if rather uncommented.)

#define PIXEL_WIDTH  11
#define PIXEL_HEIGHT 10

#define LED_TYPE     WS2811
#define COLOR_ORDER  GRB
#define DATA_PIN     3
//#define CLK_PIN    4

#define BRIGHTNESS   255


#define NUM_LEDS (PIXEL_WIDTH * PIXEL_HEIGHT)
CRGB leds[NUM_LEDS];

#define MODEL_BORDER 1
#define MODEL_WIDTH  (MODEL_BORDER + PIXEL_WIDTH  + MODEL_BORDER)
#define MODEL_HEIGHT (MODEL_BORDER + PIXEL_HEIGHT + MODEL_BORDER)

#define PIXEL_X_OFFSET ((MODEL_WIDTH  - PIXEL_WIDTH ) / 2)
#define PIXEL_Y_OFFSET ((MODEL_HEIGHT - PIXEL_HEIGHT) / 2)

#define WINDOW_X_MIN (PIXEL_X_OFFSET)
#define WINDOW_X_MAX (WINDOW_X_MIN + PIXEL_WIDTH - 1)
#define WINDOW_Y_MIN (PIXEL_Y_OFFSET)
#define WINDOW_Y_MAX (WINDOW_Y_MIN + PIXEL_HEIGHT - 1)

CRGB overrun;

CRGB& XY( byte x, byte y)
{
  x -= PIXEL_X_OFFSET;
  y -= PIXEL_Y_OFFSET;
  if ( x < PIXEL_WIDTH && y < PIXEL_HEIGHT) {
    if ( y & 0x01) {
      // Odd rows run backwards
      uint8_t reverseX = (PIXEL_WIDTH - 1) - x;
      return leds[(y * PIXEL_WIDTH) + reverseX];
    } else {
      // Even rows run forwards
      return leds[ (y * PIXEL_HEIGHT) + x ] ;
    }
  } else
    return overrun;
}

void screenscale( accum88 a, byte N, byte& screen, byte& screenerr)
{
  byte ia = a >> 8;
  screen = scale8( ia, N);
  byte m = screen * (256 / N);
  screenerr = (ia - m) * scale8(255, N);
  return;
}


void plot88( byte x, byte y, CRGB& color)
{
  byte ix = scale8( x, MODEL_WIDTH);
  byte iy = scale8( y, MODEL_HEIGHT);
  CRGB& px = XY( ix, iy);
  px = color;
}


static int16_t scale15by8_local( int16_t i, fract8 scale )
{
  int16_t result;
  result = (int32_t)((int32_t)i * scale) / 256;
  return result;
}

saccum78 gGravity = 10;
fract8  gBounce = 200;
fract8  gDrag = 255;
bool gSkyburst = 0;

accum88 gBurstx;
accum88 gBursty;
saccum78 gBurstxv;
saccum78 gBurstyv;
CRGB gBurstcolor;

#define NONE 0
#define SHELL 1
#define SPARK 2

class Dot {
  public:
    byte    show;
    byte    theType;
    accum88 x;
    accum88 y;
    saccum78 xv;
    saccum78 yv;
    accum88 r;
    CRGB    color;

    Dot()
    {
      show = 0;
      theType = 0;
      x =  0;
      y =  0;
      xv = 0;
      yv = 0;
      r  = 0;
      color.setRGB( 0, 0, 0);
    }

    void Draw()
    {
      if ( !show) return;
      byte ix, xe, xc;
      byte iy, ye, yc;
      screenscale( x, MODEL_WIDTH, ix, xe);
      screenscale( y, MODEL_HEIGHT, iy, ye);
      yc = 255 - ye;
      xc = 255 - xe;

      CRGB c00 = CRGB( dim8_video( scale8( scale8( color.r, yc), xc)),
                       dim8_video( scale8( scale8( color.g, yc), xc)),
                       dim8_video( scale8( scale8( color.b, yc), xc))
                     );
      CRGB c01 = CRGB( dim8_video( scale8( scale8( color.r, ye), xc)),
                       dim8_video( scale8( scale8( color.g, ye), xc)),
                       dim8_video( scale8( scale8( color.b, ye), xc))
                     );

      CRGB c10 = CRGB( dim8_video( scale8( scale8( color.r, yc), xe)),
                       dim8_video( scale8( scale8( color.g, yc), xe)),
                       dim8_video( scale8( scale8( color.b, yc), xe))
                     );
      CRGB c11 = CRGB( dim8_video( scale8( scale8( color.r, ye), xe)),
                       dim8_video( scale8( scale8( color.g, ye), xe)),
                       dim8_video( scale8( scale8( color.b, ye), xe))
                     );

      XY(ix, iy) += c00;
      XY(ix, iy + 1) += c01;
      XY(ix + 1, iy) += c10;
      XY(ix + 1, iy + 1) += c11;
    }

    void Move()
    {
      saccum78 oyv = yv;

      if ( !show) return;
      yv -= gGravity;
      xv = scale15by8_local( xv, gDrag);
      yv = scale15by8_local( yv, gDrag);

      if ( theType == SPARK) {
        xv = scale15by8_local( xv, gDrag);
        yv = scale15by8_local( yv, gDrag);
        color.nscale8( 255);
        if ( !color) {
          show = 0;
        }
      }

      // if we'd hit the ground, bounce
      if ( yv < 0 && (y < (-yv)) ) {
        if ( theType == SPARK ) {
          show = 0;
        } else {
          yv = -yv;
          yv = scale15by8_local( yv, gBounce);
          if ( yv < 500 ) {
            show = 0;
          }
        }
      }

      if ( (yv < -300) /* && (!(oyv < 0))*/ ) {
        // pinnacle
        if ( theType == SHELL ) {

          if ( (y > (uint16_t)(0x8000)) /*&& (random8() < 64)*/) {
            // boom
            LEDS.showColor( CRGB::White);
            //delay( 1);
            LEDS.showColor( CRGB::Black);
          }

          show = 0;

          gSkyburst = 1;
          gBurstx = x;
          gBursty = y;
          gBurstxv = xv;
          gBurstyv = yv;
          gBurstcolor = color;
        }
      }
      if ( theType == SPARK) {
        if ( ((xv >  0) && (x > xv)) ||
             ((xv < 0 ) && (x < (0xFFFF + xv))) )  {
          x += xv;
        } else {
          show = 0;
        }
      } else {
        x += xv;
      }
      y += yv;

    }

    void GroundLaunch()
    {
      yv = 600 + random16(300 + (25 * PIXEL_HEIGHT));
      xv = (int16_t)random16(600) - (int16_t)300;
      y = 0;
      x = 0x8000;
      hsv2rgb_rainbow( CHSV( random8(), 240, 200), color);
      show = 1;
    }

    void Skyburst( accum88 basex, accum88 basey, saccum78 basedv, CRGB& basecolor)
    {
      yv = (int16_t)0 + (int16_t)random16(1500) - (int16_t)500;
      xv = basedv + (int16_t)random16(2000) - (int16_t)1000;
      y = basey;
      x = basex;
      color = basecolor;
      color *= 4;
      theType = SPARK;
      show = 1;
    }

};

#define NUM_SPARKS 12

Dot gDot;
Dot gSparks[NUM_SPARKS];

void setup() {
  delay(2000);
  FastLED.setBrightness(BRIGHTNESS);
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setCorrection(TypicalLEDStrip);
  FastLED.setDither(BRIGHTNESS < 255);
}

void loop()
{
  //random16_add_entropy( random() );
  //CRGB sky1(0, 0, 2);
  //CRGB sky2(2, 0, 2);

  memset8( leds, 0, NUM_LEDS * 3);
/*
#if 1
  for ( uint16_t v = 0; v < NUM_LEDS; v++) {
    leds[v] = sky1;
  }
  for ( byte u = 0; u < 1; u++) {
    leds[random8(NUM_LEDS)] = sky2;
  }
#endif
*/

  gDot.Move();
  gDot.Draw();
  for ( byte b = 0; b < NUM_SPARKS; b++) {
    gSparks[b].Move();
    gSparks[b].Draw();
  }

  LEDS.show();
  static uint16_t launchcountdown = 0;
  if ( gDot.show == 0 ) {
    if ( launchcountdown == 0) {
      gDot.GroundLaunch();
      gDot.theType = SHELL;
      launchcountdown = random16( 350) + 1;
    } else {
      launchcountdown --;
    }
  }

  if ( gSkyburst) {
    byte nsparks = random8( NUM_SPARKS / 2, NUM_SPARKS + 1);
    for ( byte b = 0; b < nsparks; b++) {
      gSparks[b].Skyburst( gBurstx, gBursty, gBurstyv, gBurstcolor);
      gSkyburst = 0;
    }
  }

  delay(10);
}

Das kann nicht funktionieren.

Du verwendest einen Pin der für die USB-Schnittstelle reserviert ist. Das ist übrigens RX0.
Verwende einen anderen Pin als D1 (GPIO1) und D3(GPIO3).

Hallo Dieter,

danke für deine Hilfe aber das war es leider nicht. Die Feuerwerk Simulation sieht immer noch total auseinander gerissen aus. Sieht etwas so aus als würde er mit der Matrix nicht klar kommen :-(.

01-02-03-04-05-06-07-08-09-10-11
....................................................|
22-21-20-19-18-17-16-15-14-13-12
|
23-24-25-26-27-28-29-30-31-32-33

usw...

EDIT:

Habe es nun soweit das das Feuerwerk entsteht. In der XY Funktion ist ein Fehler drin. Allerdings kommt das Feuerwerk von oben reingeflogen nicht wie gewollt von unten..

Nur leider lässt es mein Programmierhorizont nicht zu, zuverstehen wo im Code der Fehler liegt oder was ich ändern müsste.

Hi

Hast Du verstanden, wie das Feuerwerk die einzelnen LEDs ansteuert?
Wenn JA -> lasse dort, statt dem Feuerwerk, nur eine LED senkrecht hochsteigen, von ganz Unten nach ganz Oben.
Dann an 2.ter Position .... 11ter Position.
Wenn Das passt (wird Es nicht !!), klappt auch das Feuerwerk.
Deine Matrix passt akut nicht zu dem Sketch - meine Prognose.

MfG

Ungetestete Idee:

CRGB& XY( byte x, byte y)
{
  y = PIXEL_HEIGHT - y;
...

Moinsen,

bitte entschuldigt, dass ich mich jetzt erst wieder melde. Hatte beruflich viel um die Ohren. Habe jetzt aber Urlaub und wieder Zeit mich meinem Hobby zu widmen.

Vielen, vielen Dank nochmal für die Denkanstöße und eure Hilfe :)!

Mittlerweile verstehe ich wie der Code die LEDs setzt und habe verstanden, warum meine Matrix nicht zum Code passt.

Natürlich möchte ich, dass wenn jemand anderes auf diesen Thread stößt auch die Lösung findet :wink: .

Letztendlich hat mir der Codeschnippsel von agmue geholfen und war meine Lösung des Problems:

agmue:
Ungetestete Idee:

CRGB& XY( byte x, byte y)

{
 y = PIXEL_HEIGHT - y;
...

Liebe Grüße,
Björn