RPM calclater

How to make a RPM calculater with arduino>…??
I wanna calculate rpms of some of my motors . I am planning to do it using a IR sensor(easiest to make)
I have attached a wheel to the motor and pasted a black circle over the wheel with only one stripe of white(see the pic, u’ll understand)
so whenever the ir rays are reflected by the white strip, arduino reads it ad calculate how many times the rays are received i.e. RPM of the motor.
I do not noe how to make a stopwatch such that the arduino stop reading the rays after a minute. :zipper_mouth_face: =(
Reagrds,
Shubham Garg

Use the millis() function.
Something like this:

void loop(){

//read the current time

current_time = millis();
//then count until 1 minute (= 60*1000 ms, 60000mS) has elapsed
while (millis()<=(current_time+60000)){
count=count+1; // every time a black/white transition is detected, will leave that to you
}
Serial.print(count);
}

How fast will the motor run? Will it run outdoor with the IR from sun mixed with your sensor? Maybe a Hall Effect Switch with a magnet is better.

Look in: http://arduino.cc/en/Reference/PulseIn Return value would be in reverse proportion to RPM.

thx every1 fr the reply...:) @crossroads, your sol works great except that whenever the wheel rotates single time, instead of showing 1 count it shows multiple of them. how to fix this?

Please post your current code so we can have a look

here is the code:

int count ;
int ir = 5 ; 
int current_time ;

void setup(){
Serial.begin(9600) ;
Serial.print("start")  ;
}

void loop(){   //read the current time

current_time = millis();
//then count until 1 minute (= 60*1000 ms, 60000mS) has elapsed
if (millis()<=(current_time+60000)){
  if(digitalRead(ir) == LOW)
  {
count=count+1; // every time a black/white transition is detected, will leave that to you
Serial.println(count);
  }
}
else
{
  
}
}

here is the result:(on a single transition)

start1
2
3
4
5
6
7
8
9
10
11
12

if(digitalRead(ir) == LOW)
{
count=count+1; // every time a black/white transition is detected, will leave that to you
Serial.println(count);
}

This is incorrect logic, what you do is check the state of the sensor, not if there is a transition. A transition is a change. To measure a change you need a current value and a previous value. See code below.

