Maybe you’ve seen a persistence-of-vision (POV) illusion before: an array of bright LEDs on the spokes of a spinning bicycle wheel that magically paints colorful animations, light effects, and messages in the night. These visual effects are always good for a “Wow!” — but we’ll go them one better and build a 3-dimensional illusion: the POV Globe.
The term persistence of vision refers to a phenomenon of human vision: a light stimulus lingers as an aftereffect on the retina for about 1/10 of a second. When light stimuli are sequenced in rapid succession, they merge into one continuous image. Scientists still argue how much of this phenomenon is shared between the eye and the brain, but the effect is real — in fact it’s the basis for film and television.
In most POV displays, a linear (1-dimensional) array of LED lights rotates around a single point, like a bike wheel. By measuring their rotation rate and controlling their flashes with millisecond precision, we can create the illusion of a 2-dimensional image lingering in thin air.
In our POV Globe, we’re adding a new dimension. We rotate a curved array of LEDs around a rotational axis, like a planet. When the flashing LEDs draw images in the air — say, the continents of the Earth — the result is a 3-dimensional, spherical illusion: a globe! Of course, our globe can make other images — like the Death Star from Star Wars, a skull, or the Make: logo — appear magically in the room. It all depends on the perfect timing of the LEDs.
This project has 4 main parts: the electronics, which control at least 24–40 LEDs using an Arduino Nano microcontroller and 74HC595 shift registers; the POV Calculator software that breaks down an image into a bit-pattern that your globe can display; the Arduino sketch that breaks this pattern into segments and sends it to the shift registers; and, finally, the mechanics that rotate the LEDs. It’s a moderately difficult project, but with a little experience on the soldering iron and some woodworking and metalworking skills, it can be accomplished in a weekend.
The microcontroller’s job is to issue a predetermined pattern of binary pixels to the large number of LEDs. This data must be sent synchronously with the ring’s rotation, triggered by a magnetic field sensor (a Hall effect probe). But the Arduino has relatively few output pins, so we resort to a trick: We use simple shift register chips, which collect the serially transmitted data (8 bits per chip) and on command make the data parallel (available all at once) at their output pins. This strategy takes advantage of the Arduino’s high-speed serial (SPI) pins, requires much less programming effort, and greatly simplifies the wiring.
This build is just a suggestion. Once your first globe is working, you’re sure to come up with ideas for extensions or modifications. We couldn’t stop at just one!
The Rotor Ring
To make the rotor ring, you can use aluminum bar stock from the hardware store, but it may tend to buckle when bending. As a nice-looking alternative, we also tried polycarbonate plastic (trade name Lexan or Makrolon), 20mm wide and 3mm thick — it was flexible enough and problem-free to work with.
Avoid acrylic (plexiglass); it tends to splinter or stick when drilled, and the globe’s centrifugal forces could cause it to crack and fail.
Before bending, holes are drilled for the LEDs, the Hall sensor, the central axis, and the balancing weights. If you use a 4.9mm drill bit, you can press-fit 5mm LEDs tightly into the ring without glue.
TIP: When drilling the LED ring, it helps to use a drilling template to prevent the drill bit from “walking”.
The more evenly the holes for the LEDs are placed, the better the globe image will be. Since our drill press runs true (and center-punching plastic sucks) we made a small drilling template from aluminum scrap, with 7 holes spaced 6mm apart. After drilling 7 holes, we advanced it and drilled again, aligning it by putting an LED in the last hole drilled. Thus we succeeded in very accurate (and stress-free) drilling.
As a guide for bending our polycarbonate strip, we used a clay flowerpot approximately the diameter of our rotor ring. We wrapped the plastic strip onto this and fixed it with metal clips, then baked it in a kitchen oven for 10 minutes at 340°F (170°C). The result was a very evenly shaped rotor ring.
For our aluminum version, we sawed a wooden disc and curved the aluminum strips around it. The diameter of the disc should be at least 20%–30% smaller than the desired rotor diameter, since the aluminum strips spring back somewhat after bending.
For easier assembly and repair, we didn’t solder the LEDs to the circuit board, but connected them with female jumper wires. These come with a connector on each end; since we need just one connector per lead, we cut them to make 2 leads from each jumper. The cable ends are stripped a few millimeters and a piece of heat-shrink tubing is slipped over each one.
On each LED, the positive lead (anode, the longer leg) is bent outward at a 90° angle. The negative lead (cathode, shorter leg) is cut to 5mm–7mm in length and bent into a small eyelet. Then the positive lead is trimmed to 10mm–15mm long and the stripped cable end is wound around it, soldered in place, and insulated with the heat-shrink.
NOTE: It’s of utmost importance that you use the correct LED leads — otherwise nothing will light up later and the work will have been for nothing. The LED’s negative lead (cathode) is always a little shorter.
IMPORTANT: Because these connections could easily be broken by the globe’s high centrifugal forces and air resistance, we’re leaving the LED leads fairly long. Together with the heat-shrink, this offers some stress relief. After soldering and shrinking, test each LED to ensure that all is in order.
Now the LEDs are pressed with a screwdriver into the prepared rotor ring. If you drilled a hole larger than 4.9mm you’ll need a little glue. Lastly, the cathode legs are soldered together with copper wire and connected to the ground (GND) of the circuit board.
When the globe is spinning, the bit-pattern that’s output to the LEDs must always begin at precisely the right instant. The purpose of the Hall sensor mounted on the ring is to fly past a stationary magnet with each revolution. This triggers a hardware interrupt on Arduino pin D2, providing the “ignition timing” for starting each output. The output frequency is also calculated from the rotational speed so that the pattern can be sent at a matching speed.
Since the direction of the magnetic field doesn’t change, only a unipolar Hall sensor will work. The sleeve of a 4mm banana jack makes a perfect holder for the fragile sensor (see below); using its panel mounting nuts, you can adjust the distance to the magnet during final assembly. The sensor we protect with a drop of glue.
Our globe is controlled by an Arduino Nano. Since it has only 13 output pins and we’ve got 40 LEDs, we’ll use its SPI pins D10, D11, and D13 to control our 74HC595 shift registers. This makes it possible to drive a lot of LEDs on only 3 pins.
Each set of 8 LEDs in our globe is driven by one 74HC595 chip. (Ideally, your total number of LEDs should be divisible by 8.) The brighter the LEDs for a given power, the better. Blue and white LEDs generally achieve the highest brightness.
The blue LEDs that we used take 3V–3.4V at 20mA current. With our 5V supply voltage, they’ll each need a current-limiting resistor of 100Ω. The datasheet for the 74HC595 tells us it can withstand a maximum 70mA total current. If all 8 LEDs are turned on, theoretically 160mA would flow through a shift register, but we measure only about 70mA, and everything works alright.
For a super-bright LED version, we recommend you control the LEDs through additional drivers. An open collector Darlington driver like the ULN2803 would work; use a common anode on the supply voltage instead of a grounded cathode.
Power is supplied to the shift registers and LEDs via the voltage regulator on the Arduino. Since this can provide a maximum 500mA, we’re limited to 7 shift registers and 56 LEDs. For more LEDs, you can add a separate 5V regulator (see the project page online for details); this also applies with the aforementioned power drivers.
Since power is not always transmitted smoothly through our globe’s ball-bearing “slip ring,” we buffer the voltage in a 2200μF electrolytic capacitor. This then transmits power to the voltage regulator pin (Vin) of the Arduino and operates the built-in voltage regulator in the opposite direction. We protect the Arduino with a diode, but still — it’s an impermissible operating status that may well “Void Your Warranty.”
If you want to use more than 56 LEDs, you can, but you’ll need to add a separate 7805 voltage regulator with heatsink, and two 100nF 50V capacitors (see schematic below).
Wire It Up
This circuit is easy to wire on plain perf board. You can relocate the mounting holes and the components for even better balance — more on that later.
We clipped the corners of our perf board to fit in our rotor ring, then we distributed the IC sockets for the shift registers evenly on the right side. Leave at least 3 or 4 holes between each socket; you’ll need the space for soldering components.
Carefully position the 74HC595s so that their outputs QB–QH (pins 1–7) face the board edge, which allows you to have a shorter connection to the male headers for the LED cables. Between the chip outputs and headers, we soldered 100Ω resistors standing upright, to save space. For output QA (pin 15) on the other side of the chip, there’s room to solder its resistor flat.
The shift registers require common lines for ground (GND pin 8 and G or OE pin 13), supply voltage (VCC pin 16 and SCLR pin 10, the red line in diagram above), SPI clock signal (SCK pin 11, green) and register clock or latch release (RCK pin 12, yellow). These signals are passed along as a kind of tapped bus to all shift registers.
The serial data from the Arduino reaches the serial input of the first shift register (SER pin 14, blue) and then the data cascades from IC to IC — from the Q’H output (pin 9) of one to the SER input of the next one. In theory you could chain dozens of these chips together, but you only need 5 or 6 to control 40 or 48 LEDs.
On the left side of the circuit board, the Arduino and the remaining components are soldered. We mounted the Arduino on female headers so we can easily exchange it if we accidentally destroy one.
Balancing the Rotor
To support the circuit board, we found an 8.5mm aluminum tube with two flanges at the hardware store (Alfer #26228), but it’s only sold on the industrial market. You’ll have to wrangle something similar on your own to attach the board to the M8 threaded rod that serves as an axis.
For rotor balancing, we screwed 4 ball bearings onto a small wooden frame, suspended the rotor on these, and adjusted the weight ratios until the rotor could stop in any position (“indifferent” equilibrium). We had already drilled holes opposite the LEDs to affix nuts and washers (and the Hall sensor) as a counterweight.
This static balancing, however, does not replace dynamic balancing during operation; that can only be done experimentally with the finished globe. Patience is needed so that placement of weights on the speeding globe does not cause it to wobble like a failed washing machine.
Supplying Flying Power
Now we have to get power to our rotating circuit board. Since we could not find a suitable slip ring, we made an unconventional solution — using a ball bearing as a slip ring instead. Grounding is no problem; we use the motor housing and the threaded-rod axis for that. The supply voltage, however, comes through the ball bearing itself, which must be isolated from the axis for this purpose.
To make our insulating spacer ring, we cut the neck off a nylon wall anchor and pushed it between the bearing’s inner ring and the threaded rod. A 3/8″ faucet washer from the plumbing aisle insulates the bearing from the M8 nut.
As a drive for our rotor we used a beefy DC motor (Pollin #310529). The speed is regulated by a PWM motor controller for DC motors; we found one for just under $7 on eBay. Since perfect alignment of the rotor axis and motor shaft is very difficult to achieve, we use a flexible shaft coupling.
We installed doorstoppers on the stand’s feet as a vibration damper.
For the first tests we mounted the shaft at the upper end too, so we could run the globe even though the rotor wasn’t perfectly balanced. In our final version, we have omitted the “tree” (and the upper bearing) entirely.
TIP: Threaded rods under tension tend to become distorted, so don’t tighten the nuts too tightly. Alternatively, you could substitute ordinary 8mm steel rod, threaded only at the ends.
On the subject of power we had a terrific (but not yet practically implemented) idea — namely to power the rotor by a dynamo (electrical generator) to produce a power supply via bearings, making coils or slip rings completely unnecessary. So we could imagine coupling the axes of two identical motors rigidly, one of the motors is bolted to the movable rotor otherwise freely described. Due to the difference in rotational speed between the axle and the stator, current is generated. At a certain speed, an equilibrium between air resistance and power consumption will adjust. Our experiments in this direction are still pending.
To display, for example, continents on the globe, we need to turn our image into a bit-pattern that can be readily integrated into an Arduino sketch. I wrote the software POV Globe Calculator (PC only) to make this easy. You can download it here.
After starting the software, you’ll set the resolution of your globe: vertical (number of LEDs) and horizontal (how many vertical segments you want to draw). Then click on New Grid in the top left corner. Load a background image if you wish, then left-click on the pixels of your grid to draw them in (blue) or right-click to delete them again (Figure ). Clicking Invert will reverse them all.
When you’re done, click the Calculate button to automatically generate the code for your LED array. Just copy it into your Arduino sketch, or store it for later revision.
Fast Serial Output
As we’ve mentioned, to produce a flickering display that’s stable in mid-air requires perfect timing of the LEDs. In our first experiments we used the Arduino’s ShiftOut command to supply the shift register with data, but it was visibly faulty at higher speeds. Upon inspection we learned that ShiftOut is realized with the slow-walking digitalWrite command. There had to be a more positive and elegant method.
To go really fast (when it comes to synchronous serial data transmission) you want to use SPI — the Serial Peripheral Interface protocol. SPI can communicate at speeds up to one-half your processor speed. The Arduino Nano’s ATmega328p runs at 16MHz, which means our SPI speeds can be up to 8MHz. Each byte (8 LEDs) requires only 1 microsecond, so all 40 LEDs are supplied in 5 microseconds. Blazing!
Here’s a sample calculation for our purposes: If you aspire to have 30 revolutions per second and 40×150 pixels, you need to transfer 4,500 records per second, each consisting of 40 bits or 5 bytes — i.e., 22,500 bytes per second. So, a byte must be issued at a leisurely 44.4 microseconds, making an elaborate parallel data transmission totally unnecessary. Note that the SPI ports on the Arduino are pins 10 (SS), 11 (MOSI), 12 (MISO), and 13 (SCK); we’re not using pin 12.
Shift Registers — Pass It On
A shift register is a clocked logic circuit that stores and supplies a push of binary data. It consists of a series of flip-flops. With each clock pulse on the clock pin (SRCLK), one bit (state HIGH or LOW) is sent to the serial data pin (SER) and stored in the register at the first flip-flop location. On the next clock pulse, that bit is passed to the next space in the register and the first space is reassigned a new bit — like a bucket brigade. Thus, the data is always shifted by one digit at each clock pulse.
In a latching register like the 74HC595, the data is first loaded into an internal buffer, then copied all at once to the output register when the latch signal is received — a HIGH pulse on the register clock pin (RCLK). This way, we can transmit the next batch of data without disturbing the existing state of the outputs (and our LEDs).
When the shift register fills up spaces QA–QH, it overflows to the Q’H output (pin 9), which continues to pass new values along to the next shift register in the daisy chain, even while the latch isn’t being triggered.
You can download the Arduino sketch and follow along with the comments to see what the code is doing. In the declaration part of the sketch, we input the basic data for our globe. The image we’re drawing is stored in a 2-dimensional array. The first dimension is the number of shift registers, the second is the number of columns to draw (referred to in the program as segments). This entire block can be generated by our POV-Calculator and then just copied into the sketch.
To start, the SPI pins are defined as outputs. Since we need a defined state for the Hall sensor, we use INPUT_PULLUP to activate the Arduino’s internal pull-up resistor on pin 2. Next, the SPI interface and the interrupts are configured.
Now we need to know the time it takes for the LED strip to make one revolution, in order to calculate the interval between outputs of the individual columns of pixels. That is, for each LED in the strip, how long do we leave it on or off, to draw our image?
For time measurement, we use the Arduino’s 16-bit Timer 1. On the first hardware interrupt (INT0) from the Hall sensor on pin D2, the interrupt handler TIMER1_INT0_vect sets Timer 1 to zero. On the next interrupt, we read the timer again; this value now represents the time (in processor clock cycles) required for the LED strip to make one complete revolution. We now divide this value by the number of segments we want to display. The result is then assigned to the 8-bit Timer 0 as the correct interval for redrawing the LEDs.
With each release of this timer (overflow interrupt TIMER0_COMPA_vect) the update flag will be set to true. This signals the loop routine that a new set of bytes is to be sent to the shift register. At the beginning of the SPI data transfers, the latch pins (RCLK) of all shift registers are set to LOW. This signals the registers that new data is coming. SPI_shiftOut now sends one byte after the other to the register. At the end of transmission, the latch pins are again pulled HIGH, causing the collected data to appear in one fell swoop at the outputs.
To ensure a smoother image, we don’t recalculate the interval for Timer 0 for every tiny speed deviation; only for those above a certain threshold. This minimizes image “twitch” when the interval is reset. The hysteresis values 1 and 2 in line 100 are experimental and may be customized accordingly.
We have also programmed an ASCII character table for displaying text, and additional routines for animation, which you’ll find in the code downloads. So you can, for example, rotate your image presentation at variable speeds.
We’re excited to see what you’ll do with your own POV Globe — show us your build on the project page online!