8431 rpm Fidget spinner

8431 RPM Fidget Spinner – Arduino Tachometer

This was a fun experiment measuring the rotational speed (rpm) of a fidget spinner using an Arduino Uno, a hall effect sensor and a neodymium magnet. Then seeing just how fast I could make the spinner spin with a shop vac!

Measuring Spinner RPM every Revolution with a Hall Effect Sensor and Neodymium Magnet

The Hall effect sensor output was connected to the Arduino Uno digital input pin 2. TheĀ  neodymium magnet was glued to a section of 8mm wooden dowel and pushed into one of the outer bearings on the fidget spinner.

Fidget spinner rpm Arduino tachometer

// Fidget spinner RPM counter
// techydiy.org
// https://creativecommons.org/licenses/by-nc-sa/4.0/

// Calculates and displays the RPM of a fidget spinner for every revolution
// Hall effect sensor connected to digital pin 2

// Uses the lcd ibrary from F Malpartida 
// https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4 ,5, 6, 7, 3, POSITIVE); 

const byte ledpin = 13;     //  Led output
const byte interruptPin = 2;  //  Hall effect sensor connected to this pin
volatile unsigned int spins =0;   // Total spins
volatile unsigned long  timenow=0;   // 
volatile unsigned long  lasttime=0;   // Last time in millis interupt routine was called
volatile unsigned int rpm=0;           // Current rpm
unsigned int displayrpm=10;  // Displayed rpm
unsigned int displayspins = 999; // Displayed spins
volatile unsigned int maxrpm=0;       // Maximum rpm   

void setup()
{
  lcd.begin(16,2);
  lcd.clear();

  pinMode(ledpin, OUTPUT);  // Onboard LED output
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), countspin, RISING); // Digital pin 2 hardware interrupt
  
}

void loop() {

  if (rpm != displayrpm | spins != displayspins) {    // Only update the display if the RPM or spins change

    displayrpm = rpm;         // Update rpm displayed
    displayspins = spins;     // Update spins displayed
    
    lcd.setCursor(0,0);
    lcd.print("RPM ");
    lcd.setCursor(4,0);
    lcd.print(rpm, DEC);       // Print the RPM on the lcd display
    lcd.print("     ");
        
    lcd.setCursor(10,0);
    lcd.print(maxrpm, DEC);     // Print the Max RPM on the lcd display
    
    lcd.setCursor(0,1);
    lcd.print("SPINS ");        // Print the no. of spin on the lcd display
    lcd.print(spins);
    lcd.print("     ");

  }    
}


// Interupt service routine for digital pin 2 
// connected to the hall effect sensor
void countspin()
{
  digitalWrite(ledpin, !digitalRead(ledpin)); // Toggle LED
  
  spins++;              // Increment spins counter
  timenow=micros();     // Read current time

  rpm = 60000000  / ( timenow - lasttime ) ;    // Calculate RPM
  lasttime=timenow;                          // Store current time
  
  if(rpm > maxrpm){     // Update max rpm if it has increased
    maxrpm=rpm;
  }

}


3144 Hall effect switch datasheet

Measuring the Spinner RPM once every second

The following sketch uses a timer 1 interrupt and a hardware interrupt to measure the RPM over a one second period.

// Fidget spinner RPM ccunter
// techydiy.org
// https://creativecommons.org/licenses/by-nc-sa/4.0/

// Measures RPM over a 1 second period
// with a minimum resolution of 60 rpm
// Increase the period to increase the resolution

// Uses the lcd ibrary from F Malpartida 
// https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home
//
// and the Timer1 library
// https://playground.arduino.cc/Code/Timer1

#include <TimerOne.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4 ,5, 6, 7, 3, POSITIVE); 

const byte ledpin = 13;              // Onboard Led
const byte interruptPin = 2;         // Hall effect sensor connected to this pin
volatile unsigned int spins =0;      // Number of spins counter
volatile unsigned int rpm=0;         // The current RPM value
volatile unsigned int maxrpm=0;      // The maximum RPM value
unsigned int displayrpm=9999;        // The currently displayed RPM value

void setup() 
{
  lcd.begin(16,2);   // Initialise lcd display
  lcd.clear();       // Clear lcd display
  
  pinMode(ledpin, OUTPUT);  // Onboard LED output   
  
  Timer1.initialize(1000000); // set a timer of length 1000000 microseconds (or 1 second )
  Timer1.attachInterrupt( timerIsr ); // attach the service routine

  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), countspin, RISING); // Digital pin 2 hardware interrupt
  
}
 
void loop()
{
   if (rpm != displayrpm) {  // Only update if the RPM value has changed
    
      lcd.setCursor(0,0);
      lcd.print("RPM ");
      lcd.print(rpm, DEC);   //  Display RPM
      lcd.print("     ");;
      lcd.setCursor(0,2);
      lcd.print("MAX ");
      lcd.print(maxrpm, DEC);    // Display maximum RPM achieved
   
   }
}
 

// Timer Interupt
// Called every one second
// Calculates rpm and updates maximum rpm

void timerIsr()
{
  rpm = spins * 60 ;  // Calculate RPM 
  spins = 0;           // Reset spin counter 

  if(rpm > maxrpm){    // Update maximum RPM
    maxrpm=rpm;
  }
}

// Hardware interupt for digitsl input 2 
// which is connected to the hall effect sensor.
// When the input transitions from low to high
// it increments the spins counter and toggles the led.
 
void countspin()
{
  digitalWrite(ledpin, !digitalRead(ledpin)); // Toggle LED
  spins++;                            // Increment spins counter
}

 

How fast can the spinner spin with a shop vac?

Spinner RPM shop vac nozzle 99999 RPM fidget spinner with a shop vac

To test the Arduino tachometer at higher rpm values, I used a shop vac. The bottom of a drinks bottle was cut off and then the bottle inserted into the shop vac blower output. I also added a small nozzle to increase the air speed.

Measuring the Spinner RPM with the timer input capture unit

It is also possible to make the Arduino timer do most of the work.

Arduino Tachometer Timer 1 Input Capture with Hall Effect Sensor - Spinner 9999 RPM Spinner 9999 RPM measurement with Arduino Tachometer

The hall effect sensor is connected to pin 8.

The timer counts the prescaled clock and then stores the count when the magnet passes over the hall effect sensor. An interrupt is generated and this then retrieves the stored count and uses it calculate the rpm value.

The prescaler is used to reduce the clock frequency.

// Fidget spinner RPM counter
// techydiy.org
// https://creativecommons.org/licenses/by-nc-sa/4.0/


// Calculates and displays the RPM of a fidget spinner for every revolution
// Hall effect sensor connected to ICP1 digital pin 8
// Using timer input capture unit


// Uses the lcd ibrary from F Malpartida 
// https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home
//

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4 ,5, 6, 7, 3, POSITIVE); 

const byte ledpin = 13;     //  Led output
const byte interruptPin = 8;  //  Hall effect sensor connected to this pin
volatile unsigned int spins =0;   // Total spins
volatile unsigned int rpm=0;           // Current rpm
unsigned int displayrpm=10;  // Displayed rpm
unsigned int displayspins = 999; // Displayed spins
volatile unsigned int maxrpm=0;       // Maximum rpm   
volatile byte countoverflow=0;       // counter overflows

void setup()
{
  lcd.begin(16,2);
  lcd.clear();

  pinMode(ledpin, OUTPUT);  // Onboard LED output 
  pinMode(interruptPin, INPUT_PULLUP);   //   Hall effect sensor connected to this pin
  
  noInterrupts();
  TCCR1A = 0;    // Normal wave generation mode
  TCCR1B = bit(ICNC1) | bit(ICES1) | bit(CS12) | bit(CS10);  // Timer counter contol register
                                                // Noise canceller, Edge detect 
                                                //  /1024 prescale clock frequency
                                                
  // TCCR1B = bit(ICES1) | bit(CS12) | bit(CS10);  // Noise canceller off instead

                                                
  TIMSK1 = bit(ICIE1) | bit(TOIE1);       // Timer interrupt mask register
                                          // Input capture interrupt enable,  Timer overflow interrupt enable

  interrupts();
}

void loop() {

  if (rpm != displayrpm | spins != displayspins) {    // Only update the display if the RPM or spins change

    displayrpm = rpm;         // Update rpm displayed
    displayspins = spins;     // Update spins displayed
    
    lcd.setCursor(0,0);
    lcd.print("RPM ");
    lcd.setCursor(4,0);
    lcd.print(rpm, DEC);       // Print the RPM on the lcd display
    lcd.print("     ");
        
    lcd.setCursor(10,0);
    lcd.print(maxrpm, DEC);     // Print the Max RPM on the lcd display
    
    lcd.setCursor(0,1);
    lcd.print("SPINS ");        // Print the no. of spin on the lcd display
    lcd.print(spins);
    lcd.print("     ");

  }    
}

