LoL Shield

Halong Bay in Vietnam...obviously

Halong Bay in Vietnam…obviously

I was raised by the NES and Atari 7800. Just kidding, I had perfectly good parents. But I did play a lot of video games back in the day, and this has instilled within me a deep-seated nostalgic fascination with pixelation*. So once I got my LoL Shield all soldered up, I thought I’d make a tiny, super pixelated, monochromatic screen and come up with a method to translate whatever picture I wanted on to it.

*Interesting side-note: Firefox was telling me that I was spelling pixelation incorrectly (I’m not, Firefox just doesn’t have pixelation in it’s dictionary…kind of ironic, but not the interesting part of the side-note) so I looked it up, and in the process found the word pixilated (with an ‘i’ instead of an ‘e’), which derives from the word pixie. It can mean eccentric, mentally disordered, or whimsical…which, if you think about Italian plumbers eating mushrooms, jumping on turtles, avoiding man-eating plants…I don’t know, I thought the two words had some interesting parallels…

Soldering...lot's of soldering

Soldering…lot’s of soldering

In order to go from an image file to a LoL Shield image I created a grasshopper program that broke the image up into the correct number of pixels and then translated that into a text file that matched the format that the sample LoL Shield code used to control the LoL Shield LEDs.

Grasshopper definition that reads an image file and eventually converts it to a text output and also a Rhinoceros preview (read from left to right)

Grasshopper definition that reads an image file and eventually converts it to a text output and also a Rhinoceros preview (read from left to right)

The Grasshopper definition creates a grid with the same number of squares as the LoL Shield has LEDs, then brings in an image file with its built-in image sampler. It samples the image in each of the squares and converts the square’s average brightness into a number between 0 and 6. It then performs a series of list managing and string concatenating operations to get all those numbers into the same format that the LoL Shield Arduino code uses. This is important because it means the data can be directly copied and pasted…if the format was different at all, you’d have to edit each of 126 values every time you changed the source image. The final text is in the yellow box, ready to be copied. On the bottom right is a separate set of operations that converts the same data into Rhinoceros shapes (Grasshopper is a Rhinoceros plug-in…Rhino is a 3D modeling program) and then ‘bakes’ them into Rhino with each value on its own layer. If you then switch to the Rhino window and give each layer a different shade of gray (or whatever color) you can get a preview of what it will look like on the LoL Shield. (With a little extra work, the Grasshopper definition could be modified to assign the colors automatically…but adding that functionality is more work than assigning the layers manually, so I didn’t ever get around to it.)

Rhino LoLShield Preview

A gray scale preview in Rhino

 

Next you just paste the text into the ‘Basic LoL Shield Test’ code and upload it onto the Arduino and voila, a perfect replica of the image file. . . well, okay, as perfect as you can get with 9 x 14 resolution…

Original

Original

Halong Bay in Vietnam...obviously

You can almost make out the sailors on the ships…

Changing images is as (relatively) easy as changing the source image in Grasshopper, re-copy pasting, and re-uploading.

Original

Original

LoL Shield Version

LoL Shield Version

The images that work the best are ones with 3 fairly distinct ‘brightness regions’…dark, medium, and bright. It works fine if the image is just a high contrast black and white, but it’s kind of boring, and pictures with a lot of subtle gradation just don’t translate that well. One limitation is that, although the brightness of the LEDs are theoretically 0-255, I had problems with anything over 6, which is why I made the numbers range from 0-6. I think this was due to imperfect soldering on my part. I think there are some semi-shorted out areas that are fine with low amounts of power (up to 7 brightness), but short out at higher levels and cause erratic light flashing etc. Still, there’s a surprising amount of variation between brightness 1 and 6 (0 is off)

The Grasshopper definition, if anyone’s interested

And the Arduino code (although it’s basically just the sample code from the LoL Shield website…no modifications were really needed…other than the pattern itself):

