So, in addition to the led library itself,

So, in addition to the led library itself, Mark and I both have higher level libraries that we use for doing a lot of our work. We use these libraries to give us things like oscillators, or patterns. I’m working n one that’s a combination of a task scheduler/oscillator library (and pool)/pattern manager.

The library is nowhere near publishing, but I can lay out some of the things that I’m doing in it to make my life easier, that may be helpful to some folks here. The sample code here is based on somewhat older versions of what I currently have (in part, because they don’t rely on extra infrastructure).

I start out with a base class that defines the interface for a pattern:

class CPattern {
protected:
CRGB *m_pLeds;
int m_nLeds;
public:
CPattern(CRGB *pStartLeds, int nLeds) : m_pLeds(pStartLeds), m_nLeds(nLeds); {}

virtual void draw() = 0;
};

Now, let’s have a “pattern” that basically fades everything in the leds that it’s given:

CFadePattern : public CPattern {
uint8_t m_nFadeAmount
public:
CFadePattern(CRGB *pStartLed, int nLeds, nFadeAmount) : CPattern(pStartLed, nLeds), m_nFadeAmount(nFadeAmount) {}

virtual void draw() {
for(int i = 0; i < m_nLeds; i++) {
m_pLeds[i].nscale8(m_nFadeAmount);
}
}
};

And how about a dot mover pattern:

CDotMover : public CPattern {
int m_nPos;
public:
CDotMover(CRGB *pLeds, int nLeds, int nStartPos) : CPattern(pLeds, nLeds), m_nPos(nStartPos) {}

virtual void draw() {
if(m_nPos >= m_nLeds) { m_nPos = 0; }
leds[m_nPos++] = CRGB::Blue;
}
};

Now, to use this stuff - I have a renderer that basically does the following (exploding it all out into the main program):

#include <FastSPI_LED2.h>

#define NUM_LEDS 100

struct CRGB leds[NUM_LEDS];

CPattern *pPatterns[] = {
new CFadePattern(leds, NUM_LEDS, 192),
// start a dot mover at led 10, over all the leds
new CDotMover(leds, NUM_LEDS, 10),
// start a dot mover at led 40, over all the leds
new CDotMover(leds, NUM_LEDS, 40),
// start a dot mover on leds 0-49, starting at the 5th led in that set
new CDotMover(leds, 50, 5),
// start a dot mover on leds 50-99, starting at the 10th led in that set
new CDotMover(leds+50, 50, 10),
NULL;
}

void setup() { LEDS.addLeds<WS2811, 6>(leds, NUM_LEDS); }

void loop() {
int iPattern=0;
while(pPattern[iPattern] != NULL) {
pPattern[iPattern++]->draw();
}
LEDS.show();
}

et. voila! Patterns!

The current incarnation of the library that i’m working on goes a bit further. It abstracts out the access to leds into classes that behave like arrays, but may do their own mapping to actual led structures differently in the background (e.g. a sliding window of leds, or skipping n leds for each led, etc…).

Also, I have a task manager that allows me to schedule tasks to run at regular intervals (so, for example, I can enforce a framerate where the renderer only draws once every Xms). Because of this, patterns have two methods - there’s an execute() method, that runs on every call to loop to allow a pattern to decide whether or not to update what it’s going to do when it draws[1]. This allows patterns to “move” at different rates than they’re drawing at. I use tasks to do things like read from sensors/inputs and make decisions, or to do other, non-led related regular tasks.

In addition, I have oscillators - so, for example, in the dot mover, instead of having it hard code to CRGB::Blue, instead, I’d have it be something like leds[i] = CHSV(m_hueOsc.get(), 255, 255); The oscillators can all run at their own rates and update independently of how they’re used. (What? some of my background is music and synthesis, and I have a love of modular synthesis…)

