Total newbie here. Ive installed FastLED on my Arduino Uno and have successfully tested my WS2812B string lights. Im trying to create a script that will illuminate 30 random leds (out of a set of 100) at once - wait for 20 seconds - then fade out and fade in 30 new random leds. Id like to use a solid amber color for the leds. Any thoughts would be much appreciated. Thanks!!
Generate 20 random numbers between 0 and 99 (both included) and store them in an array. Be aware that you might get duplicate random numbers so you need to check the array if the number was already used.
The numbers in the array will be an index into your LED array. So you can loop through that array, get the number and use that number to select a LED in your LED array and set the colour.
Fading will be the easiest if you use HSV values instead of RGB.
There is no need to swap "up to several thousand". Look at the Fisher–Yates shuffle. it's only one swap going through the list and the algorithm produces an unbiased permutation (every permutation is equally likely).
#define NUM_LEDS 100
const byte numRandomLEDs = 30;
byte randomLEDs[numRandomLEDs];
void setup() {
Serial.begin(115200);
randomSeed(analogRead(A0)); // See Arduino reference for randomSeed()
}
void loop() {
// Fill randomLEDs array with random numbers in the range 0 to NUM_LEDS-1
byte writeIndex = 0;
while (writeIndex < numRandomLEDs) {
randomLEDs[writeIndex] = random(0, NUM_LEDS); // returns 0..NUM_LEDS-1
if (latestEntryIsNotDuplicate(writeIndex)) writeIndex++;
}
// Print the contents of randomLEDs array
Serial.println("Random LEDs are:");
for (byte i = 0; i < numRandomLEDs; i++) {
Serial.print(String(randomLEDs[i]) + " ");
}
Serial.println();
delay(1000); // To slow down writing a new set of LEDs to the serial monitor
}
bool latestEntryIsNotDuplicate(byte writeIndex) {
for (byte i = 0; i < writeIndex; i++) {
if (randomLEDs[writeIndex] == randomLEDs[i]) return false;
}
return true;
}
It produces output like this on the serial monitor:
You only need to start at the top and make 30 swaps: the first with whatever is stored in 0-99, the second with whatever is in 1-99, ... the thirtieth with whatever is in 29-99.
Thanks so much for your help Dave! Ive uploaded your code to my Arduino but it doesn't seem to do anything. Is there a piece of code missing? Sorry total newbie here.
To double check, as we all make mistakes from time to time, I copied the code from my post above into a blank sketch. I uploaded it to my Uno R3 clone, and it behaved as expected. As @UKHeliBob said, I can only think that you don't have the serial monitor open and set to 115200 baud.
I don't have any experience of using WS2812B or the FastLED library. It would be better for you to look at @xfpd 's post and ask more questions if that doesn't help enough.
The FastLED "fade" example lets you group the individual WS2812 in the strand (you were selecting 30 random WS2812 to turn on, then fade, then repeat).
I would encourage your exploration of FastLED examples. If you install the library on your IDE, you will have all those examples, "a click away".
After installing the FastLED library, find the examples here:
IDE >> EXAMPLES >> FastLED >> examples
/* ============================================
code is placed under the MIT license
Copyright (c) 2024 J-M-L
For the Arduino Forum : https://forum.arduino.cc/u/j-m-l
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================
*/
#include <FastLED.h>
const byte stripPin = 2;
const byte numLeds = 100;
const byte numChosenLeds = 30;
const CRGB amber = CRGB(255, 191, 0);
CRGB leds[numLeds];
byte indexArray[numLeds];
enum {SHUFFLE, LIGHTUP, WAIT, FADE} state = SHUFFLE;
const unsigned long waitTime = 2000ul; // make it 20000ul for 20s, limiting at 2s for demo
const unsigned long fadeStepTime = 10ul;
unsigned long startTime;
void fisherYatesShuffle() {
for (size_t i = numLeds - 1; i > 0; --i) {
size_t r = random(0, i + 1); // generate rand numbers from 0 to i
size_t tmpSwap = indexArray[i];
indexArray[i] = indexArray[r];
indexArray[r] = tmpSwap;
}
}
void animateStrip() {
switch (state) {
case SHUFFLE:
fisherYatesShuffle();
state = LIGHTUP;
break;
case LIGHTUP:
fill_solid(leds, numLeds, CRGB::Black); // turn them all off
for (byte i = 0; i < numChosenLeds; i++)leds[indexArray[i]] = amber; // turn the selected ones amber
FastLED.show();
startTime = millis();
state = WAIT;
break;
case WAIT:
if (millis() - startTime >= waitTime) {
startTime = millis();
state = FADE;
}
break;
case FADE:
if (millis() - startTime >= fadeStepTime) {
fadeToBlackBy(leds, numLeds, 1);
FastLED.show();
if (leds[indexArray[0]] == CRGB::Black) { // we totally faded out
state = SHUFFLE;
} else {
startTime = millis();
}
}
break;
}
}
void setup() {
randomSeed(analogRead(A0));
Serial.begin(115200);
for (byte i = 0; i < numLeds; i++) indexArray[i] = i;
FastLED.addLeds<WS2812B, stripPin, GRB>(leds, numLeds);
}
void loop() {
animateStrip();
// you can do other stuff here as long as it does not take too long
// ....
}```
Here's code&sim for doing a shuffle of M choose N pixels.
// https://wokwi.com/projects/408578815245853697
// for https://forum.arduino.cc/t/create-code-for-a-semi-random-fastled-pattern/1299988
// Modified from https://wokwi.com/projects/374907938100932609
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
#define PIN_NEO_PIXEL 4 // Arduino pin that connects to NeoPixel
#define NUM_PIXELS 100 // The number of LEDs (pixels) on NeoPixel
#define DELAY_INTERVAL 250 // 250ms pause between each pixel
Adafruit_NeoPixel NeoPixel(NUM_PIXELS, PIN_NEO_PIXEL, NEO_GRB + NEO_KHZ800);
byte pixDeck[NUM_PIXELS]; // 255 max
void setup() {
NeoPixel.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
for (int ii = 0; ii < NUM_PIXELS; ++ii){
pixDeck[ii] = ii;
}
}
void randomizePixDeck(int nn) {
for (int ii = 0; ii < nn; ++ii) {
int jj = random(ii, NUM_PIXELS);
int save = pixDeck[ii];
pixDeck[ii] = pixDeck[jj];
pixDeck[jj] = save;
}
}
void loop() {
randomPixes(7);
}
void randomPixes(int num){
const uint32_t interval = 2000;
static uint32_t last = -interval;
uint32_t now = millis();
if (now - last >= interval) {
last = now;
NeoPixel.clear();
randomizePixDeck(num);
for (int jj = 0; jj < num; ++jj) {
NeoPixel.setPixelColor(pixDeck[jj], NeoPixel.Color(255, 0xbf, 0));
}
NeoPixel.show();
}
}
I chose N=7 here because I can count that high quickly enough.
The fading does not seem fully specified, but modifying this non-blocking pattern to add a (50sec?) fade-in-hold-fade-out pattern shouldn't be too terrible.