kitesurfer1404 / WS2812FX

WS2812 FX Library for Arduino and ESP8266
MIT License
1.58k stars 344 forks source link

Changing the order of LEDs #284

Closed moose4lord closed 3 years ago

moose4lord commented 3 years ago

I'm new to github, not sure where to post this question,

I have a similar issue, although was looking for a different kind of work around. I have a nonlinear, non symmetrical 3d object of led's. Imagine a tangle of led's on a 3d object, and I'd like to be able to map each individual led pin order, into a specific linear line.

I would like to be able to re-map the led's 1-50, but instead of sequencial order have them mapped in a specific set order. It would be like having a cross over function before the led's are sent out. so instead of led order 1,2,3,4,5,6,7....,49,50 instead I'd want 6,17,2,32,.... 45,3 led1 = led6 led2 = led 17 .... led49 = led 45 led50 = led 3 and then have the re-mapped order sent to the pre-built functions in WS2812fx

Is this possible, and is there an easy workaround?

By doing the above cross over code, would allow for easier use of setting segment ranges in certain circumstances. (less ranges to be mapped if the led order is changed)

Originally posted by @khammel2 in https://github.com/kitesurfer1404/WS2812FX/issues/178#issuecomment-842866127

moose4lord commented 3 years ago

@khammel2 asked this question in another, similar issue, so I've replicated it here as new issue, just to manage it better.

I think this situation can be handled by creating separate virtual and physical LED strips, like what is done in the ws2812fx_overlay example sketch. In this case you'd have one virtual strip, which would be used to run the animation, and another physical strip, which would be used to drive the LEDs. A look-up table would be used to translate the virtual LEDs to the physical LEDs.

This demo worked for me:

#include <WS2812FX.h>

#define LED_PIN    4
#define LED_COUNT 10

// Create instances of one virtual strip and one physical strip.
// The animations will run on the virtual strip, but the LED data
// will be mapped to the physical strip.
WS2812FX ws2812fx_v = WS2812FX(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
WS2812FX ws2812fx_p = WS2812FX(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

uint16_t ledMap[LED_COUNT] = {4,3,2,1,0,5,6,7,8,9};

void setup() {
  // Initialize the virtual strip
  ws2812fx_v.init();
  ws2812fx_v.setBrightness(64);
  ws2812fx_v.setSegment(0, 0, LED_COUNT-1, FX_MODE_LARSON_SCANNER, RED, 10000, NO_OPTIONS);
  ws2812fx_v.start();

  // Initialize the physical strip.
  ws2812fx_p.init();

  // Config custom show() functions for the virtual strip, so it's
  // pixel data gets mapped to the physical strip.
  ws2812fx_v.setCustomShow(myCustomShow);
}

void loop() {
  // Run effects only on the virtual strip.
  ws2812fx_v.service();
}

void myCustomShow(void) {
  // map virtual LEDs to physical LEDs
  for (int i=0; i < ws2812fx_p.getNumBytes(); i++) {
    ws2812fx_p.setPixelColor(i, ws2812fx_v.getPixelColor(ledMap[i]));
  }

  // Call the physical strip's show() function.
  // Note: the virtual strip's show() functions are never called.
  ws2812fx_p.Adafruit_NeoPixel::show();
}
khammel2 commented 3 years ago

Thank you for the quick reply.

So If I took your line of code, and added to the code. (still learning arduino, not sure exactly how to write complete proper case statement)

switch (trajectory) { case 0: uint16_t ledMap[LED_COUNT] = {4,3,2,1,0,5,6,7,8,9}; break; case 1: uint16_t ledMap[LED_COUNT] = {4,2,0,6,8,1,3,5,7,9}; break; case 2: uint16_t ledMap[LED_COUNT] = {9,3,1,4,5,6,7,2,8,0}; break; case 3: uint16_t ledMap[LED_COUNT] = {2,1,0,5,6,4,3,7,8,9}; break; }

As long as the ledMap array is changed before it hits this line in your code ws2812fx_p.setPixelColor(i, ws2812fx_v.getPixelColor(ledMap[i]));

I should be able to make the linear setSegment functions follow the new desired path through the 3-d matrix of led's (choosing between 0-3 for trajectories)

khammel2 commented 3 years ago

So, using the above, assuming the segments don't overlap, (no shared pixels on relatively linear path across a 3-d matrix) I could then split the segments into groups using case 0: ws2812fx.resetSegments(); ws2812fx.resetSegmentRuntimes(); ws2812fx.setSegments(0,0,3,FXMODE... ); ws2812fx.setSegments(1,4,6,FXMODE... ); ws2812fx.setSegments(2,7,9,FXMODE... ); break;

case 1:.....etc...

But what happens if I want to use two different trajectories (ledMap) with overlapping led segments at the same time. (hence they cross over a shared led). trajectory case 0, segment range 3-5 .... would be led1,led0,led5 trajectory case 1, segment range 1-4 .... would be led2,led0,led6,led8

is it possible to send two different trajectories to the segment functions and have them run at the same time, and what happens when the linear segments are trying to control the same led at the same time. the example above, led0 would be the intersection point.

moose4lord commented 3 years ago

You can't re-assign ledMap values like that. If you must have different LED mapping based on "trajectory", I would create a multidimensional array of ledMaps and use "trajectory" to select which map is active. Maybe like this:

uint8_t  trajectory = 0;
uint16_t ledMap[][LED_COUNT] = {
  {4,3,2,1,0,5,6,7,8,9}, // trajectory == 0
  {0,1,2,3,4,9,8,7,6,5}  // trajectory == 1
};
...
for (int i=0; i < ws2812fx_p.getNumBytes(); i++) {
  ws2812fx_p.setPixelColor(i, ws2812fx_v.getPixelColor(ledMap[trajectory][i]));
}

As far as overlapping maps go, I'm afraid you're at the mercy of the segment timing. Whichever segment writes to the LED last, wins. It will overwrite any color data assigned to the LED by a previous segment. Depending on what effects you're using, it may be noticeable or it may not.

khammel2 commented 3 years ago

Ok. Good to know. The overlapping maps still could come out with some neat outcomes, kind of like painting on a canvas whatever is painted last is the one that you want to see on top.

Speaking of painting, when it comes to segments, you can increase segment number by WS2812FX ws2812fx = WS2812FX(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800, 24, 24) normal max of 10 segments, but the above changes that max to 24

How do you go about changing the color palette size? (normal max of 3), how do you pass more color variables using the set segment portion (would like to know for creating custom effects) and how many of the standard fx packages can manage more than 3 colors? (would like to try a palette of up to 16, is this possible)

moose4lord commented 3 years ago

Unfortunately, the built-in effects and the current set of custom effects only support a maximum of 3 colors. Each segment can have it's own palette, so you can get more colors in your LED strip by adding more segments, but each segment is limited to 3 colors. You'd only be able to use a larger palette in custom effects you wrote yourself, in which case you can make the palette as large as you like.

khammel2 commented 3 years ago

to add more than 3 colors for the custom segment code, how do you expand the range to allow for this. I believe the limit in the main code is set to 3, how do you set this number higher?

while speaking of ws2812fx.init(); OR ws2812fx.start(); is there a way to pass the ledMap with the LED_COUNT to the init(); function to change the trajectory that way. (just passing 1 single ledMap array)?

khammel2 commented 3 years ago

One more question, well actually a two part question, well 3 and more now... One is for turning a novation launchpads controller into a WS2812fx or FastLED light show while idle, and the second is getting the led fx working better in the controllers community,

  1. how to define (or cross over array) an led string and number of led's leading into init function if led's are wired differently to controller differently than typical

    it looks like this code can turn a novation launchpad into a led device controlled by arduino https://github.com/j0uni/LaunchpadArduino (launchpad is a bit more expensive than string of led's but a lot of musicians have em kicking around, and would be fun to do led show while they are sitting idle, or other fun) How hard would it be to get ws2812fx or FASTled code running on the launchpad from an arduino?

As for light shows on launchpads, it looks like it is possible through the big hitter software DAW's : Ableton Live , FL 20. I believe the light show is triggered by sending a midi signal (note and velocity) to the launchpad from the DAW, would think it possible to have a crossover function from WS2812fx to MIDI signal using the MIDIUSB.h library. I suggest this library because it allows the arduino to act directly to the computer without having to use a midi loop port (midi loop ports are a pain). (which makes MIDIUSB.h superior to some of the other midi libraries, for building a midi controller) Note: for the MIDIUSB.h library, this only works with specific boards (atmega32u4 based boards or ARM boards) (if you want to do midi, it's worth getting a specific arduino)

I know a lot of people have been building custom midi controllers through the controllerism comunity... using usb midi library is pretty awesome for the controllerism community, as long as you are using specific arduino processors

include "MIDIUSB.h"

would be nice to combine the led fx from the LED community with the controllerism community.

   the midiusb.h library allows the arduino to come up natively in most DAW's (digital audio workstations)

ok, now that the music stuff is out of the way above, it would be neat to add the ws2812x code or fastled code to the controlerism community. (not sure if this has been done already)

Got the idea of taking launchpad and turning it into a led show pad when idle, from seeing this product, the Divoom https://www.divoom.com/product/pixoo.html and got me thinking how hard would it be to get ws2812fx or FastLed running on the Novation Launchpad, mini mk3?

Also wanted to say thank you for the ongoing support of the ws2812fx code, and apologies for the what if questions, if they keep getting harder and out of scope.

My to do list right now, as for research on led light shows, (or pony list of neat things to try, but not necessarily needed)

a deeper dive through your mic support and sound reactive led shows, OR Instead of using a mic support, how hard is it to pass a variable like BPM, or other timing characteristics from dj software to arduino and control fun led show (popular dj software like Traktor Pro 3, ... )

look through / dig through your wifi programming tips and support from arduino, and possibilitie through this create some sort of wireless button, or way to pass variables / changes from dj software or other music devices to arduino light show at a distance, what distance is possible, and are you better to pass that information over a wire depending on the distance.

    for Larger future scale project roll outs, [Master =>>> to slaves] how hard is it to pass info over wifi to several different arduinos hosting simultaneous (or close to simultaneous) light shows probably under 100 leds. (although just double check ws2812fx limit, if you went to a higher led count is about 900 currently). and what problems are likely to occur on 900 led projects.  
moose4lord commented 3 years ago

I'll address your question about expanding the color palette first. You wouldn't use the built-in, 3-color palette at all in your custom effects. Instead you would manage the colors completely within the custom effect. I wrote a quicky color fade demo that shows how this might work (see attached).

colorFadeDemo.zip

I don't think adding an LED map feature to the init() or start() functions would be appropriate, since it's a pretty uncommon use case.

moose4lord commented 3 years ago

Now on to your second set of questions. Yikes! I wish I had your ambition. :)

