Design advice for 1600 LED array installation please

Status
Not open for further replies.

billtubbs

Active member
Hi, I'm looking for some advice on the best way to connect up two Teensy controllers and a Raspberry Pi 2 in different configurations.

The Project

I'm building an irregular array of about 1600 LEDs as a kind of art installation. Got two Teensy 3.1s each driving half of the LEDs using the excellent OctoWS2811 library by Paul Stoffregen (thanks so much!).

The Goal

I want to be able to do a wide range of things with the display, some of which will need a lot of numerical processing (e.g. Complex wave simulations or image processing) and others not so much (e.g. Show a clock face).

The Problem

The two Teensy's will be be permanently mounted in the LED display with USB ports on the outside so I can program them either with a laptop or the Raspberry Pi.

The questions are:

1. What's best way to communicate with both Teensy's in real time when I want the Raspberry Pi to be the central processor and the Teensy's to be 'slaves' just updating the LEDs? I've figured out basic serial communication through the USB cable but I don't know if there are better ways of transmitting synchronous data fast (USB-Bridge perhaps?) to two Teensy's at the same time.

2. What if I want to run the display without the Raspberry Pi for simple tasks? Then the two Teensy's need a way of communicating with each other if they are sharing the processing task and sharing data to keep each other up to date on each half of the display. Again, what's the best way to connect two Teensy's for this purpose?

Note: I need to be able to switch between each mode of operation as needs be.

Thanks!
 
You are trying to build a distributed parallel computer with redundancy here, so doing it right isn't going to be easy. That said it's by no means impossible either. The easy choice is probably using the hardware serial port for inter Teensy Communication, possibly paired with the existing frame sync pin to trigger the actual display. The fun way to do it would be parallel pattern generation, with the serial traffic parsing the seed numbers for your pattern, but a frame of 800 LEDs is only 2400kb so do-able as a raw pixel stream. That said some basic compression would help, for starters while WS2811 LEDs are nominally 24 bit colour with 256 levels per colour the actual useable bit depth is closer to 32, so turning those three bytes per pixel into 2 works. Compressing them into a single byte is also doable if you can preload a colour table. After all that's what VGA did.

If you want to simplify the parsing code add a frame sync and data/command line to the inter teensy loop. Frame sync triggers the the write of whatever has been sent to the actual LEDs (rather than just 'whenever the frame fills' which will have variable time if compression is happening), and also retriggers the counter that tracks which pixel the streaming data refers to while the data/command line means you can send 'mode change' commands without having to have special escape characters eating into your colour bits, and makes the handling of dropped serial bytes more robust over header commands encoding length.

Pi's have a 3.3V hardware UART so perfectly possible to use the same interface Pi ->t1 ->t2 though getting real time hardware pin changes on a PI is a bit fiddly.

SPI and I2C are also possible for any of the legs and may give higher data rates, though as always higher data rates always mean shorter useable distances.
 
Thanks GremlinWrangler. This is really helpful advice and I am investigating your recommendations. Much appreciated.
 
1. What's best way to communicate with both Teensy's in real time when I want the Raspberry Pi to be the central processor and the Teensy's to be 'slaves' just updating the LEDs? I've figured out basic serial communication through the USB cable but I don't know if there are better ways of transmitting synchronous data fast (USB-Bridge perhaps?) to two Teensy's at the same time.

USB Serial is by far the most efficient. One Teensy will appear as /dev/ttyACM0 and other other as /dev/ttyACM1. Which is which depends on factors outside your control, so it's best to put the info onto each Teensy and query it from the RPi. See the VideoDisplay example.

Use a Multi-TT USB hub between the RPi and both Teensys for best performance.


2. What if I want to run the display without the Raspberry Pi for simple tasks? Then the two Teensy's need a way of communicating with each other if they are sharing the processing task and sharing data to keep each other up to date on each half of the display. Again, what's the best way to connect two Teensy's for this purpose?

