Regentropfen / Schneefall / Meteor mit FastLED - Problem gelöst

Hallo Leute,

weil es nichts Gescheites zu kaufen gibt, habe ich gedacht, ich könnte mich mal mit den WS2812B Stripes und den Arduino Bord beschäftigen.
Habe auch einiges verstanden und habe hier mal das Programm dazu erstellt:

#include "FastLED.h"

#define NUM_LEDS 135

#define DATA_PIN 6

#define BRIGHTNESS 100

CRGB leds[NUM_LEDS];
int randNumber = randNumber;
int section = section;

void setup() {
  
  FastLED.setBrightness(BRIGHTNESS);
  
  FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);

}

void loop() {
  
  randNumber = random(1, 4);

  switch (randNumber) {
    case 1:
      section = 0;
      break;
    case 2:
      section = 45;
      break;
    default:
      section = 90;
      break;
  }      

   for(int whiteLed = section; whiteLed < NUM_LEDS;) {
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(3000);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 1;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(1000);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 1;
      leds[whiteLed] = CRGB::White;
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 2;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(500);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 3;
      leds[whiteLed] = CRGB::White;
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 2;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(100);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 2;
      leds[whiteLed] = CRGB::White;
      FastLED.show();
      delay(20);
      whiteLed < NUM_LEDS; whiteLed = whiteLed - 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      delay(1000);
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 1;
      leds[whiteLed] = CRGB::Black;
      FastLED.show();
      whiteLed < NUM_LEDS; whiteLed = whiteLed + 1;
      delay(3000);
   }
}

Ist sehr lang geworden und ich weiß nicht, wie ich das einfacher machen kann und die Übergänge weicher gestalten kann.
Für Hilfe wäre ich sehr dankbar.

Gruß Jaon

edit: Lösung weiter unten.

Das verstehe ich nicht. Normal brauchst du einen Sensor um Regentropfen festzustellen. Versuche doch mal deine Frage zu präzisieren.

Entschuldigung, da habe ich mich falsch ausgedrückt. Ich möchte Schneefall oder Regentropfen mit LED Stripes (45 LED) simulieren. So ähnlich wie hier: https://www.youtube.com/watch?v=NET_8WdMd3Y

Gruß Jaon

Jaon: Ist sehr lang geworden und ich weiß nicht, wie ich das einfacher machen kann und die Übergänge weicher gestalten kann.

Beschreibe mal in Worten, wie der Effekt aussehen soll!

So wie ich das verstehe, hast Du insgesamt 135 LEDs in drei Sektionen a 45 LEDs. Sektion-1 startet bei LED 0, Sektion-2 startet bei LED 45, Sektion-3 startet bei LED 90.

Und der Effekt sieht irgendwie so aus, dass Du einzelne LEDs zwischen weiß (ein) und schwarz (aus) umschaltest, während das Programm die meiste Zeit mit "delay() Aufrufen blockiert wird und dabei Pause macht.

In dem von Dir erwähnten Youtube-Video dürfte es anders gemacht sein: Da wird wahrscheinlich nicht die nächste LED hart von AUS auf EIN geschaltet, sondern immer überblendet: Also während die nachfolge LED heller wird, wird die vorangegangene dunkler. Sagen wir mal mit 16 Helligkeitsstufen zwischen schwarz und weiß. Dann würde also jede der 45 LEDs in der Sektion 16Stufen heller und 16 Stufen dunkler werden, = 2x 16 Stufen mal 45 LEDsx 3 Sektionen= 4320 einzelne Phasen insgesamt, bis der Effekt einmal komplett durch alle Sektionen durchgelaufen ist.

Ich bekomme Warnungen: “warning: statement has no effect [-Wunused-value]” bezogen auf whiteLed < NUM_LEDS;

@ jurs, genau ein Überblenden brauche ich. Ob das 16 Stufen braucht, kann ich nicht sagen. Habe versucht, 1 LED leuchtet und dann geht die davor aus und die dahinter an. Aber das sieht nicht aus und braucht viel Speicher. Was davor steht ist dafür da, dass wahllos immer ein Streifen mit 45 LED's losläuft. Sind im Moment zum Testen nur 3 und sollen mal 12 werden. Geht auch noch nicht richtig, weil im Moment immer nur einer laufen kann. Sollten aber wahllose Anzahl an Streifen und wahllose Streifennummer sein.

