Program your BlinkyTape using Processing

OK, so you want to make a program that runs on your computer and sends instructions to your BlinkyTape? That’s fabulous, and you’re in the right place. (If that’s not you, sorry, you’re going to have to find training techniques for canine agility somewhere else.)

The easiest platform to program for BlinkyTape is called Processing, which is a special language and development environment intended for visual art largely based on Java. It’s what the BlinkyTape team originally used to prototype PatternPaint, so we can definitely help you get started.

Install Processing

The Processing development environment runs in Windows, Mac OS X, and Linux.

BlinkyTape is known to work with Processing version 2.2.1.

You can find downloads and detailed install instructions for your platform on the Processing Getting Started page.

Install the BlinkyTape Processing Libraries

Now that you have downloaded Processing, it’s time to download some helper code and examples. This stuff lets us make our programs a bit more simply than if we had to do everything from scratch, as you’ll see later on.

Get it.

Here is the link to what we want. This is a live GitHub repository, so it should always be up to date. Use the “Download ZIP” link on the right of the page.

Install it

Unzip this folder in your Processing libraries folder – this is located at Documents/Processing/libraries on Mac or My Documents\Processing\libraries on Windows.

Important: When you unzip the file, the resulting folder will probably be called something like BlinkyTape_Processing-master — delete everything after the underscore, or Processing won’t import the library. (It doesn’t like special characters.)

Install the ControlP5 library

The last step before firing up PatternPaint is to install a Processing library called “ControlP5.” This helps us draw interface elements.

Luckily, Processing 2 has a way to easily install ControlP5 without downloading it separately. In Processing, open the Sketch menu, followed by Import Library, then Add Library. A new Library Manager window will appear. In the “Filter your search…” box, type in ‘controlp5’ and click the ControlP5 item that appears to install it.

If you have any trouble, here’s some more info about libraries for Processing including instructions for manually installing libraries. If you need to install it manually, you can download ControlP5 from the ControlP5 home page.

Restart Processing, if it is running.

You should now see the BlinkyTape examples if you go to File | Examples. This will open a chooser-type window so you can scroll through all of your installed examples for Processing. You’ll find ours in Contributed Libraries | BlinkyTape.

The Simplest BlinkyTape Program

Here’s a Processing sketch that talks to your BlinkyTape in just about the simplest way possible. Just paste this in to a new Processing window, plug in your BlinkyTape, and press the ‘play’ button in the upper right. In a few moments, you should see a slowly-changing rainbow.

Here’s the code:

// The simplest possible way to talk to a BlinkyTape
import processing.serial.*;

Serial s;

void setup() {
// Connect to the first serial port we can find
// We assume there is a BlinkyTape there
  for(String p : Serial.list()) {
        // NOTE: you'll need to change the next line to match the serial port system, i.e. COMx on Windows
        if (p.startsWith("/dev/tty.usbmodem")) { 
        s = new Serial(this, p, 115200);
        }
  }
}

float phase = 0;

void draw() {
for(int i = 0; i < 60; i++) {
    // Make up a pretty color based on the current phase      
    color c = color((sin(phase*.9         +i*.2)+1)*128,
                    (sin(phase     + PI/2 +i*.2)+1)*128,
                    (sin(phase*1.1 + PI   +i*.2)+1)*128);

    // Send the color for the current LED to the strip,
    // being careful not to send 255 (because that would
    // cause the strip to display the pixels
    s.write((byte)min(254, red(c)));
    s.write((byte)min(254, green(c)));
    s.write((byte)min(254, blue(c)));
}

// Send a 0xFF byte to the strip, to tell it to display the pixels
s.write((byte)255);

phase += .1;
}

Most everything here is in the single for loop within the draw() routine. It goes through 60 times (once for each LED on the BlinkyTape) and calculates a color value; it then sends each one over as an individual byte. Each LED on the strip gets three bytes, one each for red, green, and blue. Then, after the for loop ends, we send a byte with the value 255 (aka 0xFF) to tell the BlinkyTape to display the colors it just received.

