Go Down

Topic: Abstrahieren eines Problems vor dem Coden / LED Strip Effekt Umsetzung (Read 1 time) previous topic - next topic

Helmuth

Hey, ich würde gern nochmal auf den Effekt zurückkommen, der hier zu sehen ist: https://www.youtube.com/watch?v=WO6LiyrEQC0

Um was zu lernen und das nachzuprogrammieren würde ich gern (mit Eurer Unterstützung) die genaue Problemstellung definieren und die Lösungen der Teilprobleme soweit abstrahieren und strukturieren, bis (mir) die Umsetzung in Code möglich ist.

Was sehen wir? Über einen LED Strip laufende Punkte - ich werde sie im folgenden Oszillatoren nennen, welche sich durch verschiedene Eigenschaften auszeichnen. Ich notiere in Klammern dahinter, wie ich diese Beschreiben würde, nämlich so:

Farbe (3 Byte)
Geschwindigkeit (1 Byte)
Richtung (1 Boolean)
Schweiflänge (1 Byte)
Lebenszeit (1 Unsigned Int)

Darüber hinaus fällt auf, dass sich Oszillatoren, welche sich auf dem Strip begegnen, additiv mischen. Oszis, welche über Anfang / Ende vom Strip hinauslaufen, kommen am anderen Ende wieder herein.

Jetzt gilt es folgende Aufgaben zu lösen:

Geeignetes Format finden, um die Eigenschaften eines Oszis zu definieren. Ein Array vielleicht?

Programmablauf ganz abstrakt:
Endlosschleife {
  Oszianzahl überwachen - wenn Oszianzahl kleiner festgelegte Größe: neue Oszis säen;
  alle Oszis im Speicher gemäß Eigenschaften um einen Schritt weiterlaufen lassen
  Oszis, deren Lebenszeit abgelaufen ist sterben lassen
  diesen kompletten Schritt rendern und ausgeben
}

Des Überblicks wegen erscheint es mir ratsam, erstmal einen Oszi zu definieren und dann diesen einen ohne Wechselwirkung mit anderen zu rendern und sichtbar zu machen.

Klingt das soweit nach einem sinnvollen Ansatz?

Für alle ANregungen und Hinweise dankbar:

Helmuth.





jurs


Was sehen wir? Über einen LED Strip laufende Punkte


Da bekommt man ja einen Augenfehler. Ich schaue mir die Scheibe mal auch bei Tageslicht an:
http://sphotos-g.ak.fbcdn.net/hphotos-ak-snc6/c68.0.403.403/p403x403/253118_279918988787295_2064405876_n.jpg


- ich werde sie im folgenden Oszillatoren nennen, welche sich durch verschiedene Eigenschaften auszeichnen. Ich notiere in Klammern dahinter, wie ich diese Beschreiben würde, nämlich so:


Ja, ein Array von Datenstrukturen in der Anzahl der maximal gleichzeitig aktiven Oszillatoren. Würde ich wohl auch so machen.


Darüber hinaus fällt auf, dass sich Oszillatoren, welche sich auf dem Strip begegnen, additiv mischen.


Da mußt Du wohl ein zweidimensionales Array mit "Berührungspunkten" verwalten, also immer Pärchen von LEDs, die sich unmittelbar optisch "nebeneineinander" aber an verschiedenen Stellen auf dem LED-Streifen befinden. Und immer wenn zwei Oszillatoren an einem Berührungspunkt aufeinander treffen, muß eine Interaktion stattfinden.

So ganz trivial scheint mir das nicht zu sein, und mit der großen Scheibe und den vielen einzeln ansteuerbaren LEDs hat er da bestimmt nicht nur finanziell ordentlich was investiert, sondern auch an Zeit für die Programmierung.



Helmuth

#2
Mar 06, 2013, 02:19 pm Last Edit: Mar 06, 2013, 03:20 pm by Helmuth Reason: 1
Hi jurs,

das mit den Berührungspunkten dachte ich mir so: jeder Oszi wird erstmal einzeln in einen kleinen Puffer1 gerendert, dieser Puffer1 wird dann in einen größeren Puffer2 (so lang wie der Strip) kopiert unter Berücksichtigung dessen, was schon drin ist. D.h. schauen, ob an gleicher Position schon was drin steht, wenn nein sofort reinschreiben, wenn ja, dann nur den wenn der neue Wert größer ist, als der alte.
Wenn das für alle Oszis durch ist, Puffer2 anzeigen, leeren und von vorn.

