I’m setting up to use an Arduino (Not sure what end type, right now it’s running on a Mega 2560 but likely will try to end up on a micro or nano) to handle talking to some WS2812 objects. The objects have really bad physical layout of the LEDs though. I need to effectively treat them as diamond-shaped with three LEDs per side, and be able to logically “flatten” them either horizontally or vertically to convert them into two rows (or columns) of six LEDs each. Then I also have to handle multiples of these strung in sequence in arbitrary positions (The code needs to be able to be told at run time which corner is up and where the objects are relative to each other). Then to make it worse, the LEDs in them start at the middle of one of the sides. So there is a side that has 12, 1, 2, then the next side has 3, 4, 5, and so on through the four sides around,. The second object having 24, 13, 14, then 15, 16, 17 and so on. If that doesn’t make sense, I apologize, it’s a pain to comprehend as is.
The preferred annoying-but-I-think-I-can-make-it-work way would be to be able to set up arbitrary arrays for individual sides that reference segments of the main full array. Then applying things to a given side in forward or reverse order would be relatively easy. CRGBArray would work great for example except for the fact that one side is split between the first two and the last LED on each device. From that point, I should be able to map out the sides that need to interact with each other.
After 17 C+±less years, I can’t for the life of me determine how to create such things. And I’m also open to better ideas. Lacking either, I’ll end up with a complex mess of spaghetti functions and bad code that will incite vast sadness and failure.
That’s a lot to try to work with! My first thought was to map it so you can at least have those first sides of each diamond be continuous so you don’t have to deal with that 12, 1, 2 layout. Then you could use CRGBArray for easily lighting up sides.
And then manually edit the numbers around the sides to be continuous all the way around (instead of the serpentine or zig-zag patterned numbers). So it became like the attached image.
[Which makes me wonder if @Garrett_Mace could add an option box for the initial pixel number in the matrix (defaulting to 0). This could be useful for this sort of situation where you have multiple matrix layouts, but want to treat them all as one super long strip that goes from matrix to matrix to matrix. You would map each matrix separately for whatever dimensions it needed to be putting in the correct starting pixel value for each subsequent matrix, and then manually put all the XYTable arrays together into one. Do you think this would be useful Garrett?]
As for the issue of determining which corner is up at run time… ouch I’m not going to attempt to think about.
@marmil I really wish there was a decent way to not have 1 (0) start in the middle of a side, but I didn’t make the hardware and breaking the $30 object to access the poorly-embedded LED strip is not in scope. XD
A lot of the advice depends on being able to do that too, and really just eases handling individual quadrants. I also need to handle animation across two quadrants of one device and then jump to another device as well. So in leds[n] terms, I’d need to animate one side as 1, 0, 11, 10, 9, 8, 13, 12, 23, 22, 21, 20. That’s why I was looking for some way to make, for example, a "side1[]’ array that 0-11 would point to those leds[] locations and then be able to just iterate through side1[0] through side1[11]. Bonus points if I could use CRGBSet. But meh. :\
I think I’m not fully understanding CRGBSet in the sense of what it’s taking to create, based on the example on the wiki. CRGB *realleds[NUM_LEDS]; CRGBSet leds(realleds, NUM_LEDS); feels like it’s missing something based on the description above it. realleds would be an array of pointers (not pixel data), and it says that CRGBSet doesn’t contain pixel data either. Which implies that there should be something more like CRGB *pleds[NUM_LEDS], pixeldata[NUM_LEDS]; pleds = pixeldata; … Either that or my C++ is even more rusty than I thought. I think I’ll go make some broken code until somebody corrects me or I remember anything.
Mapping is what will allow you not to have to deal with that funny business of the 12,1,2 layout. Thankfully you can fix their poor design in code and I would definitely recommend it!
Here are two examples using CRGBset. Once you’ve mapped your stuff, you can make a Set for every diamond, or even every quadrant of each diamond if desired.
Get your code started and then post it to http://gist.github.com and link here if you run into trouble.
@marmil That is tremendously informative and helpful. Thank you! The only thing I don’t see how to do from the examples is how to make a set from non-contiguous LEDs or otherwise get a CRGBSet for segment 1 to be 1, 0, 11. The XYMapper looks like it just functions as a precalculation for passing led[XY(2,4)] for example and having it translated the X/Y into the 1D array. This doesn’t work with a CRGBArray version of led since then led(XY(1,1),XY(1,3)) would come back as led(1,11) if I’m understanding it correctly.
As such, I’m still not understanding how I can successfully create a CRGBSet that points in order to realleds 1, 0, 11, 10, 9, 8, 13, 12, 23, 22, 21, and 20 (It goes further with more of the devices, but truncated for brevity.
Or I missed what “mapping” means in this situation.
Unfortunately you can’t make a CRGBSet for non-contiguous numbers.
Here’s another example. I don’t have a matrix to test more in-depth with, but seems like CRGBSet works with mapping.
[ Link removed due to it being a completely useless example, and so as not to confuse and anger the mobs. ]
@marmil I must be completely misunderstanding how mapping works. That looks like the “mapping” is creating a function that takes x,y as input and returns a linear led array location. In that code, the function is never called however, just defined. If the mapping was, for example, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1 … where is that data being used in the above code rather than just defined?
Meh. Turns out that the RGBSet documents are not quite accurate (silly asterisk), and the reason I couldn’t recall how to do the thing is because there is no graceful way to have data in an array in memory and then reference it in an arbitrary order in another array without dereferencing, which none of the handling code does. So yeah, stuck with making lookup arrays and/or functions and nesting loops of doom. I hate nesting loops. They leave loop droppings all around the nest.
@Kit_Parenteau I messed with this again tonight. And totally got rid of using XY mapping example as it was completely useless and I don’t want to confuse or anger the mobs!
After looking at the problem again with fresh eyes and did a mostly straight forward remap which is based on the pixel number. I /think/ this will work with that wacky layout.
Also to note in this example is there are two CRGBArrays so we can operate on an imaginary one, that has a nice layout and makes sense to the brain, and then a remap pushes those pixel values over to the wacky layout just before updating the display with show(). And because it’s a normal continuous layout using CRGBSet is possible here. Hope this is a more useful example.
@marmil That mapping is precisely what’s needed. Assuming that a CRGBArray can be addressed with leds[] form still (as opposed to leds(s,e)). Thank you!
I’ll have to give some thought to whether I want to make function blocks to handle specialized pathing of chasers or just make pathmaps. ^.^
@marmil Just a heads up that the remapper pushes the pixels forward one as, for example, actual[3] is leds[2], but leds (what we’re thinking) is the alignment on the right and actual (what is physically) is the left. But if we use those for the calculations, it gets wonky and makes brains hurt
The calcs are effectively actual[i] = leds[i-1]; so therefore it takes leds[0] and places it into actual[1], whereas we want leds[1] in actual[0] instead.
I adjusted the function to just push everything two forward instead since that works better in my situation with “north” on the diamonds related to the actual layout of the LEDs on the diamonds (the hardware designers ran things counterclockwise and started from NE being 0 with N by NE being address 1 and E by NE being 11). It makes virtual zero start at physical 2 and continues from there. I’ll figure out arbitrary facing (CCW vs CW) and arbitrary “north” later if I absolutely have to.
So, end result, remapping the evil diamonds works. Thank you most kindly! Now I get to work on segments for chase lights and fades and color changes and all kinds of fun like that.