Go Down

Topic: Revolutions Per Minute Calculating Error (Read 2303 times) previous topic - next topic

GoForSmoke

You got a bicycle wheel that will hold together at 5 ms per rev? Reality check time!

27" rim with 1"-1.25" tire, that's about 7' per rev x 200 revs/sec (@ 5ms) = 1400 ft/sec where 60 mph is 88'/sec.

Maybe change the reed switch for a Hall Effect sensor?
Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

Proud Member of the Nighthawk Robotics Club Team 569 B

#17
Jun 20, 2012, 03:11 am Last Edit: Jun 20, 2012, 03:14 am by mykiscool Reason: 1
I wasn't using my bike right away for the test I was just testing the concept by doing a simulation of moving the magnet in front with my hand. As for the hall effect, I'll look into that. My reed switch does however seem to be working because the light goes on when I move it in front of it. Also here's my new code, strangely it keeps getting 257 then a decimal like 257.45 and 257.56 rps even when I wait a long time.
Code: [Select]


//these are just some references for it to work properly
#include <StopWatch.h>
#include <LiquidCrystal.h>
//these are the microcontroller ports that an lcd screen is connected to, a status led, and the switch.
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
#define LED 13 //pin for the LED indicator (green)
#define Reed 3 //pin for the switch

//create a timer
StopWatch MySW (StopWatch::MICROS);
//state of sensor 1 or 0
byte reedState=0;
//time between pass of magnet
float timeSincePass=0;
//revolutions per second
float RPS=0;
//revolutions per minute
float RPM=0;
//last state of reed switch on or off
byte lastReedState=LOW;
long lastDebounceTime = 0;
long debounceDelay = 50;

//just some setup stuff
void setup()
{
 pinMode(LED,OUTPUT);
 pinMode(Reed,INPUT);
 Serial.begin(9600);
 lcd.begin(16, 4);
 lcd.print("Your Revs/Sec");
}


void loop()
{
 
 byte reading = digitalRead(Reed);  
 //get the state of the sensor;
 //time since pass of magnet
 timeSincePass= MySW.elapsed();
 //set the lcd cursor to write on the second line
 lcd.setCursor(0, 1);

 if (reading != lastReedState)
 {
   // reset the debouncing timer
   lastDebounceTime = millis();
 }
 
   if ((millis() - lastDebounceTime) > debounceDelay)
 {
   // whatever the reading is at, it's been there for longer
   // than the debounce delay, so take it as the actual current state:
   reedState = reading;
 }

//if the magnet engages the switch
 if (reedState==HIGH)
 {
   //turn on status led for visual purposes
   digitalWrite(LED, HIGH);
   //convert milliseconds to seconds
   RPS=(float)1000000.0/timeSincePass;
   //reset the timer storage int    
   timeSincePass=0;
   //reset the timer and start it again
   MySW.reset();
   MySW.start();
 }

 else
 {
   //turn off led otherwise
   digitalWrite(LED, LOW);
 }
 //convert seconds to minutes
 RPM=(float)RPS*60;
 
 //print the results to a screen
 lcd.print(RPS);
 lcd.print("  ");
 lcd.print(timeSincePass);
 lastReedState = reading;
}
Proud Member of the Nighthawk Robotics Club Team 569 B

GoForSmoke

I see you have read the sensor (reed switch) then if it changes from last read to start the debounce delay and if the delay is over to actually set the switch state to what is read which is not bad though 50 ms may be a bit long if you race down long hills.

But then if the state is HIGH you compute and show data... and the state may stay HIGH many times through loop() before debouncing back to low, at least 50 ms worth. You only want it to detect and calculate once per pass, otherwise your timing and resultant calculations will be wrong.

I used to have a generator light. The brightness varied with my speed until the bulb burned out, usually on the way downhill. It also dragged, that was when bike lights were incandescents. But a lightweight DC motor of the right type should generate low voltage (depending on how big a wheel is on the shaft) when driven and might give an analog reading of speed though probably not linear analog (twice the volts not being twice the speed kind of thing, probably response being a curve). However you'd have an idea of speed well before the bicycle wheel turned once.
Because face it, if the wheel has to turn 1 or 1/2 revolution to generate a reading then you will have noticeable lag in calculation and display until you really get moving. 1 rev/sec is about 5 mph with a 27" rim wheel.



Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

The Clever Monkey


