Custom LED screen on Half sphere

Status
Not open for further replies.

misterwilling

New member
Hi all,

I am starting a project that involves creating a custom sized LED screen on the inside surface of a half sphere. I plan on using about 1000 WS2813 pixels and each row will have a different number of LEDs since the arc length changes on each row.

I was planning on using a Teensy to control the LEDs and ended up buying a couple 4.0s. After researching further I’m wondering if I made the right decision on buying 4.0 since it is relatively new. I was hoping to output to all the LEDs in series, but I know that is kind of pushing it and I might have a low refresh rate. The alternative of output to different rows in parallel sounds good, but I didn’t know how much it would complicate setting up software like jinx.

Can anyone offer a suggestion if I should continue trying to use the 4.0 or switch to a version that has been out longer? Or if I use the 4.0 how difficult is it to setup the parallel outputs using a program like Jinx?
 
This is very doable and I have done it. The important question is, are your driving this via serial or by network protocol such as artnet or sACN. The octows2811 code will be common on both but the serial or Ethernet library will need to be decided. Look at my posts profile for Ethernet threads. This will get you going on the Ethernet direction.

https://m.youtube.com/watch?v=hO5ZvEu6pyM

Also if you are using different lengths you must set your leds per strip to your max length . Even if you don’t use them all on your shorter strips. Basically treat it like a use and loose it. Just map the pixels you need the rest just don’t get lighting data assigned and the empty array data gets shifted out of the shorter ends Anyways.
 
Hi,
Thanks for your reply. The “addressing” part is exactly what concerned me the most.

