California
Offline
Newbie
Karma: 0
Posts: 44
|
 |
« on: June 18, 2012, 06:59:15 pm » |
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. //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
Offline
God Member
Karma: 15
Posts: 743
Big things come in large packages
|
 |
« Reply #1 on: June 18, 2012, 07:24:11 pm » |
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
|
|
|
|
|
California
Offline
Newbie
Karma: 0
Posts: 44
|
 |
« Reply #2 on: June 18, 2012, 07:28:40 pm » |
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
God Member
Karma: 13
Posts: 776
There are 10 kinds of people, those who know binary, and those who don't.
|
 |
« Reply #3 on: June 18, 2012, 07:37:43 pm » |
//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
|
|
|
|
|
Austin, TX
Offline
Faraday Member
Karma: 42
Posts: 5248
CMiYC
|
 |
« Reply #4 on: June 18, 2012, 08:35:14 pm » |
//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
|
|
|
|
|
Sydney
Offline
God Member
Karma: 15
Posts: 743
Big things come in large packages
|
 |
« Reply #5 on: June 18, 2012, 09:12:36 pm » |
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
|
|
|
|
|
California
Offline
Newbie
Karma: 0
Posts: 44
|
 |
« Reply #6 on: June 18, 2012, 11:52:01 pm » |
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
Newbie
Karma: 0
Posts: 44
|
 |
« Reply #7 on: June 18, 2012, 11:59:14 pm » |
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
Shannon Member
Karma: 226
Posts: 14101
Lua rocks!
|
 |
« Reply #8 on: June 19, 2012, 01:07:44 am » |
Show us your new code.
|
|
|
|
|
Logged
|
|
|
|
|
California
Offline
Newbie
Karma: 0
Posts: 44
|
 |
« Reply #9 on: June 19, 2012, 08:48:03 am » |
Here's my updated code to include a debounce: //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
God Member
Karma: 13
Posts: 776
There are 10 kinds of people, those who know binary, and those who don't.
|
 |
« Reply #10 on: June 19, 2012, 09:09:11 am » |
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
Newbie
Karma: 0
Posts: 44
|
 |
« Reply #11 on: June 19, 2012, 09:42:21 am » |
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
Newbie
Karma: 0
Posts: 44
|
 |
« Reply #12 on: June 19, 2012, 09:44:32 am » |
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. //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
Faraday Member
Karma: 33
Posts: 3016
I only know some basic electricity....
|
 |
« Reply #13 on: June 19, 2012, 10:03:20 am » |
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
|
Examples can be found at Learning in the Main Site and at the Playground
|
|
|
|
New Hampshire
Offline
God Member
Karma: 13
Posts: 776
There are 10 kinds of people, those who know binary, and those who don't.
|
 |
« Reply #14 on: June 19, 2012, 12:08:06 pm » |
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
|
|
|
|
|
|