I haven't looked too much at the consumer LED devices. Some of them look interesting, so I'll have to give them some attention. Your idea of incorporating MIDI support is also interesting. I'll have to give it some thought.

Integrating with a Launchpad is probably do-able, via some kind of MIDI link, but since I don't have one of those devices, I really can't jump into that.

In terms of wireless control, there's a couple example sketches that control LEDs over a WiFi network (typically with an ESP8266 microcontroller, not an Arduino) using a web browser or Android app. See the esp8266_webinterface and ws2812fx_segments_web example sketches for inspiration.

For very large (900 LEDs) installation you need to pay particular attention to the power requirements of so many LEDs. It takes a beefy power supply, and careful wiring and decoupling to make it work reliably. Be sure to read Adafruit's Neopixel Uberguide.

khammel2 commented 3 years ago

Another side question. more so on minimizing cpu use and math calculation rounding, but could be used for setting a trajectory on a re-order matrix/lattice led project.

The what? (pixelated trig library calculations) I'm looking for a c or arduino math library that speeds up simple math operations and rounds them into a grid operation. Specifically something that is easy on processing power, I swear I've seen something before, not sure if it was arduino, or c++ library functions. It's a quicker way of calculating math trig functions, rounding to a grid of numbers. (or needed grid accuracy) As for LED calculation, this could be used on per say a grid of 8x8, 10x10, 30x30 ... etc...
(basically the size of the led grid would define how much cpu power is needed for the grid accuracy of the mathematical function)

