reading encoder  at 100kHz

Hello , for 2 weeks i'm trying to wirte code to read encoder running at 60kHz and i'm unable to :frowning: . I learnt by heart all posts about encoders , timers overflow , interrupts etc. and it's too difficult . If it is possible to run PWM at that frequency http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210751945/3 it should be possible to read also. Now i have 2 encoders on pin 2and4 and 3and5 for quadrature .

Generally i need to read 6 encoders on Arduino Mega using all hardware interrupts .
I read about timer overflow but i don't know why it doesn't work for me .

Any help would be VERY appreciated.

T.

// motor encoder
#define encoder0PinA  2
#define encoder0PinB  4


// controller encoder
#define encoder1PinA  3
#define encoder1PinB  5

#define SpeedPin     10
#define DirectionPin 12

 int encoder0Pos = 0;
 int encoder1Pos = 0;

int target = 0;
//correction = Kp * error + Kd * (error - prevError) + kI * (sum of errors)
//PID controller constants
float KP = 1 ; //position multiplier (gain) 1 
float KI = 0.02; // Intergral multiplier (gain) 0,5
float KD = 1; // derivative multiplier (gain) 0,1

int lastError = 0;
int sumError = 0;
int czas = 0 ;
//Integral term min/max (random value and not yet tested/verified)
int iMax = 100;
int iMin = 0;


void setup() { 

  pinMode(encoder0PinA, INPUT); 
  pinMode(encoder0PinB, INPUT); 
    
  pinMode(encoder1PinA, INPUT);   
  pinMode(encoder1PinB, INPUT); 
  
  pinMode(DirectionPin, OUTPUT); 
  pinMode(SpeedPin, OUTPUT); 

  attachInterrupt(0, doEncoderMotor0, CHANGE);  // encoder pin on interrupt 0 - pin 2
  attachInterrupt(1, doEncoderMotor1,CHANGE);  
} 

void loop(){
  
  
  // zakres mnozenia 0.5 - 3
  target =  encoder1Pos ;

  docalc();
}

void docalc() {

    int error = encoder0Pos - target ; // find the error term of current position - target    
       
    lastError = error;    
    sumError += error;
    
    //scale the sum for the integral term
    if(sumError > iMax) {
      sumError = iMax;
    } else if(sumError < iMin){
      sumError = iMin;
    }
    

    int ms = KP * error + KD * (error - lastError) +KI * (sumError);

    if(ms > 0){
      digitalWrite ( DirectionPin ,HIGH ); 
  
    }
    if(ms < 0){
      digitalWrite ( DirectionPin , LOW );     
      ms = -1 * ms;
        
    }

           
        
           while (ms > 500){
             
           analogWrite ( SpeedPin, 90 );
           ms = ms -4 ;        
           encoder0Pos = target ;
  
           
   }
     
    int motorSpeed = map(ms,0,800,0,200); 
    analogWrite ( SpeedPin,  motorSpeed );

}

void doEncoderMotor0(){
  
  if (digitalRead(encoder0PinA) == HIGH) {   // found a low-to-high on channel A
    if (digitalRead(encoder0PinB) == LOW) {  // check channel B to see which way
                                             // encoder is turning
      encoder0Pos = encoder0Pos - 1;         // CCW
    } 
    else {
      encoder0Pos = encoder0Pos + 1;         // CW
    }
  }
  else                                        // found a high-to-low on channel A
  { 
    if (digitalRead(encoder0PinB) == LOW) {   // check channel B to see which way
                                              // encoder is turning  
      encoder0Pos = encoder0Pos + 1;          // CW
    } 
    else {
      encoder0Pos = encoder0Pos - 1;          // CCW
    }

  }
 
}


void doEncoderMotor1(){

  // look for a low-to-high on channel B
  if (digitalRead(encoder1PinB) == HIGH) {   

    // check channel A to see which way encoder is turning
    if (digitalRead(encoder1PinA) == LOW) {  
      encoder1Pos = encoder1Pos - 1;         // CCW
    } 
    else {
      encoder1Pos = encoder1Pos + 1;         // CW
    }
  }

  // Look for a high-to-low on channel B

  else { 
    // check channel B to see which way encoder is turning  
    if (digitalRead(encoder1PinA) == LOW) {   
      encoder1Pos = encoder1Pos + 1;          // CW
    } 
    else {
      encoder1Pos = encoder1Pos - 1;          // CCW
    }
  }

}

If it is possible to run PWM at that frequency......it should be possible to read also.

Not necessarily the PWM uses hardware counters to generate the output, no code is involved. Code is needed to read the encoders and keep count of where they are.
It it essential you don't miss any pulses, if it is just a control then it normally is not. The best way is to use interrupts.

I read about timer overflow but i don't know why it doesn't work for me .

You shouldn't be using timers for this there is no need. You just need to trigger an ISR for each encoder input and look at the other encoder.

If you do need to get all the pulses then you could use some hardware to help reduce the software load. See:-
http://www.thebox.myzen.co.uk/Workshop/Rotary_Max.html

Thanks , i belive it's just impossible to do it with arduino , professionall servo drives check pulse at 6us intervall and has 32bit precision , what i can do with that code is about 5 rotates per sec with 1000 ppr encoder. Above that speed it gets mad , the motor starts to shake , i think becouse the interia of motor is too big , encoder produces huge amount of errors and it is too slow to correct the speed even if i reset errors after certain amount of them. What is strange i cannot use pulseIn to count frequency and add an exception that above cartain speed "don't speed up" .

You can also look at this -> http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1271116324 ; encoder reading procedure described is very fast.

if i remove quadrature decoding and leave just one direction , it's 2-3 times faster, so it would be great not to use digitalread() but direct port access

  if (digitalRead(3) == digitalRead(5)) {  
    encoder0Pos++;
  }
  else{
  encoder0Pos--;
  }

how to code this with direct port access on ardiuno mega ?

how to code this with direct port access on ardiuno mega

Same as you would on any other arduino:-
http://www.arduino.cc/en/Reference/PortManipulation

yes , t theoretically would be the easiest way :slight_smile: , but in practice it is not . http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1271185903/9#9