Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 13 of 13

Thread: Custom LED screen on Half sphere

  1. #1

    Custom LED screen on Half sphere

    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?

  2. #2
    Junior Member
    Join Date
    Oct 2019
    Location
    Lille, France
    Posts
    5
    I'm also interested to have some guidance for the exact same need, I'm wondering if the "different strips lengths" concept can be applied to VideoDisplay usage : https://www.pjrc.com/teensy/td_libs_OctoWS2811.html

  3. #3
    Senior Member crees's Avatar
    Join Date
    Dec 2016
    Location
    Utah
    Posts
    174
    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.

  4. #4
    Junior Member
    Join Date
    Oct 2019
    Location
    Lille, France
    Posts
    5
    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)
    Click image for larger version. 

Name:	2019-10-21 13_50_18-Window.png 
Views:	5 
Size:	27.6 KB 
ID:	17986
    (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:
    Click image for larger version. 

Name:	2019-10-23 11_13_57-Window.png 
Views:	1 
Size:	23.9 KB 
ID:	17987
    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 !

  5. #5
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    911
    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...D-strip-screen
    and
    https://forum.pjrc.com/threads/24699...ular-LED-array

  6. #6
    Junior Member
    Join Date
    Oct 2019
    Location
    Lille, France
    Posts
    5
    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?



    Hopefully I got this right

  7. #7
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    911
    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

  8. #8
    Junior Member
    Join Date
    Oct 2019
    Location
    Lille, France
    Posts
    5
    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!

  9. #9
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    911
    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.

  10. #10
    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.

  11. #11
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    911
    @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];
    }

  12. #12

    Lightbulb First Working Code

    Quote Originally Posted by mortonkopf View Post
    @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.

    Click image for larger version. 

Name:	matrix.PNG 
Views:	0 
Size:	46.1 KB 
ID:	18054

    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);
    }

  13. #13
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    911
    @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 ;-)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •