Bike Computer

Im having some trouble with a project to monitor various environmental changes while im out and about.

eventually my aim is to have an e-bike, with a few arduinos for calculation and systems managment.
features such as, atmosphereic pressure, temp, g-force/accel, compass, lighting, speed meter, etc.

right now i have a light and a proximity sensor mounted on the front fork.
the sensor is a wtb12-3p2431, and its set up so i get high resolution by spoke readings.

here is my current sketch, i can seem to get a good speed reading, the values are usually too low or too high with respect of how fast
i spin the wheel by hand.

const int buttonPin = 9;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin
const float spoke = 0.027777777777777777777777777777778;
const float pi = 3.1415926535897932384626433832795;
const float dist_spoke = 18.344444444444444444444444444444;
float dist = 0;
const float wheeldiam = 660.4; //mm
float lasttimestamp = 0;
// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status
int laststate = 0;         // variable for reading the pushbutton status
float starttime = millis();
float endtime;
int count=0;

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);  
  Serial.begin(9600);  
}

void loop(){
  buttonState = digitalRead(buttonPin);
  if (buttonState != laststate && buttonState == HIGH) { // 1/36th revolution, 36 spokes
    endtime = millis();
    count++;
    if (count >= 36) { //one full revolution
      count = 0;
    }
    dist = dist_spoke;
    float lasttimestamp_msec = (endtime-starttime);
    //Serial.print(lasttimestamp_msec);
    //Serial.print("=");
    //Serial.print(count);
    //Serial.print("=");
    Serial.println((dist*0.001)/(lasttimestamp_msec/1000));
    starttime = millis();
  }
  
  laststate = buttonState;
}

im trying to get km/h, m/s, mi/h.

according to most speedometers, they track via one rotation of the wheel.

i have a 26in wheel, with 36 spokes. so i convert 26 to mm which is 660.4mm.
then divide 660.4 by 36 to get 18.34.
i time how long it takes from one spoke to the next.
after that i divide distance by time, but when doing so MPH never come out right.

Serial.println(((dist*0.000001)*0.62137119223733396961743418436332)/(lasttimestamp_msec/3600000));
( *0.000001) = mm to km
(*0,621....) = km to mile
then 3600000 = msec to hour.

but when spinning the wheel very fast, i get serial readings of about 5.xx, and when i used to have an actual speedometer...
the tire would usually rate at about 15 mph.
any suggestions?

thanks in advance

Something to keep in mind is that with floats you will only get about 6 digits of precision...
http://arduino.cc/en/Reference/Float

I'd simplify it a bit whilst you're testing, take all the maths out of it and just count spoke traversals and see if you get viable figures. I'd time it over several spokes to minimise the integer millis() error. At normalish bike speeds you're going to be getting say 200 impulses a second and the difference between 5 milliseconds and 6 milliseconds is a large error.

thanks guys, is there any greater percision than 6 digits with any other var type?

Simplify it. There is a linear correlation between the number of spokes passing the sensor and the road speed. See how manys impulse you get in say a second, then come up with 1 number that when divided into the impulse number gives the road speed in your units of choice. With a bit of thinking outside the box it could all be done with integers. But 6 digits precision is plenty. 17.4532 MPH ?

good point pluggy, "17.4532 MPH ?" i figured that the more percision the more accurate the final result would be, my result wouldnt need to be better than
17.4 in this case.

on the other note, i want to use an accelrometer not gps.
i read once somewhere that acceleration over time is speed, thou i may be wrong.
this would give realtime speed reading on x, y, z axis.
idc for gps at all, mainly because of privacy, reliability, and precision.

back to the bike cpu...
the arduino will idle until one full rotation of wheel, afterwards.
lights engage, speed is read, and everything else goes to serial for debug.

when no spokes pass the sensor for 5 seconds, lights fade out and arduino
clears all buffers and goes into idle.

i will makea few changes to the code and get back to ya