I’m still fighting with a good abstract representation/mapping to complex structures of leds, that code will probably go through a couple more rewrites, luckily I have some projects brewing that will make good use of it! Not only that, I’m also spec’ing out a pattern controller, so that I could define, say, 100 patterns and have them fade in/out and start and stop independently of each other and/or group them together, etc… (and then have an external controller, say, that allows controlling what patterns are running and what their parameters are).

However, even without all the frameworks/harness of the task executor and render and oscillators, hopefully the drops of code above can give people enough of a starting point to abstract out their drawing code so that they can do things like change up what leds their patterns are running on (or duplicate things, or have multiple patterns running at once!).

[1] that’s a bit misleading, actually, the task scheduler allows tasks to specify when they’d like to run next, so really execute gets called when it’s next time for that task to run, not on every loop

Cool. So I’m inspired to start moving this way.

For some reason I didn’t think you could use new in Arduino… Now I’m excited and slightly nervous. I spent a long time programming in C# on radically larger machines so I have terrible habits.

I didn’t know about using : to initialize variables in class declarations. That’s cool. It feels a little obscure, but I can see that every cycle counts on these machines so I’ve started using it. I assume it’ll feel natural soon.

A lot of the time I’m doing sequences of patterns so I’m finding myself doing stuff like this (runPattern is mostly your ‘loop’) with a little stuff to set frame rate and duration). It’s pretty straightforward, but it doesn’t feel totally elegant.

pPatterns[0] = new CSolidDotPattern(leds, ledCount, CRGB::Red); runPattern(15, 1500); pPatterns[0] = new CSolidDotPattern(leds, ledCount, CRGB::White); runPattern(15, 1500); pPatterns[0] = new CSolidDotPattern(leds, ledCount, CRGB::Green); runPattern(15, 1500);

pPatterns[0] = new CThreeColorMarchPattern(leds, ledCount, CRGB::White, CRGB::Red, CRGB::Green);
runPattern(30, 3000);

(code at https://github.com/zekekoch/SantaHat/blob/master/SantaHat.ino)

Daniel, cool stuff.
Providing a framework for patterns could open a world of ‘third party’/community patterns based on the fastled lib.
Will the array of patterns allow layers ? Ie a pattern running in the background and another running on top of it ? Looks to be feasible as all is done logically before sending to the led and the last pattern will win.
The shown examples look to be 1D patterns. Will it also be applicable to 2D/xy matrixes and maybe even 3D ?.
Decoupling physical ledsequence configuration from logical is great, difficulty offcourse how to do the mapping between the two. But all at the end it are x, xy or xyz matrixes.
If i interpret your post correctly it also contains the priniple of a ‘viewport’=>a pattern applicable on a predefined subset of your ledmatrix.
Very inspiring and promising

I am just grasping this concept today after numerous re-reads. That’s how you learn…as today is “write your own library day”

@Daniel_Garcia Would you be willing to elaborate a tad in the “oscillator” category ? All my fx sequences require individual adaptation of master hue control in the CHSV realm by usually doing this: hue++; leds[i] = CHSV(hue,255,255).

bump
I could use a bit of direction still regarding this…thank you

Sorry, i missed this comment! (Notifications of posts seem to be more reliable than notifications of comments on older posts).

For my oscillators, I have a base oscillator class that looks something like this:

class Oscillator {
public:
virtual int get() = 0;
virtual int step() = 0;
};

“get” gets the current value of the oscillator, and “step” steps the oscillator forward.

then i have implementations for things like cycling a value using sin, or using cos, or something that simply, and linearly steps a number back and forth between a low and high value, or that gives a random number every time step is called, or is hooked up to the values coming out of an MSGEQ7.

@Zeke_Koch Hey Zeke, thanks for your code (and @Daniel_Garcia !) - I’ve been having fun and games playing with patterns.

What I can’t seem to work out and what I would like to do, is to set a pattern (say, CThreeColorMarchPattern) for a specific range of LEDs, rather than from 1-x. Even better would be to have multiple ranges of LEDs actioned concurrently.

Is that possible?