Step-by-Step Tutorial: Showing a Youtube video on an RGB LED panel

This tutorial demonstrates how to show a video on an LED panel connected to a Point Runner. This is achieved by streaming a segment of your PC desktop to an Intel Edison mounted on the Point Runner over WiFi.

It illustrates some of the neat features of the Point Runner and contains code which will hopefully be useful for your own projects.

Requirements

Hardware requirements for this tutorial:

  • A PC
  • An Intel Edison
  • A Tektyte Point Runner
  • An RGB LED panel: https://www.adafruit.com/products/2294
  • A power supply capable of powering the LED panel
  • A WiFi network to connect the PC and Edison (the PC may be connected through Ethernet connection instead of WiFi)

System Overview

We will be writing a program which captures a section of your PC’s display as an image, resizes it to match the resolution of the LED panel, then sends the image to the Point Runner as a collection of UDP packets. The packets are received by a listener service running on the Edison, translated to display data, and sent to the Point Runner to be output to the LED panel. The listening service and Point Runner code is provided - the focus of this tutorial is using PointRunnerLib to generate and send content.

System Setup

  1. Ensure your PC is connected to the network.

  2. Mount the Intel Edison on the Point Runner and connect the power supply.

  3. Connect to the Intel Edison via the CONSOLE port and configure it to connect to your WiFi network. Note its IP address. Once it is connected to the network you can disconnect from the console port and log in via SSH instead.

  4. Set up the required libraries and services on the Edison using PointRunnerSetup/setup.sh, as described in the Getting Started with the Point Runner section

  5. If you have a Hexa LED Power Injector, connect it to the Point Runner and connect your LED panel to Channel 1. Connect the power supply to the injector board.

  6. If you do not have a Hexa LED Power Injector, connect:

    • the Data In line on the LED panel to the data output of CH1 on the Point Runner
    • the ground connection on the LED panel to the ground of CH1 on the Point Runner
    • the positive voltage output of your power supply to the positive supply rail of your LED panel
    • the ground of your power supply to the ground connection of your LED panel

Writing the Program

This program will be written in Processing 2.2.1. It will use the Oformative ScreenCapturer library to sample a section of your PC’s display, then use the PointRunnerLib to transmit the data to the Receiver program.

Before we begin, please ensure you have installed Processing 2.2.1 and the required libraries mentioned above.

First, we will write a basic program which captures a selectable region of your PC’s display. Since our LED panel is 32 pixels wide and 8 pixels high, our program will need to generate a 32 x 8 image. But 32 x 8 is only a tiny region of the average PC display, nowhere near big enough to watch a video! To avoid this problem, we will sample a much larger region of the display, then downsize the image to the required dimensions.

// Import the ScreenCapturer library
import com.onformative.screencapturer.*;

// Initialise a ScreenCapturer
ScreenCapturer capturer;


void setup()
{
   // Create a window with the right aspect ratio to show our 32x8 image
   size(640,160);

   // Create a new 32 x 8 ScreenCapturer running at 100fps
   // This will create a selectable window which captures a section of your display as an image
   // then downsizes it to 32x8 pixels
   capturer = new ScreenCapturer(32, 8, 100);
}

void draw()
{
  // Get the current image from the ScreenCapturer
  PImage screenImg = capturer.getImage();

  // Load the pixels of the image into a buffer for reading (will be important later)
  screenImg.loadPixels();

  // If the image pixel buffer is not empty (i.e. we have recieved a valid image from the ScreenCapturer)...
  if(screenImg.pixels.length>0)
  {
        // We want to view the downsized image to verify that everything is working as intended. To do this, we first
        // create a copy of the image to display to the user
        PImage dispImg = screenImg.get();

    // Now we will the display copy of the image 20x wider and taller so that we can see it better
        dispImg.resize(screenImg.width*20,screenImg.height*20);

        // Draw the display image to the screen
        image(dispImg, 0, 0);
  }
}

When you run this program you will see two windows. One is the ScreenCapturer, used to select the area of the screen to sample - drag it around and resize it to get a feel for how it works. The other shows the selected region of the screen downsampled to 32x8 then upsized by a factor of 20 - this is roughly what we expect to see on our LED panel at the end of the tutorial.

Now that we have a working screen capture system, we will add some code to send the data to the PointRunner.

This block of code imports the required libraries and initialises a Point Runner object. Add it to the start of the program, underneath the ScreenCapturer import and initialisation:

// Import library to handle UDP communication
import hypermedia.net.*;

// Import PointRunnerLib to streamline LED panel initialisation and communication
import PointRunnerLib.library.*;

// Initialise our PointRunner
PointRunnerLib pointRunner;

This code sets up the network connection and sends configuration data to the Edison. Add it to the end of the setup() function:

// Create a PointRunnerLib instance
pointRunner = new PointRunnerLib(this);

// Define the address to which UDP packets will be sent (put your Edison't IP address here)
// The Point Runner listens for UDP display data on port 6100 so that is where we will send the packets
pointRunner.configureNetwork("192.168.1.16",6100);

// Set up one panel 32 pixels wide and 8 pixels high
pointRunner.configurePanels(1,32,8);

// Define the gamma curves - this corrects the nonlinear brightness response of the LEDs
// in the panel. Feel free to experiment, but the default values here should work pretty
// well for most RBG LEDs
pointRunner.setGamma(2.2,2.4,2.8);

This code extracts the red, green ang blue colour data from each pixel in the image, then sends it as UDP data to the Edison along with the pixel’s x and y coordinates. The Edison stores this information in a 2D buffer, allowing it to recreate the image. Insert this code into your draw() function, inside the if() statement, underneath the image() command:

// Iterate through all pixels in the 32 x 8 image buffer
for (int i = 0; i < 256; i ++) {

  // Save the colour of this pixel to a temporary variable
  color tempColour;
  tempColour = screenImg.pixels[i];

  // Extract the red, green and blue channels from the colour
  int tempR = (tempColour>>16)&(0xFF);
  int tempG = (tempColour>>8)&(0xFF);
  int tempB = (tempColour)&(0xFF);

  // Send the colour data of this pixel to the Point Runner's display buffer.
  // To get the X-coordinate of the pixel we use i%32,
  // and to get the Y-coordinate we use floor(i/32)
  pointRunner.drawPixel(0,i%32,floor(i/32),tempR,tempG,tempB);
}

// Update the LED panel with the data from the (now fully loaded) display buffer
pointRunner.updatePanel(0);

The program is now complete.

Testing

Power up the Point Runner (with the Edison mounted) and power supply. Wait around 30 seconds for the Edison to finish booting. Once the boot has completed, run your Processing program - you should see a section of your screen displayed on the LED panel.

To play a video on the panel, simply open up a Youtube video on your PC and drag the Screen Capturer window over the top.