Creating a 1 meter RGB POV display with Raspberry Pi and LPD8806 LED strips

First attempt to display a PNG image.

I set out to create a large POV display for a local quarterly art installation called The Urban Art Project, in Great Falls, Montana.  The space is 8 feet wide, 5′ 8″ tall, and around 17 inches deep.  Two 1 meter rotors fit nicely in the space.

Creating a machine that must run in a harsh environment for 3 months was the most challenging part of this project.  It was a challenge to keep the displays running without throwing money at them for better components.  Ultimately the motors failed, which were too expensive to replace.  My budget was up.  See the updated postmortem section for details of the many failure modes.  🙂

3d Printed Parts
CNC Machined Parts
A/C Motors Tested
Possible Enhancements
Photo Gallery


I wanted a project that would incorporate mechanical, electronic, and software elements, and eventually deliver a canvas to build artistic creations upon.  The spinning POV display has caught my attention for years because of it’s apparent simplicity, yet it requires all of the disciplines listed.  Based on what I’ve found with Google, there aren’t very many large format RGB displays.  Challenge accepted!


  • Must run continuously for 90 days.  Ideally longer.
  • Must withstand temperatures of 100 F degrees.
  • Must achieve a minimum of 5 frames per second.
  • Must achieve an angular resolution of <LEDs across> * pi, or at least 188 divisions.
  • Display PNG, JPG and animated GIF images.
  • On-site software update via WiFi.

Hardware Used

  • LPD8806 LED strips with 60 LEDs per meter.  LEDs the full length of the rotor.  This seems like a no-brainer, but it reduces the needed RPM for good persistence by a factor of 2.
  • WS8212 LED strips were used to prototype before I had the LPD strips.  They proved to be too slow for this display, just as Adafruit’s product page advised.
  • Raspberry Pi A+
  • 3.3v -> 5v level shifter for SPI communication and WiFi dongle.
  • Level shifter and power/led/sensor connections are mounted on an Adafruit perma-proto board.
  • Hall effect sensor US5881LUA.
  • Timing belt and pulleys to reduce A/C motor RPM and increase torque to rotor.
  • 6 conductor (2 amps each) 12mm slip ring.  2 conductors for +5v, 2 conductors for ground, 2 conductors for SPI communcation.  Rated to 250 RPM.  These units worked great for around 3 weeks when overdriven to around 500 RPM.
  • Custom built 4 conductor carbon brushed slip rings.  These worked adequately for the remainder of the project.  Very noisy digital connection.
  • Carbon fiber arrow shafts for rotor arms.
  • Machined aluminum rotor hub.
  • Skateboard bearings.
  • USB Wireless Adapter 802.11n/g/b
  • Linksys WiFi router with dd-wrt router configured to bridge from my Samsung hotspot.