The why? (importance of cpu power, and being able to change the led map/matrix and trajectory (or led cross over table)) Where this would come in useful is you could use something simple of say a cosine function, and map this to a grid of 8x8, using limited cpu power, going step by step, rounding to a specific pixel grid. Now the neat part here is that once you have this linear trajectory mapped from the trig operation, you could then send it to the WS2818fx of FASTled code, to traject some neat moving lines of leds on a flat 2d 8x8 grid, or a 3d led grid / lattice. (re-mapped with the above trajectory map, hence an interested in changing the order of the led mapping)

 let's call this in math terms trig art. in terms artist would recognize let's use spirograph   

Now if you wanted to get into more complex art patterns, you could think of the trig trajectory as a moving spirograph, or solid line spirograph with the FX_MODEs overlaid on that trajectory. and other fun nifty math trajectories, and still keep the cpu power low if you we're to use pixelated or rounded quick math operators. (which is much appreciated in a lot of coding projects)

Now for complex solid 3-d shapes , with external led light structure, or internal lattice structure, if you we're able to change the mapping in advance, either static change or dynamic crossover table of the led mapping you could tell that trajectory to go in any direction. (I guess something like a lattice structure), by being able to define the trajectory function ( the linear order in which you want the lights to be turned on) you could do some nifty trig functions to map the order in which you want the lights to turned on, with 50 or so nifty FX_MODE of how those lights turn on.

Anywho, the above calculation, if simplified in coding, would make for an awesome toolbox, to create/make for some neat grid effects / light show / or fireworks looking things, and if you can keep cpu use of the complex trig function for spirograph or other neat math trajectories to a minimum this would pack very nicely into arduino, in some math equations.

Both WS2812fx and FASTled have awesome straight line art generators pre built in, but think of this as drawing a line on a grid/lattice of leds and having whatever line pattern drawn display the specific FX_MODE

I suck at coding, but I think the easiest way to get around this would be to be able to

  1. define the grid order of led's(map,matrix or latice),
  2. and define the linear trajectory through the map(matrix or latice), sent by the set.segment functions

So if there was an easy way to change the LED Order Matrix, and set the trajectory mapping for this thread, would suit well for 2d and 3d led lattices. (regardless of the distance, or order of the leds on the lattice)