/*
Basic LoL Shield Test

Writen for the LoL Shield, designed by Jimmie Rodgers:

http://jimmieprodgers.com/kits/lolshield/

This needs the Charliplexing library, which you can get at the
LoL Shield project page: http://code.google.com/p/lolshield/

Created by Jimmie Rodgers on 12/30/2009.
Adapted from: http://www.arduino.cc/playground/Code/BitMath

History:
December 30, 2009 – V1.0 first version written at 26C3/Berlin

This is free software; you can redistribute it and/or
modify it under the terms of the GNU Version 3 General Public
License as published by the Free Software Foundation;
or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <avr/pgmspace.h>  //AVR library for writing to ROM
#include <Charliplexing.h> //Imports the library, which needs to be
//Initialized in setup.

//Sets the time each frame is shown (milliseconds)
const unsigned int blinkdelay = 1000 / 50;

/*
The BitMap array is what contains the frame data. Each line is one full frame.
Since each number is 16 bits, we can easily fit all 14 LEDs per row into it.
The number is calculated by adding up all the bits, starting with lowest on
the left of each row. 18000 was chosen as the kill number, so make sure that
is at the end of the matrix, or the program will continue to read into memory.

Here PROGMEM is called, which stores the array into ROM, which leaves us
with our RAM. You cannot change the array during run-time, only when you
upload to the Arduino. You will need to pull it out of ROM, which is covered
below. If you want it to stay in RAM, just delete PROGMEM
*/