@ agmue, habe das Programm oben noch einmal abgeändert und bei mir eingespielt. Es geht ohne Fehlermeldung. Das Programm ist nur mittendrin gekürzt, weil es sonst nicht hier rein passt. Sollte im Moment ungefähr jeweils nur 30 LED angesteuert werden.

Jaon:
Es geht ohne Fehlermeldung.

Richtig, es geht ohne Fehlermeldung, wohl aber mit einer Warnung. Die siehst Du nur, wenn Du sie in den Voreinstellungen der IDE einschaltest. Die Anweisung ist syntaktisch richtig, inhaltlich aber ohne Sinn.

Jaon:
Geht auch noch nicht richtig, weil im Moment immer nur einer laufen kann. Sollten aber wahllose Anzahl an Streifen und wahllose Streifennummer sein.

Hier kommst Du auf den Kern des Problems: Dein Programm läuft, ist aber zu wenig flexibel. Was Du brauchst, wäre Multitasking, hat der Arduino aber nicht. Lösen läßt sich das mit einer quasi gleichzeitigen Verarbeitung durch möglichst häufiges Durchlaufen von loop ohne Blockaden wie delay oder lange Schleifen.

Dazu wurde hier im Forum schon viel geschrieben, auch von mir: Anleitung Ein Endlicher Automat entsteht mit einigen Links.

Als Anregung hätte ich einen Kometenschweif, den ich für meine APA102 geschrieben habe:

#include "FastLED.h"
#define LEDS_PRO_ABSCHNITT 45
// #define DATA_PIN 6			// Data pin that led data will be written out over, WS2812B
#define NUM_LEDS      135		// How many leds are in the strip?
#define LED_TYPE   APA102
#define COLOR_ORDER   BGR
#define VOLTS           5
#define MAX_MA       4000
#define BRIGHTNESS 255

CRGB leds[NUM_LEDS];		// This is an array of leds.  One item for each led in your strip.
// CRGBArray<NUM_LEDS> leds;

const byte schweiflaenge = 10;
uint16_t kometPos[(NUM_LEDS / LEDS_PRO_ABSCHNITT)] = {0, 0, 0};
uint32_t verzMillis[(NUM_LEDS / LEDS_PRO_ABSCHNITT)] = {20, 20, 20};
uint32_t altMillis[(NUM_LEDS / LEDS_PRO_ABSCHNITT)];
uint32_t aktMillis;
byte komet = 0;

void setup() {
  FastLED.setBrightness(BRIGHTNESS);  // set master brightness control
  // FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);		// WS2812B
  FastLED.setMaxPowerInVoltsAndMilliamps(VOLTS, MAX_MA);		    // APA102
  FastLED.addLeds<LED_TYPE, COLOR_ORDER>(leds, NUM_LEDS); 	// APA102 an SPI
}

void loop() {
  aktMillis = millis();
  if (!schweif(komet)) {
    kometPos[komet] = 0;
  }
}

bool schweif(byte k) {
  if (k >= (NUM_LEDS / LEDS_PRO_ABSCHNITT)) return false;
  if (aktMillis - altMillis[k] >= verzMillis[k]) {
    altMillis[k] = aktMillis;
    uint16_t ersteLed = k * LEDS_PRO_ABSCHNITT;
    uint16_t letzteLed = ((k + 1) * LEDS_PRO_ABSCHNITT) - 1;
    uint16_t pos = kometPos[k];
    if (pos == 0) {
      pos = ersteLed;
    }
    if (pos <= letzteLed) {
      leds[pos] = CRGB::White;
      kometPos[k] = ++pos;
    } else {
      return false;
    }
    FastLED.show();
    fadeToBlackBy( leds, NUM_LEDS, 110);
  }
  return true;
}

Danke. Das ist genau das, was ich meinte. Nur am Anfang sollte es langsam losgehen und zum Schluß noch ein Punkt kurz an bleiben. Wie an der Dachrinne ein Regentropfen nach unten fällt.
Ich habe das bei mir viel zu aufwändig gemacht.
Habe das hier für mich angepasst:

#include "FastLED.h"
#define NUM_LEDS 135
#define LEDS_PRO_ABSCHNITT 45
#define DATA_PIN 6
#define BRIGHTNESS 100

CRGB leds[NUM_LEDS];

const byte schweiflaenge = 10;
uint16_t kometPos[(NUM_LEDS / LEDS_PRO_ABSCHNITT)] = {0};
uint32_t verzMillis[(NUM_LEDS / LEDS_PRO_ABSCHNITT)] = {20};
uint32_t altMillis[(NUM_LEDS / LEDS_PRO_ABSCHNITT)];
uint32_t aktMillis;
byte komet = 0;

void setup() {
  FastLED.setBrightness(BRIGHTNESS);
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);

}

void loop() {
  aktMillis = millis();
  if (!schweif(komet))
  {
    kometPos[komet] = 0;
  }
}

bool schweif(byte k) {
  if (k >= (NUM_LEDS / LEDS_PRO_ABSCHNITT)) return false;
  if (aktMillis - altMillis[k] >= verzMillis[k]) {
    altMillis[k] = aktMillis;
    uint16_t ersteLed = k * LEDS_PRO_ABSCHNITT;
    uint16_t letzteLed = ((k + 1) * LEDS_PRO_ABSCHNITT) - 1;
    uint16_t pos = kometPos[k];
    if (pos == 0) {
      pos = ersteLed;
    }
    if (pos <= letzteLed) {
      leds[pos] = CRGB::White;
      kometPos[k] = ++pos;
    } else {
      return false;
    }
    FastLED.show();
    fadeToBlackBy( leds, NUM_LEDS, 200);
  }
  return true;
}

Fehlt mir nur noch die wahllosen Abschnitte und wahllose Pausenlänge dazwischen.
Vielleicht gehen auch mehrere Abschnitte gleichzeitig.

Jaon: Vielleicht gehen auch mehrere Abschnitte gleichzeitig.

Das habe ich zwar nicht probiert, sollte aber schon jetzt funktionieren, denn komet ist eine Variable.

Jaon: Fehlt mir nur noch die wahllosen Abschnitte und wahllose Pausenlänge dazwischen.

Da ist fadeToBlackBy etwas problematisch, weil es auf alle LEDs wirkt.

Das mit dem wahllos bekomme ich mit meiner Variante so nicht hin. Da fehlt mir die Einstiegslednummer. Wo wird die zugewiesen? Wie kann man das mit dem fadeToBlackBy so ändern, dass es passt?

Ach so. Bei mir geht das hinter uint16 und 32 mit den 3 Zahlen nicht.

Jaon: Das mit dem wahllos bekomme ich mit meiner Variante so nicht hin. Da fehlt mir die Einstiegslednummer. Wo wird die zugewiesen?

Ändere mal komet = 1;, dann werden die zweiten 45 Leds angesteuert. In meiner Variante habe ich das getestet, hat funktioniert.

Komet = 1 sind die nächsten LED, aber es geht auch schneller. Habe nichts anderes geändert. Wie kann ich das dann aber noch wahllos machen? Mit dem Random von mir klappt das nicht. Habe ich versucht.

Das habe ich hier noch mal eingefügt. Kommt mir komisch vor: Bei mir geht das hinter uint16 und 32 mit den 3 Zahlen nicht. Wozu ist das?

Habe jetzt mal mit einfachen Mitteln so etwas dargestellt. Vielleicht braucht das mal jemand.
Mir ist aufgefallen, dass es bei mehr als 600 LED mit dem UNO kritisch wird.

Dank an alle.

Meteor_7_Streifen_315_LED_warmweiss.zip (1.49 KB)

Schneeflocken_7_Streifen_315_LED_warmweiss.zip (959 Bytes)