GEAR RPM

Dear Arduino lover,

I am trying to calculate gear rpm (which has 36 teeth). For some reasons, I am getting different rpm values than the real tachometer. I suppose that my rpm calculation logic might be wrong.

My simple code to do so is:

sr = analog.Read(A1);
if(sr<10 ) {
val = HIGH;
}
else {val = LOW;}

if (val == 1 and prev_val == 0){
timer = micros();
rpm = ((1000000*60)/((timer - ct)*35));
ct = micros();
Serial.println(rpm);
}
prev_val = val;

The sensor values for interfacing gear tooth is analog 3-4 and when not interfacing gear tooth is 200.

In the above code i made a quick logic summary that i use, could you help me out with suggestions.

Thanks in advance.

What is sensing the gear teeth? What is the RPM range of the gear? Post ALL your code.

Gear RPM range is about 0 to 4000 RPM.

So up to 2400 pulses per second (down to 416 microseconds between pulses).

I think you may need a digital rather than analog sensor.

For testing my sensor operation I am using low RPM speeds only (up to 800 rpm) and still getting wrong (lower rpm) comparing to digital tachometer of sensor.

johnwasser:
So up to 2400 pulses per second (down to 416 microseconds between pulses).

I think you may need a digital rather than analog sensor.

So, is there speed difference between the analog and digital signals reading?

I don't think the problem is that you are using analogRead(). I think the problem is that you are missing teeth because something in your sketch is taking more than half a millisecond and you aren't checking the analog input often enough to see every tooth. If you miss a tooth you will get an RPM reading that is HALF the actual speed. If you are LATE reading a tooth (you don't look at the input within a microsecond or two of the signal changing) you will get longer intervals and therefore lower speeds.

What sensor are you using?

johnwasser:
I don't think the problem is that you are using analogRead(). I think the problem is that you are missing teeth because something in your sketch is taking more than half a millisecond and you aren't checking the analog input often enough to see every tooth. If you miss a tooth you will get an RPM reading that is HALF the actual speed. If you are LATE reading a tooth (you don't look at the input within a microsecond or two of the signal changing) you will get longer intervals and therefore lower speeds.

What sensor are you using?

Actually I tried to read rpm using very simple code as I posted above, but still reading wasn't perfect.

I am using magneto-type hall effect sensor, which works up to 20kHz.
link:

Output waveform
rectangular waveform
Hi : 5V±0.5V
Lo : +0.5V or less

That is a 5V digital signal. You can use A1 as a digital pin so no need to re-wire. Set pinMode(A1, INPUT); and digitalRead(A1);

Better yet, connect it to an external interrupt pin and measure the time for 36 interrupts.

johnwasser:
Output waveform
rectangular waveform
Hi : 5V±0.5V
Lo : +0.5V or less

That is a 5V digital signal. You can use A1 as a digital pin so no need to re-wire. Set pinMode(A1, INPUT); and digitalRead(A1);

Better yet, connect it to an external interrupt pin and measure the time for 36 interrupts.

On my main project I use arduino base plc to do very simple tasks and since that plc operates at 24V I used analog read for input.
I tried Arduino UNO just for RPM calculating as you mentioned but the rpm reading was still same, lower than actual one.

Askat:
Gear RPM range is about 0 to 4000 RPM.

when you say 4000, you mean the axle is turning at max 4000rpm OR teeth pulses are max 4000 per minute?

Askat:
I tried Arduino UNO just for RPM calculating as you mentioned but the rpm reading was still same, lower than actual one.

Did your sketch use interrupts to measure the RPM? If not, you are probably missing pulses which would give you a lower speed.

const byte RPMSensor_DIPin = 2;
const byte GearTeeth = 36;

volatile unsigned long MicrosecondsPerRevolution = 0;

void setup()
{
  pinMode(RPMSensor_DIPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(RPMSensor_DIPin), pulse, RISING);
}

void pulse()
{
  static unsigned long revolutionStartTime = 0;
  static byte counter = 0;
  counter++;
  if (counter >= GearTeeth)
  {
    unsigned long time = micros();
    MicrosecondsPerRevolution = time - revolutionStartTime;
    revolutionStartTime = time;
    counter = 0;
  }
}

void loop()
{
  unsigned long mpr;
  noInterrupts();
  mpr = MicrosecondsPerRevolution;
  interrupts();

  if (mpr != 0)
  {
    Serial.print(60000000.0 / mpr);  // Display RPM
  }
  
  delay(10000);
}

GRuser:
when you say 4000, you mean the axle is turning at max 4000rpm OR teeth pulses are max 4000 per minute?

The sensor spec says it is good for 20 kHz (or 20,000 RPM on a 60-tooth gear). Since the gear here is 36-tooth the sensor should be good up to 33,333 RPM.

johnwasser:
The sensor spec says it is good for 20 kHz (or 20,000 RPM on a 60-tooth gear). Since the gear here is 36-tooth the sensor should be good up to 33,333 RPM.

ok, hadn t see the link.

Askat:

sr = analog.Read(A1);

if(sr<10 ) {
val = HIGH;
}
else {val = LOW;}

if (val == 1 and prev_val == 0){
timer = micros();
rpm = ((1000000*60)/((timer - ct)*35));
ct = micros();
Serial.println(rpm);
}
prev_val = val;

[/quote]

is it sure that this sketch compiles?

...
sr = analog.Read(A1);
...

johnwasser:
Did your sketch use interrupts to measure the RPM? If not, you are probably missing pulses which would give you a lower speed.

Thank you very much John, I will try to check RPM with interrupts.

GRuser:
is it sure that this sketch compiles?

Sorry I just typed code here, since I had no access to lab computer at that time.
So my code for rpm reading was like:

int sw = analogRead(rpm_sensor);   
       if (sw < 10){   // Reading with 24V operating device (1 unit where stands for 0.03V)
         val = LOW;
         }
       if(sw>140){
         val=HIGH;
         }

       if(val == 1 and prev_val==0){
         t = micros();
         rpm = (1000000*60/((t-ct)*35));
         
         if(rpm>0 && rpm>rpm_max){
           rpm_max = rpm;
          }

         ct = micros();
       }
       prev_val=val; 
      Serial.println(rpm);

@johnwasser

Excellent Code as always Sir! I'm just running it from my pulse generator at the moment, but certainly looks like something that I can use.

You have more juicy code here: get crank angle

I think I'll need something like this to get the get the timing right for the next step of my project. Just need a few minute (hours? days?) to modify it for my needs.

Your help/code on my last project was incredibly useful, so don't be surprised if I start stalking your threads here :wink:

Cheers!

Matt

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.