Hope you all doing fine these days. I am trying to replicate these futuristic blue/purple lights that move on kind of that maze shape using any WS2812 library. timestamp 0:00 - 0:10 seconds of the video. I was thinking of the Gradient (WLED) or Cylon (FastLED) effect but I have no idea how to use it multiple times in a single LED strip in the same segment. I want to use it multiple times, with different speeds, and at least use two different colors. and with some randomizations. and I don't like to use the delay() inside my code. so I'm asking you all good friendly people in this forum could you please point me in the right direction.
video link.
I have no idea what you mean by "same segment". Having said that, you can break you're strip up in pieces in software. The usual way that people see is something like
void loop()
{
for (int i = 0; i < NUMLEDS; i++)
{
leds[i] = CRGB::Red;
}
FastLED.show();
}
But there is no reason why you can't use something like
void loop()
{
int i;
for (i = 0; i < NUMLEDS / 3; i++)
{
leds[i] = CRGB::Red;
}
for (; i < (NUMLEDS * 2) / 3; i++)
{
leds[i] = CRGB::White;
}
for (; i < NUMLEDS; i++)
{
leds[i] = CRGB::Blue;
}
FastLED.show();
}
That will make the first third of the strip red, the second third white and the last third blue.
Thank you for your quick reply.
what I mean by "same segment" is I just need to have one segment.
i don't want to break my strip into pieces. my strip has 1200 LEDs. so I would like to use the entire (1200) strip as one segment.
if you can see the video you will understand what I mean.
thank you again.
Note that I never said to physically divide the strip. You can do that in software (as I demonstrated)
I looked at the video and still have no idea about 'one segment'.
I can visualise what you might want to achieve. You have one strip and divide it (in software) in a number of pieces. Each piece needs to basically have it's own pattern running. Or, as in the video they all run (seem to be) running the same pattern.
thank you again for taking the time to help. Maybe "segment" is not the correct word. just ignore the word "segment" for now. all I want is to do is replicate the LED effect in the video using an Arduino compatible MCU. I tried the FastLED Cylon effect but I have no idea to run multiple times through the entire strip. when I see delay() in any code I get headaches. Maybe they have used some kind of advanced device. look like we can not do it with Arduino.
Dear flashko.
thank you for taking the time to help me.
I have a couple of different boards including Due and Mega. I do not have that fancy boards they released recently. and I have some ESP32's also. I also think 1200 LEDs is too much for an Arduino. the LED strip I have used has 300 LEDs and it is 5 meters long. so I solder 4 strips together. I am hoping to use only a single strip with a suitable Arduino or ESP. I already have 40 strips. I think I will only have to use 25 or 30 strips. I will look into FAB LED tomorrow. it is almost 2.30 AM ill come with the result tomorrow.
and the first video (the one that looks like a snake) is something similar to what I'm looking for.
Thanks again.
stay safe.
It runs multiple time; it will go up and down and up and down etc. So that is not a clear description what you want to achieve. I guess you want the same effect on different parts of the strip. In the below code (based on the original cylon), I've re-introduced the term segment; the strip will programmatically be split in pieces based on NUM_SEGMENTS. Each segment shows the same pattern.
// https://forum.arduino.cc/t/ws2812b-how-to-use-the-same-effect-with-multiple-instants-with-different-speeds-and-different-colors-on-the-same-zone/958668/5
#include <FastLED.h>
// How many leds in your strip?
#define NUM_LEDS 60
// how many segments (pieces)
#define NUM_SEGMENTS 2
// number of leds in each segment
#define SEGMENT_SIZE (NUM_LEDS / NUM_SEGMENTS)
// For led chips like Neopixels, which have a data line, ground, and power, you just
// need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock,
// ground, and power), like the LPD8806, define both DATA_PIN and CLOCK_PIN
#define DATA_PIN A1
// Define the array of leds
CRGB leds[NUM_LEDS];
void setup() {
Serial.begin(57600);
Serial.println("resetting");
LEDS.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
LEDS.setBrightness(84);
}
void fadeall()
{
for (int i = 0; i < NUM_LEDS; i++)
{
leds[i].nscale8(250);
}
}
void loop()
{
static uint8_t hue = 0;
Serial.print("x");
// First slide the led in one direction
for (int i = 0; i < SEGMENT_SIZE; i++)
{
// Set the i'th led to red
leds[i] = CHSV(hue++, 255, 255);
// copy led[i] to the other 'segments'
for (uint8_t segmentCnt = 1; segmentCnt < NUM_SEGMENTS; segmentCnt++)
{
leds[i + (segmentCnt * SEGMENT_SIZE)] = leds[i];
}
// Show the leds
FastLED.show();
// now that we've shown the leds, reset the i'th led to black
// leds[i] = CRGB::Black;
fadeall();
// Wait a little bit before we loop around and do it again
delay(10);
}
Serial.print("x");
// Now go in the other direction.
for (int i = (SEGMENT_SIZE) - 1; i >= 0; i--)
{
// Set the i'th led to red
leds[i] = CHSV(hue++, 255, 255);
// copy led[i] to the other 'segments'
for (uint8_t segmentCnt = 1; segmentCnt < NUM_SEGMENTS; segmentCnt++)
{
leds[i + (segmentCnt * SEGMENT_SIZE)] = leds[i];
}
// Show the leds
FastLED.show();
// now that we've shown the leds, reset the i'th led to black
// leds[i] = CRGB::Black;
fadeall();
// Wait a little bit before we loop around and do it again
delay(10);
}
}
See if you understand; you will need to adjust the pin and NUM_LEDS; you can play with NUM_SEGMENTS. On a strip with 60 leds, it does not look as nice as the original.
Don't worry about that; you can easily replace it by a millis() based approach. And by the time you have 1200 leds and you want a proper refresh rate (see below), you will probably have removed the delay from the for-loops.
That is not so much the Arduino; a Mega has enough memory to handle 1200 leds. Your problem will be the time that it takes to update a strip and that is purely due to the characteristics of the strip; and there is no way around that (definitely not with one long strip).
The transfer of one bit takes 1.25 microseconds, 8 bits will take 10 microseconds. You need 3 bytes per pixel so 30 microseconds. Times 1200 gives you 36 milliseconds. Based on that, your maximum refresh rate will be slightly over 25Hz.
Your Arduino boards, especially ESP32, have enough memory for 1200 LEDs, but you will need quite a powerful power supply. I made the effects of the two videos with the same program, only the definitions of the individual lights were changed. Below one of the videos is a link to the Arduino program I wrote a few years ago. Maybe it will help you. Good luck.
I do these with objects that have their own idea of what pixels to turn on and off to which color, and when, like little model trains all running on the same track.
You’ll have to figure out how colors mix when the trains, if they were physical objects, collide or overtake one the other.
Simple: red train, green train, blue train, three at once and each only writing one byte of the color value.
Harder: mix RGB colors: each train reads the current color and (somehow) mixes in its color.
East hard: the last train to ”talk” to a pixel rules and just obliterates the previous color.
In your loop, goose (run) all the train objects one step so each train makes its way according to your desire, like which way it is moving and how fast and how long it is.
If that makes any sense, it will be easy. If it doesn’t, it still might be. Easy.
a7
@flashko My Bulgarian is a bit rusty, and google translate doesn’t help, but code is code and that looks very flexible.
I think I see the color mixing options section, Imma hafto look closely at that and try it with some of my stuff, which by comparison is kinda primitive.
Hello, @alto777. My goal was to make the program flexible and easy to work with. There may be room for improvement but it still works. When I wrote it, I explained to my friend only the individual options for the color segments, and in just a few minutes he made completely different effects from mine, without even understanding how the program itself works.
With a few potentiometers, the speed of movement of the effects could be affected and the base color of the whole strip could be changed, along with how to mix the colors when they overlap. Some lines in the program are for testing purposes. I tried to translate the more important comments but please be condescending to my English.
// library for WS2812B https://github.com/cpldcpu/light_ws2812
/*
WS2812 datasheet
LED characteristic parameter
Emitting color Wavelength(nm) Luminous intensity(mcd) Current(mA) Voltage(V)
Red 620-630 550-700 20 1.8-2.2
Green 515-530 1100-1400 20 3.0-3.2
Blue 465-475 200-400 20 3.2-3.4
*/
#include <WS2812.h>
// const boolean debug = true;
byte
c,
colorMix = 0, // how mixing colors
a,
b
;
const byte
len = 150, // number of leds
speedPot = A1, // relative change of speed
mixPot = A4, // 4 modes of mixing colors
brightness = 255 // max brightness
;
WS2812 LED ( len ); // number of LED
cRGB color, clr;
const cRGB // GRB define color constant
black = { 0, 0, 0 },
white = { brightness, brightness, brightness },
gray = { brightness / 4, brightness / 4, brightness / 4 },
red = { 0, brightness, 0 },
green = { brightness, 0, 0 },
blue = { 0, 0, brightness },
yellow = { brightness, brightness, 0 },
cyan = { brightness, 0, brightness },
magenta = { 0, brightness, brightness }
;
cRGB pattern = black;
struct Line // define rope object
{
const cRGB Color; // color
int Position; // start position
const byte Linear; // length
const word Time; // time between steps aka speed
unsigned long Next; // time for next step
const word Pause; // time to pause after leds strip end
const boolean Cycle; // cyclic or not moving
boolean Path; // direction of movement
boolean Change; // yes or not next time to step
const boolean Direction; // head nad tail relative to direction - head is brighten than tail
boolean Active; // on or off
};
Line rope [] = // several rope object
{
// clr, pos, n, dt, t, p, cycle, path, chng, dir, act
{ white, 0, 2, 20, 0, 4000, true, true, false, true, true },
{ red, len/2 - 1, 16, 200, 0, 0, false, true, false, true, false },
{ blue, len/2, 16, 200, 0, 0, false, false, false, true, false },
{ green, len - 1, 4, 80, 0, 2000, true, false, false, true, true }
// { white, 4, 2, 1000, 0, 4000, true, true, false, true }
};
const byte N = sizeof ( rope ) / sizeof ( Line );
void clearLEDall ( cRGB blank )
{
for ( byte n = 0; n < len; n ++ )
{
LED.set_crgb_at ( n, blank );
}
}
byte scale ( byte scl, byte lngth, byte lnr, boolean drctn ) // fast integer nonlinear brightness
{
if ( !scl ) return 0;
unsigned long S = lnr;
if ( drctn ) S -= lngth; else S = ++ lngth;
S *= S * scl;
S /= lnr;
S /= lnr;
byte result = S;
if ( !result ) result = 1;
// if ( debug ) Serial.println ( result );
return result;
}
void setup ()
{
// if ( debug ) Serial.begin ( 115200 );
LED.setOutput ( D5 ); // pin for WS2812B
}
void loop ()
{
boolean change = false;
a = b = 1; // скорост и миксиране
word s = analogRead ( speedPot ), m = analogRead ( mixPot );
if ( s < 480 ) a = map ( s, 0, 480, 8, 2 );
if ( s > 544 ) b = map ( s, 544, 1023, 2, 64 );
colorMix = map ( m, 0, 1023, 0, 4 );
unsigned long T = millis ();
// if ( T > 16384 ) rope[0].Active = false; // tets on/off
if ( T > 16384 ) rope[1].Active = true; // test on/off
if ( T > 32768 ) rope[2].Active = true; // test on/off
// if ( T > 65536 ) { rope[1].Active = false; rope[2].Active = false; } // test on/off
for ( byte n = 0; n < N; n ++ ) //
{
// if ( rope[n].Next <= millis () )
// if ( millis () >= rope[n].Next ) // по-малка програма
// if ( millis () >= rope[n].Next && rope[n].Active )
if ( T >= rope[n].Next && rope[n].Active )
{
rope[n].Change = change = true;
if ( !rope[n].Pause )
// if ( rope[n].Pause == 0 )
// rope[n].Next += rope[n].Time * a / b; // време за следваща стъпка
rope[n].Next = T + rope[n].Time * a / b; // време за следваща стъпка
else
{
// if ( ( rope[n].Position == ( len + rope[n].Linear - 1 ) ) || ( rope[n].Position == -( rope[n].Linear - 1 ) ) )
if ( rope[n].Position == ( len + rope[n].Linear - 1 ) && rope[n].Path || rope[n].Position == -rope[n].Linear && !rope[n].Path )
// rope[n].Next += rope[n].Pause * a / b;
rope[n].Next = T + rope[n].Pause * a / b;
else
// rope[n].Next += rope[n].Time * a / b;
rope[n].Next = T + rope[n].Time * a / b;
}
// if ( debug ) Serial.println ( rope[n].Next );
}
}
if ( change )
{
// if ( debug ) Serial.println ( "Change" );
// clearLEDall ( pattern ); // optional set color base on led strip
// /*
switch ( colorMix ) // different color led strip base from color mode mix
{
case 0: clearLEDall ( black ); break;
case 1: clearLEDall ( white ); break;
case 2: clearLEDall ( gray ); break;
case 3: clearLEDall ( black ); break;
}
// */
for ( byte n = 0; n < N; n ++ )
{
if ( rope[n].Active )
{
if ( !rope[n].Pause )
{
if ( rope[n].Cycle )
{
if ( rope[n].Position == len + rope[n].Linear && rope[n].Path ) rope[n].Position -= len;
if ( rope[n].Position == -rope[n].Linear && !rope[n].Path ) rope[n].Position = len;
}
else
{
// if ( rope[n].Path && ( rope[n].Position == ( len + rope[n].Linear ) ) )
if ( rope[n].Position == len + rope[n].Linear && rope[n].Path )
{
rope[n].Path = !rope[n].Path;
rope[n].Position = len - 1;
}
// if ( !rope[n].Path && rope[n].Position == -rope[n].Linear )
if ( rope[n].Position == -rope[n].Linear && !rope[n].Path )
{
rope[n].Path = !rope[n].Path;
rope[n].Position = -1;
}
}
}
else
{
if ( rope[n].Cycle )
{
// if ( rope[n].Position == len + rope[n].Linear - 1 ) rope[n].Position = -1;
if ( rope[n].Position == len + rope[n].Linear && rope[n].Path ) rope[n].Position = -1;
if ( rope[n].Position == -rope[n].Linear && !rope[n].Path ) rope[n].Position = len;
}
else
{
if ( rope[n].Position == len + rope[n].Linear - 1 )
{
rope[n].Path = !rope[n].Path;
rope[n].Position = len;
}
if ( rope[n].Position == -rope[n].Linear )
{
rope[n].Path = !rope[n].Path;
rope[n].Position = -1;
}
}
}
for ( int length = 0; length < rope[n].Linear; length ++ )
{
int point = rope[n].Position;
// if ( debug ) { Serial.print ( "Point and Position :" ); Serial.println ( point ); }
// if ( rope[n].Path ) point -= length; else point += length;
// if ( debug ) { Serial.print ( "Point and Length :" ); Serial.println ( point ); }
point = point - length * ( rope[n].Path - !rope[n].Path );
if ( rope[n].Cycle && !rope[n].Pause )
{
if ( point >= len ) point -= len;
if ( point < 0 ) point += len;
// if ( debug ) { Serial.print ( "Position :" ); Serial.println ( rope[n].Position ); Serial.print ( "Point :" ); Serial.println ( point ); Serial.println (); }
}
if ( point < len && point >= 0 )
{
color = LED.get_crgb_at ( point );
clr = rope[n].Color;
clr.r = scale ( clr.r, length, rope[n].Linear, rope[n].Direction );
clr.g = scale ( clr.g, length, rope[n].Linear, rope[n].Direction );
clr.b = scale ( clr.b, length, rope[n].Linear, rope[n].Direction );
switch ( colorMix ) // color mode mix
{
case 0: // OR
color.r |= clr.r;
color.g |= clr.g;
color.b |= clr.b;
break;
case 1: // AND
color.r &= clr.r;
color.g &= clr.g;
color.b &= clr.b;
break;
case 2: // XOR
color.r ^= clr.r;
color.g ^= clr.g;
color.b ^= clr.b;
break;
case 3: // sum
color.r += clr.r;
color.g += clr.g;
color.b += clr.b;
break;
}
LED.set_crgb_at ( point, color );
}
}
if ( rope[n].Change )
{
rope[n].Change = false;
// if ( rope[n].Path ) rope[n].Position ++; else rope[n].Position --;
rope[n].Position = rope[n].Position + rope[n].Path - !rope[n].Path;
}
// if ( debug ) Serial.println ( rope[n].Position );
}
}
LED.sync ();
}
}