(code not tested or compiled …

#define IRPIN 5

unsigned int count;  // can only be positive
unsigned long current_time;
int prevState;  //  LOW = BLACK, HIGH = WHITE
int newState;

void setup()
{
  Serial.begin(115200) ;
  Serial.println("Start RPM 0.1") ;
  pinMode (IRPIN, INPUT);
}

void loop()
{ 
  count = 0;  
  prevState = digitalRead(IRPIN );   // read the reference state
  current_time = millis();

  //count until 1 minute (= 60*1000 ms, 60000mS) has elapsed
  while (millis() - 60000L <= current_time )  // use L for LONG math !!!
  {
    newState = digitalRead(IRPIN);
    if (prevState == LOW && newState == HIGH)  // this is a transition from LOW to HIGH
    {
      count++
    }
    prevState = newState;
  }
  Serial.println();
  Serial.print("RPM: ")
  Serial.println(count);
}

Succes,
Rob

@robtillaart
here is the code(compiles)

#define IRPIN 5

unsigned int count;  // can only be positive
unsigned long current_time;
int prevState;  //  LOW = BLACK, HIGH = WHITE
int newState;

void setup()
{
  Serial.begin(115200) ;
  Serial.println("Start RPM 0.1") ;
}

void loop()
{ 
  count = 0;  
  prevState = digitalRead(IRPIN );   // read the reference state
  current_time = millis();

  //count until 1 minute (= 60*1000 ms, 60000mS) has elapsed
  while (millis() - 60000L <= current_time )  // use L for LONG math !!!
  {
    newState = digitalRead(IRPIN);
    if (prevState == LOW && newState == HIGH)  // this is a transition from LOW to HIGH
    {
      count++ ;
    }
    prevState = newState;
  }
  Serial.println();
  Serial.print("RPM: ") ;
  Serial.println(count);
}

here is he result

2eÆ?J$!6
???
?

what’s wrong with this?

Serial.begin is set 115200. You probably have your serial monitor set to 9600.

Mark

Check your baud rates - your original code was at 9600, the latest is at 115200 - what is your serial monitor set at?

@robtillart,

while (millis() - 60000L <= current_time ) // use L for LONG math !!!

Should this be UL for unsigned long, to agree with millis() and current_time?

Should this be UL for unsigned long, to agree with millis() and current_time?

point is that 60000 is not in the int range so should be declared as a datatype larger than int.
Long is OK, Unsigned long is probably better as it keeps the whole math in unsigned long.

Thanx for this addition.

BaudRate (why 115200)
I changed the baudrate as it takes 12x less time at 115200 than 9600 to transmit a character. It gives the inner loop While (millis() - 60000L <= current_time) … the change to stop after 60000 millis (almost) exactly. Recall there was a print of count in this while loop earlier. This print would take a few millis @9600 but @115200 it prints in less (or about) than 1 millis. Reading the code over before posting made me decide to remove the print statement altogether to optimize the timing to the max.

Rob

Hi guys. I just read at the discussion here, and the RPM counter program do sample every minute. Just like : Turn / minute. OK But What if it can be reprogram to take sample every second. Like : Sample -->Numbers of Turn / second re-calculate into Turns / min and display the result via serial ? I assume the motor is a high speed type ( electric motor ) So the data sample will be for example : 15 count in 1 second---> Take 15 * 60 = 900 rpm. Heh, I just don't like to wait every minute. Just an idea.

Good idea but (there is allways a but) you get the granularity. 900 RPM jumps to 960 RPM or 840 RPM

You should count per second, but keep a sum of the last 60 seconds or so.

something like this: not ideal but

#define IRPIN 5

unsigned int count;  // can only be positive
unsigned long current_time;
int prevState;  //  LOW = BLACK, HIGH = WHITE
int newState;

void setup()
{
  Serial.begin(115200) ;
  Serial.println("Start RPM 0.1") ;
  pinMode (IRPIN, INPUT);
  prevState = digitalRead(IRPIN );   // read the reference state
}

int idx;
int count[60];
int sum; 

void loop()
{ 
  current_time = millis();

  idx = (current_time/1000) % 60;
  sum = sum - count[idx];           // remove current second of prev minute

  // COLLECT
  count[idx] = 0;
  while (millis() - 1000L <= current_time )  // use L for LONG math !!!
  {
    newState = digitalRead(IRPIN);
    if (prevState == LOW && newState == HIGH)  // this is a transition from LOW to HIGH
    {
      count[idx]++ ;
    }
    prevState = newState;
  }
  sum = sum + count[idx];       // add current second of this minute

  // DISPLAY
  Serial.println();
  Serial.print("RPM: ") ;
  Serial.println(sum);
}

drawback is that it has a delay, the running average of the last 5 seconds iso 60 will follow the RPM faster.

I like the discussion going on, :D :D..

@CrossRoads, I did changed the baudrate to 9600 and

Serial.println("Start RPM 0.1") ;

to "start RPM 1" the result was like this

RPM = 0 RPM = 0 RPM = 0

"0" val was not changing..:(...

I did changed the baudrate to 9600 and

Don't you want the baud rate to be as high as possible, so that you don't miss too many pulses when you're printing results?

Don’t you want the baud rate to be as high as possible, so that you don’t miss too many pulses when you’re printing results?

i’ll change the baud rate, that’s not the prob here, the thing is why it is showing RPM = o everytime and i also removed “count = 0”
here is the final code

#define IRPIN 5

unsigned int count;  // can only be positive
unsigned long current_time;
int prevState;  //  LOW = BLACK, HIGH = WHITE
int newState;

void setup()
{
  Serial.begin(115200) ;
  Serial.println("Start RPM 01") ;
}

void loop()
{ 
   prevState = digitalRead(IRPIN );   // read the reference state
  current_time = millis();

  //count until 1 minute (= 60*1000 ms, 60000mS) has elapsed
  while (millis() - 60000L <= current_time )  // use L for LONG math !!!
  {
    newState = digitalRead(IRPIN);
    if (prevState == HIGH && newState == LOW)  // this is a transition from LOW to HIGH
    {
      count++ ;
    }
    prevState = newState;
  }
  Serial.println();
  Serial.print("RPM: ") ;
  Serial.println(count);
}

That is a valid response if the wheel is not moving.

So the question is does the sensor work?

What is the output of this minimal sketch that should detect the pulse..

#define IRPIN 5

void setup()
{
  Serial.begin(115200) ;           /////////////////////////  fastest baudrate is needed !!
  Serial.println("Start test RPM sensor  0.1");
  pinMode (IRPIN, INPUT);
}

void loop()
{ 
  if (digitalRead(IRPIN) == HIGH) Serial.println(millis());
}

Well, the obvious answer is that "count" is not being incremented. Now, I think that pins default to input, but I always like to be sure.

@

Start test RPM sensor  0.1
2
2
2
3
3
3
3
4
4
4
4
5
5
5
5
6
6
6
6
7
7
7
7
7

it stops when not detecting