Ring Segments Example - AlbertGBarber/PixelSpork GitHub Wiki

Overview:

This page lists a number of example segment sets for a commonly available set of Ws2812b rings (61 LEDs total) (pictured below). Each example will include a diagram of the segment set layout, the code for the set, and an example gif of the streamer effect running on the segment set. The streamer effect will be the same for each segment set (unless otherwise noted):

StreamerSL streamer( <<A segment set>>, cybPnkPal_PS, 0, 4, 4, 10, 50);

So, the streamer is using colors from the cybPnkPal_PS palette (magenta, orange, and teal), with a streamer length of 4 and a spacing of 4. The background is blank. Colors use 10 steps to transition, with 50ms between each step.

When watching the gifs, I recommend following a color wave as it moves though the segment set.

This page is intended to supplement the segment basics guide by providing multiple examples of entire segment sets.

The LED Rings:

Assume that the rings are wired together from the outer ring to the inner most ring, going clockwise around each ring. In other words, the strip starts at the top pixel of the outer ring, and moves clockwise around each ring, spiraling inward until it gets to the final center pixel. There are 61 LEDs in total. The number of LEDs in each ring are 24, 16, 12, 8, and 1.

Also assume that somewhere else in the code we have defined the FastLED LED color storage array named leds.

CRGB leds[61];

The segment example code only includes the code needed to setup each segment set. For a running setup, see the basic setup guide.

Example 1: The Rings as a Single Segment.

In this example we will represent the rings as one long segment, in the order they are wired in. This creates a 1D line.

The code:

//A section array with a single section, with all the LEDs in order from 0 to 60.
const PROGMEM segmentSecCont mainSec[] = { {0, 61} }; 

//Create 1 segment for the lone section
SegmentPS mainSegment = { mainSec, SIZE(mainSec), true }; 

//Create the segment set from the lone segment
SegmentPS *main_arr[] = { &mainSegment };
SegmentSetPS mainSegments( leds, NUM_LEDs, main_arr, SIZE(main_arr) );

The code above groups the rings into one segment containing a single continuous section with all the LEDs in order. The resulting segment set is just a 1D line and is equivalent to the strip itself.

This is probably the only segment set setup that is almost identical across multiple shapes and LED configurations, with the only difference being the number of LEDs.

The Streamer Effect Running on the Segment Set:

Example 2: 2D Disk:

In this example, we form the rings into a 2D disk by organizing each ring into a separate segment.

The Code:

//Create a segment for each ring using one continuous section for each
const PROGMEM segmentSecCont ringSec0[] = { {0, 24} }; //ring 0, 24 pixels
SegmentPS ringSegment0 = { ringSec0, SIZE(ringSec0),  true };

const PROGMEM segmentSecCont ringSec1[] = { {24, 16} }; //ring 1, 16 pixels
SegmentPS ringSegment1 = { ringSec1, SIZE(ringSec1), true };

const PROGMEM segmentSecCont ringSec2[] = { {40, 12} }; //ring 2, 12 pixels
SegmentPS ringSegment2 = { ringSec2, SIZE(ringSec2), true };

const PROGMEM segmentSecCont ringSec3[] = { {52, 8} }; //ring 3, 8 pixels
SegmentPS ringSegment3 = { ringSec3, SIZE(ringSec3),true };

const PROGMEM segmentSecCont ringSec4[] = { {60, 1} }; //ring 4, 1 pixel (this is the disk's center pixel)
SegmentPS ringSegment4 = { ringSec4, SIZE(ringSec4), true };

//With all the segments created, we can group them into a segment set to form the disk
//First we create an array with all the ring segments, ordered from greatest to least LEDs
SegmentPS *rings_arr[] = { &ringSegment0 , &ringSegment1, &ringSegment2, &ringSegment3, &ringSegment4 };

//Now we create our disk segment set
SegmentSetPS diskSet( leds, SIZE(leds), rings_arr, SIZE(rings_arr) );

Each ring is just segment, with one continuous section. The segment set is all the rings grouped together. Because the segment set has mulitple segments, it is 2D. Most effects will use its 2D properties when drawing. The example streamer effect draws along segment lines.

The Streamer Effect Running on the Segment Set:

Example 3: Each Ring as a "Single" Section:

For this setup we are making use of "single" sections. A "single" section is treated as single LED by effects, but actually contains multiple LEDs. All the LEDs in a "single" section always have the same color.

In the setup below, we make each ring a "single" section, with the yellow line on the diagram below marking the first LED in each section. We will use one segment to group all the sections, resulting in a 1D segment set. This results in a quick way of "transposing" a the 2D disk segment set from above.

The Code:

//Place all the rings in one segment, each as a separate section, 
//Each ring is treated as one pixel (indicated by the additional "true" in the section definitions)
//You'll notice that the sections are the same as the rings from the 2D disk example
const PROGMEM segmentSecCont ringSingleSec[] = { {0, 24, true}, {24, 16, true}, {40, 12, true}, {52, 8, true}, {60, 1, true} };