void setup() {
LedSign::Init(DOUBLE_BUFFER | GRAYSCALE);  //Initializes the screen
}
void loop() {
//  int b;
//  LedSign::Clear(0);
// // LedSign::Flip(true);
//  for (int y=0; y<=8; y++) {
//    for (int x=0; x<=13; x++) {
//       // LedSign::Clear(0);
//       b=y;
//       if (b<1) {b=1;}
//       if (b>7) {b=7;}
//        LedSign::Set(x, y, b);
//        LedSign::Set(5, 0, 0);
// LedSign::Set(6, 4, 0);
// LedSign::Set(5, 2, 0);
// LedSign::Set(5, 3, 0);
// LedSign::Set(13, 7, 0);
// LedSign::Set(6, 5, 0);
// LedSign::Set(7, 3, 0);
//       LedSign::Flip(true);
//      delay(250);
//    }
//  }
LedSign::Set(0, 8, 0);
LedSign::Set(0, 7, 1);
LedSign::Set(0, 6, 3);
LedSign::Set(0, 5, 2);
LedSign::Set(0, 4, 1);
LedSign::Set(0, 3, 1);
LedSign::Set(0, 2, 1);
LedSign::Set(0, 1, 6);
LedSign::Set(0, 0, 6);
LedSign::Set(1, 8, 0);
LedSign::Set(1, 7, 4);
LedSign::Set(1, 6, 3);
LedSign::Set(1, 5, 1);
LedSign::Set(1, 4, 1);
LedSign::Set(1, 3, 1);
LedSign::Set(1, 2, 6);
LedSign::Set(1, 1, 6);
LedSign::Set(1, 0, 6);
LedSign::Set(2, 8, 0);
LedSign::Set(2, 7, 0);
LedSign::Set(2, 6, 1);
LedSign::Set(2, 5, 1);
LedSign::Set(2, 4, 1);
LedSign::Set(2, 3, 1);
LedSign::Set(2, 2, 1);
LedSign::Set(2, 1, 6);
LedSign::Set(2, 0, 6);
LedSign::Set(3, 8, 0);
LedSign::Set(3, 7, 3);
LedSign::Set(3, 6, 0);
LedSign::Set(3, 5, 1);
LedSign::Set(3, 4, 0);
LedSign::Set(3, 3, 1);
LedSign::Set(3, 2, 6);
LedSign::Set(3, 1, 6);
LedSign::Set(3, 0, 6);
LedSign::Set(4, 8, 1);
LedSign::Set(4, 7, 3);
LedSign::Set(4, 6, 0);
LedSign::Set(4, 5, 1);
LedSign::Set(4, 4, 0);
LedSign::Set(4, 3, 1);
LedSign::Set(4, 2, 1);
LedSign::Set(4, 1, 6);
LedSign::Set(4, 0, 6);
LedSign::Set(5, 8, 0);
LedSign::Set(5, 7, 3);
LedSign::Set(5, 6, 3);
LedSign::Set(5, 5, 1);
LedSign::Set(5, 4, 0);
LedSign::Set(5, 3, 1);
LedSign::Set(5, 2, 6);
LedSign::Set(5, 1, 6);
LedSign::Set(5, 0, 6);
LedSign::Set(6, 8, 1);
LedSign::Set(6, 7, 4);
LedSign::Set(6, 6, 3);
LedSign::Set(6, 5, 4);
LedSign::Set(6, 4, 5);
LedSign::Set(6, 3, 5);
LedSign::Set(6, 2, 6);
LedSign::Set(6, 1, 6);
LedSign::Set(6, 0, 6);
LedSign::Set(7, 8, 1);
LedSign::Set(7, 7, 4);
LedSign::Set(7, 6, 2);
LedSign::Set(7, 5, 4);
LedSign::Set(7, 4, 5);
LedSign::Set(7, 3, 5);
LedSign::Set(7, 2, 6);
LedSign::Set(7, 1, 6);
LedSign::Set(7, 0, 6);
LedSign::Set(8, 8, 4);
LedSign::Set(8, 7, 4);
LedSign::Set(8, 6, 5);
LedSign::Set(8, 5, 2);
LedSign::Set(8, 4, 1);
LedSign::Set(8, 3, 4);
LedSign::Set(8, 2, 6);
LedSign::Set(8, 1, 6);
LedSign::Set(8, 0, 6);
LedSign::Set(9, 8, 3);
LedSign::Set(9, 7, 3);
LedSign::Set(9, 6, 3);
LedSign::Set(9, 5, 2);
LedSign::Set(9, 4, 1);
LedSign::Set(9, 3, 1);
LedSign::Set(9, 2, 1);
LedSign::Set(9, 1, 6);
LedSign::Set(9, 0, 6);
LedSign::Set(10, 8, 4);
LedSign::Set(10, 7, 3);
LedSign::Set(10, 6, 3);
LedSign::Set(10, 5, 2);
LedSign::Set(10, 4, 1);
LedSign::Set(10, 3, 1);
LedSign::Set(10, 2, 1);
LedSign::Set(10, 1, 6);
LedSign::Set(10, 0, 6);
LedSign::Set(11, 8, 3);
LedSign::Set(11, 7, 2);
LedSign::Set(11, 6, 2);
LedSign::Set(11, 5, 1);
LedSign::Set(11, 4, 1);
LedSign::Set(11, 3, 1);
LedSign::Set(11, 2, 1);
LedSign::Set(11, 1, 1);
LedSign::Set(11, 0, 2);
LedSign::Set(12, 8, 3);
LedSign::Set(12, 7, 3);
LedSign::Set(12, 6, 3);
LedSign::Set(12, 5, 1);
LedSign::Set(12, 4, 1);
LedSign::Set(12, 3, 1);
LedSign::Set(12, 2, 1);
LedSign::Set(12, 1, 1);
LedSign::Set(12, 0, 6);
LedSign::Set(13, 8, 2);
LedSign::Set(13, 7, 0);
LedSign::Set(13, 6, 0);
LedSign::Set(13, 5, 0);
LedSign::Set(13, 4, 0);
LedSign::Set(13, 3, 1);
LedSign::Set(13, 2, 1);
LedSign::Set(13, 1, 1);
LedSign::Set(13, 0, 1);

// LedSign::Set(5, 0, 0);
// LedSign::Set(6, 4, 0);
// LedSign::Set(5, 2, 0);
// LedSign::Set(5, 3, 0);
// LedSign::Set(13, 7, 0);
// LedSign::Set(6, 5, 0);
// LedSign::Set(7, 3, 0);
LedSign::Flip(true);
delay(500);

//  delayMicroseconds(5);
//  LedSign::Clear(0);
//  LedSign::Set(4, 3, 1);
//  LedSign::Flip(true);
//  delayMicroseconds(5);
}

Leave a Reply