Introduction: Persistence of Vision LED Staff
It is well known that even after a light has been turned off, human eye keeps "seeing" it for a fraction of second. This is known as Persistence of Vision, or POV, and it allows one to "paint" pictures by quickly moving a strip of LEDs, drawing one line of an image at a time in quick succession. If you search online (e.g. on Etsy), you can find quite a few toys based on this idea: pois, staffs, and more.
However, these are expensive: typical prices for a POV staff of decent resolution start at $500, and they use proprietary software, so there is no easy way to modify their behavior or add extra functionality. Thus, when looking for a birthday gift for a friend who enjoys painting with light, I decided to create my own open source version using readily available components.
My project builds upon the outstanding work of Phillip Burgess and Erin St Blaine from Adafruit; however, I made a few changes, upgrading the electronics.
Below are key features of this project:
- It is a two-sided staff, of total length 141 cm (55in); it is not collapsible. Each side of the staff has two 50cm/72 pixels LED strips, for the total of 288 LEDs. Thus, you can use it to show images with 72-px resolution.
- Staff is powered by two 18650 Li-Ion batteries, which should be enough for at least 1 hr show, possibly as much as 2 hours, depending on intensity of your images. The batteries can be recharged via micro-USB connector; full charge time is about 5 hrs.
- Images (in bitmap format) can be easily uploaded to the staff by connecting the staff to a computer, where it appears as a USB storage device. It has enough memory for about 50 images.
The order in which images are shown is described in a separate plain text file, where you can put a list of images and durations. An image can be listed there several times, or none at all.
- The staff contains an Inertial Motion Unit (IMU) which can be used to detect when the staff is in motion. The software uses it to adjust update frequency for images, so the images will not appear stretched or compressed regardless of how fast you are rotating it. You can also use it for controlling your show: e.g. stopping the staff horizontally is used as a signal to move to the next image in the slideshow.
- The software is based on Arduino IDE. It is available under an open source license and is easy to modify to suit your needs.
This project is open source; all code and schematics are available in my github repository under MIT license.
You will need the following supplies:
- APA102 (DotStar) LED strip, 144 LED/meter, black PCB, from Adafruit or Aliexpress. You need 4 strips of 50cm (72 LEDs); you can also buy longer strips and cut them into 50cm pieces. The strips should not be waterproofed. Adafruit strips come with waterproof sheathing which you can just remove and discard.
- Two 18650 Li-Ion batteries. Look for high-capacity (at least 3000mAh), protected batteries from a reputable manufacturer such as Panasonic, Samsung, or Sanyo; I recommend these batteries by Sanyo or Panasonic. Do not try to save money by buying no-name battery on eBay or Amazon.
- Polycarbonate tube, 11F(55in/141cm), 1 inch outer diameter, from flowtoys.com
- Two endcaps and tennis grip for the tube from Amazon
- 1/2 inch square wood dowel, from HomeDepot or any other hardware store. You need 4 ft (or two 2ft pieces)
- Adafruit ItsyBitsy M4 or ItsyBitsy nRF52840microcontroller. The nRF52840 is slightly more expensive, but it comes with Bluetooth, which opens many additional possibilities. However, current version of my code doesn't use Bluetooth - this is planned for future upgrades. Do not use 32u4 or M0 ItsyBitsy - they do not have enough RAM for our purposes.
- Custom POV shield board for ItsyBitsy and two custom power distribution boards designed by myself. You can make them yourself by downloading the schematics, BOM, and Gerber files from github, or buy all three together from my store on Tindie
- Rocker switch
- Wiring: it is best to use silicone-insulated wiring, as it is much more flexible than regular PVC insulated one. You need 20 AWG wires for power (2.5m red, 1 m black) and 24-26 awg for signal (two different colors of your choice, 50 cm each)
- 8mm diameter black shrink wrap tubing, 1 meter
- Three JST XH 4 position connectors with 15 cm or longer wire leads, 22awg. Such connectors are commonly used as balancing leads for charging lithium battery packs. Note that 4 position connector would be sold as 3s balancing lead (one lead for each of battery cells and one for common ground).
If you are comfortable crimping your own connectors, you can buy instead JST XH housing and contacts from Digikey or Mouser and make your own leads; this would simplify some of the steps below.
- 3d printed spacers and switch mount. The STEP files can be found in the hardware folder of the github repository. You will need 3 spacers and one switch mount. You can use any 3d printer and any kind of filament (PLA, ABS, ...).
- Narrow (2mm) black zipties. Note: most 4 in zipties have width of 0.1"=2.5mm, which is too wide for us - you really need 2mm or narrower.
- Breakaway male headers, 0.1"
If you are buying your LEDs from AliExpress and are prepared to wait 3-4 weeks for free delivery option, the total price of the components above would be about $150 (including shipping). If you are buying your LEDs from Adafruit, add $60 to the price above.
If you choose to spray-paint the wood dowels black for better look (recommended), you also need black spray paint.
You can buy the kit of parts which contains some (but not all!) of the above parts from my store on Tindie: https://www.tindie.com/stores/irobotics/. This way, you can avoid buying a pack of ten switches when you only need one.
You will need the usual tools and supplies: wire strippers, flush cutters, scissors, decent soldering iron, shrink wrap, electric tape, heat gun for shrinking the shrink wrap, sharp model knife or utility knife. Needless to say, you will also need a computer to program the microcontroller and a USB charger to charge the batteries.
It is assumed that you already have some experience with Arduino and with basic electronic projects, at least at the level of soldering headers to boards or splicing wires.
Step 1: Overview
The assembled staff will consist of the following subassemblies:
- Two 18650 batteries and wiring in the middle of the staff. The batteries are separated from each other and from LED assemblies by 3d printed spacers; total length of the batteries+spacers is about 28 cm.
- Two LED assemblies, one on each side of the staff. Each assembly consists of two 50 cm LED strips attached to a wood dowel. The LED strips will be soldered to a round power distribution board at the interior end of the dowel. The LED assembly are connected to each other and battery by JST XH connectors, plugging into the headers on power distribution boards.
- At one end of the staff, there is a switch, with two wires leading from it to the batteries in the middle and protected by endcap with an opening for the switch
- At the opposite end of the staff, the controller, consisting of the ItsyBitsy microcontroller attached to the custom POV shield board, protected by endcap. A 4-wire cable is plugged into the JST XH header on the POV shield; the wires run the length of LED assembly to the center
- Tennis racket grip tape covering the battery assembly in the middle of the staff, for better grip.
Step 2: Software
If you are using the kit of parts from my Tindie store which includes ItsyBitsy M4 (this option was added in Dec 2020), you can skip this step - the ItsyBitsy is already preprogrammed for you!
We begin by programming the ItsyBitsy microcontroller. This can be done in one of two ways:
- using a pre-built binary. This is the easiest method for people who have little or no programming experience. However, this doesn't allow you to customize the staff for your needs
- building from source. This provides most flexibility, as it is easy to modify the code for your needs, but requires some (very modest) familiarity with Arduino IDE.
In either case, you need to download the latest release from the github repository. Download Source code.zip archive (or Source code.tar.gz if you are on Linux); despite the name, this archive contains not only source code but also binaries and sample images. After downloading, extract it to a temporary location.
Using pre-built binaries
Connect your ItsyBitsy to the computer using a micro-USB cable. (If you are doing it for the first time, you might get a message about installing drivers; in this case, wait until it tells you that your hardware is ready to use.) Double-click the reset button; your ItsyBitsy should appear as an external drive on your computer, with a name like ITSYM4BOOT. Open that drive in your file browser window; inside you should see files CURRENT.UF2, INDEX.HTM, and UF2_INFO.TXT.
Now open in another file browser window the directory extracted from the downloaded archive from github. Find in it directory binaries and find there the subdirectory matching the type of Itsy Bitsy you have (M4 or nRF52840). Inside it, you will find two files: formatter.UF2 and povstaff-vX.X.UF2, where X.X is the version number.
You first need to upload and run formatter.UF2 file, which will format the internal flash storage of the microcontroller for future use (you only need to do this once). To do that, drag the file formatter.UF2 to ITSY**BOOT drive; if you get a question "do you want to copy this file without its properties, click "Yes". After that, the ItsyBitsy will reboot, ITSY**BOOT will disappear from your computer, and the formatter script will run; you won't see any visible output.
Double-click the reset button again; ITSY**BOOT drive should again appear on your computer. This time, drag povstaff-vX.X.UF2 to it. Again, the ItsyBitsy will reboot.
This is all - microcontroller now contains the povstaff software.
Compiling from source
You will need Arduino IDE (version 1.8.6 or higher). Make sure you have the following libraries installed:
- Adafruit DotStar
- Adafruit BusIO
- Adafruit TinyUSB
- Adafruit Unified Sensor
- Adafruit MPU6050
- Adafruit SPIFlash
- SdFat - Adafruit fork. Note: you need the Adafruit fork, not the original SdFat library!
See this page if you need help installing libraries.
Install the board support files for your board as described here (for ItsyBitsy M4) or here (ItsyBitsy nrf52840). Verify that it works by connecting your ItsyBitsy to computer, selecting the appropriate board type and port, and running the Blink sketch. If you use ItsyBitsy M4, choose in the menu Tools->USB Stack->TinyUSB.
Next, you need to format the QSPI flash storage included on the board. To do so, find in the menu File->Examples->Adafruit SPIFlash->SdFat_format. Edit the line
#define DISK_LABEL "EXT FLASH"
replacing EXT FLASH by a label of your choice, up to 11 symbols (e.g. "POVSTAFF"). Upload the sketch to your board and start the serial monitor at 115200 baud. You should see a message asking you to confirm reformatting; respond "OK" to confirm and you should see message "Formatted flash".
You are now ready to upload the main sketch to the board. In the extracted archive from github, find file code/povstaff/povstaff.ino and open it in Arduino IDE. Upload it to the Itsy Bitsy board.
Warning: uploading images to ItsyBitsy can only be done after you solder it to the POV shield board: the software relies on the voltage divider circuit on the shield to detect when the board is connected to USB. If you want to test the board without the shield, use jumper wires to connect A1 pin to 3.3V.
Step 3: Soldering the POV Shield
Solder the male headers to the ItsyBitsy; for ItsyBitsy M4, only solder the headers along the two long sides of the board. Now solder the POV shield board to these headers underneath the Itsy Bitsy, forming a "sandwich" of two boards as shown in the photos above. Note: all components of the POV shield should be on the outside, not inside the sandwich!
After you are done soldering, use diagonal cutters to trim the long pins of the headers so they are not in the way.
Step 4: Making the LED Assemblies
- Take the 1/2 inch wood dowels and cut them using hacksaw to produce two pieces of 51cm each. Try to keep your cuts square.
- Optional: spray-paint the pieces black and leave to dry. This will give the staff a much more polished look (while it is off; once it is on, no one will notice what color the dowels are).
- Get the LED strip(s). If they are inside waterproof sheaving, remove and discard the sheaving. If they have any wires soldered, de-solder them; remove excess solder using a braid wick. If you ordered 1m or 2m strips, cut them into 50 cm pieces, making sure to leave as large as possible soldering pads in the beginning of each strip (this should be easy, as usually longer strips are created by soldering together 50cm ones, so you will be just undoing someone else's work).
- Solder breakaway male headers to the beginning of each LED strip as shown in the photos. The easiest way to do it is by plugging the male headers into a long strip of female headers, putting it it flat on the workbench (ideally, on silicone or other heat-resistant mat) and taping them to the mat to keep headers in place, as shown in the photos above. Then align the LED strip and use some weight to keep it in place while you are soldering the headers.
Please note: you are soldering the short side of the header to the strip, leaving the long side free.
You will be soldering very close to the first LED, so please watch your iron carefully - do not touch the LED!
- All APA102 strips have 4 signal lines: Ground (GND, commonly abbreviated G), Clock (CLK, or CI for Clock In), Data (DAT, or DI), and VCC, or 5V. However, the order of these signal lines on the strips is varies between manufacturers. Thus, now is a good time to write it down for future use. Put the strip on the desk with the beginning of the strip to the left, and write down the signals, going from top to bottom and labeling them A... D. For example, for the strip in the photos above you would get the following list:
- Remove the backing paper from the adhesive strip on the back of the LED and attach the strip to the wood dowel so that the plastic spacers on the soldered headers are flush with the end of the dowel. Attach the other strip to the opposite side of the dowel. Repeat with the other dowel.
- Take the power distribution boards and solder them to the headers as shown in the photos. The boards should be flush with the end of the wood dowel. Use diagonal cutters to cut off extra length of header pins.
Keep this list readily available through the rest of assembly - you will refer to it more than once.
You should now have two completed LED assemblies.
Note: the adhesive on LED strips is not very strong, so your strips might start peeling off. It is OK; we will make a more permanent attachment later.
Step 5: Wiring the Control Board
- [If you bought the kit of parts from my Tindie store in Dec 2020 or later, you can skip this step - just use the included JST XH connector with 55 cm leads.]
Take one of the JST XH connectors with leads. Solder additional silicone wires (22-24 awg) to the leads, making the total length about 55-57 cm (including the connector). It is suggested that you choose the wire colors to match the signal carried, using red for VCC, black for GND, etc. You can see which wire carries which signal by plugging it into the header on the POV shield board and consulting the labels next to the header.
Try making the splices as small as possible so that it would be easy to fit inside the tube; to make it even easier, stagger the splices, making connection for different wires in different places (for example, cutting VCC and GND 10 cm from the connector, and the other two wires, 15 cm from the connector).
- Take one of the LED assemblies created in the previous step. Note that the power distribution board has 4 more holes which haven't yet been used. Strip about 5mm of each of the 4 wires of the wire assembly you just made and put the stripped wires through these holes (from the side of the LED assembly) and solder them as shown in the photos above. The signals (VCC, GND, ...) should be matched to labels on the board (A, B, C, D) using the table you wrote down in Step 3.
- To hide the wires and make it look neater, take the 8 mm shrink wrap tubing. Cut about 50-51 cm long piece. Normally, shrink wrap tubing of this diameter is sold as flat, with the lettering on one side. Use scissors to cut the tubing open lengthwise, from one end to the other, doing it on the side with lettering. Carefully put the wires into the tubing and arrange it along the dowel, the opened side down. Make sure the wires are lying flat and not crossing each other.
- Use zipties to hold the LED strips and the wiring to the dowel. The zipties should fit in the spaces between LEDs (this is why we needed 2mm wide ones). The head of the zipties should be in the middle of the empty side of the dowel (without LEDs or wiring) - not at the corner!
Place zipties every 7-8 cm or so. Tighten them and trim.
Step 6: Wiring the Batteries
In this step, you will be soldering leads to Li-Ion batteries. This could be dangerous if not done right! Please read all instructions carefully and wear eye protection. You are working at your own risk!
- Cut about 5-6 cm of 20awg red wire; strip about 1 cm off one end and solder to the positive terminal of one of the 18650 batteries by carefully following instructions on this page. Now solder 13 cm black 20awg wire to the negative terminal. Once again, be certain to follow instructions! Repeat the same with the other battery.
- Take two JST XH connectors with leads. If the leads are longer than 15 cm, cut them to 15 cm (including the connector). Plug (temporarily) each connector into the power distribution board at the end of LED assembly and use labels on the board (A...D) together with the table you created in Step 3 to identify the signal (VCC, GND, ...) for each wire lead. Use colored shrink wrap tubing, colored electric tape, or some other means to label the wires; once you have done that, you can unplug the connector from LED assembly.
- Strip about 1cm from each wire lead. Solder CLK wire of first wire assembly to the CLK wire of the second; do not forget to put shrink tubing on the wire before soldering. Repeat the same with DAT wires; use heat gun to shrink the tubing. Make sure that the total length of the assembled wire harness, from one JST XH connector to the other, is at least 28 cm.
- Cut about two 70 cm long pieces of red 20awg wire for switch leads. Solder one of them together with the two VCC leads from two JST XH connectors, and the other, together with the two leads from positive battery terminals as shown in the wiring diagram above. Again, do not forget to put the heat shrink tubing on the wires before soldering; once you completed soldering, use heat gun to shrink the tubing.
- Solder together the GND leads of both JST XH connectors with the two leads from negative terminals of the battery, as shown in the wiring diagram. Do not forget the shrink tubing.
- Use electric tape to tape the wires to the batteries, placing the batteries 5cm apart (later, we will put a 4.5cm 3d printed spacer between them). Make sure the wires are not crossing each other on battery surface - if they do, resulting assembly might not fit in the tube. Test that the battery assembly fits inside the tube (it is OK if it is a tight fit).
The ends of JST XH connectors must be at least 5cm away from battery ends. It is OK if there is extra length of wiring between batteries - there will be room to hide it.
Step 7: Wiring the Switch
- Place the remaining LED assembly (NOT the one with the control board leads) next to the battery assembly, on the side with the switch leads, putting the 3d printed spacer between them. Run the switch leads through the cutout in the power distribution board at the end of the LED assembly and along the side of the wood dowel. They should be long enough to run the length of the assembly and extend at least another 5 cm beyond the end of the wood dowel; if they are longer, trim them to 5cm beyond the end of the dowel.
- Strip about 5mm off the end of each of the switch wire leads and solder them to the terminals of the switch as shown in the photo. It doesn't matter which lead is attached to which terminal. Make sure the switch is in OFF position before continuing.
- As in Step 5, use 8 mm shrink tubing to hide the wires running along the wood dowel. Use zipties to attach the tubing to the dowel.
Step 8: Assembling the Staff
Arrange all pieces together in this order:
- LED assembly (with switch leads)
- battery assembly
- second LED assembly (with control board leads)
- Control board (ItsyBitsy +POV shield)
Plug in the wires from the batteries into JST XH headers on the LED assemblies. Plug the controller wires into JST XH header on the POV shield board.
Do a basic test by turning the switch on; if the batteries are charged (at least partially) the LEDs should flash for 2 seconds showing the battery voltage.
Put the 3d printed spacers between the two batteries and also between the batteries and each LED assembly as shown in the photo. Put the switch in 3d printed switch holder. Cut out a thin (5mm or less) 22mm diameter circle from some soft material (e.g. packing foam) and insert it between the Control board and the wood dowel.
Now carefully insert the whole assembly into the polycarbonate tube, control board end first. If you have done everything correctly, once fully inserted, the control board will stop less than 1cm away from the end of the tube.
Step 9: Finishing Up
Take the two PVC endcaps. Use model knife or utility knife to cut in one of them a rectangular opening of about 11x17mm or slightly more (it need not be very precise). I also used the flush cutters for finishing up.
Put the endcap with the opening on the switch end of the staff. Put the other endcap on the opposite end.
Finally, apply the tennis overgrip tape over the middle part of the tube, containing the battery assembly. You can watch this video to see the proper way of applying the overgrip tape: https://www.youtube.com/watch?v=HNc34XlUBww. Make sure to keep the overlaps between tape turns small - if you make them too large, your tape will run out before you reach the end of battery+spacer assembly.
Congratulations, you have completed your staff!!
Step 10: First Use
To test your staff, make sure the switch is OFF. Remove the cap from the side containing the control board; connect the staff to the computer using a microUSB cable. It should appear as an external USB drive, with the name POVSTAFF.
Go to the directory containing the extracted archive from github (see Step 2); find there directory images. It should contain some sample bitmap file(s) and the file imagelist.txt. Drag all these files to POVSTAFF folder, then eject it (as you would normally eject a USB drive). Disconnect the staff from the computer and replace the cap.
The staff is now ready to use. To use it, turn the switch ON; the staff should briefly flash, showing the battery voltage, and then go blank, waiting for you to start the show. Just start twirling the staff and it will come to life!
For full operating instructions, including instructions on uploading your own images and creating your own slideshows, please see the file USER_GUIDE.pdf in the extracted github archive (also attached to this step)
You can download more images from Visual POI website: https://visualpoi.zone/patterns/; please follow the instructions in the user guide to upload them to the staff.
Step 11: Final Comments
Below are some thoughts about this design and future plans.
- Currently, there are two ways to switch from one image to the next: either providing the duration of how long the image should be shown in imagelist.txt file, or stopping the staff in horizontal position. I plan to experiment with other ways to control the show - such as using Bluetooth app. If anyone has suggestions, I would be happy to hear them.
- Charging the staff is done while the batteries are connected to LEDs. Even with LEDs off, they still consume significant power (about 300mA), slowing down the charging process. Again, something to think about for future releases
- It would be nice to make the staff collapsible, so it can be turned into a couple of pois. This would require significant work - both mechanical (making rigid connection and designing electric connections to be easily plugged/unplugged) and electronic (we would need two controller boards). So this is a longer project.
If you have any comments or suggestions, please write them below!
I would like to thank Adafruit for developing much of the software and hardware used in this project and making it available under open source licenses. I would also like to thank all the people on Adafruit discord for their help.
Runner Up in the
Battery Powered Contest