Pages: [1] 2   Go Down
Author Topic: Revolutions Per Minute Calculating Error  (Read 2089 times)
0 Members and 1 Guest are viewing this topic.
California
Offline Offline
Jr. Member
**
Karma: 0
Posts: 58
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
//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);
}
« Last Edit: June 18, 2012, 07:01:31 pm by mykiscool » Logged

Proud Member of the Nighthawk Robotics Club Team 569 B

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1287
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

It is possible that you are counting multiple times each time the sensor is triggered, as the code will execute very fast.

You need to include some form of trigger detection. This is done by remembering if the digital input was low or high the last time you checked and only counting the low to high (or high to low) transitions.

A relatively straightforward way to do this is to use an interrupt that will be triggered on the transition only - there is lots of stuff on hte board on how this can be done.
Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

California
Offline Offline
Jr. Member
**
Karma: 0
Posts: 58
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok thanks that's a good idea. Ill look into it and get back to you if it doesn't work.
Logged

Proud Member of the Nighthawk Robotics Club Team 569 B

New Hampshire
Offline Offline
God Member
*****
Karma: 17
Posts: 781
There are 10 kinds of people, those who know binary, and those who don't.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
//convert milliseconds to seconds
RPS=(float)timeSincePass*1000;

You convert milliseconds to seconds by dividing by 1000, not multiplying by 1000.

Then RPS is 1 / time for 1 revolution (I assume that's your timeSincePass value).
Logged


Fort Lauderdale, FL
Offline Offline
Faraday Member
**
Karma: 71
Posts: 6144
Baldengineer
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
//convert milliseconds to seconds
RPS=(float)timeSincePass*1000;
You convert milliseconds to seconds by dividing by 1000, not multiplying by 1000.

It is also a good practice to make your constants match the kind of math you are doing.  "1000" is an integer constant.  "1000.0" is a float constant.
Logged

Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.c

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 33
Posts: 1287
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I also don't see any of the logic that I would expect in this code.

There are 2 ways to do this:
1. Count how long it takes for one revolution (sec/rev) and then take the reciprocal to get rev/sec. You will probably count ms so a conversion will be required.
2. Count the number of 'clicks' in a second (or partial second) and then use the count directly.

What was your intention here?
« Last Edit: June 18, 2012, 10:02:16 pm by marco_c » Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

California
Offline Offline
Jr. Member
**
Karma: 0
Posts: 58
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

My intention was to measure the speed of a bike wheel as it turns in revolutions per second or minute and then calculate that to the actual speed using the wheel size. Also I tried using a debounce to make sure I wasn't getting the magnetic reed giving me 2 readings and I still have the same thing not the right reading. Any suggestions?
Logged

Proud Member of the Nighthawk Robotics Club Team 569 B

California
Offline Offline
Jr. Member
**
Karma: 0
Posts: 58
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I sort of made it into a reciprocal when I divided 1000 by the milliseconds which would be the same as dividing 1 by the seconds. Ex: 5 seconds = 5/1 1 divided by 5 = 1/5 opposite of 5/1. I think the math is right as far as i can tell. Constructive criticism would be appreciated to help me find the right solution.
Logged

Proud Member of the Nighthawk Robotics Club Team 569 B

Global Moderator
Melbourne, Australia
Offline Offline
Brattain Member
*****
Karma: 511
Posts: 19306
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Show us your new code.
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

California
Offline Offline
Jr. Member
**
Karma: 0
Posts: 58
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's my updated code to include a debounce:

Code:

//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;
//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)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);
  lastReedState = reading;
}
Logged

Proud Member of the Nighthawk Robotics Club Team 569 B

New Hampshire
Offline Offline
God Member
*****
Karma: 17
Posts: 781
There are 10 kinds of people, those who know binary, and those who don't.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I sort of made it into a reciprocal when I divided 1000 by the milliseconds which would be the same as dividing 1 by the seconds. Ex: 5 seconds = 5/1 1 divided by 5 = 1/5 opposite of 5/1. I think the math is right as far as i can tell. Constructive criticism would be appreciated to help me find the right solution.

I don't see any divisions anywhere.
Logged


California
Offline Offline
Jr. Member
**
Karma: 0
Posts: 58
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ooops sorry I thought I made that division change that he suggested Ill change it and get back to you.
Logged

Proud Member of the Nighthawk Robotics Club Team 569 B

California
Offline Offline
Jr. Member
**
Karma: 0
Posts: 58
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok now I'm getting somewhat more realistic numbers like 200 and 250 revs per second, but still those are the only 2 readings I'm getting.

Code:

//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;
//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)1000/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;
}
Logged

Proud Member of the Nighthawk Robotics Club Team 569 B

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 99
Posts: 4835
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

My intention was to measure the speed of a bike wheel as it turns in revolutions per second or minute and then calculate that to the actual speed using the wheel size. Also I tried using a debounce to make sure I wasn't getting the magnetic reed giving me 2 readings and I still have the same thing not the right reading. Any suggestions?

Just be aware that "wheel size" depends on tire pressure, tire width and load on the wheel as well as the nominal diameter. At 75 psi it will be less than at 90 or 110.

IMO you should make a small solid wheel that the bicycle wheel turns and find the rpms of that.
Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

New Hampshire
Offline Offline
God Member
*****
Karma: 17
Posts: 781
There are 10 kinds of people, those who know binary, and those who don't.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Ok now I'm getting somewhat more realistic numbers like 200 and 250 revs per second, but still those are the only 2 readings I'm getting.

It's a resolution issue, in this case the resolution of your timer.

milliseconds returns whole millisecond results, so:
1000/4 = 250.
1000/5 = 200.

You'll never get any values between 4 and 5, so you'll never get any results between 250 and 200.

One easy option here is to switch to a higher resolution timer, ie use micros() instead of millis.  You'll need to adjust your calculations appropriately.
Logged


Pages: [1] 2   Go Up
Jump to: