#define VELOCITY_SAMPLE_TIME 10 //sample time (ms) between velocity checks
#define ENCODER_COUNTS 250
#include "Encoder.h"
unsigned long VelocityTimeStamp=0;
Encoder encoderFL(27, 29);
Encoder encoderFR(45, 43);
Encoder encoderRL(31, 33);
Encoder encoderRR(41, 39);
void setup()
{
Serial.begin(9600);
encoderFL.initilise();
encoderFR.initilise();
encoderRL.initilise();
encoderRR.initilise();
//Attach Interupts to both pins for each encoder(for full resolution)
attachInterrupt(encoderFL.pin_a,doEncoderFL,CHANGE);
attachInterrupt(encoderFL.pin_b,doEncoderFL,CHANGE);
attachInterrupt(encoderFR.pin_a,doEncoderFR,CHANGE);
attachInterrupt(encoderFR.pin_b,doEncoderFR,CHANGE);
attachInterrupt(encoderRL.pin_a,doEncoderRL,CHANGE);
attachInterrupt(encoderRL.pin_b,doEncoderRL,CHANGE);
attachInterrupt(encoderRR.pin_a,doEncoderRR,CHANGE);
attachInterrupt(encoderRR.pin_b,doEncoderRR,CHANGE);
}
void loop()
{
updateVelocity();
//ENCODER DEBUG
Serial.print(encoderFL.getPosition(),DEC);
Serial.print(" ");
Serial.print(encoderFR.getPosition(),DEC);
Serial.print(" ");
Serial.print(encoderRL.getPosition(),DEC);
Serial.print(" ");
Serial.print(encoderRR.getPosition(),DEC);
Serial.print(" ---- ");
Serial.print(encoderFL.getVelocity(),DEC);
Serial.print(" ");
Serial.print(encoderFR.getVelocity(),DEC);
Serial.print(" ");
Serial.print(encoderRL.getVelocity(),DEC);
Serial.print(" ");
Serial.print(encoderRR.getVelocity(),DEC);
Serial.println();
}
//Wrapper Functions to call correct encoder object method on interupt
void doEncoderFL(){
encoderFL.doCount();
}
void doEncoderFR(){
encoderFR.doCount();
}
void doEncoderRL(){
encoderRL.doCount();
}
void doEncoderRR(){
encoderRR.doCount();
}
//Function to calculate velocity of encoders once every VELOCITY_SAMPLE_TIME
void updateVelocity(){
if(VelocityTimeStamp+VELOCITY_SAMPLE_TIME<millis()){
encoderFL.calculateVelocity();
encoderFR.calculateVelocity();
encoderRL.calculateVelocity();
encoderRR.calculateVelocity();
VelocityTimeStamp=millis();
}
}
#ifndef __ENCODER_H__
#define __ENCODER_H__
#include "Arduino.h"
//This class is designed to manage the encoders
//Four instances of this class are created: one for each encoder
//The methods in this class are called by interupts (attached in the setup function of the main program)
//There is a wrapper function called 'doEncoder' in the main function designed to call the correct encoder method
//this function is required as interupts cannot call object methods directly (unless static there is no pointer)
class Encoder {
public:
int pin_a;
int pin_b;
// constructor : sets pins as inputs and turns on pullup resistors
Encoder(int A, int B){
// Set pin a and b to be input
Evelocity=0;
Eposition=0;
EpositionCache=0;
pin_a=A;
pin_b=B;
};
void initilise(){
pinMode(pin_a, INPUT);
pinMode(pin_b, INPUT);
// Turn on pullup resistors
digitalWrite(pin_a, HIGH);
digitalWrite(pin_b, HIGH);
}
void doCount(){
//Serial.println("Doing Count");
State = (digitalRead(pin_a)<<1)|digitalRead(pin_b);
switch(State)
{
case 0:
if(PreviousState==1)Eposition++;
else Eposition--;
break;
case 1:
if(PreviousState==3)Eposition++;
else Eposition--;
break;
case 2:
if(PreviousState==0)Eposition++;
else Eposition--;
break;
case 3:
if(PreviousState==2)Eposition++;
else Eposition--;
break;
}
PreviousState=State;
}
// returns current position
long int getPosition () {
return Eposition;
};
float getVelocity () {
return Evelocity;
};
void calculateVelocity(){
Evelocity = (float(Eposition-EpositionCache)/float(millis()-TimeStamp))*1000/(ENCODER_COUNTS*4);
TimeStamp = millis();
EpositionCache=Eposition;
}
// set the position value
void setPosition ( const long int p) {
Eposition = p;
};
private:
float Evelocity;
unsigned long TimeStamp;
long int EpositionCache;
volatile long int Eposition;
byte State;
byte PreviousState;
};
#endif // __ENCODER_H__