ok here is a test code

#include "Timer.h"
Timer t;
const float dist_spoke = 18.344444444444444444444444444444;
float dist = 0;
//const float wheeldiam = 660.4; //mm
//float lasttimestamp = 0;
// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status
int laststate = 0;         // variable for reading the pushbutton status
float starttime = 0;
float timer = 0;
float idletime = 0;
int count=0;
int idle=0;
void setup() {
  // initialize the LED pin as an output:
  pinMode(9, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(8, INPUT);  
  Serial.begin(9600);  
  t.every(1000, printser); 
}

void loop(){
  buttonState = digitalRead(8);
  if (buttonState != laststate && buttonState == HIGH) { // 1/36th revolution, 36 spokes
    count++;
  }
  laststate = buttonState;
  t.update();
}

void printser() {
  Serial.println(count);
  count = 0;
}

i can get about 80 spokes/second by hand
then i multiply 'count' by 'spoke_dist' to get mm/s right?

i cant exactly convert mm to km/h or mile/h.
if float only supports 6 digit percision, then it will not work, because
6.2137119223733396961743418436332e-7, is way beyond.
even from mm to m, and m to km...when i try to use the variable the result is too small
so it always returns 0.00.

any ideas?

I'd take it further than that. Work out by hand what 80 spokes a second comes out to in MPH (or whatever) and then divide spokes per second by a number that gives the correct MPH figure. Then you just use that number for all spokes per second in arduino . It minimises the impact of the limited precision of real numbers.

You said you can spin the wheel at 15MPH by another method, if that is the same as 80 spokes per second then you just divide 80 by 5.33 to get 15 miles per hour. You divide any spokes per second by 5.33 to get the speed in MPH. It avoids any contact with impossibly small numbers.

Bear in mind a 26 inch wheel will not have a rolling distance of Pi times 26" , it needs to be determined by experiment with you sat on the bike. Tyres and pressures affect the rolling distance.

Bear in mind that the accelerometer is only going to measure you accelerating, once you hit a speed and maintain it the accelerometer is not going to give you valuable information.

with regards to monitoring speed I'd have used a magnet and switch like every other bike computer manufacturer, they can't be wrong.......can they?

PeteOC:
Bear in mind that the accelerometer is only going to measure you accelerating, once you hit a speed and maintain it the accelerometer is not going to give you valuable information.

with regards to monitoring speed I'd have used a magnet and switch like every other bike computer manufacturer, they can't be wrong.......can they?

ur right, but once ur acceleration reaches a maximum your going 'that' speed, and any negative acceleration would mean ur slowing down right?

pluggy:
I'd take it further than that. Work out by hand what 80 spokes a second comes out to in MPH (or whatever) and then divide spokes per second by a number that gives the correct MPH figure. Then you just use that number for all spokes per second in arduino . It minimises the impact of the limited precision of real numbers.

You said you can spin the wheel at 15MPH by another method, if that is the same as 80 spokes per second then you just divide 80 by 5.33 to get 15 miles per hour. You divide any spokes per second by 5.33 to get the speed in MPH. It avoids any contact with impossibly small numbers.

Bear in mind a 26 inch wheel will not have a rolling distance of Pi times 26" , it needs to be determined by experiment with you sat on the bike. Tyres and pressures affect the rolling distance.

thanks, ill check out

new, issue... i was using a npn transistor and an inductor. while driving the circuit with abt 25 volts, the arduino was powered using usb.
well while using the fade sketch the arduino resets. now everytime i plug it in via usb, it powers up, pin 13 led binks twice, the computer reconises it, then it disconnects from usb, and the pin 13 led slowly fades along with the power led.

think its dead?

On an arduino uno pin 13 can't be pwm'd with analog write, but if the power led fades it sounds like a power issue, maybe your drawing too much from the usb port? Also the small chip on the board is a 8 or 16u2 and handles the usb communication, and the fact it connects seems it works, and the disconnect is probably due to the lack of power from the usb
try powered from an external 5v supply

On first glance I notice that:

  1. You should be using "unsigned long" for all times since millis() returns an unsigned integer number of milliseconds representing time.
  2. You don't have any debounce on your spoke switch. This is critical in your application.
    Check out Schmitt trigger here on this site.
  3. Even 3 digits of precision would be more than enough for everything. A float is fine.

THE MATH: say you count up N spokes in a constant interval of T seconds

miles/hour = (N spokes / T seconds) * (1 revolution / 36 spokes) * (DiamMM * Pi mm / revolution) * (1 inch / 25.4 mm) * (1 ft / 12 inch) * (1 mile / 5280 ft) *
(60 seconds / 1 minute) * (60 minutes / 1 hour)

The trick is units cancellation. Write out the above with numerators on top of denominators. Then cancel out units that are in both the top and bottom.
What you are left with is "mile" on top and "hour" on bottom and a constant number that you multiply by the count N to get miles/hour
Perhaps this helps (or needs more explanation)
Cheers!

lol, thanks very much. but dev is suspended atm: arduino is dead and no money for replacment :stuck_out_tongue:

You can always spend the extra time optimizing, never hurt to have a more effecient code
or do you know what died? If its the 8/16u2 you can still communicate if you can get a usb to serial converter or use an rs232 port
if its the atmega328 then you need a new one
if its a part on the board itself, perhaps it can me removed and replaced/jumped out

I've done all sorts of speedo and tacho designs over the years and never needed floating point.


Rob

Nobody seems to have pointed out the obvious yet that your original maths/measurement isn't correct. You're saying it's a 26inch wheel, then dividing that by 36 spokes to get the distance between spokes. Well 26 inches refers to the DIAMETER of the wheel and you are dividing by 36, suggesting you thought it referred to the circumference. You need to be dividing the circumference of the wheel by 36, not the diameter.

I'd measure the circumference manually as it will vary depending on what tyre you have fitted, but an approximation using pi would give:
3.14*660.4 = 2075mm

So you're speed calculation is out by a factor of about 3, taking your calculation of 5mph up to around 15mph which is what you wanted. Problem solved :wink:

Heres the math for diameter in inches (26) and transforming the count N of 1 sec worth of spokes into MPH.
So,
Diameter = 26 and
T = 1.0

miles/hour = (N spokes / T seconds) * (1 revolution / 36 spokes) * (Diameter * Pi inch/ revolution) * (1 ft / 12 inch) * (1 mile / 5280 ft) *
(60 seconds / 1 minute) * (60 minutes / 1 hour)

MPH = N * 0.12892

You might want to update faster than 1 sec. Since you are counting spokes (as opposed to a magnetic, once per revolution sensor) you have that luxury.
Just multiply the above constant by the number of times per second you are updating. Ex. twice a second makes T = 0.5, effectively multiply the constant by 2 giving:

MPH = N * 0.2578

You should probably round MPH to the nearest tenth MPH with something like:

roundedMPH = (float)((int)(MPH * 10.0 + 0.5)) / 10.0;

Say N is 57 for one interval,
then MPH = 14.6946 and you display
rounded MPH = 14.7

winner10920:
You can always spend the extra time optimizing, never hurt to have a more effecient code
or do you know what died? If its the 8/16u2 you can still communicate if you can get a usb to serial converter or use an rs232 port
if its the atmega328 then you need a new one
if its a part on the board itself, perhaps it can me removed and replaced/jumped out

it is an atmega328.
after having it powered off for a few days, i plugged it into usb. it stayed on, led blinked twice. i hit reset led blinded twice again.
then power led faded away, and usb device went away. and atmega328 gets hot when pluggin into ext power supply. i can upload new code
until power led fades. the sketch runs as well. it gets hot enough to burn my finger and i think its shutting down because of thermal shutdown