//Create the single segment
SegmentPS ringSingleSeg = { ringSingleSec, SIZE(ringSingleSec), false };

//Create the segment set
SegmentPS *ringsSingleSeg_arr[] = { &ringSingleSeg };
SegmentSetPS ringSingleSet( leds, NUM_LEDs, ringsSingleSeg_arr, SIZE(ringsSingleSeg_arr) );

When effects draw on the segment set, it is treated as a 1D line because it only has a single segment, this is the yellow line in the layout diagram above. The Streamer effect works as normal, shifting bands of color along the single line, however because the sections are "single", the color bands are copied along the whole rings. This is a quick way of "transposing" the 2D disk segment set.

The Streamer Effect Running on the Segment Set:

Note that for this example, I have changed the streamer length to 1, and the spacing to 3.

Example 4: Rings Split Into Halves, Each Half is One Segment:

In this example, we'll split disk into two halves by splitting each ring into two. We'll then combine the ring halves into two segments. This will cause effects to treat the segments as two parallel lines (although they'll be squashed into the half ring shapes). Note that we're defining the ring sections by simply cutting each 2D disk segment in half. This results in the section connections jumping around and the split line being offset. On the diagram below, the section connections are numbered in pairs, so that "0" connects to "0", "3" to "3", etc.

The Code:

//Rings split in halves, and join them into a two segments,
//so we have series of ring half sections, each belonging to one of two segments
const PROGMEM segmentSecCont halfSec0[] = { {0, 12}, {24, 8}, {40, 6}, {52, 4}, {60, 1} }; //The right half segment
SegmentPS halfSeg0 = { halfSec0, SIZE(halfSec0), true }; 

const PROGMEM segmentSecCont halfSec1[] = { {12, 12}, {32, 8}, {46, 6}, {56, 4}, {60, 1} }; //The left half segment
SegmentPS halfSeg1 = { halfSec1, SIZE(halfSec1), true };

//Create the segment set from the 2 segments
SegmentPS *half_arr[] = { &halfSeg0 , &halfSeg1 };
SegmentSetPS halfSegs( leds, NUM_LEDs, half_arr, SIZE(half_arr) );

The segment set setup is fairly straight forward, we're just splitting the rings in half. We've kept it simple by using long continuous sections, but this does result in the ring split being off-center, and the section connection points jumping around. Effects see this segment set as two parallel lines of equal length,so each segment line is 2 LEDs long. However, because the segments are mirrored in a back-to-front, disconnected kind of way (it's hard do describe in words), the segment line pixels are actually on opposite side so of the rings. In practice, this still looks good with a lot of effects (in fact, you get a lot of neat happenings because of the disconnected-ness).

The Streamer Effect Running on the Segment Set:

Example 5: Rings Split Into Halves, Each Half is One Segment in a Single Connected Line:

Looking back at the previous example, how would we perfectly split the rings in half so that they mirror each other? We also want the segment sections to form a continuous line, instead of jumping around. Tracing the segments is easy enough (see the layout diagram below), but actually putting it into code is more tricky.

For this situation, it may be easier to use a mixed section for each half, and just list all the LEDs. However, for learning purposes I'll do the layout using continuous sections.

Firstly, to trace a continuous line, some sections need to be reversed. We can handle this by setting their lengths to be negative, as explained here. Next, to mirror the segments, we need the center vertical line of LEDs to be shared between both segments. There's no problem with sharing pixels, but it makes the left side sections more complicated. The left half sections want to start or end on the top center LEDs, but the ends of the sections don't connect to these LEDs. To include them, we'll need to insert them as single length sections.

The code:

//To mirror the two ring halves, we need to have both segments share the center line of LEDs
//We also need to connect the ring halves so they form an unbroken line, instead of jumping around
//To do this we need to use negative section lengths because we need to connect at the end of some sections

//The right segment is fairly straight forward, with every other section being reversed in order to connect properly
const PROGMEM segmentSecCont halfCenSec0[] = { {0, 13}, {32, -9}, {40, 7}, {56, -5}, {60, 1} };
SegmentPS halfCenSeg0 = { halfCenSec0, SIZE(halfCenSec0), true };

//The left hand section is like the right hand, but we have a bunch of extra 1 LED segments
//This is because we need to include the top center line LEDs, which are the starting LEDs of each ring.
const PROGMEM segmentSecCont halfCenSec1[] = { {0, 1}, {23, -12}, {32, 8}, {24, 1}, {40, 1}, {51, -6}, {56, 4}, {52, 1}, {60, 1} };
SegmentPS halfCenSeg1 = { halfCenSec1, SIZE(halfCenSec1), true };

//Create the segment set
SegmentPS *halfCen_arr[] = { &halfCenSeg0 , &halfCenSeg1 };
SegmentSetPS halfCenSegs( leds, NUM_LEDs, halfCen_arr, SIZE(halfCen_arr) );

The code above creates the two mirrored segments. Like example 4, the effects treat the segment set as two equal parallel lines. However, unlike example 4, the segments are truly mirrored, so we get neat mirrored effects that snake into the center of the rings.

The Streamer Effect Running on the Segment Set: