Items:
- Arduino Uno
- Quadrature Rotary Encoder(600ppr)
Im trying to develop a code that calculates the RPM and Angular Displacement of a shaft that will be moving a maximum speed of 5000RPM. I don't need angular displacement at speeds over 100rpm because in my experience the arduino looses the position of the shaft. The current code i have is using 2 signals on interrupts from a 600ppr encoder and is accurately calculating angular displacement of a shaft CW & CCW at low speeds. I have an old code that splits the signals and uses one to calculate rpm and one to calculate angular displacement but if the shaft is backspun, it will lose the position. My question is, is it possible to calculate the rpm of the motor/shaft by calculating the value change of the encoder over a period of time(the difference in time of the interrupts) instead of using the interrupts for a separate rpm function and how do i code this?
My code below was available on a website that sold encoders. It originally had a loop function and 1 other function. I modified that code to calculate angular displacement correctly. Recently(in the code below) i copied the secondary function (updateEncoder) in order to calculate rpm by measuring the time between the two interrupts but it's not calculating RPM correctly, the angular displacement is still working.
Things im unsure about:
- With 2 signals of a 600ppr encoder im getting, 2400ppr. Is this too much for the arduino to handle, can it process the interrupts quickly enough?
- If the answer to some of these questions are no, would it work better with an 180ppr encoder? I have one available as well.
- Is it better to use micros or millis, from research ive seen that micros overloads after 70mins, but this wont be a problem as it wont be ran this long. If micros is more accurate is it better to go with?
#include <LiquidCrystal_I2C.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
//these pins can not be changed 2/3 are special pins
int encoderPin1 = 2;
int encoderPin2 = 3;
volatile int lastEncoded = 0;
volatile float encoderValue = 0;
volatile float Angle1 = encoderValue;
volatile float Angle2 = encoderValue;
volatile float CoterminalFactor = encoderValue;
volatile int CoterminalInt = encoderValue;
volatile int Check = 0;
volatile float Time1 = 0;
volatile float Time2 = 0;
volatile float Time3 = 0;
volatile float rpm1 = 0;
volatile float rpm2 = 0;
volatile float rpm = 0;
long lastencoderValue = 0;
int lastMSB = 0;
int lastLSB = 0;
void setup() {
lcd.init(); //initialize the lcd
lcd.backlight(); //open the backlight
Serial.begin (19200);
pinMode(encoderPin1, INPUT);
pinMode(encoderPin2, INPUT);
digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
digitalWrite(encoderPin2, HIGH); //turn pullup resistor on
//call updateEncoder() when any high/low changed seen
//on interrupt 0 (pin 2), or interrupt 1 (pin 3)
attachInterrupt(0, updateEncoder1, CHANGE);
attachInterrupt(1, updateEncoder2, CHANGE);
}
void loop(){
//Do stuff here
//Serial.println(encoderValue);
//Serial.println(Angle1);
//Serial.println(Angle2);
Serial.println(Time1);
Serial.println(Time2);
Time3 = ((Time2-Time1)/1000000);
rpm = (abs((rpm2-rpm1)));
//Serial.println((Time3);
//Serial.println((abs(Time3)),5);
delay(1000); //just here to slow down the output, and show it will work even during a delay
lcd.clear();
lcd.print(F("RPM="));
//lcd.print(rpm);
lcd.setCursor(0,1);
lcd.print(F("Angle="));
lcd.print(Angle2);
lcd.print(char(223));
}
void updateEncoder1(){
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 --;
Angle1 = encoderValue*0.15;
CoterminalInt = encoderValue/2400;
CoterminalFactor = encoderValue/2400;
Angle2 = (CoterminalFactor - CoterminalInt)*360;
lastEncoded = encoded; //store this value for next time
rpm1 = encoderValue;
Time1 = micros();
}
void updateEncoder2(){
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 --;
Angle1 = encoderValue*0.15;
CoterminalInt = encoderValue/2400;
CoterminalFactor = encoderValue/2400;
Angle2 = (CoterminalFactor - CoterminalInt)*360;
lastEncoded = encoded; //store this value for next time
rpm2 = encoderValue;
Time2 = micros();
}