Serial1 is the simplest.

If the distance isn't long, you can connect GND to GND, TX1 to RX1 and RX1 to TX1. If the distance is within a few feet, a 100 ohm resistor at each TX1 pin and keeping the 3 wires close or inside a shielded cable might work. For long distance, you might need RS232 (1 wire per signal) or RS485 (2 wires per signal) chips to get the signals reliably send and received between the boards. RS232 is very reliable up to about 20-50 feet. RS485 works up to thousands of feet.
 
Thanks PaulStoffregen. This is great. My Teensy's are right next to each other so I will connect the Serial1 pins directly. Also, I'll investigate what a Multi-TT USB hub is because I was just going to use two USB cables. Maybe I could put this hub inside the display so then I would only need one cable from the RPi to the display. Presumably I could power the hub from the 5V supply inside the display.
 
When the hub is connected to your Raspberry Pi, or any Linux machine, you can use "lsusb -v" to get lots of info about it and all other connected USB devices.

For example, here's info about one of the hubs connected to my Linux desktop machine:

Code:
Bus 002 Device 121: ID 2109:2812  
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.10
  bDeviceClass            9 Hub
  bDeviceSubClass         0 Unused
  bDeviceProtocol         1 Single TT

As you can see, it's a cheap Single TT type. :(

Often these cheap ones are fine, especially when you only have 1 full speed (12 Mbit/sec) or low speed (1.5 Mbit/sec) device, or when no 2 devices use significant bandwidth at the same time.

But when you have two of more Teensys (which are 12 Mbit/sec) doing lots of communication, a Multi-TT hub will allow much better sharing of the upstream 480 Mbit/sec connection.
 
Last edited:
... a Multi-TT hub will allow much better sharing of the upstream 480 Mbit/sec connection.

Project is coming along and I have all three devices communicating now!

I have been using my own protocol for serial communications between the devices but now I want to open up the code to other users and I wonder, should I rather adopt a standard?

I've been looking at Firmata (which has your name on it!). It looks good but it's very general purpose and I wonder if it adds too much unnecessary functionality given my specific custom application here (driving 1593 LEDS using your OctoWS2811 library). How compatible is Formata with OctoWS2811?

What do you recommend?
- Use an industry standard protocol like Firmata
- devise my own protocol that suits my specific needs

B.t.w. the host is a Raspberry Pi running Python scripts.

thanks your advice is much appreciated!

161231photo_LEDdisplay.jpg
 
Last edited:
USB Serial is by far the most efficient. One Teensy will appear as /dev/ttyACM0 and other other as /dev/ttyACM1. Which is which depends on factors outside your control, so it's best to put the info onto each Teensy and query it from the RPi.
What I have done in the past is use udev rules to handle cases like this. From my RPI notes, I used to have a couple of FTDI devices that would attach to my robot, so in this case they showed up as /dev/ttyUSB0 and ...ttyUSB1.

I would then find out information about these devices using a command like: udevadm info --query=property --name=ttyUSB0

Which gives lots of information about the devices and then create a /udev/rules file like the one the Teensy needs on a Linux machine.

On one machine I had a file 99-usb-serial.rules which contained:
Code:
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="A800fclo", SYMLINK+="ttyXBEE"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="A4014UWE", SYMLINK+="ttySSC-32"
Again this was FTDI, but it created two new symbolic links: /dev/ttyXBEE and /dev/ttySSC-32 Then my code could always look for these files and took away the issue of sometimes the device was /dev/ttyUSB0 and other times /dev/ttyUSB1
 
... my code could always look for these files and took away the issue of sometimes the device was /dev/ttyUSB0 and other times /dev/ttyUSB1

Thanks KurtE. I may look into that method but I already solved that problem. I used some serial communication whereby each Teensy is asked to report who they are and then they are thus identified by the RPi. Here is my Python code to find all the Teensy's on the USB port. I'm not sure if it is robust but it works for me. It relies on the fact that my Teensy's always seem to connect with a name that starts with 'ttyACM'.