3d Printed Parts2015-09-14 11.02.27

  • Timing pulleys (
  • Hall effect sensor mount
  • LED strip mount to arrow shaft mounts
  • Motor fans
  • Bearing blocks for main rotor shaft.

CNC Machined Parts12015154_10153610779218088_4908512399410608213_o

  • Rotor hub
  • Motor mounts
  • Enclosure legs and back

A/C Motors Tested

  • Random 9″ fan motor – I threw this one out.  Similar to the 4M076D, but smaller.  Way underpowered.  4:1 pulley ratio resulted in around 200 RPM at the rotor.
  • Dayton 4M076D – 1/40 HP, 3000 RPM – underpowered, cooled with a desk fan, with 7.8:1 pulley ratio the rotor turned at ~250 RPM.  Got almost too hot to touch, but not as bad as the smaller, similar motor.  This was a bargain find at a local motor shop.
  • Dayton 3M563B – 1/40 HP, 1550 RPM – plenty of power but no built-in fan, so it required additional cooling.  This was a used motor that eventually died.  I decided to not pursue this one because of the cooling requirement.
  • Holmes 20″ box fan (Target) – Currently testing with a 6.5:1 pulley ratio.  I added a 120mm fan to the front of the 30 tooth pinion.  Rotor speed is ~320 RPM, and the motor is comfortably warm to the touch after over 1 hour.  Overnight tests showed excessive heat.
  • Century Motor # 419 – 1/15 hp 1550 RPM 115/230V CCWSE TEFC 3.3″.  This was the final production motor.  I ordered two and both ultimately failed.  The retainer clips on the main shaft wore out.  I was able to rebuild them by shimming the axle with washers.  These worked sufficiently but were not highly reliable.


The software stack was based on a standard Raspian image.

Initially I developed test routines for the LPD8806 and WS8212 strips using C code samples.  These were great for quick testing and making sure things worked.

Once I incorporated the hall effect sensor and prepared to display images, I needed access to GPIO and more rapid development.  I started using Python and the AdaFruit GPIO library which supported GPIO interrupts.

Pure Python was sufficient for test patterns and displaying static images.  I was able to achieve around 150 divisions per rotation at 250 RPM, using the PIL and Pillow image libraries.

Once I started working on GIF animations it became clear that I needed more speed. Python was doing too much behind the scenes to achieve decent performance.  I started work on a C-based framebuffer extension for Python which: initialized the SPI bus, set up double buffering for smoothness, monitored the hall effect sensor to determine refresh rate, calculated angular lines interpolated from the frame buffer, and finally, fired those arrays of data down the SPI bus to the strips.

The Python script imported the C extension and used the frame buffer directly via the PySDL library.  I could then use the SDL drawing routines to draw lines, text, and images directly into a fast and simple RGB buffer.

The Python+C implementation yielded over 400 divisions per rotation at 500 RPM – a huge improvement over pure Python.

Possible Enhancements

  • Rotary encoder – Every motor exhibits a certain amount of jitter in it’s rotation speed.  Using a single Hall effect sensor allows the software to determine the rotor’s position and speed once per revolution.  So you occasionally see the display rotate a few degrees for a single frame, then recover.  This effect looks cool and retro, but could be prevented.  Using a rotary encoder would allow the software to correct speed variations many times per revolution.  Combined with a Hall effect sensor, a very steady image could be created.
  • Properly rated motors – Using inexpensive motors with homebrew cooling allowed this project to happen, but if money were no object, the clear choice is a TEFC (enclosed, fan cooled) motor of appropriate size.  These start at around $100 each.  I ended up paying $115 each for motors that were still lacking.
  • More LEDs – Using LPD8806 LEDs, a C language frame buffer and SPI driver, twice as many LEDs can be driven.  Especially on a faster Raspberry Pi.  The current setup incorporates a delay after each update to minimize CPU usage. An FPGA is a cool exercise, but is not strictly needed.


These displays were subject to temperature extremes from below freezing to over 100 F.  They were in a black painted display case, in direct sun at times, and in an unheated space in the Montana winter.  Adhesives and materials fail quickly at those extremes.  Here are some things that failed…

  • Double sided 3m tape used to mount the LED strips failed.  This was possibly the first failure.  Extreme heat in the daytime and centrifugal forces caused the tape to fail on one display.  The strips flapped loose and eventually the data and power wires broke loose.  The strip was then thrashing around tethered by a ziptie at the end of the rotor shaft.  Luckily it didn’t break the window.  The strip eventually caught on the enclosure legs and stripped the teeth from the drive pulley.  Much of the strip’s LEDs were damaged, and I was forced to replace the entire strip.  I solved this by securing the strips with black zip ties along the full length of the rotor shaft.
  • Inexpensive slip rings failed. The slip rings allowed the power, ground, and two digital signal wires to pass from the stationary Raspberry Pi into the rotating hub. I was hoping I could overdrive these for a while, but they failed faster than expected.  It started with digital noise appearing in the image.  Eventually, the image became completely unrecognziable, or failed to display if the power and ground connections failed.  I used 3 of these slip rings, then proceeded to design my own replacement.
  • Motors failed.  After testing several options, I bought fairly expensive TEFC (Totally Enclosed, Fan Cooled) motors rated for continuous duty.  These were the recommendation of the salesperson at a large motor seller on ebay.  I expected these to run without issues, but both eventually failed.  In both cases, the retainer clips on the motor shaft wore away, causing the bearings to rub on the motor housing.  Heat then destroyed the bearings and they seized.  Protection circuitry luckily kicked in and prevented them from catching fire.
  • Small LED strip failures.  Several random LEDs failed, which was likely due to vibration.  Their solder connections had broken, so a quick reflow with some flux solved the problem.  For future projects I would construct a continuous mounting bracket for the entire strip to be stuck to.  It would be more rotating mass, but would solve this, and the mounting problem listed above.

Ultimately the strips lasted most of the 3 month planned installation.  I’d like to try this again some day, using what I’ve learned.  Meanwhile I’ve created another LED installation for the same community art project, this time with no moving parts.