Question about calculating RPM from encoder

Hello
I am trying to record RPM as soon as I get new pulse from encoder
For one revolution, I found out that the number of pulses is 42000.
As the motor spins, I timed once and as the new pulse came out, I timed again to calculate the difference of time.

so I got the equation of RPM
rpm = ((float)incre_temp/42000.0)/((float)incre_time/(1000.0*60.0));
incre_temp is the differnce of pulse
incre_time is the difference of pulse as pulse changes.

I could not get the correct RPM

Please look at my code and correct me if you see the problem.

#define DIR_PIN 8
#define STEP_PIN 9
#define motorenable 10

int encoder0PinA = 2;
int encoder0PinB = 3;

volatile long encoder0Pos = 0;
volatile int encoder0PinALast = LOW;
volatile int n = LOW;
volatile int m = LOW;
int valNew = 0;
int valOld = 0;

long temp;
long incre_temp;
float rpm;
long incre_time;
long finish;

void setup()
{
pinMode(DIR_PIN, OUTPUT);
pinMode(STEP_PIN, OUTPUT);
pinMode(motorenable, OUTPUT);

pinMode (encoder0PinA,INPUT);
pinMode (encoder0PinB,INPUT);
Serial.begin (115200);
attachInterrupt(1, CountA, CHANGE);
attachInterrupt(0, StateB, FALLING);
}

void loop()
{
long pulse = 42000;
double motor_speed = 1;
int dir = (pulse < 0)? HIGH:LOW;
digitalWrite(motorenable, HIGH);
long start = millis();
digitalWrite(DIR_PIN,dir);
digitalWrite(STEP_PIN, motor_speed);

if(temp >= pulse)
{
digitalWrite(motorenable, LOW);
delay(100000);

}
Serial.print("Position: ");
Serial.println(temp);
incre_temp = abs(temp-encoder0Pos);
incre_time = finish - start;
rpm = ((float)incre_temp/42000.0)/((float)incre_time/(1000.0*60.0));
Serial.print("RPM: ");
Serial.println(rpm);
}

void CountA()
{
n = digitalRead(encoder0PinA);
if ((encoder0PinALast == LOW) && (n == HIGH))
{
if (m == LOW)
{
temp = encoder0Pos--;
finish = millis();
}
else
{
temp = encoder0Pos++;
finish = millis();
}
}
}
void StateB()
{
m = digitalRead(encoder0PinB);
}

For one revolution, I found out that the number of pulses is 42000.

How fast is this thing revolving? In one of your other posts, you said this encoder is attached to a 12000 RPM motor. That would be 504,000,000 pulses per minute or 8,400,000 pulses per second. You can't fire that many interrupts in 1 second, even if the ISR just did a return.

All variables references in an ISR MUST be declared volatile. Are all of yours? No.

Is temp a good name for a global variable? Hell, no.

Are m and n meaningful names? No.

After 42000 pulses, regardless of how often you miss interrupts, you shut the motor off and delay for some ridiculous period of time. Then, you try to calculate RPM.

While the motor is running, you print out temp to the serial port. A few thousand interrupts later, you record compute incre_temp. A few thousand interrupts later, you record incre_time. Then, you compute rpm.

And, you don't get a good value. Well, duh.

That and millis() doesn't work in an ISR.

millis() doesn't work in an ISR.

It works, in that it returns a value.

It doesn't work, in that the value doesn't change during an ISR, so calling it more than once will not result in different values.

Just to be clear.

For one revolution, I found out that the number of pulses is 42000.

Then quite simply you are using the wrong encoder for the job.

Then quite simply you are using the wrong encoder for the job.

Attach that encoder to the earth, and you would get 115 pulses a day (almost 5 an hour). If you could attach the other end to something else, that is. The Arduino could keep up with that rate of pulses.

Holy Foucault's pendulum Batman!

@PaulS
Thank you for your reply
I actually have no idea how fast my motor runs. I just mentioned in the code that the speed is 0.1. If i put it as 1(max speed), the encoder could not read the pulse. so the only choice I have was 0.1(which is slower than what we need.)
The motor info is
https://downloads.maxonmotor.com/Katalog_neu/eshop/Downloads/Katalog_PDF/maxon_ec_motor/EC-max-programm/new/newpdf_11/EC-max-22-283837_11_EN_164.pdf

and could you explain what the ISR is? I am sorry this is my first time I use arduino code.

To calculate incre_temp and incre_time, what do you mean a few thousand interrupts later? then what do I need to fix it? Can you show me what I miss?

Thanks.

also I got the number of pulses of one revolution
500*84 = 42000

