Go Down

Topic: Rotary encoder 1000 rpm (Read 153 times) previous topic - next topic

jimlathe

 hi   
i am trying to use a Incremental Optical Rotary Encoder with 600 ppr to get an rpm on a  moter
 iam using the arduino due

 this code works from RPM 0 to about 800 but when the RPM is higher then 800 it does not work it give 0 as the encoder Value and the RPM  can anyone look at this code and find out why it is doing this   

 thanks
jim

Code: [Select]

//pin2 = A-channal(Green) pin3 = B-channal(White)
int encoderPin1 = 2;
int encoderPin2 = 3;

  //encoader variables
volatile long lastEncoded = 0;
volatile long encoderValue = 0;
volatile long lastencoderValue = 0;
volatile long lastMSB = 0;

// variables RPM
int rpm = 0 ;

void setup() {
  Serial.begin (115200);
 
//encoader pins
  pinMode(encoderPin1, INPUT);
  pinMode(encoderPin2, INPUT);
 
//pullup resistors
  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  digitalWrite(encoderPin2, HIGH); //turn pullup resistor on

 //on interrupt 0=pin 2   1=pin 3
  attachInterrupt(2, updateEncoder, CHANGE);
  attachInterrupt(3, updateEncoder, CHANGE);
 
}


void loop(){
 
 // print RPM
   rpm = ((encoderValue *60)/2400) ;
   Serial.print("RPM-----------");
   Serial.println(rpm);
   Serial.println(encoderValue);
 encoderValue=0;

 // 1 second delay
 delay(1000);
 
 }



// encoader interrupt
void updateEncoder(){

 int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

 
if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;

  lastEncoded = encoded; //store this value for next time
 
}

westfw

#1
Nov 10, 2018, 11:33 pm Last Edit: Nov 11, 2018, 03:08 am by westfw Reason: RPM vs RPs
600 ppr at 800 rpm is 480000 interrupts per second; that may be beyond what your arduino is capabale of doing, at least using the normal Arduino functions like digitalRead().  If 800 works, and you only need to handle 1000 as the max, you might look at using direct digital IO or finding a digitalReadFast() library.  Otherwise you might need to throw extra hardware at the problem, and/or consider a different method.

Edit: oops.  My calculations were interrupts per minute...   I always seem to forget that factor when dealing with RPM, vs everything else that is timed in seconds.  (OTOH, there's probably more than one interrupt per encoder "tick"?)

outsider

#2
Nov 11, 2018, 01:05 am Last Edit: Nov 11, 2018, 01:15 am by outsider
Both interrupts on "CHANGE", 2400 per rev, at 800 RPM, that's 1920000 per second whoops, 32000 per second   :o .

DKWatson

#3
Nov 11, 2018, 01:23 am Last Edit: Nov 11, 2018, 01:25 am by DKWatson
800rpm is 13-1/3 revolutions per second. Using a 600ppr encoder to measure rpm is the wrong tool for the wrong job.,
Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi

outsider

#4
Nov 11, 2018, 01:27 am Last Edit: Nov 11, 2018, 01:31 am by outsider
Have you tried interrupt on FALLING or other algorithms? 

@DKWatson:
  I was going to ask if the OP was counting pulses for position control or just looking for RPM.

DKWatson

#5
Nov 11, 2018, 01:45 am Last Edit: Nov 11, 2018, 01:46 am by DKWatson
One would hope that had if (s)he wanted position information, it would have been mentioned. My experience suggests that once you're above a couple of revs/sec, position is not the question. Remember that positional accuracy is a fractional thing, a fractional of one revolution. If one is intent on using the wrong tool, at least find a way to filter out the first 599 pulses, after all, for measuring rpm it's only every 600th pulse that matters.
Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi

DKWatson

Before the pedants jump in with the usual rhetoric, look at a simple bit of math. 1000rpm is 16 - 2/3 revs/sec. At 600ppr, that's 10,000 pulses per second. That's a period (time between pulses) of 100us. The resolution of micros() is 4us. So, if you measure pulse timing at 100us, rpm = 1000. If however, you measure 104us, rpm = 962. At 96us, rpm = 1042. How accurate is that?

The same measurement using a hall effect sensor or some other device intended for measuring revolutions, 1000 rpm has a revolutional period of 60ms, that's 60,000us. If you measure 60,004, rpm = 999.93. In fact to get the same 'lack-of-accuracy' the timing would need to be out by approximately +/- 2,300us.
Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi

ard_newbie


jimlathe board is a DUE, and a DUE has 2 hardware quadrature decoder. With this board, the right way to measure speed of a quadrature encoder is certainely not with digitalread() function....

See this thread, reply #55 for a working example sketch with a quadrature encoder of 1024 ppr (= 4 * 1024 edges per revolution) up to 3500 RPM:

http://forum.arduino.cc/index.php?topic=140205.45

Go Up