Software

The Digital LED strip requires very fast data signal and you can't just use the GPIO libraries to do it. You must have hardware SPI installed, this is not included in the default "Wheezy" distribution and requires a firmware update, so please use Occidentalis!

On the software front, we started with “Occidentalis,” the Adafruit Raspberry Pi Educational Linux Distro. This has a few features baked in that make this project a lot simpler, including hardware SPI support…it’s super fast and easy, with no bitbang kludges required. Alternatively you can install SPI support yourself

Our light painting script relies on the Python Image module, which is not installed by default. With your Raspberry Pi connected to the internet, log in and type:

sudo apt-get install python-imaging

Occidentalis also has sshd built in, making it easy to get images from a desktop machine to the Raspberry Pi. For example, in a Terminal window on my Mac I could type:

scp image.png [email protected]:

Or use a secure FTP client:

Here’s the complete Python script for the light painting project. Even with lots of comments, it’s not a large program at all:
#!/usr/bin/python

# Light painting / POV demo for Raspberry Pi using
# Adafruit Digital Addressable RGB LED flex strip.
# ----> http://adafruit.com/products/306

import RPi.GPIO as GPIO, Image, time

# Configurable values
filename  = "hello.png"
dev       = "/dev/spidev0.0"

# Open SPI device, load image in RGB format and get dimensions:
spidev    = file(dev, "wb")
print "Loading..."
img       = Image.open(filename).convert("RGB")
pixels    = img.load()
width     = img.size[0]
height    = img.size[1]
print "%dx%d pixels" % img.size
# To do: add resize here if image is not desired height

# Calculate gamma correction table.  This includes
# LPD8806-specific conversion (7-bit color w/high bit set).
gamma = bytearray(256)
for i in range(256):
	gamma[i] = 0x80 | int(pow(float(i) / 255.0, 2.5) * 127.0 + 0.5)

# Create list of bytearrays, one for each column of image.
# R, G, B byte per pixel, plus extra '0' byte at end for latch.
print "Allocating..."
column = [0 for x in range(width)]
for x in range(width):
	column[x] = bytearray(height * 3 + 1)

# Convert 8-bit RGB image into column-wise GRB bytearray list.
print "Converting..."
for x in range(width):
	for y in range(height):
		value = pixels[x, y]
		y3 = y * 3
		column[x][y3]     = gamma[value[1]]
		column[x][y3 + 1] = gamma[value[0]]
		column[x][y3 + 2] = gamma[value[2]]


# Then it's a trivial matter of writing each column to the SPI port.
print "Displaying..."
while True:
	for x in range(width):
                spidev.write(column[x])
                spidev.flush()
		time.sleep(0.001)
	time.sleep(0.5)
The script needs to be run as “root” because it accesses the GPIO hardware, i.e.:

sudo python lightpaint.py

After opening the SPI device (for communicating with the LED strip), the script then loads an image using the Python Image module, converting it to RGB format if necessary. As an interpreted language, Python isn’t always the quickest thing…rather than repeatedly process each row or column of an image on the fly, the entire image is pre-processed once from the native RGB format into the hardware-specific format required of the LED strip, held in a list of bytearrays. We can then quickly dump each of these arrays directly to the SPI port without any further work. Decoding and holding all this intermediate data would be inconceivable on Arduino!

The software is smart enough that it will use the height of the image as the number of pixels to address. So if you have 64 pixels, make sure your images are 64 pixels tall, etc!
Last updated on 2015-09-09 at 03.55.50 PM Published on 2012-08-10 at 12.00.09 PM