// Input capture interrupt routine 
ISR(TIMER1_CAPT_vect){

    TCNT1 = 0;              // Reset counter to zero
    rpm = 60000000 / (( ICR1 + countoverflow * 65535 ) * 64 );    // Total count
    countoverflow = 0;
    
   // digitalWrite(ledpin, !digitalRead(ledpin)); // Toggle LED
    spins++;              // Increment spins counter

    if(rpm > maxrpm){     // Update max rpm if it has increased
      maxrpm=rpm;
    }
}


// Counter overflow interrupt routine
ISR(TIMER1_OVF_vect){
    TCNT1 = 0;            // Reset counter to zero
    countoverflow++;      // Increment the counter over flows
    digitalWrite(ledpin, !digitalRead(ledpin)); // Toggle LED

}

 

Measuring Spinner RPM with a Light Dependent Resistor (LDR)

Measuring the spinner speed is also possible using a light source along with a photo transistor or a light dependent resistor (LDR) as a receiver.

The fidget spinner breaks the light beam and the Arduino measures the resulting pulse.

In this case I have used an LDR and a 1K resistor connected as a potential divider, with the output connected to pin 8.

The sketch takes account of the number of arms on the fidget spinner and once again uses the input capture interrupt.

// Fidget spinner RPM counter
// techydiy.org
// https://creativecommons.org/licenses/by-nc-sa/4.0/


// Calculates and displays the RPM of a fidget spinner for every part revolution
// Light dependent resistor (LDR)  connected to ICP1 digital pin 8
// Using timer input capture unit


// Uses the lcd ibrary from F Malpartida 
// https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home
//

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4 ,5, 6, 7, 3, POSITIVE); 

const byte spinnerarms = 3;   // The number of arms on the spinner
const byte ledpin = 13;     //  Led output
const byte interruptPin = 8;  //  LDR connected to this pin
volatile unsigned int spins =0;   // Total spins
volatile unsigned int rpm=0;           // Current rpm
unsigned int displayrpm=10;  // Displayed rpm
unsigned int displayspins = 999; // Displayed spins
volatile unsigned int maxrpm=0;       // Maximum rpm   
volatile byte countoverflow=0;       // counter overflows

void setup()
{
  lcd.begin(16,2);
  lcd.clear();

  pinMode(ledpin, OUTPUT);  // Onboard LED output 
  pinMode(interruptPin, INPUT_PULLUP);   //   Hall effect sensor connected to this pin
  
  noInterrupts();   // Turn off interrupts
  TCCR1A = 0;    // Timer counter contol register. Normal wave generation mode
  TCCR1B = bit(ICNC1) | bit(ICES1) | bit(CS12) | bit(CS10);  // Timer counter contol register
                                                // Noise canceller, Edge detect 
                                                //  /1024 prescale clock frequency
                                                
  // TCCR1B = bit(ICES1) | bit(CS12) | bit(CS10);  // Noise canceller off instead

                                                
  TIMSK1 = bit(ICIE1) | bit(TOIE1);       // Timer interrupt mask register
                                          // Input capture interrupt enable,  Timer overflow interrupt enable

  interrupts();   // Turn interrupts on
}

void loop() {

  if (rpm != displayrpm | spins != displayspins) {    // Only update the display if the RPM or spins change

    displayrpm = rpm;         // Update rpm displayed
    displayspins = spins;     // Update spins displayed
    
    lcd.setCursor(0,0);
    lcd.print("RPM ");
    lcd.setCursor(4,0);
    lcd.print(rpm, DEC);       // Print the RPM on the lcd display
    lcd.print("     ");
        
    lcd.setCursor(10,0);
    lcd.print(maxrpm, DEC);     // Print the Max RPM on the lcd display
    
    lcd.setCursor(0,1);
    lcd.print("SPINS ");        // Print the no. of spin on the lcd display
    lcd.print(spins / spinnerarms );   // Adjust for part spins
    lcd.print("     ");

  }    
}

// Input capture interrupt routine 
ISR(TIMER1_CAPT_vect){

    TCNT1 = 0;              // Reset counter to zero
    rpm = 60000000 / (( ICR1 + countoverflow * 65535 ) * 64 * spinnerarms);   // Calculate RPM
    countoverflow = 0;
    
    digitalWrite(ledpin, !digitalRead(ledpin)); // Toggle LED
    spins++;              // Increment spins counter

    if(rpm > maxrpm){     // Update max rpm if it has increased
      maxrpm=rpm;
    }
}


// Counter overflow interrupt routine
ISR(TIMER1_OVF_vect){
    TCNT1 = 0;            // Reset counter to zero
    countoverflow++;      // Increment the counter over flows
}





 

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.