Trying to accurately measure speed using a hall effect and magnet attached to a wheel. This function can be the main function and run without being interrupted, but I do have other small functions that need to run. So if this function counts one wheel rotation then does other stuff, and comes back, that's fine.
How I decided to do it was sample Millis, then count falling edges until 5000MS has passed. I'm going to shorten this down to 1000ms when I implement it, but I can't move a magnet on my breadboard that fast, so for testing, it's 5000ms. I can't come up with a good way, that doesn't hang while still catching falling edges. Note, the vehicle needs to be accurate from 5mph to 120mph, which is around 1 to 18 RPM. Also, the hall effect is normally HIGH and goes LOW when the magnet passes it.
Here is what I have.
// record MILLIS , count ticks, after MILLIS + 1000, compute speed
int future = millis()+5000;
int ticks = 0;
while(future > millis()) // 1 second hasn't passed
{
// COUNT RISING EDGES
if(digitalRead(speedPin) == HIGH){ //if the input to goes HIGH again (senses magnet)
if(digitalRead(speedPin) == LOW){ //and then it goes LOW (no magnet) we know one pulse happened.
ticks++;
}
}
}
// speed is ticks per second
Serial.print("Ticks: "); Serial.println(ticks);
ticks = 0;
Serial.println("Pulse Time: 5000ms");
My issue is that it's not counting accurately. Is there a better way?
Just checking your maths.
120 miles per hour
2 miles per minute
3560 yards per minute
about 59 yards per second
divide this by 18 gives a wheel circumference of about 10 feet.
divide by pi gives a diameter of about 3 foot?
OK with a bit of maths, I find that 1mph is equivalent to 17.6 inches per second.
So here's a rough sketch that could get you started. I've no doubt that there's probably a few bugs in it but hopefully enough to give you the general idea.
#define wheelDiameter 17
float wheelCircumference;
volatile unsigned long lastPulse=0;
volatile unsigned int MPH;
void setup()
{
wheelCircumference = wheelDiameter * 3.14;
Serial.begin(9600);
//NOTE THIS WILL EXPECT THE INPUT TO BE ON PIN 2
//IT WON'T WORK WITH ANY OTHER PIN
attachInterrupt( 0, pulseISR, RISING);
}
unsigned long lastDisplay=0;
void loop()
{
unsigned long t=millis();
//If wheel isn't turning, MPH will not get updated
//So we'll reset it here if sensor hasn't been triggered for four seconds
if ((t - lastPulse) > 4000)
MPH=0;
//only update display once per second
if ( ( t-lastDisplay) >= 1000)
{
Serial.print(MPH,DEC);
Serial.println(" MPH");
lastDisplay=t;
}
}
void pulseISR() {
unsigned long newPulse = millis();
unsigned long turnTime = newPulse - lastPulse;
float inchesPerSecond = wheelCircumference * 1000 / turnTime;
float mph = inchesPerSecond / 17.6;
MPH = mph;
lastPulse=newPulse;
}