Pages: [1]   Go Down
Author Topic: ReadingRPM code from Playground adapted for a bicycle  (Read 673 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 33
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi All,

I am attempting to adapt the http://www.arduino.cc/playground/Main/ReadingRPM code from the playground for my specific purposes.
Instead of reading a fan's RPM, I want to read the RPM from a bicycle.  I've got a cyclocomputer sensor attached to my stationary bike and a magnet on the spoke, so we're dealing with a basic reed switch. 

The code actually works well.  I have it set to calculate the RPM every rotation and print the value to the serial monitor. 
I'm using the RPM values to determine whether or not to send play or stop messages to a Robertsonics MP3 Trigger. 

Here's the issue:  The RPM can only be calculated when the magnet passes the sensor each time.  So if the magnet passes the sensor and then the wheel does not complete another full rotation, the RPM value will not be updated.  I've installed a brake on the bicycle and it's possible to stop the wheel very quickly.  In other words, the bike will be stopped (or close to stopping), but the computer doesn't know that, so the track continues to play even though I'd like it to stop.

So right now, the sound will stop if the RPM falls below a set value, but if that low value is never recieved (because of the brake), the sound will keep going.  I'd like the program to be able to detect if the wheel has stopped without making another full rotation.

The ReadingRPM code uses interrupts, and I wonder if it might make more sense to use digitalRead(), allowing me to measure the time in between rotation.  This might be possible within the interrupt function, but I'd be pretty clueless on how to do that.

Here's the code as it stands.  I'd appreciate any help or suggestions for how to make my program more robust.  I realize I could just remove the brake or maybe add more magnets, but having a software solution would be preferable.
Thanks!

Code:
/*Reed switch from cyclocmputer attached to Digital Pin 2.  Magnet attached to spoke. 
 Take constant readings and send serial messages to Robertsonics MP3 trigger if certain conditions are met */
 
 volatile byte rpmcount;

 unsigned int rpm;

 unsigned long timeold;
 
 int bikePlaying = 0;
 
 byte volume = 255;

 void setup()
 {
   Serial.begin(38400);
   attachInterrupt(0, rpm_fun, RISING);
   Serial.write('v');      //Serial message for volume
   Serial.write(volume);   //Set volume at lowest value

   rpmcount = 0;
   rpm = 0;
   timeold = 0;
 }

 void loop()
 {
   if (rpmcount >= 1) {
     //Update RPM every 1 count, increase this for better RPM resolution,
     //decrease for faster update
     
     rpm = 30*1000/(millis() - timeold)*rpmcount;
     timeold = millis();
     rpmcount = 0;
     Serial.println(rpm,DEC);
     
     if((rpm >= 80) && (bikePlaying == 0)){    //if a certain RPM is reached
      Serial.write('t');                       //Play Track 2 stored on MP3 Trigger
      Serial.write(2);
       
       bikePlaying = 1;       
       
       while (volume != 1) {       
         fadeIn();                          //Fade volume in from min to max.
       }
       
       delay(3000);
     }
   
     if ((rpm <= 40) && (bikePlaying == 1)) {      //If RPM falls below 40 and MP3 was playing
     
       while (volume < 255) {
        fadeOut();                                //Fade out,
      }     
     
      if (volume = 255) {                        //Then Stop.
     
      Serial.write('O');    //Serial message for "stop"
      bikePlaying = 0;      //playing is off....
      delay(3000);
     
      }
     }
   }
 }


 void rpm_fun()
 {
   rpmcount++;
   //Each rotation, this interrupt function is run twice
 }
 
 
void fadeOut() {
volume += (240/100);
delay(40);
Serial.write('v');
Serial.write(volume);
}

void fadeIn() {
volume -= (240/100);
delay(40);
Serial.write('v');
Serial.write(volume);
}

Logged

0
Offline Offline
Shannon Member
****
Karma: 200
Posts: 11730
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You are currently only calculating the speed on the reed switch event.  You can also calculate the speed on a regular clock tick on the assumption that the reed switch is about to make contact.  If this second reading is _lower_ than the other value it means you are decelerating and you should override the reading with this lower value.  That way the current speed reading will decrease towards zero when you stop pedalling rather than staying as the value from the last compete revolution.
Logged

[ I won't respond to messages, use the forum please ]

Offline Offline
Newbie
*
Karma: 0
Posts: 33
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the reply.

It sounds like you're suggesting that I also calculate the speed of the wheel at all times, and compare each speed value to the one before it to detect deceleration.
Is that correct?  Is there anything I should keep in mind considering this would be utilizing an interrupt function versus analogRead?

That would solve the problem that came up when pedalling and then allowing the wheel to come to rest naturally.

But what about pedalling and then hitting the brake, which on a stationary trainer makes the wheel stop almost instantly?
It seems that if the wheel was rotating regularly and then immediately stopped (without another switch contact), the speed or RPM reading wouldn't update.
Maybe I'm missing something there.
Logged

Pages: [1]   Go Up
Jump to: