Problem with Interrupt in closed-loop control of DC motor

Hello,

I'm projecting a closed-loop control with a PID for a DC motor. I've created two Interrupt functions for my encoder and another one to call my control function every time fraction (Time.One). When the motor is rotating fast, only the Encoder Interrupt functions are being called, which means my controller it's not doing anything and the system becomes unstable. Do I have to work only with low speeds or there's something I can do to improve my controller?

Thanks

Encoder_com_Proporcional.ino (2.64 KB)

Have you reviewed the different techniques in the Playground? Your current program has many interrupts configured: Timer1, 2 encoder pins, serial output (not a big load), and the default Timer0 for millis. Maybe some of the work should happen in loop instead of an interrupt?

Cheers,
/dev

Why are you using digitalRead() on the same pins that the interrupt was triggered from ? Seems just unnecessary duplication.

Why not have a separate ISR for each interrupt pin ?

Your controlador() function has a lot of code in it for an ISR. Can you not get a lot of that stuff out of there and into loop() or a function called by loop() ?

You could probably use the technique in several things at a time in place of the TimerOne library.

...R

Please modify your original postings to place the code within the code tags </> on the upper tool bar. It will make it easier for people to see your code and assist you.

When the motor is rotating fast

How fast is the motor turning, and what are the encoder counts per revolution?

Your encoder ISR can be made faster by replacing the digitalRead() of the two pins with bitRead(). Without adding any complexity, you will achieve most of the benefit, which can be made using direct port manipulation and reading both pins at the same time. Your ISR might be made slightly faster by using an array with values of +1,-1,0 with the array index representing the value of the four bits of the past and present encoder states rather than the conditional tests you have, but I'm not sure if it will be significant.

void encoder()
{
   int Aatu,Batu;
  // Aatu = digitalRead(canalA);
  // Batu = digitalRead(canalB);

   Aatu = bitRead(PIND,2); //Interrupt0
   Batu = bitRead(PIND,3); //Interrupt1

   if ((Aant==LOW)&&(Bant==LOW))
   {
     if (Aatu==HIGH) posatual++;
     if (Batu==HIGH) posatual--;     
   }
   if ((Aant==LOW)&&(Bant==HIGH))
   {
     if (Aatu==HIGH) posatual--;
     if (Batu==LOW)  posatual++;     
   }
   if ((Aant==HIGH)&&(Bant==LOW))
   {
     if (Aatu==LOW)  posatual--;
     if (Batu==HIGH) posatual++;     
   }
   if ((Aant==HIGH)&&(Bant==HIGH))
   {
     if (Aatu==LOW)  posatual++;
     if (Batu==LOW)  posatual--;     
   }
   Aant=Aatu;
   Bant=Batu;
}

I am not familiar with the TimerOne library. Is controlador an ISR, and are interrupts are disabled when controlador is called? The controlador function is using the value of posatual and because the value can more than one byte if interrupts are not disabled when the value is read, it can change during the reading and create unstable readings. If interrupts are not already disabled you may need to surround the reading of posatual with noInterrupts() and interrupts() to protect the value.