Bike Speedometer

I am testing code for a bike speedometer (using a reed switch and magnet on the wheel). The problem is, the code returns a speed that is always higher than the actual speed. Right now I have it set up with a button acting as the reed switch, and with an estimate of an 80in wheel circumference. I calculated that the speed at one revolution per second should be 4.56 mph:
80 inches / 63360 inches = .0012626 miles, the circumference in miles
1 second / 3600 seconds = .000277 hours, the time for one revolution
.0012626 miles / .000277 hours = 4.558 mph, the speed at 1 rps
I have modified the code to automatically act as if the wheel is turning at one revolution per second, and it returns 5.6mph, the same result as when I simply press the button once per second. I have noticed that when the revolutions per second are doubled, so is the difference between the theoretical speed and the speed returned by the code.
Here's the code, both the original and the code modified for 1 rps:

const int inputPin = 8;
unsigned long time[5] = {
  0, 0, 0, 0, 0};
int lastButtonState = LOW;
float curSpeed = 0;

void setup() {
  pinMode(inputPin, INPUT);
  Serial.begin(19200);
}

void loop(){
    int reading = digitalRead(inputPin);
    if (reading != lastButtonState) {
      if (reading == HIGH) {
        unsigned long curTime = millis();
        for(int i=4; i>0; i--) {
          time[i] = time[(i-1)];
        }
        time[0] = curTime;
        curSpeed = getSpeed();
        Serial.println(curSpeed);
      }
      lastButtonState = reading;
    }
}

float getSpeed() {
  float avgSpeed;
  avgSpeed = (time[0] - time[4]); //Difference in time b/w first and fifth rev.
  avgSpeed = (avgSpeed / 3600000); //Convert to hours
  //Divide circumference in miles by hours, gives mph (80 inches per rev. times 5 revs, then converted to miles)
  avgSpeed = (.006313131313131313131313 / avgSpeed);
  //This line was for debugging, it takes away the need to convert to hours
  //avgSpeed = (22727.27273 / avgSpeed);
  return avgSpeed;
}

Modified:

const int inputPin = 8;
unsigned long time[5] = {
  0, 0, 0, 0, 0};
int lastButtonState = LOW;
float curSpeed = 0;

void setup() {
  pinMode(inputPin, INPUT);
  Serial.begin(19200);
}

void loop(){
  while(true) {
    delay(1000);
    int reading = HIGH;
    //int reading = digitalRead(inputPin);
    //unsigned long curTime = millis();
    if (reading != lastButtonState) {
      if (reading == HIGH) {
        unsigned long curTime = millis();
        for(int i=4; i>0; i--) {
          time[i] = time[(i-1)];
        }
        time[0] = curTime;
        curSpeed = getSpeed();
        Serial.println(curSpeed);
      }
      //lastButtonState = reading;
      reading = LOW;
    }
  }
}

float getSpeed() {
  float avgSpeed;
  avgSpeed = (time[0] - time[4]); //Difference in time b/w first and fifth rev.
  avgSpeed = (avgSpeed / 3600000); //Convert to hours
  //Divide circumference in miles by hours, gives mph (80 inches per rev. times 5 revs, then converted to miles)
  avgSpeed = (.006313131313131313131313 / avgSpeed);
  //This line was for debugging, it takes away the need to convert to hours
  //avgSpeed = (22727.27273 / avgSpeed);
  return avgSpeed;
}

What is the cause of this difference between theoretical speed and the speed returned by the code?

Could be the result of contact bounce from the magnetic reed switch. Why don't you try some debouncing either in software of with external filtering and see if that helps. There is stuff about debouncing switches in the Arduion playground site.

Lefty

From time[0] to time[4] there is 4 revolutions not 5.

Also I would suggest a Hall effect switch as a sensor, they should last longer than the reed contact element.

From time[0] to time[4] there is 4 revolutions not 5.

Thanks, this fixed it! At least within reasonable bounds (.05 mph)