Ist übrigens das Burning Man Projekt von Daniel Garcia, dem Autor von FastSPI_LED. Habe ich live gesehen, in der Wüste.  :D

Ich gehe nicht davon aus, das es hier eine schnelle triviale Lösung gibt, es ist ok für mich, wenn sich das über einen längeren Zeitraum entfaltet...

Beste Grüße, Helmuth

Edit - Konkreter Zwischenbericht zur Grundstruktur:
Code: [Select]
// Konzeptstudie zur Umsetzung von "Liquid Eye"
// auf einem RGB Strip

#include <FastSPI_LED.h>

#define NUM_LEDS 20               // Striplänge
#define OSZILLATORS 1             // Anzahl Oszillatoren
#define OSZILLATOR_MAX_LENGHT 10  // Länge eines Oszillators

// Array mit den Eigenschaften der einzelnen Oszillatoren:
// r, g, b, speed, dirction, tail, lifetime
byte oszillators[OSZILLATORS][7];

// Zwischenspeicher des Bitmaps von einem Oszillator
byte actual_oszillator[OSZILLATOR_MAX_LENGHT][3];

// Zwischenspeicher des Bitmaps der gesamten Ausgabe
byte buffer[NUM_LEDS][3];

// der eigentliche Bildspeicher
struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;

//----------------------------------------------------------------
void setup(){
  FastSPI_LED.setLeds(NUM_LEDS);
  FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2801);
  FastSPI_LED.init();
  FastSPI_LED.start();
  leds = (struct CRGB*)FastSPI_LED.getRGBData();
 
  init_oszillators();
}

//----------------------------------------------------------------
void loop() {
  render_oszillators_to_buffer();
  show_buffer(); 
}

//----------------------------------------------------------------
void init_oszillators() {
  // erstmal nur einen
  oszillators[0][0] = 255; //rot
  oszillators[0][1] = 127; //grün
  oszillators[0][2] = 0;   //blau
  oszillators[0][3] = 2;   //Geschwindigkeit (1-10)
  oszillators[0][4] = 1;   //Richtung (0 oder 1)
  oszillators[0][5] = OSZILLATOR_MAX_LENGHT - 1; //Schweif
  oszillators[0][6] = 30;  //Lebensdauer in Sekunden
}

// zum Anzeigen des Berechneten
void show_buffer(){
  // anzeigen
  for(int i = 0 ; i < NUM_LEDS; i++ ) {
    leds[i].r = buffer[i][0];
    leds[i].g = buffer[i][1];
    leds[i].b = buffer[i][2];
  }
  FastSPI_LED.show();
  // und löschen
  for(int i = 0 ; i < NUM_LEDS; i++ ) {
    leds[i].r = 0;
    leds[i].g = 0;
    leds[i].b = 0;
  }
 
}

void render_oszillators_to_buffer() {
  // mit allen Oszillatoren:
  for(int i = 0 ; i = OSZILLATORS; i++ ) {
 
    // einzelnen Oszillator in actual_oszillator rendern...
   
    // actual_oszillator in buffer rendern...   
   
  }
}


Helmuth

Ich hoffte, jetz das ausbaufähige Grundgerüst zu haben:

Wie wir sehen, sehen wir nichts (auf dem Strip)  :smiley-red:

Jemand eine Idee?

Code: [Select]
// Konzeptstudie zur Umsetzung von "Liquid Eye"
// auf einem RGB Strip

#include <FastSPI_LED.h>

#define NUM_LEDS 20               // Striplänge
#define OSZILLATORS 1             // Anzahl Oszillatoren
#define OSZILLATOR_MAX_LENGHT 10  // Länge eines Oszillators

// Array mit den Eigenschaften der einzelnen Oszillatoren:
// r, g, b, speed, dirction, tail, lifetime
byte oszillators[OSZILLATORS][7];

// Zwischenspeicher des Bitmaps von einem Oszillator
byte actual_oszillator[OSZILLATOR_MAX_LENGHT][3];

// Zwischenspeicher des Bitmaps der gesamten Ausgabe
byte buffer[NUM_LEDS][3];

// der eigentliche Bildspeicher
struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;

//----------------------------------------------------------------
void setup(){
  FastSPI_LED.setLeds(NUM_LEDS);
  FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2801);
  FastSPI_LED.setDataRate(5);
  FastSPI_LED.init();
  FastSPI_LED.start();
  leds = (struct CRGB*)FastSPI_LED.getRGBData();
  // Eigenschaften zuweisen
  init_oszillators();
}

