Introduction: Programmable POV Fidget Spinner
Note: Updated design at https://www.instructables.com/id/Geek-Spinner/. Use these instructions if your board version is 0.0 or 0.1 or uses a CR1220 Battery.
Fidget spinners are fun, and you can find one at about any check-out counter for just a few bucks these days, but what if you could build your own? And it had LEDs? And you could program it to say or show whatever you wanted? If that sounds geeky cool, THIS IS THE PROJECT FOR YOU.
I've always been interested in using blinking LEDs to get kids interested in programming. The most simple project with an Arduino microcontroller is to blink an LED on and off. Then you get them to see how fast an LED can blink before it looks like it is on continuously (about 12 millisecond intervals). Then you shake the LED back and forth and you can see it blink again! This phenomena is call "persistence of vision" (POV) and is how this project works. It can lead to discussions of both how the eye works and how incredibly fast computers are.
This project uses a programmable 8-bit microcontroller, eight LEDs, and a coin cell. It spins using a standard skateboard bearing, and uses a Hall-effect sensor and a magnet to determine rotation. It is made using beginner-friendly through-hole parts and can be programmed using the Arduino programming environment.
Enough talking, let's get making . . .
Step 1: Gather the Parts, Tools, and Supplies
It is always frustrating to get half-way through a build and find you are missing something. Here is what you'll need:
- 1 ea, Purple PCB, lovingly manufactured in the US by OSH Park
- 1 ea, Attiny 84, Atmel ATTINY84A-PU, https://www.digikey.com/short/3019qn
- 1 ea, Tactile switch, Omron B3F-1020, https://www.digikey.com/short/3019j2
- 1 ea, Slide Switch SPDT Through Hole, E-Switch EG1218, https://www.digikey.com/short/3vhd5t
- 1 ea, Battery holder, Linx BAT-HLD-012-THM, https://www.digikey.com/short/3vhd5m
- 8 ea, 3mm Red LED 160 Mcd, Wurth 151031SS04000, http://www.digikey.com/short/33354d
- 8 ea, 330 ohm 1/8W, Stackpole CF18JT330R, http://www.digikey.com/short/333rf2
- 1 ea, 0.1 uF cap, KEMET C320C104M5R5TA, http://www.digikey.com/short/7j4hb0
- 1 ea, Magnetic switch, Melexis MLX92231LUA-AAA-020-SP, https://www.digikey.com/short/qcn9nq
- 1 ea, 608 Skateboard Bearing, https://www.amazon.com/
- 1 ea, small rare earth magnet, http://r.ebay.com/ckBXqk
- 2 ea, 3D printed caps (STL file attached).
- 1 ea, CR1220 battery, Panasonic BSP or equivalent, https://www.digikey.com/short/3vwzr1
Tools and Supplies:
For my workshops, I use SparkFun's Beginner's ToolKit which has everything you need except the tweezers:
- Soldering iron.
- Solder
- Wire nippers
- Desoldering braid
- Super glue
Programming the Attiny (Step 4, not required if you buy this as a kit):
- Arduino (please avoid the cheap Chinese clones and support your US Open Source Manufactures).
- Arduino AVR Programming Shield
A kit for this project is available on Tindie.com (minus the battery). Purchasing the kit will save you the time and expense of ordering from several different vendors and avoid the minimum PCB order premium. Also, programming an Attiny is not trivial, and if you buy the kit, it will already be pre-programmed. You will also be helping me develop and share other projects in my workshops!
Attachments
Step 2: Resistance Is Essential.
We are going to assume you have some kit-building experience. If you need some help soldering, head over to www.sparkfun.com/tutorials/213 to brush up or watch the Geek Girl explain it at
I like starting with the resistor because a) they are relatively heat resistant while you are getting into your soldering groove and the iron is coming up to temp, b) they have no polarity, so orientation is not critical, and c) they are the lowest component on the board so sit tight when soldering.
There are eight 330-ohm current limiting resistors, one for each of the LEDs. You can do one at a time, or all eight at once. Bend the leads, insert them in the positions marked "330", and solder the leads in place. Clip them flush with the cutters.
Step 3: Let There Be Light
Now that you've got your soldering groove going, it is time to do the light emitting diodes, which are both heat sensitive and have a polarity. The long leg of the LED is the anode, or the positive (+) lead. It goes in the square pad, or the one marked "+" (photo 1). Solder one lead in and then check that the LED is seated correctly (photo 2). If not, hold the iron to the solder join and press the LED until it seats correctly. This gets much harder to do if both leads are soldered. Once you are satisfied, solder the other lead in place.
You can solder the LED one at a time, or all eight at once. Trim the leads flush.
Note: The LEDs are a tight fit. You may need to file the edges of one or two to get them to seat flat and in a line
Step 4: Code?
Note: If you have a "Rev. 0.0" board, see Step 13 for information about correctly hooking up to program an installed chip.
Yes, this project needs some code. And, if you were paying attention, in Step 1 I told you that programming an Attiny was not trivial. I use the Arduino, it's programming environment, and my AVR programmer. If you buy a kit from me, it will already be programmed, and you can skip this step!
The chip can be programmed before soldering in place (photo 2), or after it has been soldered in place using the ISP header on the bottom of the PCB (photo 3). In either case, the programming is as follows:
- Download the Arduino Programming Environment.
- Install support for the Attiny 85 from either:
- http://highlowtech.org/?p=1695. (Arduino Tiny)
- https://github.com/SpenceKonde/ATTinyCore (Attiny Core)
- Upload the "Arduino as ISP sketch":
- [File] -> [Examples] -> [Arduino as ISP].
- Attached the AVR Programming Shield.
- Attach the Pogo Adapater.Position the pogo adapter on the ISP header on the board. The positive and negative pads are marked so you can orient the header correctly.
- Select the correct chip:
- Arduino Tiny: "Attiny 84 @ 8 Mhz"
- Attiny Core: "Attiny 24/44/84"
- Chip "Attiny 84"8 Mhz (Internal)
- Pin Mapping "Counter Clockwise"
- Select the Programmer, [Tools] -> [Programmer] -> [Arduino as ISP]
- Set the programming fuses, [Tools] -> [Burn Bootloader]
- Upload the attached sketch, [File] -> [Upload using programmer]
The biggest source of errors I get involve not having the pins aligned correctly.
Attachments
Step 5: Brains
This project is powered by my favorite 8-bit microcontroller, the ATMEL Attiny84. It has more than enough I/O to handle all the LEDs and the other inputs (Hall sensor, button) without having to do anything tricky.
The orientation of a DIP ("dual inline package") chip is usually indicated either by a hole adjacent to pin one, or a divot on the end of the chip containing pin one, as is the case here. Align the chip with the symbol on the PCB and insert the chip. Solder one pin on opposite sides, and check that both the chip is flat against the PCB and that the orientation is correct. It gets really hard to fix after this. Trust me on this.
Once you are assured it is in correctly, solder the remaining pins and then cut them flush.
While we are here, solder in your 0.1 uF capacitor. It doesn't have a polarity, and is used to filter transients in the power caused by blinking the LEDs.
Step 6: Power
This project is powered by a 3-volt lithium battery. The Attiny needs only 1.8 volts to run, so a coin cell is perfect.
Orient the holder so that the opening is away from the switch. Like the chip, solder one pin on each side and then check that it is fully seated and in the correct orientation.
Solder the remaining leads and then cut them flush.
Step 7: Button and Switch
We need an input to switch modes, so we have a tactile button attached to an input on the microcontroller. Insert the legs into the four pad and push firmly to seat. Solder the legs and trim them flush.
We also want to turn the power off to save the battery, so I've added a single-pole, single-throw switch to control power. Solder the center lead in position and then verify it is seated. Solder the remaining leads and cut them flush.
Step 8: Spin on This
Fidget spinners are usually based on 608ZZ skateboard bearing which has an outer diameter of 22 millimeters. To make this work with a circuit board, I've added a pad that is just slightly larger than 22 mm, and we will solder the bearing into the pad.
To make it spin on a flat plane, I use coins to hold the board level while it is soldered in place. This will take significantly more heat than normal soldering, so raise the temperature on your iron if possible, and hold the iron against both the pad and bearing case until the solder flows on both. Create several solder joins on both side.
Note: If the bearing has shield and grease, I usually remove the shields and degrease them so they spin longer.
Step 9: Check It Out
Without the magnetic sensor, we can still check the LEDs out:
- Insert a battery with the positive side outward.
- Switch the spinner on and then press the button until all (hopefully) the LEDs are on (see the video).
- Spin the spinner and see the pattern.
If an LED does not light, it may be installed backward, or have been heat-damage. Un-solder it and put a new one in.
Step 10: Where Are We?
In order to show messages instead of just patterns, we need to know the position of the spinner in relation to the circle. We will use a Hall-effect sensor and a magnet. This is similar to how combustion engines know when to fire the spark to get the most power. Orientation and alignment of both the sensor and magnet are critical for this to work.
With the cap in place for reference, insert the sensor with the face (with the markings on it) toward the bearing (photo 1). Solder it in place.
The sensor I select is triggered by the north pole of a magnetic field, so you will need to figure out the orientation of the magnet. The best way to do this is to set a mode other than the pattern from the previous step and then find the side of the magnet that starts the LEDs blinking (see video 1). Glue the magnet with the side that worked facing outward. Double check your work (video 2).
Step 11: Operations
With your magnet and sensor in place, you are ready to check out the full awesomeness of your Geek Spinner. The mode of the spinner is shown by the LED that is lit on power up or after a button press (D0 - D7). The mode is changed by pressing the button (see video).
int modes = 8; // number of modes available // 0 -> text "Hello World!" // 1 -> RPM // 2 -> time in seconds // 3 -> spin count // 4 -> spin count (total) // 5 -> "lilly pad" pattern // 6 -> shape 1 (heart) // 7 -> shape 2 (smile)
Step 12: Trouble Shooting
There are two alternative pin mappings for the Attiny core that are causing a lot of confusion. Here is some code to trouble shoot issues with the pin mapping, Hall sensor, and the button.
/*
Code for testing the operation of the Hall sensor and button. Arduino IDE Setting [Tool] -> [Board] -> [AttinyCore]: Arduino Tiny: "Attiny 84 @ 8 Mhz" Attiny Core: "Attiny 24/44/84" Chip "Attiny 84" 8 Mhz (Internal) Pin Mapping "Counter Clockwise
LED D0 should be lit except when in proximity of Hall sensor. LED D1 should light when button pushed.
Troubleshooting: Inspect solder joints. Battery good (voltage <2.7 causes Hall sensor to not work). Hall sensor marking facing magnet. Magnet oriented correctly (only senses North field). See https://youtu.be/tbNR_tVFYQ8
Alternate Pin mapping ("clockwise"): // Version 0.0 or 0.1 with clockwise pin mapping int ledPin1 = 10; // Chip pin 3 PB1 int ledPin2 = 9; // Chip pin 2 PB0 int magPin = 0 ; // Chip pin 13 PA0 int buttonPin = 1; // Chip pin 12 PA1
*
/ Spinner version 0.0 or 0.1 with counter-clockwise pin mapping int ledPin1 = 0; // Chip pin 3 PB1 int ledPin2 = 1; // Chip pin 2 PB0 int magPin = 10; // Chip pin 13 PA0 int buttonPin = 9; // Chip pin 12 PA1
void setup() { pinMode(ledPin1, OUTPUT); pinMode(ledPin2, OUTPUT); pinMode(magPin, INPUT_PULLUP); pinMode(buttonPin, INPUT_PULLUP); }
void loop() { int val1 = digitalRead(magPin); if (val1){ digitalWrite(ledPin1, HIGH); } else { digitalWrite(ledPin1, LOW); }
int val2 = digitalRead(buttonPin); if (!val2){ digitalWrite(ledPin2, HIGH); } else { digitalWrite(ledPin2, LOW); } }
Step 13: But Wait, There Is More . . .
The "heart" and "smiley" patterns were created by using a polar graph to show how the eight segments would look every 5 degrees of rotation.
By Hand:
- Download and print the full-resolution image (picture 1).
- Fill in the blocks to make your image (picture 2).
- Along the radial, starting a 0, calculate the byte using black = 1, white = 0;
- The first radial of the heart is 1, 0, 0, 0, 0, 0, 0, 0, so the byte = 0b100000000;
- Continue until you are done (hint, if your image is symmetrical, you only need to do half).
- Paste your bytes into the "textAndShapes.h" section of sketch under "shape_1[]" or "shape_2[]".
Using Python:
- Install Python.
- Install Python's Image library.
- Download the attached "readGraph.py" script.
- Download full-resolution image (picture 1).
- Open the image in your favorite editor (GIMP or MS Paint).
- Use the "Fill" command with black color selected to fill the segments you want lit (picture 2).
- Save the image in the same directory as the "readGraph.py" script and change the file name in the script to match it:
im = Image.open('heart.png')
- Run the script and paste the output into "textAndShapes.h" section of sketch under "shape_1[]" or "shape_2[]".
Either way, feel free to share your creation (picture and code) in the comments!
Attachments
Step 14: Revisions and Errata
Revision 0.0: There are a couple of issues with the Revision 0.0 boards
- First, and most embarrassing, is that the ISP header on the bottom of the board is "mirrored". In order to program the chip in place, you will have to jury-rig a jumper to swap the pins. Luckily, connecting two jumpers together (as shown in photo 1) will do the trick. The other way would be to jumper into a breadboard.
- LEDs 6 & 7 are swapped. This is easily fixed in software, but annoying that I didn't catch it.
int LEDS[] = {0, 1, 2, 3, 4, 5, 6, 7};
Revision 1.0:
- Uses CR2032 Battery (more power).
- Uses low-profile SPDT slide switch.
- Components rearranged for better weight distribution.
Step 15: Credits and Final Thoughts
I certainly didn't come up with this all on my own.
- My first hands-on experience with POV was with a project from Nick Sayer called the POV Twirlie: https://www.tindie.com/products/nsayer/pov-twirlie...
- The thought "LED + Fidget spinner = POV" popped into my brain after seeing Techydiy's Instructable https://www.instructables.com/id/LED-FIDGET-SPINNER/
- Any time you have an awesome idea, someone has already done it: https://www.instructables.com/id/POV-Arduino-Fidget-Spinner/. Surface mount soldering is something I can do, but not really beginner friendly. His code was also a little over my head, but I did use his ideas about displaying RPM and counts.
- I was able to understand and used snippets of Reger-men's POV Clock code to display text: https://github.com/reger-men/Arduion-POV-clock/blob/master/clock.ino
No project is ever complete or perfect. Here are some thoughts I have going forward:
- Balance: Data sheets rarely have information about the weight of the components, so it is hard to make even an educated guess about the balance without just building it. The battery is obviously the heaviest component. I added holes on each end so I could add weight as needed to balance it.
- Battery: A CR1220 doesn't hold much juice (about 35 mAh). Moving to a CR2032 would give you significantly more energy (225 mAh), but again, weight . . .
- Clockwise? If you noticed, the text only displays correctly if you spin in the clock-wise direction. Spinning the other direction creates a mirror image. Adding a second Hall sensor or magnet would allow you to derive rotation direction (Sean's project did this).
- Color? Using programmable RGB LEDs would allow you to do colors. They are typically surface mount though.