Now for most people when they think grid, they think of a square of led's 8x8. but what if you put leds anywhere over lets say a object people know, how bout a Dog for this instance But the led's are in a mish mash of different locations on the dog. (the segment operator you have lets you choose segments as ears, nose, tail, legs, etc...) but the led's would have to be strung and grouped on the dog in the order of the segment ranges, to minimize the number of segments needed.
[another workaround i guess would be instead of passing a range variable in the set.segment code ( start, and finish) If you could pass a string variable of pre-defined trajectory led's instead for a segment] being able to change or define the grid/matrix/mapping/lattice afterword's, as close to a matrix as possible later on down the road, instead of having to wire every led in the desired linear order of the fx_mode, you could then change the order of the grid/matrix/mapping/lattice 3-d object, on the Dog

I guess my question is:

  1. How do you , or is there a way to define the grid/matrix/mapping/lattice at the start of the setup() code, or other part of the init(), such as a cross table
  2. Other, or best methods of passing a trajectory path to lattice of leds
  3. What are the methods to minimize computing of mathematical and trigonomic operations, rounding operations on a 8x8 grid (or in ws2812fx , the max grid size would be 30x30, based on a max of 900 leds)
moose4lord commented 3 years ago

Math isn't my forte, so I'm probably not the right person to comment on your question. But in my experience, these kind of low precision, high performance math functions you're talking about are carried out by creating a lookup table. As a matter of fact, the Adafruit_Neopixel library, which forms the backbone of WS2812FX, has a built-in sine function table for quick sine calculations:

/* A PROGMEM (flash mem) table containing 8-bit unsigned sine wave (0-255). */
static const uint8_t PROGMEM _NeoPixelSineTable[256] = {
  128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173,
  176,179,182,185,188,190,193,196,198,201,203,206,208,211,213,215,
  218,220,222,224,226,228,230,232,234,235,237,238,240,241,243,244,
  245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255,
  255,255,255,255,254,254,254,253,253,252,251,250,250,249,248,246,
  245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,220,
  218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,
  176,173,170,167,165,162,158,155,152,149,146,143,140,137,134,131,
  128,124,121,118,115,112,109,106,103,100, 97, 93, 90, 88, 85, 82,
   79, 76, 73, 70, 67, 65, 62, 59, 57, 54, 52, 49, 47, 44, 42, 40,
   37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 15, 14, 12, 11,
   10,  9,  7,  6,  5,  5,  4,  3,  2,  2,  1,  1,  1,  0,  0,  0,
    0,  0,  0,  0,  1,  1,  1,  2,  2,  3,  4,  5,  5,  6,  7,  9,
   10, 11, 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35,
   37, 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76,
   79, 82, 85, 88, 90, 93, 97,100,103,106,109,112,115,118,121,124};

The _NeoPixelSineTable array is indexed with an integer in the range 0-255 (representing an angle between 0 and 2 pi radians), and the array returns the appropriate sine(x) result (again expressing the -1 to 1 result as an integer in the range 0-255).

Integrating your grid/matrix/mapping/lattice technique into the start() or init() functions, as I mentioned before, isn't a good fit for the WS2812FX library, since it's so application specific. I think it's better handled by a custom show() function, as we've been discussing.

As for the actual mapping technique, you should probably team up with someone who's a wiz at 3D, spacial modeling. Maybe a game developer. They're usually pretty good at that kind of thing.

khammel2 commented 3 years ago

Thanks again for the help. I still haven't had a chance to test the method you have given above for the order mapping changes, but would like to look into a couple different methods of doing so, for the mapping order of the led's before being passed to the linear function library. I will try to get back to you if I see a better or different way to do so. (there's usually a couple ways to do the same thing)

I have another question, this one more in scope with the WS2812fx library, for each of the effects (1-56, +extra custom modes)

FX_MODE_STATIC KEYWORD2FX_MODE_BLINK KEYWORD2FX_MODE_BREATH KEYWORD2FX_MODE_COLOR_WIPE KEYWORD2FX_MODE_COLOR_WIPE_INV KEYWORD2FX_MODE_COLOR_WIPE_REV KEYWORD2FX_MODE_COLOR_WIPE_REV_INV KEYWORD2FX_MODE_COLOR_WIPE_RANDOM KEYWORD2FX_MODE_RANDOM_COLOR KEYWORD2FX_MODE_SINGLE_DYNAMIC KEYWORD2FX_MODE_MULTI_DYNAMIC KEYWORD2

Is there anywhere that someone has listed all of the above effects? but more specifically, documentation for the typical best speeds, colors and options to pass for each effect? _ws2812fx.setSegment(0, 0, 99, FX_MODE_STATIC, PURPLE, 2000, NOOPTIONS); For some modes they only need one color, for others 3 colors works best? For some fx_modes 2000ms works best , but for others maybe 50ms and for other fx_modes they have different options such as

NO_OPTIONS LITERAL1REVERSE LITERAL1GAMMA LITERAL1FADE_XFAST LITERAL1FADE_FAST LITERAL1FADE_MEDIUM LITERAL1FADE_SLOW LITERAL1FADE_XSLOW LITERAL1FADE_XXSLOW LITERAL1FADE_GLACIAL LITERAL1SIZE_SMALL LITERAL1SIZE_MEDIUM LITERAL1SIZE_LARGE LITERAL1SIZE_XLARGE LITERAL1

which option works best for each mode?

If someone had time (it's going to be a pain to do). but feel like a chart explaining each fx_mode would save a lot of time for the end user, if they new roughly what worked best for each mode. (I guess this would be extra documentation I'm looking for, which would help the end user quickly put together a light show on the linear light strips, using the above functions)

each fx_mode, color variable: split out by which one works best with say (single,double,or triple color), (if you wanted to get more artistic, which ones work with contrasting colors, which one work better with blending color palettes) time variable: which one work better with large or small numbers, or which ones work better with options variable: which option is best passed for which fx_mode?

                  ColorVar                             TimeVar                          Options                                            Options description

_fxmode1 1 5ms-30ms Which options work best descrions.... _fxmode2 3 40ms No_Option _fxmode3 2 3000-5000ms Option2 _fxmode4 1 2000ms Option3

for an art or design perspective (for describing passing colors variable to the led light strip, it's nice to know roughly what the led light programing is going to do for a function before passing all of the variables. )

As for other custom led fx, where is the best place to find the community shared effects ? (specifically the ones that work with the way the segment part of the coding is laid out)

khammel2 commented 3 years ago

The 3d stuff is out of the scope of this ws2812fx code, but Going back to your spatial modeling and 3d wiz comment, stuff get's a bit more difficult but still possible to learn math wise. I'm going to guess if you are able to code come of the above stuff, you have a pretty decent mathematics background. a lot of problems start to arise with the computational power needed in 3d calculations. proper foundation for a roots up development, can solve some of the speed or processing power needed. If you think of it as a pen and paper problem, if you lay out the proper equation it can solve the problem quicker. Depending on what you are trying to achieve visual wise in a game , there should be a better way to fit everything into that box. Some of that pixelated games, run a lot quicker than some of these heavy 3d fx packages. (the speed of a calculation, you can think of the importance of this like the reaction times needed in professional sports, or in a driving instance, you want a highly skilled operator) a lot of folks start thinking you need more cpu, or a bigger graphics card, but a lot of it comes down to how the software was written from the ground up. talk to some of these folks who had little processing power to work with, and they will teach you tricks to work with the limited resources we have. frankly I think we are spoiled today to have the graphic user interface to work with, and point and click technology, or push a button and this machine does what you want. You would swear some of these companies are crooked, making the old software not run effectively on their 'phones' (or miniature portable computers), forcing you to buy a new cell phone just so they can make money. Some of it might come down to virus's and spyware on these phones which are causing the old technology to stop working. Or lack of support.

money isn't everything either, we don't need more cell phones. we need to work as a world to keep everyone here healthy, and safe. safe home, proper food, oxygen, and water. we also need more trees in this world.

anywho, it is still good to understand the fundamentals and mathematics of how some of these things work, and to have things coded properly. Imagine you landed on a planet and had minimum tools to work with, how do you build a computer from the ground up? How do you load an operating system on the thing? How do you do this with minimal technology. We'll they landed someone on the moon (this ain't a planet), using the processing power that fits in a calculator, we do need to be able to continue to understand those calculations (be it pixelated grid movements for speed and saving on processing power, or more accurate long distance calculations; that problem would boil down to what sort of precision is needed in which case)

moose4lord commented 3 years ago

Unfortunately, I think what "works best" is pretty subjective. You and I might have very different ideas about what looks best. Also, how an effect looks depends a lot on the number of LEDs in the strip and how far away it is being viewed. If I create an effect and view it on my test setup, which is a strip of 144 LEDs viewed from 2 feet away, it looks completely different than if I run the effect on the strip outside my house, which is a strip of 600 LEDs viewed from 50 feet away. Besides, I think part of the fun of working with programable LEDs is just experimenting with them. Rather than creating documentation about all the effects and options, I think it's better if folks just sit down with the esp8266_webinterface or ws2812fx_segments_web example sketches and play. They'll learn a lot more from that rather than reading some documentation. Plus it's fun! :)

As far as community shared effects go, there are none. At least none that I am aware of. I think most people are pretty happy with the set of built-in effects, so there's not a lot of effort put into creating custom effects.

I agree with you...fewer cell phones...more trees. :)