Here’s my matrix layout: (the whole matrix is 40x50, only around 1400 leds will be actually present)
2019-10-21 13_50_18-Window.png
(black = there a led, white = there isn't)

but if I set my ledPerStrip according to the number of leds that on the raw, I’m guessing ending up with something like this:
2019-10-23 11_13_57-Window.png
which will totally change the image, right ?

Assuming I’m using one Teensy GPIO per raw, is there a way to add an “offset” that will allow me to declare : “my strip is 10 leds longs and start with an offset of 8 leds from left to right” (based on 50 LED Matrix WIDTH)
Thanks !
 
It looks to be like you could use a led reference array. This is where you put the led number into an array that can be looped through in the usual plus one loop, but will grab the correct pixel info for the placement. This is done by putting the correct pixel place locations into the led array array in consecutive order. there is an example discussed at the following link, with the final post having the solution:
https://forum.pjrc.com/threads/28842-iregular-shaped-LED-strip-screen
and
https://forum.pjrc.com/threads/24699-Best-approach-for-non-rectangular-LED-array
 
Hi,

Thanks a lot sir!! the guitar shape example is kinda exactly what I'm looking for !

Based on that example, I guess I'll have to do the same (mapping each raw individually, which is ok for me) but I just don't know how to do so with the OctoWS2811 adapter split to 8 raws. If you have any guidance.

I also like the second idea of modifying copy Processing function (since I'm about to use it with movie2serial).

But taking a step back, I'm wondering where this modification should be done..
- On the video processing side to edit the frames to be sent to Teenys
- On the Teensys side to edit the full frames recevied

I would think it's more flexible to have it on the Teenys side so that I'm able to change the video source easily (from movie2serial to Touch Designer or Glediator for instance) but sending full frames is maybe not the best way in terms of performance?

:confused:

Hopefully I got this right
 
personally, I would leave all processing, Jinx and glediator output as standard, and do the pixel shifting at the Teensy end. This way you repurpose the code more easily for different input streams. The streamed frames will always use the same frame buffer, and the pixel mapping will always use the same process. the Teensy should have enough horsepower to take care of it for the number of pixels you are talking about
 
Right, great, thanks !

I start looking up some examples of OctoWS2811 Teensy code, and the to declare the matrix might be in here

Code:
OctoWS2811 leds(ledsPerStrip, displayMemory, drawingMemory, config);

in ColorWipe example, the ledsPerStrip is set simply
Code:
const int ledsPerStrip = 9;
and in VideoDisplay example, it's set to fit 1 teensy according with the offsets (I guess)
Code:
const int ledsPerStrip = LED_WIDTH * LED_HEIGHT / 8;

So my question is, how can I remap each ledsPerStrip.

I'm testing it on a 7x9 matrix with a "diamond" shape like this
Code:
static const int16_t ledStrip0[] = {3,4,5};
static const int16_t ledStrip1[] = {2,3,4,5 6};
static const int16_t ledStrip2[] = {1,2,3,4,5,6,7};
static const int16_t ledStrip3[] = {0,1,2,3,4,5,6,7,8,9};
static const int16_t ledStrip4[] = {1,2,3,4,5,6,7};
static const int16_t ledStrip5[] = {2,3,4,5 6};
static const int16_t ledStrip6[] = {3,4,5};

From source code (github), OctoWS2811 constructor numPerStrip (first) arg is a uint32_t, I'm a little bit confused on what to do next

Thanks a lot for all your help!
 
Hi, the way to get the led colour from the array of all the pixel data is to imagine the whole frame of pixel data in the buffer as a consecutive list of pixel values, and not to worry about what octows is doing. It will divide up the pixels the way you describe. The example you give:
static const int16_t ledStrip0[] = {3,4,5};
static const int16_t ledStrip1[] = {2,3,4,5 6};

should be something like:
static const int16_t ledStrip0[] = {3,4,5};
static const int16_t ledStrip1[] = {8,9,10,11,12};
static const int16_t ledStrip0[] = {20,21,22,23,24,25,26};
static const int16_t ledStrip1[] = {35,36,37,38,39,40,41,}; etc etc

the number in the curly braces is the led number in the consecutive grid of the image.
 
Thanks for the reply Nouk, glad to see someone else working on a similar project. I have opted to work with the Teensy 3.6 and OctoWS2811 as well.

Thanks for the help Crees and mortonkopf! I am following along and currently trying a similar small diamond shape matrix to work out the kinks before I move on to the full size display.
 
@nouk, following on from the above post, your led reference array would therefore be something like:

int myled[] = {3,4,5,8,9,10,11,12,20,21,22,23,24,25,26,35,36,...etc};

you image data is held in another array, for example

int imageData[] = {0x333333, 0x333333, etc...}

and when you come to access the image frame to put into the leds, your first led, number 0, would want the pixel info at the image location 3, led 1 wants pixel 4 info, led 2 want pixel 5, led 3 wants 8. etc. working your way through the led one by one, and working your way through the pixel locations held in the myles[] array one by one. This way you can write a for loop that places the pixel data in the right place fro the leds. Something perhaps like:

for (int x=0, x<mynumberofleds; x++) {
led[x] = imageData[x];
}
 
First Working Code

@nouk, following on from the above post, your led reference array would therefore be something like:

int myled[] = {3,4,5,8,9,10,11,12,20,21,22,23,24,25,26,35,36,...etc};

you image data is held in another array, for example

int imageData[] = {0x333333, 0x333333, etc...}

and when you come to access the image frame to put into the leds, your first led, number 0, would want the pixel info at the image location 3, led 1 wants pixel 4 info, led 2 want pixel 5, led 3 wants 8. etc. working your way through the led one by one, and working your way through the pixel locations held in the myles[] array one by one. This way you can write a for loop that places the pixel data in the right place fro the leds. Something perhaps like:

for (int x=0, x<mynumberofleds; x++) {
led[x] = imageData[x];
}

I followed these instructions and ended up getting code to work. Thanks so much for the help, I could not get this done without the help. I was originally trying a different route where I used an array to declare the amount of LEDs that were mapped. This seemed quicker than having to create an array for each pixel.
For example:

Code:
static const int16_t ledCountPerRow[] = {4,4,6,6,6,6,8,10,10,8,6,6,6,6,4,4};

My first attempt at this failed, so I went with defining an array that contained all of the led positions as described above and in the linked guitar example above. I ended up using a spreadsheet to visualize the LED locations and used copy paste from the SS to put the leds numbers in the array. I did it line-by-line this time since I was only doing 100 LEDs.

matrix.PNG

The code below is my first attempt so it may be a bit messy, and I'm a mechanical engineer so writing good code is not my strong point.

In my example I am using 2 outputs of the OctoWS2811. There are a total of 100 LEDs with each output controls 50 LEDs. Glediator is setup to control a matrix that is 10 wide and 16 tall. The program reads each frame in its entirety then runs the setPixel function for only the LEDs assigned in ledShape[] (I changed the variable name of "ledsPerStrip" to "ledsPerOutput" as it made more sense to me for this situation. )

Code:
// Glediator example with OctoWS2811, by mortonkopf
//
// https://forum.pjrc.com/threads/33012-Gladiator-with-OctoWS2811-working-example

// You can also use Jinx to record Glediator format data to a SD card.
// To play the data from your SD card, use this modified program:
// https://forum.pjrc.com/threads/46229&viewfull=1#post153927

#include <OctoWS2811.h>

const int ledsPerOutput = 50;
const int ledsPerRow = 10;
const int NUM_ROWS = 16;
const int NUM_LEDS_MATRIX = 160;
const int NUM_LEDS_SHAPE = 100;
static const int16_t ledShape[] = {3,4,5,6,
                                    13,14,15,16,
                                    22,23,24,25,26,27,
                                    32,33,34,35,36,37,
                                    42,43,44,45,46,47,
                                    52,53,54,55,56,57,
                                    61,62,63,64,65,66,67,68,
                                    70,71,72,73,74,75,76,77,78,79,
                                    80,81,82,83,84,85,86,87,88,89,
                                    91,92,93,94,95,96,97,98,
                                    102,103,104,105,106,107,
                                    112,113,114,115,116,117,
                                    122,123,124,125,126,127,
                                    132,133,134,135,136,137,
                                    143,144,145,146,
                                    153,154,155,156};

DMAMEM int displayMemory[ledsPerOutput*6];
int drawingMemory[ledsPerOutput*6];
int ledMatrix[NUM_LEDS_MATRIX];
// int pixelDrop = 0;
// int pixelCnt = 0;

const int config = WS2811_GRB | WS2811_800kHz;
OctoWS2811 leds(ledsPerOutput, displayMemory, drawingMemory, config);

void setup() {
  leds.begin();
  leds.show();
}

int serialGlediator() {
  while (!Serial.available()) {}
  return Serial.read();
}

void loop() {
  byte r,g,b;
  int i;

  while (serialGlediator() != 1) {}

  for (i=0; i < NUM_LEDS_MATRIX; i++) {
    
        b = serialGlediator();
        r = serialGlediator();
        g = serialGlediator();
        
        ledMatrix[i] =  Color(r,g,b);
      }
      
  for (i=0; i < NUM_LEDS_SHAPE; i++) {

        leds.setPixel(i, ledMatrix[ledShape[i]]);
      }

  leds.show();
}

/* Helper functions */
// Create a 24 bit color value from R,G,B
unsigned int Color(byte r, byte g, byte b)
{
  return (((unsigned int)b << 16) | ((unsigned int)r << 8) | (unsigned int)g);
}
 
@misterwilling. glad you got it working with the approach we discussed, it seems like a lot of work at first, but actually makes everything very straight forward and whats more, reuseable for different inputs. RE variable names. Yes, easily readable code works for me every time ;-)
 
Status
Not open for further replies.
Back
Top