Go Down

Topic: LEDs (WS281x) über SPI "funkeln" lassen (Read 950 times) previous topic - next topic

Leon333

Hallo liebes Forum!

Ich bin neu im gesamten Bereich der Microcontroller und Programmierung, habe jedoch einige ambitionierte Projekte oder Ideen, die ich langfristig verwirklichen möchte.
Dafür habe ich mir ein paar (kleinere) Ziele gesetzt und habe auch schon die ersten paar (sehr winzigen) Zielchen erreicht.
Ich bitte hier die eingefleischten Programmierer und Microcontroller-Spezialisten nicht zu sehr über mich herzufallen, sollte ich eine (oder mehrere) dämliche Frage stellen :D :D
(nur nebenbei: Suchfunktion und google haben mir leider nicht geholfen)

Nun aber zu meinem (ersten) Anliegen:

Ich habe LEDs mit integriertem WS2812B, welche außer der Spannungsversorgung noch einen Datenkanal haben.
Der WS2812B ist bis auf ein paar bauliche veränderungen (soweit ich das gesehen habe) identisch mit LEDs der WS2811er Reihe.

Nun habe ich mir ein Arduino UNO zugelegt und wollte die LEDs mal zum leuchten bringen.
Das ist dank der FAST_SPI Bibliothek selbst für mich als absoluter Neuling relativ unkompliziert gewesen (wäre noch schneller gegangen, wenn ich früher gewüsst hätte, das man GND der LEDs mit dem GND des Arduino verbinden muss um flackern der LEDs zu beseitigen...).

Die LEDs sind alle einfach ansteuerbar, auch wenn noch einige Dinge für mich relativ undurchschaubar sind, wie z.b. dass die LEDs ein logarythmus ähnliche Helligkeitskurve beim ansteuern haben. (Das bekomme ich aber hoffentlich noch in den Griff).

Mein nächstes Ziel ist es die LEDs "funkeln" zu lassen.
Genauer erklärt:
Ich möchte, dass die LEDs zufällig, voneinander unabhängig und unterschiedlich schnell heller und dunkler leuchten.

Im Internet habe ich dazu schon eine Klasse gefunden, die mir aus einem HSV-Farbraum die RGB Farben umwandelt. (in meinem Fall aufgrund der ansteuerung genauer eigentlich: GRB)
Hierbei kann ich den Helligkeitsparameter (V) einstellen, bzw. darüber die LEDs heller und dunkler leuchten lassen.

Ein Beispiel dafür:

Code: [Select]

void funkeln(int thiscolor, int thissat, int thisminbright, int thismaxbright, int thismindelay, int thismaxdelay) {
  int random_bright = random(thisminbright,thismaxbright);
  int random_delay = random(thismindelay,thismaxdelay);
  int random_bool = random(0,random_bright);
  int thisColor[3];
 
  if (random_bool < 10)
  {
    HSVtoRGB(thishue, thissat, random_bright, thisColor);
    set_color_led(random(0,NUM_LEDS), thisColor[0], thisColor[1], thisColor[2]);
       
    LEDS.show();   
    delay(random_delay);

  }


void setup() {
  LEDS.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
}

void loop() {
//funkeln(int Farbwert, int Sättigung, int MinimaleHelligkeit, int MaximaleHelligkeit, int MinimalePause, int Maximale Pause);
funkeln(180, 255, 20, 60, 0, 100);
}



Das klappte schonmal, ist allerdings noch nicht so ausgereift wie ich es gerne hätte.
Bei dem gezeigten Beispiel wird immer nur eine (zufällige) LED mit einem anderen Farbwert überschrieben.
Diese hat dann schlagartig eine andere Farbe (bzw. Helligkeit) - das wirkt mir persönlich zu unruhig.

Ich hätte gerne:
1. Das eine zufällige Anzahl von LEDs (0-MaximaleAnzahlLEDs) gleichzeitig geändert werden.
2. Die LEDs mehr Pulsieren, als nur einen neuen Farbwert zu bekommen.

Hierbei habe ich jedoch starke Probleme.
Ich hatte schonmal soetwas angefangen (Auszug):

Code: [Select]

// zufällige Anzahl an LEDs auswählen die bei diesem Durchlauf "funkeln" sollen
int random_anzahlLeds= random(0,NUM_LEDS);

for(int i = 0; i < random_anzahlLeds; i++ )
{
 
  //Array initialisieren der mitschreibt welche LED geändert wurde
  int farbeGeaendert[random_anzahlLeds];
 
  //zufällige LED die geändert wird
  int random_Led= random(0,NUM_LEDS); 
 
   //wenn die Farbe von LED x bereits geändert worden ist
  while(Arrays.asList(farbeGeaendert).contains(random_Led))
  {
     //wähle eine andere LED aus zum ändern
     random_Led= random(0,NUM_LEDS);
  }
     
  //in den Array schreiben, welche LED geändert wurde
  farbeGeaendert[i] = random_Led;
 
  leds[random_Led].g = color[0];
  leds[random_Led].r = color[1];
  leds[random_Led].b = color[2]; 
 




Leider bekomme ich hier den Fehler "'Arrays' was not declared in this scope" in der Zeile in der ich mittels "while(Arrays.asList(farbeGeaendert).contains(random_Led))" versuche, herraus zu finden, ob diese LED schon geändert wurde.
Ich weiß zwar, das es theoretisch egal ist, ob eine LED mehrfach vom farbwert geändert wird, weil es eigentlich eh nur "zufällig" funkeln soll, aber ich möchte es vom Prinzip her richtig machen.
Vielleicht weiß jemand ja wie ich einen Array auf die Existenz eines bestimmen integer Wertes prüfen kann.


Nun zum funkeln:

Eeeigentlich (!) hätte ich es gerne, das die LEDs einzelnd (jede für sich zufällig), dynamisch (in kleinen schritten heller/dunkeler werden und nicht direkt mit helligkeit x überschrieben werden) und unterschiedlich schnell heller und dunkler werden.

Das ist allerdings noch etwas sehr viel zu schwer für mich (schon alleine das Thema "Array" war nicht so ganz einfach für mich).

Daher wollte ich gerne per Zufall entscheiden lassen, ob eine LED gleich bleiben, heller oder dunkler werden soll um einen ähnlichen Effekt zu erzielen.
Das sah dann etwa so aus:
Code: [Select]
//soll die led die farbe ändern? (0= nein , 1= heller, 2=dunkler)
      random_funkel = random(0,2);


funktioniert leider nicht. Ich muss es auf
Code: [Select]
random_funkel = random(0,3);
stellen.
Wie ist die Funktion random zu verstehen?
random( Anfang, Ende)
oder
random(Anfang, Schrittweite) ?
Das mein erster Ansatz nicht funktioniert spricht eigentlich für letzteres.

Nun wollte ich den LED Farbwert einer LED auslesen und dann entweder heller oder dunkler machen.
Laut Wikipedia ist die Helligkeit (V) des HSV-Farbraums gleich dem hellsten Wert aus RGB.

Daher wollte ich so die Helligkeit ermitteln und dann die LED entweder verdunkeln oder erhellen:
Code: [Select]
//HSV-Helligkeit ermitteln
for(int j=0; j<=2 ; j++)
      {
        if(leds[random_Led][j] > brightness_thisLed)
        {
          brightness_thisLed=leds[i][j];
        }
      }

      //eins heller funkeln lassen   
      if(random_funkel == 2)
      {
        if(thisMinHelligkeit < brightness_thisLed)
        {
          brightness_thisLed = brightness_thisLed - 1;
        }
      }
   
      //eins dunkler funkeln lassen
      if(random_funkel == 1)
      {
        if(thisMaxHelligkeit>brightness_thisLed)
        {
       
          brightness_thisLed = brightness_thisLed  + 1;
        }
      }

      //RGB farbwerte ermitteln
      HSVtoRGB(thisFarbwert, thisSaettigung, brightness_thisLed, color);   

      //farben "schreiben"
      leds[random_Led].g = color[0];
      leds[random_Led].r = color[1];
      leds[random_Led].b = color[2]; 

    LEDS.show(); 


Das funktioniert jedoch nicht. Wahrscheinlich kann man so wie ich es versuche nicht auf die Farben der LEDs zugreifen, die Umrechnung von RGB in V oder sonst ein denkansatz ist von mir grundlegend falsch.
Ich hoffe jemand hat Mitleid mit mir und kann mir helfen :D

Ich danke schonmal im Vorfeld für jede Unterstützung!



Code: [Select]

 while(Arrays.asList(farbeGeaendert).contains(random_Led))



Hallo,
Dein Konstrukt von oben sieht ja fast aus wie Java, da gibt es Listen von Arrays. Es kann natürlich sein, dass Du eine Lib eingebunden hast, die eine solche Klasse auch auf dem Arduino implementiert, weiß ich aber nicht, der Anfang Deines Sketches fehlt. Wenn Du nicht irgendein "#include <...>" für eine Listenklasse hast, funktioniert das so nicht. Über Arrays in C++ kannst Du hier was lesen: http://www.elektronik-bastelkeller.de/C_Ardu_3_8.php. Einen Artikel über die Ansteuerung der WS2812 RGB-Leds gibt es im Mikrokontroller.net hier: http://www.mikrocontroller.net/articles/WS2812_Ansteuerung. Vielleicht helfen Dir diese beiden Stellen ja schon mal weiter...
Gruß,
Ralf
Es gibt 10 Arten von Menschen, die einen verstehen Binär, die anderen nicht...

Leon333

Na super jetzt ist meine Antwort weg...
hatte so lange geschrieben, das ich nicht mehr angmeldet war -.-

Ich hab gerade keine Lust das alles nochmal zu tippen, daher in kurz:
Du hast recht, da hab ich wohl die programmiersprachen vertrauscht.
Ich hab leider keine vergleichbare Methode gefunden, daher durchsuche ich den array jetzt mittels for-Schleife - nicht wirklich schön, aber es geht.
Falls jemand ne C-Methode kennt, die einen Array auf die existenz eines integer-wertes prüft bitte sagen.

Außerdem habe ich nach meinem Beitrag gestern ein paar fortschritte gemacht.
Dennoch scheint das Problem an der Umrechnung von RGB in HSV bei mir zustande zu kommen.

Meine HSV zu RGB Methode sieht so aus:
Code: [Select]
void HSVtoRGB(int hue, int sat, int val, int color[3]) {
  // hue: 0-359, sat: 0-255, val (lightness): 0-255
  int r, g, b, base;

  if (sat == 0) { // Achromatic color (gray).
    color[0]=val;
    color[1]=val;
    color[2]=val;
  }
  else  {
    base = ((255 - sat) * val)>>8;
    switch(hue/60) {
    case 0:
      r = val;
      g = (((val-base)*hue)/60)+base;
      b = base;
      break;
    case 1:
      r = (((val-base)*(60-(hue%60)))/60)+base;
      g = val;
      b = base;
      break;
    case 2:
      r = base;
      g = val;
      b = (((val-base)*(hue%60))/60)+base;
      break;
    case 3:
      r = base;
      g = (((val-base)*(60-(hue%60)))/60)+base;
      b = val;
      break;
    case 4:
      r = (((val-base)*(hue%60))/60)+base;
      g = base;
      b = val;
      break;
    case 5:
      r = val;
      g = base;
      b = (((val-base)*(60-(hue%60)))/60)+base;
      break;
    }
    color[0]=r;
    color[1]=g;
    color[2]=b;
  }


Diese habe ich von hier und sie funktioniert bestens. (ist ja auch nicht von mir :D )

Die Umrechnung von RGB in HSV mache ich so, wobei mich nur der "V" (Helligkeits-)Wert interessiert:
Code: [Select]
int brightness_thisLed=0;
    int random_Led= random(0,NUM_LEDS); 

    for(int i = 0; i <= random_anzahlLeds; i++ )
    {       
      for(int j=0; j<=2 ; j++)
      {
        if(leds[random_Led][j] > brightness_thisLed)
        {
          brightness_thisLed=leds[random_Led][j];
        }
      }

Zumindest ist laut Wikipedia das V gleich dem MAX der R G B Werte.

Mittlerweile bin ich dennoch soweit, das die LEDs flimmern.
Diese werden immer zufällig eins heller, eins dunkler oder bleiben gleich.

Dadurch flimmern alle was ich auch gut finde.
Allerdings hätte ich es gerne, das ein paar LEDs auch mal ab und zu ein bisschen "pulsieren", also mehrere Helligkeitsstufen heller oder dunkler werden.
Leider fehlt es mir dazu an einer schematischen Lösung. Ich weiß nicht, wie ich das hinbekommen kann.
Die LEDs sollen ja noch schlagartig z.b. +6 heller werden (das erinnert dann an Strobo-Effekten), sondern schrittweise immer einen heller werden bis sie bei +6 angekommen sind...
Gleichzeitig sollen allerdings die anderen LEDs nicht aufhören zu flimmern, nur weil eine mal einen Sprung von mehreren Helligkeitsstufen macht.

Ich hoffe jemand weiß, wie man soetwas unter einen hut bringen kann.

Das jetzt von mir in aller kürze.
Wenn ich Zeit habe, schreibe ich wieder ausführlicher (echt ärgerlich, dass der ganze ausführliche Text mit Code Beispielen weg ist! )

Liebe Grüße

Go Up