Sending 3 x 60 bytes for color followed by a single 255 is about all it takes to talk to your BlinkyTape. This will always work, as long as you have a standard firmware on your Blinkytape. However, if you’re programming in Processing, you’re probably not going to want to use your BlinkyTape like this.

Using the BlinkyTape class

So now you’ve Processing installed, you have some example code, and you’re all ready to get going. Fantastic. Let’s get you going on a new project that demonstrates a helper class for using BlinkyTape with Processing, called (creatively) BlinkyTape. You’ll find it as a file called BlinkyTape.pde in several of the included examples, including the BlinkyTapeDirect. When you open that project, you can find this file already open in a tab — just copy & paste the contents of that tab into your Processing projects.

This class can be used in a couple of ways. You can use it to set pixels individually with a .pushPixel() method, and then call .update() when you’re done. There are also .getIndex() and .setIndex() methods so you can go right to setting the LED you want. There’s another very clever way to use this class, however, which is the .render() method. This takes an area of the screen and renders an approximation of it to an attached BlinkyTape. It’s neat because it lets you use the robust functionality for drawing that’s built into Processing and translate that into blinking LEDs!

If that sounds complicated, don’t worry — we’ll got through this in greater detail in these examples.

Let’s get started.

Go ahead and start a new Processing sketch and call it something like ‘BlinkyFoo’.

Grab the BlinkyTape class and add it to your new sketch

The easiest way to use a class in Processing is to add it in as another tab in your new sketch. Open one of the other examples from BlinkyTape using the File | Examples menu — I’d recommend ‘BlinkyDirect.’

This new sketch will open in a separate window and you’ll see that it has a tab called BlinkyTape. Click on that tab and copy the entire contents (command-a or control-a is your friend here, so you don’t miss anything.)

Go back to the new ‘BlinkyFoo’ sketch you created, then click on the down arrow near the tab.

BlinkyFoo

This will give you an option to create a new tab. Make a new one, call it ‘BlinkyTape’ and past in the code you copied. This is a common way to add classes in Processing.

Add this code

Download this code and paste it into your new project. You’ll also need to grab this image and save it in a folder called ‘data’ within your Processing sketch save folder. Again, that will be something like Documents/Processing/BlinkyFoo.

Let’s give it a go!

Plug your Blinkytape in and press the icon that looks like a play button in the upper-right-hand corner of the Processing window. If all goes according to plan, you’ll see a new window appear with that image you just downloaded, and a small rectangle in the middle. You can click the rectangle and move it around, and when you do that, you should see the colors changing to match (or at least approximate) what’s being displayed in the rectangle on the screen.

So, what’s happening here?

That’s a great question. There are a few things that you’ll want to pay attention to.

First, we declare an ArrayList of BlinkyTape objects and call it bt:

ArrayList<BlinkyTape> bt = new ArrayList<BlinkyTape>();

Next, in the processing "setup()" function:

// auto connect to all blinkyboards
  for(String p : Serial.list()) {
    if(p.startsWith("/dev/cu.usbmodem") || p.startsWith("/dev/ttyUSB") || p.startsWith("COM")) {
      bt.add(new BlinkyTape(this, p, numberOfLEDs));
    }
  }

Here, we’re trying to auto-connect to any serial port as if it’s a BlinkyBoard. We’re instantiating a new BlinkyTape object with each seemingly-valid serial port we find — this means it should work with several BlinkyTape strips (they will each show the same thing.) You might run into some trouble with this if you’re still on dialup, but hopefully it will work for now.

And here is where we ask the BlinkyTape to update:

for(int i = 0; i < bt.size(); i++) {
    bt.get(i).render(bx, by, bx + (scaleFactor * numberOfLEDs), by + scaleFactor);
    bt.get(i).send();
  }

We just iterate through each of our instantiated leds objects, and then we ask each of them to do a sendUpdate. The sendUpdate method takes four coordinates, takes a look at what’s there in the Processing image window, creates an approximation, and displays it on the BlinkyTape. Pretty cool right?

For some insight on the rest of the program, have a look at this Processing example.

Inside the BlinkyTape class