500 is from the encoder
and 84 is the ratio of the gear box

I actually dont know how those combination made the one revolution, but looks like it did.

ISR = Interrupt service routine - in other words the function that is called when the interrupt occurs.

Look at the nominal speed column in your link (on page 1). Which specific motor do you have? The nominal speeds shown range from 7,300 RPM to 8,260 RPM. The no-load speeds go up to 12,100 RPM

and 84 is the ratio of the gear box

Up or down?

500 is from the encoder

Is the encoder on the motor or on the gearbox?

If you are getting 42,000 pulses per revolution, and turning 12,100 RPM, that's 8,400,000+ pulses per second. At 16Mhz, you'd have 2 clock cycles to call the interrupt, have it do it's thing, and return. The return alone takes one clock cycle.

There is just no way to keep up. If, on the other hand, the motor is turning 7,300 RPM, geared down 84 to 1, the output is about 87 RPM. If the encoder is on the output shaft, there are 43000+ pulses per minute, or ~7200 per second. That gives you more than 2000 clock cycles to deal with an interrupt.

So, you really need to define what RPM the motor is running at, how it is geared, and where the encoder is positioned. It makes the difference between difficult and impossible.

Interrupts really need to be disabled while you copy the values used to compute RPM, and then re-enabled before computing anything and before trying to print anything.

You also need to describe your overall project in more detail. There may be better motor choices or better means of stopping the motor with more precision. But, right now, all we have to go on is the minimal, conflicting information you are providing.

let me explain the project in general then.
I am using 2*(motor + gearbox + encoder combined) and linear encoder to make automatic shifting device.
From the x,y coordinate system, I use each motor to be the x and y axis to move our shifter.
From the encoder the motor will rotate the desired revolution to move the shifter and at the same time, if there is friction or some other external force to prevent the motion, I am trying to shut down the motor. Thats why I am trying to get rpm from the encoder.

The raio of the gear box is 84:1.
I am using the geax box of
https://downloads.maxonmotor.com/Katalog_neu/eshop/Downloads/Katalog_PDF/maxon_gear/Planetengetriebe/new/newpdf_11/GP-22-C-143971_11_EN_222-223.pdf
order number is 143984

encoder
https://downloads.maxonmotor.com/Katalog_neu/eshop/Downloads/Katalog_PDF/maxon-tacho/Encoder-HEDS-5540/new/newpdf_11/ENC-HEDS-5540-500imp-110511_11_EN_266-267.pdf

Right now we have motor + gearbox + encoder combined from the maxon motor.

Combined motor + gearbox + encoder, I get the 42000 pulses per revolution. 500 counts per turn but from the gear box ratio, I multiplied 500* 84 = 42000. Is this still wrong?

Also from the code I have "double motor_speed = 1;" which set it up as maximum speed but no idea how fast it runs right now.
Or do I assume "double motor_speed = 1" as normial speeds 12100RPM which reduces to 12100/84 = 144 due to the gear box ratio?

Right now, the only thing I could do is change to "double motor_speed = .1;" so that the encoder could read it.

Thank you.

Right now, the only thing I could do is change to "double motor_speed = .1;" so that the encoder could read it.

This motor_speed?

  digitalWrite(STEP_PIN, motor_speed);

digitalWrite() accepts an int as the second argument. If you pass a double it will be truncated. So, any value less than 1.0 will become 0.0.

Using a variable named motor_speed with a digital pin is silly.

order number is 143984

OK, so it's an 84 to 1 reduction. So the output shaft is turning 1/84th the speed of the motor shaft.

Right now we have motor + gearbox + encoder combined from the maxon motor.

Well, yippee skippee. Still doesn't tell us anything. Where is the encoder in this mix? On the motor shaft or on the gearbox shaft? If necessary, take a picture!

Combined motor + gearbox + encoder, I get the 42000 pulses per revolution. 500 counts per turn but from the gear box ratio, I multiplied 500* 84 = 42000. Is this still wrong?

Depends. Where it the encoder? If if is on the motor, then there are 42000 pulses per turn of the gearbox output shaft. If it is on the gearbox output shaft, then there are 500 pulses per revolution of the gearbox shaft.

But, I think you are using the wrong hardware. A couple of linear actuators would be much easier to accurately position, and much faster.

well the location of the encoder is at output of motor.

Thank you for the suggestion and we also thought of using actuators but we were not able to find one that would match our project description.

we'll let me review all the replies and see how that goes. thanks people!

Can you put the encoder on the gearbox output?
Are you using the motor to turn a lead screw for your linear motion?