[Solved] Rotary encoder laggy

Hi,

I am a new Arduino user. I got an Arduino Leonardo recently,which I am using to emulate 6 keys and 2 rotary encoders; one encoder for X mouse axis,the other one,for Y axis.

I have a problem with my encoders. Here is my program :

int VOLL1 = 3;
int VOLL2 = 2;
int VOLR1 = 4;
int VOLR2 = 5;

const int BTA = A0;
const int BTB = A1;
const int BTC = A2;
const int BTD = A3;
const int FXL = A4;
const int FXR = A5;

volatile int lastEncodedL = 0;
volatile int lastEncodedR = 0;

long lastencoderValueL = 0;
long lastencoderValueR = 0;

int lastMSBL = 0;
int lastMSBR = 0;
int lastLSBL = 0;
int lastLSBR = 0;

void setup() {
  pinMode(VOLL1, INPUT); 
  pinMode(VOLL2, INPUT);
  pinMode(VOLR1, INPUT); 
  pinMode(VOLR2, INPUT);

  Keyboard.begin();

  pinMode(BTA, INPUT);
  pinMode(BTB, INPUT);
  pinMode(BTC, INPUT);
  pinMode(BTD, INPUT);
  pinMode(FXL, INPUT);
  pinMode(FXR, INPUT);(

  digitalWrite(VOLL1, HIGH);
  digitalWrite(VOLL2, HIGH);
  digitalWrite(VOLR1, HIGH);
  digitalWrite(VOLR2, HIGH);
}
void loop(){ 
  int MSBR = digitalRead(VOLR1);
  int LSBR = digitalRead(VOLR2);

  int encodedR = (MSBR << 1) |LSBR;
  int sumR  = (lastEncodedR << 2) | encodedR;

  if(sumR == 0b1101 || sumR == 0b0100 || sumR == 0b0010 || sumR == 0b1011) 
  {
    Mouse.move(10,0,0);
  }
  if(sumR == 0b1110 || sumR == 0b0111 || sumR == 0b0001 || sumR == 0b1000) 
  {
    Mouse.move(-10,0,0);
  }
  lastEncodedR = encodedR;
  
  int MSBL = digitalRead(VOLL1);
  int LSBL = digitalRead(VOLL2);

  int encodedL = (MSBL << 1) |LSBL;
  int sumL  = (lastEncodedL << 2) | encodedL;

  if(sumL == 0b1101 || sumL == 0b0100 || sumL == 0b0010 || sumL == 0b1011) 
  {
    Mouse.move(0,10,0);
  }
  if(sumL == 0b1110 || sumL == 0b0111 || sumL == 0b0001 || sumL == 0b1000) 
  {
    Mouse.move(0,-10,0);
  }
  lastEncodedL = encodedL;
 
  if (digitalRead(BTA) == HIGH)
  {
    Keyboard.press('d');
  }
  else
  {
    Keyboard.release('d');
  }
  if (digitalRead(BTB) == HIGH)
  {
    Keyboard.press('f');
  }
  else
  {
    Keyboard.release('f');
  }
  if (digitalRead(BTC) == HIGH)
  {
    Keyboard.press('j');
  }
  else
  {
    Keyboard.release('j');
  }
  if (digitalRead(BTD) == HIGH)
  {
    Keyboard.press('k');
  }
  else
  {
    Keyboard.release('k');
  }
  if (digitalRead(FXL) == HIGH)
  {
    Keyboard.press('c');
  }
  else
  {
    Keyboard.release('c');
  }
  if (digitalRead(FXR) == HIGH)
  {
    Keyboard.press('n');
  }
  else
  {
    Keyboard.release('n');
  }
}

The rotary encoder part is all from bildr Rotary Encoder + Arduino - bildr .

When I use the Arduino with the rotary encoder part only,they work great. No lag,no rubberbanding; they go smooth in each direction like they are meant to. But when I run this full program,keys go fine,but encoders are really choppy. They sometime change direction,they’re sloppy,they’re not running smooth at all.

Any ideas why,or how I could optimize this program? I guess the arduino lags because of all the things running in that loop…

Thanks !

I don't know about your encoder issue, but don't you want to be pressing and releasing keys when the corresponding switches BECOME pressed or BECOME released, not ARE presses or ARE released?

IchiSumeragi:   if (digitalRead(BTA) == HIGH)   {     Keyboard.press('d');   }   else   {     Keyboard.release('d');   }

I think you need some extra logic to pick out the transitions of the key lines so you can generate Keyboard.press() just on the low->high transition and vice versa. As things are here you are generating a continuous stream of Keyboard.release() or Keyboard.press() on all your keys, all the time.

@PaulS: I am sorry,I am not an english native speaker. I don't understand what you mean: you mean,by become pressed,that it only triggers the pushing once?

@gardner: I see what you want to point out. I'm going to try with something like an (if digitalRead(BTA) == LOW) {Keyboard.release('d')}. Thanks for your advice ;)

Edit: still laggy with a release on a LOW state like above. =(

You need interrupt-driven encoder reading, otherwise delays in the loop() will lose transitions. Ideally you use direct port manipulation to read encoder pins so you read both pins simultaneously, but this matters more with high speed motor encoders.

Hmm... problem is,I don't seem to have enough pins on my Arduino for 4 interrupt wires. Is one wire per encoder enough to trigger an interrupt or do you need both wires to be on interrupt pins?

Look at the state change detection example. It shows how to determine that a switch has changed state, from released to pressed, or from pressed to released.

You only want to call the Keyboard.press() and Keyboard.release() methods when the corresponding switch has changed state.

IchiSumeragi: still laggy with a release on a LOW state like above. =(

Try something like:

static char old_BTA = LOW;
char this_BTA = digitalRead(BTA);
if (this_BTA == HIGH && old_BTA == LOW)
  {
    Keyboard.press('d');
  }

if (this_BTA == LOW && old_BTA == HIGH)
  {
    Keyboard.release('d');
  }
old_BTA = this_BTA;

Thanks a lot,it works perfectly ;) I didn't thought about that,I didn't paid attention to the low state actually being always activated...

IchiSumeragi: Hmm... problem is,I don't seem to have enough pins on my Arduino for 4 interrupt wires. Is one wire per encoder enough to trigger an interrupt or do you need both wires to be on interrupt pins?

On the Uno you can use pin-change interrupts to respond to changes on any pin at all.