Can someone please help me with this code. It is supposed to detect the revolutions per second on a bicycle wheel and then convert it to revolutions per minute. The magnetic sensor code works fine, the timer resets itself when it passes by, but no matter what speed or increment of time i wait to pass the magnet by again, it only comes up with 2 readings 5,000 and 6,000, which are not goods revolution per second readings. I expect to get some number like 230.14 or something random like that. My code is below. Any help is appreciated.


Code: [Select]

//these are just some references for it to work properly
#include <StopWatch.h>
#include <LiquidCrystal.h>
//these are the microcontroller ports that an lcd screen is connected to, a status led, and the switch.
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
#define LED 13 //pin for the LED indicator (green)
#define Reed 3 //pin for the switch

//create a timer
StopWatch MySW;
//state of sensor 1 or 0
byte reedState=0;
//time between pass of magnet
float timeSincePass=0;
//revolutions per second
float RPS=0;
//revolutions per minute
float RPM=0;

//just some setup stuff
void setup()
{
 pinMode(LED,OUTPUT);
 pinMode(Reed,INPUT);
 Serial.begin(9600);
 lcd.begin(16, 4);
 lcd.print("Your Revs/Sec");
}


void loop()
{
 //get the state of the sensor
 reedState=digitalRead(Reed);
 //time since pass of magnet
 timeSincePass= MySW.elapsed();
 //set the lcd cursor to write on the second line
 lcd.setCursor(0, 1);

//if the magnet engages the switch
 if (reedState==HIGH)
 {
   //turn on status led for visual purposes
   digitalWrite(LED, HIGH);
   //convert milliseconds to seconds
   RPS=(float)timeSincePass*1000;
   //reset the timer storage int    
   timeSincePass=0;
   //reset the timer and start it again
   MySW.reset();
   MySW.start();
 }

 else
 {
   //turn off led otherwise
   digitalWrite(LED, LOW);
 }
 //convert seconds to minutes
 RPM=(float)RPS*60;
 
 //print the results to a screen
 lcd.print(RPS);
 lcd.print("  ");
 lcd.print(timeSincePass);
}



There was a lively conversation about this on another thread recently. If you _really_ need error correction, you might want to look into rotary encoding and Gray codes.
I yield() for co-routines.

#20
Jul 15, 2012, 02:15 am Last Edit: Jul 16, 2012, 10:37 pm by Nick Gammon Reason: 1
Thanks for all your help, I fixed it.

Code: [Select]
//these are just some references for it to work properly
#include <StopWatch.h>
#include <LiquidCrystal.h>
//these are the microcontroller ports that an lcd screen is connected to, a status led, and the switch.
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
#define LED 13
#define Reed 3 //pin for the switch

//create a timer
StopWatch MySW (StopWatch::MICROS);
//state of sensor 1 or 0
byte reedState=0;
//time between pass of magnet
unsigned long timeSincePass=0.0;
//revolutions per second
float RPS=0.0;
//revolutions per minute
float RPM=0.0;
//last state
byte lastreedState=0;

//just some setup stuff
void setup()
{
 pinMode(LED,OUTPUT);
 pinMode(Reed,INPUT);
 Serial.begin(9600);
 lcd.begin(16, 4);
 lcd.print("RPM");
}


void loop()
{  
 reedState=digitalRead(3);
 //get the state of the sensor;
 //time since pass of magnet
 timeSincePass= MySW.elapsed();
 //set the lcd cursor to write on the second line
 

 //if the magnet engages the switch
 if (reedState != lastreedState && reedState==HIGH)
 {
   //turn on status led for visual purposes
   //convert milliseconds to seconds
   RPS=(float)1000000.0/timeSincePass;
   //reset the timer storage int    
   timeSincePass=0;
   //reset the timer and start it again
   MySW.reset();
   MySW.start();

 }

 if (reedState==HIGH)
 {
   digitalWrite(LED, HIGH); // gives a visual aid to tell when it is being magnetized
 }

 else
 {
   digitalWrite(LED, LOW); //Turns off when no magnet is detected
 }

 //convert seconds to minutes
 RPM=(float)RPS*60.0;
 

 //print the results to a screen
 lcd.print(RPM);
 lcd.setCursor(0, 1);
 lcd.print("Time  ");
 lcd.print(timeSincePass);  
 lcd.print(" MPH ");
 lcd.print();
 lastreedState = reedState;

 Serial.begin(9600);
 Serial.println(RPM);
}


Moderator edit: [code] ... [/code] tags added. (Nick Gammon)
Proud Member of the Nighthawk Robotics Club Team 569 B

Go Up