Code:
addresses = ('/dev/ttyACM0', '/dev/ttyACM1')


class Display1593(object):
    """Irregular LED array driver class."""

    def __init__(self):
        self.tys = None


    def connect(self, addresses=addresses):

        print "Finding Teensies..."

        tty_files = []
        for file in os.listdir('/dev'):
            if file.startswith('ttyACM'):
                tty_files.append(file)

        print "Trying to connect to Teensies..."

        self.tys = []
        for a in tty_files[0:2]:
            self.tys.append(Teensy('/dev/' + a))

        if len(self.tys) != 2:
            raise Display1593Error("Could not find two Teensies to connect to.")

        for t in self.tys:
            t.connect()

        if self.tys[0].name == 'Teensy2':
            self.tys[0], self.tys[1] = (self.tys[1], self.tys[0])
            print "(Teensies swapped)"

        if (self.tys[0].name, self.tys[1].name) != ('Teensy1', 'Teensy2'):
            raise Display1593Error(
                "Could not find the right pair of Teensy controllers.  "
                "Found these instead: %s, %s" % (
                    self.tys[0].name,
                    self.tys[1].name
                )
            )


If you have any advice on the serial communication protocol question I just asked it would be much appreciated!
 
Last edited:
Just returning to this post to ask a follow-up question. I just learned about I2C protocol:

I2C addresses several drawbacks in the other communication protocols, giving it an advantage over the others in some applications. These include:
- The ability to connect multiple masters to multiple slaves
- Synchronicity (just like SPI), which means higher speed communication
- Simplicity: implementation only requires two wires and some resistors

Any reason why this wouldn't be a good idea for my application here?
 
Yes! Same project. It’s been working quite well for a few years but I’m struggling with a few communication issues. E.g. trying to get the RPi (master) to send the data for all LEDs to both Teensys (slaves) fast enough over the USB to change the whole display before one of them refreshes. Might just be a syncing issue. Also I’m getting some corrupted data transmissions now and then. Maybe the wireless transmitter?
 
Have you considered using sACN or artnet? Requires You to neteork them up. One teensy can do several thousand leds synced by a raspberry pi. It’s a major shift from what your doing but it works well
 
Have you considered using sACN or artnet? Requires You to neteork them up. One teensy can do several thousand leds synced by a raspberry pi. It’s a major shift from what your doing but it works well

To be more clear, this is my current setup:

led_display_architecture.jpg

I'm wondering if there is a better (easier, faster, more reliable) way to handle the communication between the Raspberry Pi Zero and the two Teensies. There is no problem with the Teensies controlling the LEDs. That is working well but I have to write code for them to listen and receive instructions and data from the RPi to change some or all the LEDs intermittently. The maximum size of a data communication to each Teensy is 798 x 3 bytes but two of these 'packets' have to be sent by the RPi and I'm not sure how to get them both sent and received before both Teensy update the LEDs (they are synced together and update at the same time).

Would sACN or artnet work for communicating bytes between RPi and 2 Teensies?

Also I was advised that each Teensy can only handle about 1000 LEDs, hence I used two in parallel.

I'd like to stick with what I've got first and see if I can get it working but just wanted to make sure there isn't a simpler solution out there since I'm running into a few problems (which maybe are solvable).
 
My current setup I can handle 5440 pixels on one teensy3.2.

This one is about 1600 pixels


Rpi has no problem controlling this setup. Check out falcon pi player project and the enormous lights they control. Again this is a big direction change for your current setup but works well. If your able to adapt your code to artnet or sACN then it’s worth Considering. There is syncing abilities with artnet and sACN.

I would think that what you have should be able to factor in a sync method. Typically it’s the start of the serial data with a unique character that could tell both teensy to “frame or led send”
 
Status
Not open for further replies.
Back
Top