Need help creating a water effect using FastSPI, WS2811 and an Arduino Uno

I´m currently awaiting my first arduino (Uno Rev 3) to play with and I think I could already use some help. As a first project I want to drive 11 WS2811 LEDs using the Arduino and the FastSPI libary. I want to imitate a water like effect using those LEDs, but I´m a bit stuck on how to archieve this. Basically what I want is a behavior like this:

  • Turn on all 11 LEDs and let them display a nice deep blue (this should be no problem at all, but I cant test it yet until my Uno arrives)
  • Randomly fade LEDs to a brighter blue color and then back to the deep blue from before
  • Fading should not be applied to more than 3 or 4 LEDs at a time, those 3 or 4 LEDs should not (or not always) start the fading at the same time

This should create the effect I´m aiming for, but I´m not really sure how to turn this into code... in fact im kind of lost and would be thankful for any Ideas. :smiley:

Might be a good idea to read some C++ programming web sites while you're waiting.

It's not that hard to do at all. You just have to keep track of which LEDs are in a "static" phase and which ones are doing something. Arrays are good for this. For a xmas window display, I create several different types of effects on similar strings, including a rain/snow-like one. If you're interested, you can see the video here:

I forgot: those are running on a custom 328P board, but for all intents and purposes, they could also be running on an Uno. I used FastSPI and WS2801 strings (though I will be switching to WS2811 shortly).

The way I created that is by using a separate 328P for each string. With the new FastSPI library, I will probably change the design to use multiple strings instead. However, the individual units communicate with each other via I2C to stay in sync. There's a master module that has an RTC on it which is responsible for turning on the display at 6pm and off at 6am. Since these all run off of old computer PSUs, the master module simply turns off the PSUs. I use the 5VSB rail to keep power to the master.

Thanks for the replys so far. :wink:

Right now I'm trying to learn the basics, but whats really bugging me right now is not the syntax or not knowing what a loop or an array is. My problem is thinking in a way like that... :smiley:

First of all I would create an array that holds the amount of leds. Then I would loop through that array setting them to my desired base color. I might even get a random fade working by looking at examples, but I'm not sure how to keep track of the leds that are fading right now and how to limit them to an amount of 3 or 4 at a time.

I would have to count the currently fading leds and loop them like "if less than 4 are fading now, fade the current led". But that would not create the kind of randomness I'm trying to archieve... My only idea here would be a small (random?) delay.

ingrimsch:
First of all I would create an array that holds the amount of leds. Then I would loop through that array setting them to my desired base color.

FastSPI takes care of the array for you:

// code based on FastSPI_LED.  FastSPI_LED2 is slightly different
#include <FastSPI_LED.h>
#define NUM_LEDS 32
struct CRGB { unsigned char b; unsigned char r; unsigned char g; };
struct CRGB *leds;

void setup() {
  ...
}

void loop() {
  for (int px = 0; px < NUM_LEDS) px++) {
    leds[px].r = 0;
    leds[px].g = 0;
    leds[px].b = 128;  //any value between 0 to 255
  }
  FastSPI_LED.show();
  ...
}

Now you have a blue string.

ingrimsch:
I might even get a random fade working by looking at examples, but I'm not sure how to keep track of the leds that are fading right now and how to limit them to an amount of 3 or 4 at a time.

Arrays. Picking a random LED is easy, just hit a random(NUM_LEDS) to pick one. As for keeping track of which ones are in a 'fade' phase, keep an array with their index numbers. So after selecting the random LED, insert that value into an array so that let's say you have LEDs 4, 7, and 13 fading, put those three values in an array.

This allows you to then use that array to remember which LEDs are fading, and by counting how many elements the array has in it, you will know how many LEDs are fading and you can set your limits based on that.

ingrimsch:
I would have to count the currently fading leds and loop them like "if less than 4 are fading now, fade the current led". But that would not create the kind of randomness I'm trying to archieve... My only idea here would be a small (random?) delay.

Yep, you can do that too. If you look at my video, there's one pattern that's all about randomness, it's a white and blue twinkling one. It randomly picks which LED to address next. It checks whether that LED is currently on and ignores it. It randomly chooses what color that LED will be when it turns on. And it randomly select both how long the LED is turned on for and how long it remains off afterwards.

The rain/snow like one also has randomness built into it: how fast the flake falls, how bright the flake is, and the delay between flakes. Random is a fun thing to play with.

This might be what you're looking for. If it isn't, you can modify it to do exactly what you want.

#include <FastSPI_LED.h>

#define NUM_LEDS 60
#define PIN 8

// Sometimes chipsets wire in a backwards sort of way
// struct CRGB { unsigned char b; unsigned char r; unsigned char g; };
struct CRGB{unsigned char g; unsigned char r; unsigned char b;};
struct CRGB *leds;

int gr[9] = {50, 100, 150, 200, 255, 200, 150, 100, 50}; //highlights

void setup()
{
  FastSPI_LED.setLeds(NUM_LEDS+1); //one additional for rotation
  FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2811);
  FastSPI_LED.setPin(PIN);
  FastSPI_LED.init();
  FastSPI_LED.start();
  leds = (struct CRGB*)FastSPI_LED.getRGBData();
  }

void loop()
{
  int i, j, k;
  memset(leds, 0, NUM_LEDS * 3); //clear the display
  for(i = 0 ; i < NUM_LEDS; i++ ) { //fill with blue
    leds[i].b = 192;
  }
  for (i=0; i<NUM_LEDS; i+=20){  //add the green
    for (j=0; j<9; j++){
      leds[i+j].g =gr[j];
    }
  }
  for (j=0; j<NUM_LEDS; j++){ //rotate display
    leds[NUM_LEDS]=leds[0];
    for ( i=0; i<NUM_LEDS; i++){
      leds[i]=leds[i+1];
    }
        
      FastSPI_LED.show(); 
      delay(60);
  }     
}