OK, great, so you’ve seen how to use BlinkyTape to render a section of your Processing window on your BlinkyTape. Great. Now, what happens if you want to go deeper?

Luckily, we can have a look inside to see how the BlinkyTape protocol works. What we’ll find is that we’re just sending three bytes to the BlinkyBoard (the BlinkyTape’s controller) to set the color for each LED. To actually make the tape display, we send it a single byte with a value of 255. That means each normal RGB value has a maximum value of 254, not 255 (more on this later).

So what else is in here?

As we saw earlier, the constructor takes the parent object, a string with the name of a serial port, and the number of LEDs in your strip. Right now, that’s 60 for all BlinkyTapes, but you never know…

BlinkyTape(PApplet parent, String portName, int numberOfLEDs) {

When you instantiate an BlinkyTape object, it creates a new Serial object for internal use.

To see what’s going on with the numberofLEDs variable, let’s go check out something in the render() routine we used earlier.

// Note: this should be sized appropriately
byte[] data = new byte[m_numberOfLEDs*3 + 1];
int dataIndex = 0;

So, here the method is creating an array of bytes that’s sized to have one red value, one green value, and one blue value for each LED on the strip – and one more byte at the end for that ‘255’ value which will make the strip update. And remember how we can’t send any 255 values? Here’s how we check when we’re assigning the variables:

data[dataIndex++] = (byte)min(254, r);
data[dataIndex++] = (byte)min(254, g);
data[dataIndex++] = (byte)min(254, b);

Not so fast…

OK, so now you’re thinking, awesome! Let’s just load up that array with 180 color values and that last ‘255’, then we just fire it off to the BlinkyBoard and we start blinking away. Well…that’s basically true, but with one notable exception: the serial communication for a tiny little Atmel-powered board is not very fast, and if we send too much data at once, we’ll crash it. Since that’s the case, we need to send the data in smaller chunks.

The BlinkyTape class has a master .update() method which just checks to make sure that the last byte is the right one to tell the tape to update itself, and then calls .send() That’s method that starts this process, and then a few other routines that work together to make sure that the little board’s USB serial doesn’t get all choked with data. Most of the heavy lifting takes place in the sendNextChunk() method, so take a look there. The quick version is that it seems like sending chunks of no more than 64 bytes keeps the BlinkyTape happy.

Troubleshooting

If the program fails to compile or upload, or the BlinkyTape is not doing what you expected, there could be a number of things to check.

Compile Errors

Sometimes, when you try to run your new BlinkyTape program, down at the bottom of the Processing window, you’ll see something like this:

processing_bork

This means that there’s a problem of some sort which won’t let your program compile properly. Often, it’s just a typo or another simple syntax error, like forgetting a semi-colon at the end of a line or using the wrong kind of parenthesis. If it’s a bigger issue, you might need to check out the Processing language reference or some of the other information available on the ‘webs. Pro tip: Google searching specific bits of code will often quickly lead to useful forum or stackoverflow pages.

BlinkyTape Not Acting Right

Uh oh. This is where it gets fun. ¯\(°_o)/¯

First off, save your program, close Processing, and disconnect your BlinkyTape for a moment. Then reconnect your tape and try it again.

This will fix a few common errors with the Java serial library. If that doesn’t take care of it, but your program is acting right, take a moment to look through your code, thinking your logic through. If you’ve borrowed from examples around the web, make sure that you haven’t skipped important parts. Go back to the language reference and make sure that your usage is proper. It might take some time to figure out what went wrong, but you’ll get to the bottom of things eventually.

But I don’t want to use Processing!

Oh man, sorry we went on about Processing for so long! We get it, you’re into Lisp or Haskell or Fortran or whatever. That’s great. We’re really happy about that, but we’re going to need you to help us spread support for BlinkyTape to other platforms. This Processing-based tutorial should give you a good idea about how to get started.

As it happens, there have been some efforts already. You can find some work for python here in a BlinkinLabs Github repository and we understand that there is a Perl module to be found in good old CPAN. Check out this usage example.

Last, we just want to say that we’re super excited to see the amazing things you come up with!