//----------------------------------------------------------------
void loop() {
  render_oszillators_to_buffer();
  show_buffer(); 
}

//----------------------------------------------------------------
void init_oszillators() {
  // erstmal nur einen
  oszillators[0][0] = 255; //rot
  oszillators[0][1] = 127; //grün
  oszillators[0][2] = 0;   //blau
  oszillators[0][3] = 2;   //Geschwindigkeit (1-10)
  oszillators[0][4] = 1;   //Richtung (0 oder 1)
  oszillators[0][5] = OSZILLATOR_MAX_LENGHT - 1; //Schweif
  oszillators[0][6] = 30;  //Lebensdauer in Sekunden
}

// zum Anzeigen des Berechneten buffer
void show_buffer(){
  // anzeigen
  for(int i = 0 ; i < NUM_LEDS; i++ ) {
    leds[i].r = buffer[i][0];
    leds[i].g = buffer[i][1];
    leds[i].b = buffer[i][2];
  }
  FastSPI_LED.show();
  // und danach löschen
  for(int i = 0 ; i < NUM_LEDS; i++ ) {
    buffer[i][0] = 0;
    buffer[i][1] = 0;
    buffer[i][2] = 0;
  }
}

// gesamten nächsten Schritt in buffer rendern
void render_oszillators_to_buffer() {
  // mit allen Oszillatoren:
  for(int i = 0 ; i = OSZILLATORS; i++ ) {
 
    // einzelnen Oszillator in actual_oszillator rendern...
    render_this_one_to_actual_oszillator(i);
   
    // actual_oszillator in buffer rendern...
    render_actual_buffer_to_main_buffer();   
   
  }
}

void render_this_one_to_actual_oszillator(byte count){
  // Schweif berechnen (Länge steht in oszillators[count][5])
  for(int i = 0 ; i = oszillators[count][5]; i++ ) {
    //jeder Punkt ein bisschen dunkler
    actual_oszillator[i][0] = oszillators[count][0]/(i+1);
    actual_oszillator[i][1] = oszillators[count][1]/(i+1);
    actual_oszillator[i][2] = oszillators[count][2]/(i+1);
  }

   
void render_actual_buffer_to_main_buffer(){
  // zum Testen erstmal nur statisch reinkopieren
   for(int i = 0 ; i = OSZILLATOR_MAX_LENGHT; i++ ) {
     buffer[i][0] = actual_oszillator[i][0];
     buffer[i][1] = actual_oszillator[i][1];
     buffer[i][2] = actual_oszillator[i][2]; 
 
   }
}   

Eisebaer

hi,

  for(int i = 0 ; i = OSZILLATORS; i++ ) {

das hast Du mindestens dreimal falsch drin:      ==

gruß stefan

marcusw

Vorallem solltees entweder < oder <= heißen, da es bei "for" nicht die Abbruch- sondern die Laufzeitbedingung ist

Helmuth

Ok, danke.

Ich habe heute offensichtlich voll ein Brett vorm Kopf: nichtmal show_buffer(); allein funktioniert, nach dem 2. Aufruf MUSS doch alles leer sein.

Vielleicht sollte ich mal ein paar Tage was anderes machen...

Code: [Select]
// Konzeptstudie zur Umsetzung von "Liquid Eye"
// auf einem RGB Strip

#include <FastSPI_LED.h>

#define NUM_LEDS 20               // Striplänge
#define OSZILLATORS 1             // Anzahl Oszillatoren
#define OSZILLATOR_MAX_LENGHT 10  // Länge eines Oszillators

// Array mit den Eigenschaften der einzelnen Oszillatoren:
// r, g, b, speed, dirction, tail, lifetime
byte oszillators[OSZILLATORS][7];

// Zwischenspeicher des Bitmaps von einem Oszillator
byte actual_oszillator[OSZILLATOR_MAX_LENGHT][3];

// Zwischenspeicher des Bitmaps der gesamten Ausgabe
byte buffer[NUM_LEDS][3];

// der eigentliche Bildspeicher
struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;

//----------------------------------------------------------------
void setup(){
 FastSPI_LED.setLeds(NUM_LEDS);
 FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2801);
 FastSPI_LED.setDataRate(7);
 FastSPI_LED.init();
 FastSPI_LED.start();
 leds = (struct CRGB*)FastSPI_LED.getRGBData();
 // Eigenschaften zuweisen
 init_oszillators();
}

//----------------------------------------------------------------
void loop() {
 show_buffer();
 show_buffer();
 //render_oszillators_to_buffer();
 //show_buffer();  
}

//----------------------------------------------------------------
void init_oszillators() {
 // erstmal nur einen
 oszillators[0][0] = 255; //rot
 oszillators[0][1] = 127; //grün
 oszillators[0][2] = 0;   //blau
 oszillators[0][3] = 2;   //Geschwindigkeit (1-10)
 oszillators[0][4] = 1;   //Richtung (0 oder 1)
 oszillators[0][5] = OSZILLATOR_MAX_LENGHT - 1; //Schweif
 oszillators[0][6] = 30;  //Lebensdauer in Sekunden
}

// zum Anzeigen des Berechneten buffer
void show_buffer(){
 // anzeigen
 for(int i = 0 ; i < NUM_LEDS; i++ ) {
   leds[i].r = buffer[i][0];
   leds[i].g = buffer[i][1];
   leds[i].b = buffer[i][2];
 }
 FastSPI_LED.show();
 // und löschen
 for(int i = 0 ; i < NUM_LEDS; i++ ) {
   buffer[i][0] = 0;
   buffer[i][1] = 0;
   buffer[i][2] = 0;
 }
}

// gesamten nächsten Schritt in buffer rendern
void render_oszillators_to_buffer() {
 // mit allen Oszillatoren:
 for(int i = 0 ; i < OSZILLATORS; i++ ) {
 
   // einzelnen Oszillator in actual_oszillator rendern...
   render_this_one_to_actual_oszillator(i);
   
   // actual_oszillator in buffer rendern...
   render_actual_buffer_to_main_buffer();    
   
 }
}

void render_this_one_to_actual_oszillator(byte count){
 // Schweif berechnen (Länge steht in oszillators[count][5])
 for(int i = 0 ; i < oszillators[count][5]; i++ ) {
   //jeder Punkt ein bisschen dunkler
   actual_oszillator[i][0] = oszillators[count][0]/(i+1);
   actual_oszillator[i][1] = oszillators[count][1]/(i+1);
   actual_oszillator[i][2] = oszillators[count][2]/(i+1);
 }
}  
 
void render_actual_buffer_to_main_buffer(){
 // zum Testen erstmal nur statisch reinkopieren
  for(int i = 0 ; i < OSZILLATOR_MAX_LENGHT; i++ ) {
    buffer[i][0] = actual_oszillator[i][0];
    buffer[i][1] = actual_oszillator[i][1];
    buffer[i][2] = actual_oszillator[i][2];  
 
  }
}    

Eisebaer

hi,

ja, solche bretter kenn' ich. dqa kann ich Dir nicht helfen, ich weiß nicht, wie man die 2801er ansteuert.

aber:

Code: [Select]

struct CRGB { unsigned char g; unsigned char r; unsigned char b; };
struct CRGB *leds;
CRGB buffer[NUM_LEDS];


ist möglich, und Du kannst sie dann mit buffer.r usw. anreden.

gruß stefan

Helmuth

Hi Eisebaer,
danke für den moralischen Beistand. Ich mache mit den 2801 nichts anderes als z.B. in diesem Sketch (welches tadellos läuft), alles was die Ausgabe betrifft 1:1 rauskopiert...
Ich geh´ jetzt in die Kneipe, dann wird darüber geschlafen und morgen geht es mit frischem Elan weiter.

Grüße, Helmuth

Code: [Select]
// A concept of a smooth and fast crossfade between
// 2 different pictures on an adressable RGB strip.
//
// Thanks to DanielGarcia@gmail.com for the FastSPI library
// and thanks to the support from all the guys in the
// german Arduino forum!
//
// Do with it whatever you like, but make it awesome!
//
// If you´d like to use it right away, select your
// chipset and striplength first. Wiring: DATA 11, CLOCK 13
// Tested @ Arduino Uno r3. It works because of limited RAM
// up to a lenght of 210 LEDs on an UNO with no other code
// arround.
// Yes, it eats loads of RAM, because it needs the complete
// memory for storing the stripcontent itself x3.
// But it´s worth the quality of the effect i think. :-)

#include <FastSPI_LED.h>

// That is the length of your strip.
#define NUM_LEDS 25

// Change the order of your rgb here.
struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;

// to save, what you see right now on the strip (current frame)
byte old_frame[NUM_LEDS][3];

// the place for the stuff you want to see in future (next frame)
byte new_frame[NUM_LEDS][3];

// save what you see right now to old_frame for fading away from it later
void copy_led_array_to_old_frame(){
  for(int i = 0; i < NUM_LEDS; i++ ) {
    old_frame[i][0] = leds[i].r;
    old_frame[i][1] = leds[i].g;
    old_frame[i][2] = leds[i].b;
  } 
}

// fade to new content over a number of steps with wait_ms delay between the steps
void fade_from_old_to_new_frame(int steps, int wait_ms){
  for(int a=0; a < steps; a++){ // over the steps
    for(int b=0; b < NUM_LEDS; b++){ // over the whole lenght
      leds[b].r = (int)old_frame[b][0] + ((int)new_frame[b][0] - (int)old_frame[b][0]) * a / steps; //over the red
      leds[b].g = (int)old_frame[b][1] + ((int)new_frame[b][1] - (int)old_frame[b][1]) * a / steps; //the green
      leds[b].b = (int)old_frame[b][2] + ((int)new_frame[b][2] - (int)old_frame[b][2]) * a / steps; //and the blue LEDs
    }
    FastSPI_LED.show();
    delay(wait_ms); 
  }
}

/*
//some stuff you don´t really need, execpt for understanding and playing
//(and maybe for debugging your project...)

//set color of a single LED, don´t show
void set_color_led(int adex, int cred, int cgrn, int cblu) { 
  leds[adex].r = cred;
  leds[adex].g = cgrn;
  leds[adex].b = cblu; 
  }
 
//create and show something unique
void create_random_pixels(){
  for(int i = 0 ; i < NUM_LEDS; i++ ) {
    set_color_led(i, random(255), random(5), random(255));
  }
  FastSPI_LED.show();
}

//make the content of the new_frame visible immediately
void show_new_frame(){
  for(int i = 0 ; i < NUM_LEDS; i++ ) {
    leds[i].r = new_frame[i][0];
    leds[i].g = new_frame[i][1];
    leds[i].b = new_frame[i][2];
  }
  FastSPI_LED.show();
}

//just to compare: show the saved old_frame you started with again
void show_old_frame(){
  for(int i = 0 ; i < NUM_LEDS; i++ ) {
    leds[i].r = old_frame[i][0];
    leds[i].g = old_frame[i][1];
    leds[i].b = old_frame[i][2];
  }
  FastSPI_LED.show();
}

*/

// Here is the place for your own creativity.
// Put in the stuff you want to see in the next frame.
// Formulas, precalculated or saved images, whatever.
// Some very simple examples:

// fill new_frame with some linear color fade
void fill_new_frame_with_content(){
  for(int i = 0 ; i < NUM_LEDS; i++ ) {
    new_frame[i][0] = (i*255)/NUM_LEDS;
    new_frame[i][1] = 255-((i*255)/NUM_LEDS);
    new_frame[i][2] = 0;
  }
}

// ...with a different color fade
void fill_new_frame_with_different_content(){
  for(int i = 0 ; i < NUM_LEDS; i++ ) {
    new_frame[i][1] = (i*255)/NUM_LEDS;
    new_frame[i][2] = 255-((i*255)/NUM_LEDS);
    new_frame[i][0] = 0;
  }
}

//  ...just with some random dots
void fill_new_frame_with_random_content(){
  for(int i = 0 ; i < NUM_LEDS; i++ ) {
  new_frame[i][1] = random(255);
  new_frame[i][2] = random(255);
  new_frame[i][0] = random(255);
  }
}
   
void setup(){
  FastSPI_LED.setLeds(NUM_LEDS);
  FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2801);
  FastSPI_LED.setDataRate(7);
  FastSPI_LED.init();
  FastSPI_LED.start();
  leds = (struct CRGB*)FastSPI_LED.getRGBData();
}

void loop() {
  // I hope, the names speak for themself.
  // Try it with differnt delays
  copy_led_array_to_old_frame();
  fill_new_frame_with_content();
  // Try it with differnt delays (second number)
  // and with different numer of frames (first one)
  // in case you´re using very long strips
  fade_from_old_to_new_frame(256,0); 
  //delay(1000);
 
  copy_led_array_to_old_frame(); 
  fill_new_frame_with_different_content();
  fade_from_old_to_new_frame(256,0);   
  //delay(1000);
 
  copy_led_array_to_old_frame(); 
  fill_new_frame_with_random_content();
  fade_from_old_to_new_frame(256,0); 
  //delay(1000);
}


Go Up