RPM - not working

I lifted some code others have posted to do a sanity check. I have a 6 window 1" optical wheel on a motor shaft. I have a commercial RPM meter to check against. I am crazy off. The code comments in the post (can't remember where) said scale the number based on the number of windows your wheel has. So I adjusted it to 6 holes per revolution. I am reading 23k RPM when I should be in the 4k RPM range or something. See capture below...RPM and hole counter from the interrupt. Any help is much appreciated.

23520.00
2374
23700.00
2369
23640.00
2372
23700.00
2372
23700.00
2392
23880.00
2382
23820.00

float rpm = 0;
int pid;
unsigned long millisBefore;
volatile int holes;
void setup()
{
  Serial.begin(9600); 
  pinMode(2, INPUT);
  attachInterrupt(digitalPinToInterrupt(2), count, FALLING);
  delay(1000);

}
void loop()
{
 
  if (millis() - millisBefore > 1000) {
    rpm = (holes / 6)*60;
    holes = 0;
    millisBefore = millis();
  }
  
  delay(2000);
  Serial.println(rpm);
 
  Serial.println(holes);
}

void count() {
  holes++;
}

Hi,
Can you post a circuit diagram of your project please?
A hand drawn image will be good.

Can you post image(s) of your project, showing the optical sensor assembly?

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

Hi,
Try this edit to your code, I have edited the equation to use all float variables.
Also set the IDE monitor to 115200 baud, much better.

float rpm = 0;
int pid;
unsigned long millisBefore;
volatile int holes;
void setup()
{
  Serial.begin(115200);
  pinMode(2, INPUT);
  attachInterrupt(digitalPinToInterrupt(2), count, FALLING);
  delay(1000);
}
void loop()
{
  if (millis() - millisBefore > 1000)
  {
    rpm = ((float)holes * 60.0) / 6.0;
    holes = 0;
    millisBefore = millis();
  }
  delay(2000);
  Serial.print(" Holes = ");
  Serial.print(holes);
  Serial.print("   RPM = ");
  Serial.println(rpm);
}

void count()
{
  holes++;
}

Tom... :smiley: :+1: :coffee: :australia:

You MUST protect variables shared with interrupt routines from corruption, while they are being accessed in the main program.

Here is how to fix that problem. Replace this:

   Serial.print(holes);

with this

  noInterrupts();
  int holes_copy = holes;
  interrupts();
  Serial.print(holes_copy);

Hi Tom,

The values are off....I am running the motor real slow and my commercial counter says 2,110 RPM

Holes = 1173 RPM = 11610.00
Holes = 1131 RPM = 11730.00
Holes = 1139 RPM = 11310.00
Holes = 1157 RPM = 11390.00
Holes = 1164 RPM = 11570.00
Holes = 1368 RPM = 11660.00
Holes = 1504 RPM = 13680.00
Holes = 1474 RPM = 15060.00
Holes = 1459 RPM = 14740.00
Holes = 1461 RPM = 14610.00
Holes = 1478 RPM = 14630.00
Holes = 1461 RPM = 14780.00
Holes = 1486 RPM = 14610.00
Holes = 1489 RPM = 14880.00
Holes = 1487 RPM = 14900.00

Also the numbers seem all over the place when counting holes. Weird.

At least partially because of the issue noted above. Also, if the optical setup is not completely reliable, you will be getting spurious counts at the edges, or missing counts. The only way to be sure is to use an oscilloscope to look at the detector output.

What is the optical detector? Post a link or photo.


This is a 3-D printed wheel and sensor. I will check out the output signal on the Oscope. Tomorrow, my workshop is in the garage. Will post back what I find.

The detector is just a phototransistor, so you can expect spurious counts on the transitions. https://www.mouser.com/datasheet/2/143/ITR9608-41267.pdf

Most people use a comparator with hysteresis to clean up the signal. These inexpensive wheel encoders from DFRobot use that principle, and work surprisingly well. https://www.robotshop.com/en/dfrobot-wheel-encoders-dfrobot-3pa-4wd-rovers-2pk.html

Incidentally, I believe that this equation is correct (revolution counts per second, times 60 seconds/minute):
rpm = (holes / 6)*60;

Tom reversed the numerical quantities, which seems not to be correct.

Mixing delay() and millis() is not good. During the delay(2000) the ISR is still incrementing the value of holes so the number will be twice what you expect to collect in one second.
Post a link to that module marked ITR-9608. It may be you need a pull up resistor.

Hi,
What happens if you cover the encoder so it is in the dark?

rpm = ((float)holes * 60.0) / 6.0;

Is the same, (BODMAS) just I believe multiplying first will give a number with more accurate division in a 8 bit world.
What Is BODMAS & What is BIDMAS? Explanation for Parents.

That's what I think.. Tom.. :smiley: :coffee: :+1:

You are right, I didn't notice that change in operators.

Both reduce to holes*10 which is exact for integer arithmetic.

[quote="6v6gt, post:9, topic:998037"
ITR-9608
[/quote]

This is the module URL ITR9608-Photo Sensor - CQRobot-Wiki.
Actually this ISR only needs to happen once every 5mins. It is a subroutine in a bigger code I wrote. The other stuff is debugged and works. I just need to go into a subroutine for 100ms to capture enough counts to do a bit of math to figure out RPM.

This simplifies to "* 10"

If you don't have a scope, turn the motor shaft by hand and check to see if you get multiple transitions from the sensor, as a slot passes.

So I got some image captures running at 5,108 rpm on a commercial meter. No jitter clean transitions. No multiple noise edges. The screen grabs have cursors measuring the pulse edges including period and frequency.



According to the scope, 505 Hz = 5050 RPM, so that agrees with the commercial meter.

Have you fixed the interrupt corruption problem?

Did all the changes. Still the same thing. I resorted to good old pulsein and it gave the same crudd. I moved from an uno to mega. Same thing. I'm frustrated by this.....

2110 RPM times 6 pulses per revolution should be 12660 pulses per minute or 211 pulses per second.

Your Arduino is reading about 6 times that. :frowning:

Are you sure your Arduino and the device producing the pulses share a Ground?

Power is from the Arduino board for the optical sensor. Yes common ground.

Very mysterious!