Bike Speedometer Using Reed Switch


I would like to track the speed of a bicycle wheel in MPH using a reed switch and a magnet on the wheel. I found a piece of code using interrupts to track the speed and modified it to fit my needs, but it doesn't quite calculate the speed properly. It usually prints the same value or multiples of that value no matter how quickly/slowly I bike. I would like the speedometer to be as accurate as possible and am considering adding more magnets to the wheel and then averaging the outputs per rotation for higher resolution.

Anyway, here is the code I have so far:

int reedSwitch = 2;
int radius = 12;
float circumference;
float mph;
volatile byte timer;
unsigned long passedtime;

void isr()
   //Each rotation, this interrupt function is run twice, so take that into consideration for
   //calculating mph

   //Update count
void setup(){

   //Intiates Serial communications

   attachInterrupt(0, isr, RISING); //Interrupts are called on Rise of Input

   pinMode(reedSwitch, INPUT_PULLUP); //Sets reedSwitch as input

   timer = 0;
   mph = 0;
   passedtime = 0; //Initialise the values
   circumference = 6.28 * radius;
void loop() {;
   if (millis() % 1000 == 0){
        detachInterrupt(0); //Interrupts are disabled
        mph = ((56.8*circumference)/(millis() - passedtime)*timer) // Get the MPH while interrupt is detached
        passedtime = millis();
        timer = 0;
        Serial.println("Speed in MPH:");
        Serial.println(mph); //Print out result to monitor
        attachInterrupt(0, isr, RISING);   //Then restart the interrupt processing

What is "bikeRotation = analogRead(A0)" good for? And how is the sensor wired and the wheel fittet? Is radius measured in apples or bananas?

I thought I took the bikeRotation line out, that part was for the potentiometer that is mounted onto the handlebars to track their orientation relative to the rest of the bike. I will edit that out.

The sensor is connected to the Arduino's GND and digital pin 2 and uses the board's internal pull-up resistor. It is mounted to the stem that connects the seat to the back wheel and the magnet is on the inside of the wheel. Also the radius of is measured in inches.

1. How many interrupt ticks are generated when the bike's wheel makes one complete rotation.

2. How much speed will you compute from this formula mph = ((56.8*circumference)/(millis() - passedtime)*timer) under the following data?

(a) assume 1 interrupt tick during one complete rotation of the bike's wheel (b) assume total interrupt counts 500 = timer (c) Circumference is known : 6.28 * 12" = 75.36" (d) assume that you have traveled for 5 min; so, millis() = 300 000 (ms) (e) passedtime = 0

3. Can you explain, the sources of the constants 56.8 and 6.28 in your formula?

BTW: In calibrating a speed meter, it is a usual practice to determine the K Factor. A K Factor is a value that the sensor produces (in the form of counts) when the bike (car) travels 1km/1 mile distance with new tyres. When the tyres get old, the inspector makes another measurement which is known as W Factor (wheel factor). For a Taxi Cab to remain qualified, the difference between W and K must be less than 1% (the regulation of the Transport Authority).

Can you explain, the sources of the constants 56.8 and 6.28 in your formula?

6.28 is two times crippled Pi and 56.8 is “seconds per hour / inches per mile * 1000”, I guess. And according to the posted code, the timer increments by two for each revolution.

@OP: Please check my comments here:

void loop() {; // < No ";" here

   bikeRotation = analogRead(A0); // This suggests partial code posted, bad boy!

   if (millis() % 1000 == 0) { //This is a bad idea, use "millis() - passedtime >= 1000" instead.
        detachInterrupt(0); //Interrupts are disabled

        //timer increments by two per revolution so you either need to
        //divide it by two (slower) or multiply it by 0.5f (faster) when using it
        //multiplication (*0.001f) is also used instead of "/ 1000" (millis per second)

        //InchesPerSecond = circumference * timer * 0.5f * (millis() - passedtime) * 0.001f
        //InchesPerHour = InchesPerSecond * 3600
        //MilesPerHour = InchesPerHour / 63360

        //The following calculation makes no sense to me....
        mph = ((56.8*circumference)/(millis() - passedtime)*timer) // Get the MPH while interrupt is detached

        //I have moved around a couple of lines..

        timer = 0; //Reset timer first
        passedtime = millis(); //Reset passed time
        attachInterrupt(0, isr, RISING); //Re-attach the interrupt

        //Serial communication is done after all the other stuff in order to
        //prevent any overhead from the serial interface to interfere with
        //the math and timing
        Serial.println("Speed in MPH:");
        Serial.println(mph); //Print out result to monitor

Try if this gives you better numbers :slight_smile:

Instead of detaching and attaching the interrupts to guard the calculation try using cli() and sei() functions instead

Wow thanks for all your input guys! @Danios90, your suggestions to fix the code worked perfectly.