Programmable POV Fidget Spinner

9,802

109

41

Published

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:


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):

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!

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:

  1. Download the Arduino Programming Environment.
  2. Install support for the Attiny 85 from either:
  3. Upload the "Arduino as ISP sketch":
    • [File] -> [Examples] -> [Arduino as ISP].
  4. Attached the AVR Programming Shield.
  5. 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.
  6. 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"
  7. Select the Programmer, [Tools] -> [Programmer] -> [Arduino as ISP]
  8. Set the programming fuses, [Tools] -> [Burn Bootloader]
  9. Upload the attached sketch, [File] -> [Upload using programmer]

The biggest source of errors I get involve not having the pins aligned correctly.

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!

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.

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.

4 People Made This Project!

Recommendations

  • Microcontroller Contest

    Microcontroller Contest
  • Casting Contest

    Casting Contest
  • Woodworking Contest

    Woodworking Contest
user

We have a be nice policy.
Please be positive and constructive.

Tips

Questions

41 Comments

Hello,

i can't find heart.png file (only hearth.jpg) and also can't find makeGraph.py.

i tried to convert heart.jpg to heart.png but the script readgraph doesn't work.

Where can i get this files ?

Thank you.

The Melexis Magnetic Switch link in the parts list should be updated to https://www.digikey.com/short/qcn9nq

1 reply

Good catch! Thanks.

The spinner works after two changes:
First, I modified the code:
int LEDS[] = {10, 9, 8, 7, 6, 5, 3, 4};

byte ledPin = 0;
byte magPin = 0; // Hall effect sensor,
byte magPullUp = 0; // Pin A0 / D0
byte touchPin = 1; // Push button A1 / D1

However, the words and images did not form correctly. For example "World" was un-readable.

The second change is to adjust the gap between the magnet and the magnetic switch by slightly bending the sensor away from the magnet until the images form correctly.

This is an excellent project. Thank you.

byte touchPullUp = 1;

Hello,

As the ATTiny can be reprogrammed, it has to be removable easily from the PCB, can i solder a 14 pin ship support like this (

https://www.aliexpress.com/item-img/in-stock-LM290... ) instead of soldering the chip itself ?

Regards,

3 replies

As i don't have any AVR programmer and shield, i added a dip connector to remove it easily for reprogramming.

It also works fine, new weight doesn't affect much spinning

IMG_3763.JPG

Nice! Thanks for posting a picture.

I couldn't get the link to work, but I assume you are talking about something like this, which would work (but I'm not sure how it would affect the balance):
CONN IC DIP SOCKET 14POS TIN, 3M 4814-3004-CP, https://www.digikey.com/short/31cmn3 (or equivalent).

The Attiny can be programmed in place using the ISP header.

Thank you !!!! you found my mistake !! Boot loader was set to 1 MHz instead of 8 Mhz.

All is now working fine, shapes and texts now fit perflectly !

Best Regards from France

1 reply

Good work. Bonus points for being persistent!

Thank you for this tutorial.

How to program the Attiny without avr programming shield with arduino ? do i need to adapt your code ? i have errors when compiling :fatal error : EEpromex.h :no such file or directory

Regards,

1 reply

Depending on your version of the IDE, you may be able to use:
"EEprom.h" instead. If not, download and install EEpromex.h from the instructions at https://github.com/thijse/Arduino-EEPROMEx.

Is your Python script for mapping the polar data to LEDs available for download?

1 reply

Oops. I was supposed to finish Step 12.

I have, and have upload the script "readGraph.py"

Let me know if it makes sense and you are able to follow it.

Why do you separate touchPin and touchPinPullup (and same with mag)? Why not just use one declaration for each as INPUT_PULLUP? Then you wouldn't need to digitalWrite them HIGH either. Or does the ATTiny not support INPUT_PULLUP?

1 reply

The short answer is that I was using an older “tiny” CORE which had different numbering for digital and analog, and thus I had to indicate both.  This is the "counter-clockwise" pin mapping. If you dig into the code, you see it is a mute point because I do digitalRead() on the button instead of analogRead().

I'm going to rewrite the sketch to use the newer "clockwise" pin mapping which should clear up that problem.

And yes, I'll switch to using the INPUT_PULLUP declaration because it makes it clear what you are doing.  I need to get in the habit of that.


Just got my 1.0 boards; have already built one of the 0.1 boards but lost my magnets so had to order more...thanks for creating the boards. These are awesome gifts.

FYI, the 1.0 boards still say CR1220 on the silkscreen.

The "byte" is the datatype of the variable:
https://www.arduino.cc/en/Reference/Byte

I use "byte" instead of "int" because it saves memory (one byte instead of two).

So the LEDs work. Does the button advance the modes? Be sure the Hall sensor is facing the correct way and that the magnet is oriented correctly. Both those have got me more than once.

I'll work on a couple of trouble-shooting programs to load that may help figure out what it going on.

When attempting to burn the bootloader with the YAPS I get the following error (note: have tried multiple chips, all purchased from the link above):

avrdude: stk500_recv(): programmer is not responding

avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x00

I have the chip directly on the YAPS. Selected ATtiny84 with an internal clock of 8Mhz (have also tried other speeds as well as external clock). Have also done various combinations of resetting the Arduino and YAPS before programming. Still no luck. Any ideas? :)

1 reply

The error indicates a failure to communicate with the Arduino. A couple of things to check:
- With the Arduino disconnected, check what com ports are listed ([Tools]->[Port]).
- Plug the Arduino in, wait a few seconds, and set the port to the new com port.
- Ensure the green heartbeat LED is blinking. If not, reset the Arduino.

Let me know how it goes.