Solved:time lag as encoders control the mouse via Arduino serial communication

Hell folks,

I need your insight and help. I am working on a project to use the data from two encoder to control the mouse cursor in my PC. The two encoder data from a hand robot: one records my finger range of motion data, one records my thumb range of motion data. Two encoder data send out from the robot computer via RS232 and logic level convertor to my Arduino Leonardo. And Leonardo is connected to another computer where the encoder data controls the mouse cursor to play game. One encoder data controls the x coordinate, another controls the y coordinate.

My problem lies here. The two encoder data directly correspond to the fingers and thumb movement data. When fingers and thumb move at a moderate speed, the mouse cursor moves in a kind of synchronized manner (by naked eye standard). When fingers and thumb move faster, there is quite obvious delay in the mouse cursor movement, although there is no encoder data lost while Arduino and game computer process the data. In other words, the mouse cursor will follow the same movement done by fingers and thumb, but is quite a delay response. And moreover, when fingers and thumb move even faster to a certain level, the mouse cursor movement starts going wild and seems to me that there is kind of overflow problem happening to Arduino. And it also seems to me this problem is non versatile since it persists even after I reloads the code and turn off and on Arduino. But the problem usually disappears after I restart my game computer.

Hope anyone shares some insight and idea on it. Thanks a lot in advance. The arduino code is attached here. In the code, f and t are defined to be the encoder data of fingers and the encoder data of thumb.

const int switchPin = 2;
const int mouseButton = 3;
const int ledPin = 13;

int value = 0;

boolean mouseIsActive = false;
int prevSwitchState = HIGH;
int prevButtonState = LOW;

int toggle = 0;
int flag = 0;

int f;
int t=0;

float f1;
float t1;

int f_prev = 0;
int t_prev = 0;
// dont forget to change back 
int datain_Byte[6];
int th;
int fi;
int z;

void setup()
{
  pinMode(switchPin,INPUT);
  pinMode(ledPin,OUTPUT);
  Serial.begin(115200);
  Serial1.begin(115200);
  Mouse.begin();
  while(!Serial);
}

void loop()
{
  mouseActiveFcn();
  dataReading();
   
  if (mouseIsActive == true){
    
    switch(z){
    case 1:{
      while(z == 1){
      dataReading();
      if(value == 1){
      angryBirdGame();
      }
      angryBirdMouseButton();
      mouseActiveFcn();
      if(z != 1 || mouseIsActive == false){
        break;
      }
    }
    }
    
    case 2: {
      while (z == 2){
      dataReading();
      if(value == 1){
      bubbleShootGame();
      }
      clickMouse();
      mouseActiveFcn();
      if(z != 2 || mouseIsActive == false){
        break;
      }
    }
    }
 
    case 3:{
      while (z == 3){
      dataReading();
      if(value == 1){
      bowlingGame();
      }
      mouseActiveFcn();
      if (z != 3 || mouseIsActive == false){
        break;
      }
      }
        
   }
   case 4:{
     while (z == 4){
       dataReading();
       if(value == 1){
         shoppingGame();
       }
       clickMouse();
       mouseActiveFcn();
       if (z != 4 || mouseIsActive == false){
         break;
       }
     }
   }
   case 5:{
     while (z == 5){
       dataReading();
       if(value == 1){
         golfGame();
       }
       clickMouse();
       mouseActiveFcn();
       if (z != 5 || mouseIsActive == false){
         break;
       }
     }
   }
   
   case 6: {
     while (z == 6){
       dataReading();
       if(value == 1){
       panggame();
       }
       mouseActiveFcn();
       if (z != 6 || mouseIsActive == false){
         break;
       }
     }
   }
       
   default:{
     while(1){
       dataReading();
       generalMove();
       mouseActiveFcn();
          if( z == 1 ){
     break;
   }
     else if (z == 2){
       break;
     }
     else if (z == 3) {
       break;
     }
     else if (z == 4) {
       break;
     }
     else if (z == 5) {
       break;
     }
     else if (z == 6){
       break;
     }
     else if (mouseIsActive == false){
       break;
     }
     }
    
    }
    }
      
   delay(10);
  }
  }

  
  void mouseActiveFcn(){
    int switchState = digitalRead(switchPin);
  if (switchState != prevSwitchState) {
    if (switchState == LOW) {
      mouseIsActive = !mouseIsActive;
      digitalWrite(ledPin, mouseIsActive);
    }
  }
   prevSwitchState = switchState;
   delay(10);
  }
  
  void dataReading()
  {
            if(Serial1.available()>5) {
      
      for (int n = 0; n < 6; n++)
      {
        datain_Byte[n] = Serial1.read();
        value = 1;
      }
          z = 256*datain_Byte[1] + datain_Byte[0];
          f = (256*datain_Byte[3] + datain_Byte[2])/10;
          t = (256*datain_Byte[5] + datain_Byte[4])/10;
          //Serial.println(f);
          //Serial.println(t);
          f_prev = f;
          t_prev = t;     
      }
          else {
            value = 0;
            f = f_prev;
            t = t_prev;
          }

    
  }
  
  
  void angryBirdGame(){
       //th = map(t,0,20,38,22);
       th = map(t,0,18,28,13);
       //fi = map(f,0,42,70,90);
       fi = map(f,0,48,70,88);
       Mouse.move(th, fi, 0);
  }
  
  void angryBirdMouseButton(){
       int buttonState = digitalRead(mouseButton);
       if (buttonState == HIGH && prevButtonState == LOW) {
     // if the mouse is not pressed, press it:
     toggle++;
     if(toggle == 1)
     {
     if(t < 5 && f < 6){
       if (!Mouse.isPressed(MOUSE_LEFT)) {
         Mouse.press(MOUSE_LEFT); 
       }
     //Serial.println(toggle);  
     }
     else
     { toggle = 0;
     //Serial.println(toggle); 
     }
   }
   else if(toggle == 2)
   {
     // else the mouse button is not pressed:
     // if the mouse is pressed, release it:
     if (Mouse.isPressed(MOUSE_LEFT)) {
       Mouse.release(MOUSE_LEFT); 
     }
     toggle = 0;
   }
   }

   prevButtonState = buttonState;  
  }
  
  void bubbleShootGame(){
       th = map(t,0,18,80,0);
       fi = map(f,0,48,100,0);
       Mouse.move(th, fi, 0);
  }
  
  void clickMouse(){
     int buttonState = digitalRead(mouseButton);
   if (buttonState == HIGH && prevButtonState == LOW) {
     Mouse.click();
   }
   prevButtonState = buttonState;
   delay(10);
  }
  
  void shoppingGame(){
    th = map(t,0,18,115,0);
    fi = map(f,0,48,108,0);
    Mouse.move(th,fi,0);
  }
  
  void golfGame(){
     th = map(t,0,7,65,60);
     fi = map(f,0,17,95,100);
       Mouse.move(th, fi, 0);
       //delay(10);
  }
  
  void panggame(){
    Serial.write(t);
    Serial.write(f);
    //delay(100);
  }
   
  
  void generalMove(){
       th = map(t,0,7,0,120);
       fi = map(f,0,17,0,120);
       Mouse.move(th, fi, 0);
     int buttonState = digitalRead(mouseButton);
   if (buttonState == HIGH && prevButtonState == LOW) {
     Mouse.click();
   prevButtonState = buttonState;
   }
   delay(10);
  }
  
  void holdMouse(){
     int buttonState = digitalRead(mouseButton);
   if (buttonState == HIGH && prevButtonState == LOW) {
     // if the mouse is not pressed, press it:
     toggle++;
     if(toggle == 1)
       if (!Mouse.isPressed(MOUSE_LEFT)) {
         Mouse.press(MOUSE_LEFT); 
       }  
   }
   else if(toggle == 2)
   {
     // else the mouse button is not pressed:
     // if the mouse is pressed, release it:
     if (Mouse.isPressed(MOUSE_LEFT)) {
       Mouse.release(MOUSE_LEFT); 
     }
     toggle = 0;
   }
   prevButtonState = buttonState;
   delay(10);
   }

I suspect you need to reorganize your program.

Just call dataReading() once in each iteration of loop() and don't use WHILE anywhere so that loop() can repeat as quickly as possible. Ditto for mouseActiveFcn() - and maybe for others.

...R

Robin2, thanks a lot again for the quick suggestion. Just curious what does you mean by "Ditto for"? Sorry I am not quite savvy for internet slang. Thanks.

Ji

Sorry. Ditto is much older slang than the internet. It just means "the same"

...R

I see. Thanks again.

hi Robin2,

Just want to update the progress. Based on the suggestion, I chopped off those unnecessary while loops and other stuff. The revised code is attached below. The problematic phenomenon still persists. Again in the code, the integer z represents the selection of games. When z = 1, it gets into angrybird game. At the same time, I open the serial monitor to see how z is updated. As I gently move my finger and thumb robot, I can see the value of z stays at 1. As I move my fingers and thumb robot faster and faster, the z value stays at 1. The mouse map for z =1 is very small. However, when I select z == 2 from my robot computer, as I move the fingers and thumb robot faster and faster, the z reaches to -22784 and stays there, and my finger and thumb robot lost the control of robot. the mouse map for z = 2 almost covers my computer screen. Thereafter, no data from encoder come to the Arduino as TX LED is not on anymore. The computer that controls the fingers and thumb robot sends the z value as int16.

Do you think there is something to do with the function MAP i used in the code. It seems to me when I map to a larger range, and as I move the robot faster and faster, the Arduino can't process the input correctly anymore. Please let me know what you think. Thanks a lot.

const int switchPin = 2;
const int mouseButton = 3;
const int ledPin = 13;

int value = 0;

boolean mouseIsActive = false;
int prevSwitchState = HIGH;
int prevButtonState = LOW;

int toggle = 0;
int flag = 0;

int f;
int t=0;

float f1;
float t1;

int f_prev = 0;
int t_prev = 0;
// dont forget to change back 
int datain_Byte[6];
int th;
int fi;
int z;

void setup()
{
  pinMode(switchPin,INPUT);
  pinMode(ledPin,OUTPUT);
  Serial.begin(115200);
  Serial1.begin(115200);
  Mouse.begin();
  while(!Serial);
}

void loop()
{
  mouseActiveFcn();
  dataReading();  
  if (mouseIsActive == true){
    if (z == 1 ){
      if(value==1){
        angryBirdGame();
      }
      angryBirdMouseButton();
    }
    
    if( z== 2){
      if(value==1){
        bubbleShootGame();
      }
      clickMouse();
    }
  delay(20);
   }
       
  }

  
  void mouseActiveFcn(){
    int switchState = digitalRead(switchPin);
  if (switchState != prevSwitchState) {
    if (switchState == LOW) {
      mouseIsActive = !mouseIsActive;
      digitalWrite(ledPin, mouseIsActive);
    }
  }
   prevSwitchState = switchState;
   delay(10);
  }
  
  void dataReading()
  {
            if(Serial1.available()>5) {
      
      for (int n = 0; n < 6; n++)
      {
        datain_Byte[n] = Serial1.read();
        value = 1;
      }
          z = 256*datain_Byte[1] + datain_Byte[0];
          f = (256*datain_Byte[3] + datain_Byte[2]);
          t = (256*datain_Byte[5] + datain_Byte[4]);
          Serial.println(z);
         // Serial.println(f);
         // Serial.println(t);
          //Serial.println();
          f_prev = f;
          t_prev = t;     
      }
          else {
            value = 0;
            f = f_prev;
            t = t_prev;
          }

    
  }
  
  
  void angryBirdGame(){
   
       //th = map(t,0,20,38,22);
       th = map(t,0,130,28,13);
       //fi = map(f,0,42,70,90);
       fi = map(f,0,480,70,88);
      // Serial.println(th);
       //Serial.println(fi);
       Mouse.move(th, fi, 0); 
  }
  
  void angryBirdMouseButton(){
       int buttonState = digitalRead(mouseButton);
       if (buttonState == HIGH && prevButtonState == LOW) {
     // if the mouse is not pressed, press it:
     toggle++;
     if(toggle == 1)
     {
     if(t < 5 && f < 6){
       if (!Mouse.isPressed(MOUSE_LEFT)) {
         Mouse.press(MOUSE_LEFT); 
       }
     //Serial.println(toggle);  
     }
     else
     { toggle = 0;
     //Serial.println(toggle); 
     }
   }
   else if(toggle == 2)
   {
     // else the mouse button is not pressed:
     // if the mouse is pressed, release it:
     if (Mouse.isPressed(MOUSE_LEFT)) {
       Mouse.release(MOUSE_LEFT); 
     }
     toggle = 0;
   }
   }

   prevButtonState = buttonState;  
  }
  
  void bubbleShootGame(){
       th = map(t,0,180,80,0);
       fi = map(f,0,480,100,0);
       Mouse.move(th, fi, 0);
  }
  
  void clickMouse(){
     int buttonState = digitalRead(mouseButton);
   if (buttonState == HIGH && prevButtonState == LOW) {
     Mouse.click();
   }
   prevButtonState = buttonState;
   delay(10);
  }
  
  
  void generalMove(){
       th = map(t,0,7,0,120);
       fi = map(f,0,17,0,120);
       Mouse.move(th, fi, 0);
     int buttonState = digitalRead(mouseButton);
   if (buttonState == HIGH && prevButtonState == LOW) {
     Mouse.click();
   prevButtonState = buttonState;
   }
   delay(10);
  }
  
  void holdMouse(){
     int buttonState = digitalRead(mouseButton);
   if (buttonState == HIGH && prevButtonState == LOW) {
     // if the mouse is not pressed, press it:
     toggle++;
     if(toggle == 1)
       if (!Mouse.isPressed(MOUSE_LEFT)) {
         Mouse.press(MOUSE_LEFT); 
       }  
   }
   else if(toggle == 2)
   {
     // else the mouse button is not pressed:
     // if the mouse is pressed, release it:
     if (Mouse.isPressed(MOUSE_LEFT)) {
       Mouse.release(MOUSE_LEFT); 
     }
     toggle = 0;
   }
   prevButtonState = buttonState;
   delay(10);
   }

Can you provide one or two sentences that describe what each of your functions is supposed to do.

...R

Absolutely. Sorry for the confusion. The comments on the main function of code have been added to the relevant lines.

const int switchPin = 2;
const int mouseButton = 3;
const int ledPin = 13;

int value = 0;

boolean mouseIsActive = false;
int prevSwitchState = HIGH;
int prevButtonState = LOW;

int toggle = 0;
int flag = 0;

int f;
int t=0;

int f_prev = 0;
int t_prev = 0;
// dont forget to change back 
int datain_Byte[6];
int th;
int fi;
int z;

void setup()
{
  pinMode(switchPin,INPUT);
  pinMode(ledPin,OUTPUT);
  Serial.begin(115200);
  Serial1.begin(115200);
  Mouse.begin();
  while(!Serial);
}

void loop()
{
  mouseActiveFcn(); // a push button controls the power to the Arduino.
  dataReading(); // get data from robot encoder. The data consists game selection integer z, 
                 //finger rotation angle, thumb rotation angle. Because the Arduino define integer
                 // as 2 bytes. Each piece of data consists of six bytes.
                 
                 // a physical control box has button to turn on and off the arduino.
                 // If it is on, mouseIsActive == true, the following lines will be
                 // executed. 
  if (mouseIsActive == true){
    if (z == 1 ){ // z is the integer that is generated by robot computer which 
                  // selects the game people like to play. 
      if(value==1){ // value = 1 incidates that the encoder data from robot comes in. Then
                    // Arduino takes control of game computer mouse. If value = 0, the computer mouse
                    // plays the game. 
        angryBirdGame(); // Arduino mouse is activated from map function
      }
      angryBirdMouseButton(); // Arduino controls the mouse key hold and release
    }
  }
//    
    if( z== 2){ // the same logic with z = 1;
      if(value==1){
        bubbleShootGame(); // Arduino mouse is activated from map function
      }
      clickMouse(); // Arduino activates the mouse key click function
    }
       
  }

  
  void mouseActiveFcn(){
    int switchState = digitalRead(switchPin);
  if (switchState != prevSwitchState) {
    if (switchState == LOW) {
      mouseIsActive = !mouseIsActive;
      digitalWrite(ledPin, mouseIsActive);
    }
  }
   prevSwitchState = switchState;
   delay(10);
  }
  
  void dataReading()
  {
            if(Serial1.available()>5) {
      
      for (int n = 0; n < 6; n++)
      {
        datain_Byte[n] = Serial1.read();
        value = 1;
      }
          z = 256*datain_Byte[1] + datain_Byte[0];
          f = (256*datain_Byte[3] + datain_Byte[2]);
          t = (256*datain_Byte[5] + datain_Byte[4]);
          Serial.println(z);
         // Serial.println(f);
         // Serial.println(t);
          //Serial.println();
          f_prev = f;
          t_prev = t;     
      }
          else {
            value = 0;
            f = f_prev;
            t = t_prev;
          }

    
  }
  
  
  void angryBirdGame(){
   
       th = map(t,0,130,28,13);
       fi = map(f,0,480,70,88);
       Mouse.move(th, fi, 0); 
  }
  
  void angryBirdMouseButton(){
       int buttonState = digitalRead(mouseButton);
       if (buttonState == HIGH && prevButtonState == LOW) {
     // if the mouse is not pressed, press it:
     toggle++;
     if(toggle == 1)
     {
     if(t < 5 && f < 6){
       if (!Mouse.isPressed(MOUSE_LEFT)) {
         Mouse.press(MOUSE_LEFT); 
       }
     //Serial.println(toggle);  
     }
     else
     { toggle = 0;
     //Serial.println(toggle); 
     }
   }
   else if(toggle == 2)
   {
     // else the mouse button is not pressed:
     // if the mouse is pressed, release it:
     if (Mouse.isPressed(MOUSE_LEFT)) {
       Mouse.release(MOUSE_LEFT); 
     }
     toggle = 0;
   }
   }

   prevButtonState = buttonState;  
  }
  
  void bubbleShootGame(){
       th = map(t,0,180,80,0);
       fi = map(f,0,480,100,0);
       Mouse.move(th, fi, 0);
  }
  
  void clickMouse(){
     int buttonState = digitalRead(mouseButton);
   if (buttonState == HIGH && prevButtonState == LOW) {
     Mouse.click();
   }
   prevButtonState = buttonState;
   delay(10);
  }
  
  
  void generalMove(){
       th = map(t,0,7,0,120);
       fi = map(f,0,17,0,120);
       Mouse.move(th, fi, 0);
     int buttonState = digitalRead(mouseButton);
   if (buttonState == HIGH && prevButtonState == LOW) {
     Mouse.click();
   prevButtonState = buttonState;
   }
   delay(10);
  }
  
  void holdMouse(){
     int buttonState = digitalRead(mouseButton);
   if (buttonState == HIGH && prevButtonState == LOW) {
     // if the mouse is not pressed, press it:
     toggle++;
     if(toggle == 1)
       if (!Mouse.isPressed(MOUSE_LEFT)) {
         Mouse.press(MOUSE_LEFT); 
       }  
   }
   else if(toggle == 2)
   {
     // else the mouse button is not pressed:
     // if the mouse is pressed, release it:
     if (Mouse.isPressed(MOUSE_LEFT)) {
       Mouse.release(MOUSE_LEFT); 
     }
     toggle = 0;
   }
   prevButtonState = buttonState;
   delay(10);
   }

Your code formatting is very poor. It has taken me a long time to make it readable. Use the autoformat option in the Arduino IDE.

I notice that you have a test

    if (mouseIsActive == true){
        if (z == 1 )

but the corresponding if (z == 2) is NOT within the If (mouseIsActive
(Very obvious with proper formatting)

Might that be the problem?

...R

Robin2,

Thanks a lot for the help. Sorry for the very formatting and for taking your quite long time to spot that. You just taught me a lesson on the importance of formatting. Yes, that should be inside the IF condition of MouseActive =true as well. However, the issue still persists. When I select z =2, the mapping range gets bigger. As I move faster and faster of my robot, the cursor movement on the game computer starts delaying and eventually the cursor stops the move. And then I check the serial monitor of Z output from Arduino. Z is not 2 anymore. It becomes some random number like 727, or -22207 and as such.

const int switchPin = 2;
const int mouseButton = 3;
const int ledPin = 13;

int value = 0;

boolean mouseIsActive = false;
int prevSwitchState = HIGH;
int prevButtonState = LOW;

int toggle = 0;
int flag = 0;

int f;
int t=0;

int f_prev = 0;
int t_prev = 0;
// dont forget to change back 
int datain_Byte[6];
int th;
int fi;
int z;

void setup()
{
  pinMode(switchPin,INPUT);
  pinMode(ledPin,OUTPUT);
  Serial.begin(115200);
  Serial1.begin(115200);
  Mouse.begin();
  while(!Serial);
}

void loop()
{
  mouseActiveFcn(); // a push button controls the power to the Arduino.
  dataReading(); // get data from robot encoder. The data consists game selection integer z, 
  //finger rotation angle, thumb rotation angle. Because the Arduino define integer
  // as 2 bytes. Each piece of data consists of six bytes.

  // a physical control box has button to turn on and off the arduino.
  // If it is on, mouseIsActive == true, the following lines will be
  // executed. 
  if (mouseIsActive == true){
    if (z == 1 ){ // z is the integer that is generated by robot computer which 
      // selects the game people like to play. 
      if(value==1){ // value = 1 incidates that the encoder data from robot comes in. Then
        // Arduino takes control of game computer mouse. If value = 0, the computer mouse
        // plays the game. 
        angryBirdGame(); // Arduino mouse is activated from map function
      }
      angryBirdMouseButton(); // Arduino controls the mouse key hold and release
    }
  //    
  if( z== 2){ // the same logic with z = 1;
    if(value==1){
      bubbleShootGame(); // Arduino mouse is activated from map function
    }
    clickMouse(); // Arduino activates the mouse key click function
  }
  }

}


void mouseActiveFcn(){
  int switchState = digitalRead(switchPin);
  if (switchState != prevSwitchState) {
    if (switchState == LOW) {
      mouseIsActive = !mouseIsActive;
      digitalWrite(ledPin, mouseIsActive);
    }
  }
  prevSwitchState = switchState;
  delay(10);
}

void dataReading()
{
  if(Serial1.available()>5) {

    for (int n = 0; n < 6; n++)
    {
      datain_Byte[n] = Serial1.read();
      value = 1;
    }
    z = 256*datain_Byte[1] + datain_Byte[0];
    f = (256*datain_Byte[3] + datain_Byte[2]);
    t = (256*datain_Byte[5] + datain_Byte[4]);
    Serial.println(z);
    // Serial.println(f);
    // Serial.println(t);
    //Serial.println();
    f_prev = f;
    t_prev = t;     
  }
  else {
    value = 0;
    f = f_prev;
    t = t_prev;
  }


}


void angryBirdGame(){

  th = map(t,0,130,28,13);
  fi = map(f,0,480,70,88);
  Mouse.move(th, fi, 0); 
}

void angryBirdMouseButton(){
  int buttonState = digitalRead(mouseButton);
  if (buttonState == HIGH && prevButtonState == LOW) {
    // if the mouse is not pressed, press it:
    toggle++;
    if(toggle == 1)
    {
      if(t < 5 && f < 6){
        if (!Mouse.isPressed(MOUSE_LEFT)) {
          Mouse.press(MOUSE_LEFT); 
        }
        //Serial.println(toggle);  
      }
      else
      { 
        toggle = 0;
        //Serial.println(toggle); 
      }
    }
    else if(toggle == 2)
    {
      // else the mouse button is not pressed:
      // if the mouse is pressed, release it:
      if (Mouse.isPressed(MOUSE_LEFT)) {
        Mouse.release(MOUSE_LEFT); 
      }
      toggle = 0;
    }
  }

  prevButtonState = buttonState;  
}

void bubbleShootGame(){
  th = map(t,0,180,80,0);
  fi = map(f,0,480,100,0);
  Mouse.move(th, fi, 0);
}

void clickMouse(){
  int buttonState = digitalRead(mouseButton);
  if (buttonState == HIGH && prevButtonState == LOW) {
    Mouse.click();
  }
  prevButtonState = buttonState;
  delay(10);
}


void generalMove(){
  th = map(t,0,7,0,120);
  fi = map(f,0,17,0,120);
  Mouse.move(th, fi, 0);
  int buttonState = digitalRead(mouseButton);
  if (buttonState == HIGH && prevButtonState == LOW) {
    Mouse.click();
    prevButtonState = buttonState;
  }
  delay(10);
}

void holdMouse(){
  int buttonState = digitalRead(mouseButton);
  if (buttonState == HIGH && prevButtonState == LOW) {
    // if the mouse is not pressed, press it:
    toggle++;
    if(toggle == 1)
      if (!Mouse.isPressed(MOUSE_LEFT)) {
        Mouse.press(MOUSE_LEFT); 
      }  
  }
  else if(toggle == 2)
  {
    // else the mouse button is not pressed:
    // if the mouse is pressed, release it:
    if (Mouse.isPressed(MOUSE_LEFT)) {
      Mouse.release(MOUSE_LEFT); 
    }
    toggle = 0;
  }
  prevButtonState = buttonState;
  delay(10);
}

What do you see when you print the raw values of f and t ?

How about meaningful names for f, t and z

Have you any idea how many "hits" my text editor gets when I ask it to find "t"

...R

nice point, Robin2. Attached is revised code. Let me know if anything else needs to be rewritten. Thanks a lot for the critics.

const int switchPin = 2;
const int mouseButton = 3;
const int ledPin = 13;

int value = 0;
boolean mouseIsActive = false;
int prevSwitchState = HIGH;
int prevButtonState = LOW;
int toggle = 0;
int flag = 0;
int fingerAngle= 0; //fingerAngle from encoder
int thumbAngle =0;//thumbAngle from encoder
int fingerAngle_prev = 0; // previous finger angle from encoder
int thumbAngle_prev = 0; // previous thumb angle from encoder
int datain_Byte[6];
int thumbAngle_pixel = 0; // thumb angle mapped to pixels on game computer screen
int fingerAngle_pixe = 0; // finger angle mapped to pixels on game computer screen
int gameSelection = 0; //gameSelection

void setup()
{
  pinMode(switchPin,INPUT);
  pinMode(ledPin,OUTPUT);
  Serial.begin(115200);
  Serial1.begin(115200);
  Mouse.begin();
  while(!Serial);
}

void loop()
{
  mouseActiveFcn(); // a push button controls the power to the Arduino.
  dataReading(); // get data from robot encoder. The data consists game selection integer z, 
  //finger rotation angle, thumb rotation angle. Because the Arduino define integer
  // as 2 bytes. Each piece of data consists of six bytes.

  // a physical control box has button to turn on and off the arduino.
  // If it is on, mouseIsActive == true, the following lines will be
  // executed. 
  if (mouseIsActive == true){
    if (gameSelection == 1 ){ // z is the integer that is generated by robot computer which 
      // selects the game people like to play. 
      if(value==1){ // value = 1 incidates that the encoder data from robot comes in. Then
        // Arduino takes control of game computer mouse. If value = 0, the computer mouse
        // plays the game. 
        angryBirdGame(); // Arduino mouse is activated from map function
      }
      angryBirdMouseButton(); // Arduino controls the mouse key hold and release
    }
    //    
    if( gameSelection== 2){ // the same logic with z = 1;
      if(value==1){
        bubbleShootGame(); // Arduino mouse is activated from map function
      }
      clickMouse(); // Arduino activates the mouse key click function
    }
  }

}


void mouseActiveFcn(){
  int switchState = digitalRead(switchPin);
  if (switchState != prevSwitchState) {
    if (switchState == LOW) {
      mouseIsActive = !mouseIsActive;
      digitalWrite(ledPin, mouseIsActive);
    }
  }
  prevSwitchState = switchState;
  delay(10);
}

void dataReading()
{
  if(Serial1.available()>5) {

    for (int n = 0; n < 6; n++)
    {
      datain_Byte[n] = Serial1.read();
      value = 1;
    }
    gameSelection = 256*datain_Byte[1] + datain_Byte[0];
    fingerAngle = (256*datain_Byte[3] + datain_Byte[2]); //current finger angle
    thumbAngle  = (256*datain_Byte[5] + datain_Byte[4]); //current thumb angle
    Serial.println(gameSelection);
    fingerAngle_prev = fingerAngle;
    thumbAngle_prev = thumbAngle;     
  }
  else {
    value = 0;
    fingerAngle = fingerAngle_prev;
    thumbAngle = thumbAngle_prev;
  }


}


void angryBirdGame(){

  thumbAngle_pixel = map(thumbAngle,0,130,28,13); //this function maps the thumb angle from encoder to the game computer pixel setting
  fingerAngle_pixel = map(fingerAngle,0,480,70,88);
  Mouse.move(thumbAngle_pixel, fingerAngle_pixel, 0); 
}

void angryBirdMouseButton(){
  int buttonState = digitalRead(mouseButton);
  if (buttonState == HIGH && prevButtonState == LOW) {
    // if the mouse is not pressed, press it:
    toggle++;
    if(toggle == 1)
    {
      if(thumbAngle_pixel < 5 && fingerAngle_pixel < 6){
        if (!Mouse.isPressed(MOUSE_LEFT)) {
          Mouse.press(MOUSE_LEFT); 
        } 
      }
      else
      { 
        toggle = 0;
      }
    }
    else if(toggle == 2)
    {
      // else the mouse button is not pressed:
      // if the mouse is pressed, release it:
      if (Mouse.isPressed(MOUSE_LEFT)) {
        Mouse.release(MOUSE_LEFT); 
      }
      toggle = 0;
    }
  }

  prevButtonState = buttonState;  
}

void bubbleShootGame(){
  thumbAngle_pixel = map(thumbAngle,0,180,80,0);
  fingerAngle_pixel = map(fingerAngle,0,480,100,0);
  Mouse.move(thumbAngle_pixel, fingerAngle_pixel, 0);
}

void clickMouse(){
  int buttonState = digitalRead(mouseButton);
  if (buttonState == HIGH && prevButtonState == LOW) {
    Mouse.click();
  }
  prevButtonState = buttonState;
  delay(10);
}


void holdMouse(){
  int buttonState = digitalRead(mouseButton);
  if (buttonState == HIGH && prevButtonState == LOW) {
    // if the mouse is not pressed, press it:
    toggle++;
    if(toggle == 1)
      if (!Mouse.isPressed(MOUSE_LEFT)) {
        Mouse.press(MOUSE_LEFT); 
      }  
  }
  else if(toggle == 2)
  {
    // else the mouse button is not pressed:
    // if the mouse is pressed, release it:
    if (Mouse.isPressed(MOUSE_LEFT)) {
      Mouse.release(MOUSE_LEFT); 
    }
    toggle = 0;
  }
  prevButtonState = buttonState;
  delay(10);
}

By the way, when I comment out the game playing part in my code like map() and the mouse.move()function, the z always gives me the correct way I need. No matter how fast I move my robot. The another thing is, when I select the angry bird game with z = 1, the mouse cursor control seems fine even when I move the robot swiftly. I assume that is because the mapped range for the angry bird game is small not large. But the mapped range when z = 2 is quite large.

void angryBirdGame(){ //z=1

  thumbAngle_pixel = map(thumbAngle,0,130,28,13); //this function maps the thumb angle from encoder to the game computer pixel setting
  fingerAngle_pixel = map(fingerAngle,0,480,70,88);
  Mouse.move(thumbAngle_pixel, fingerAngle_pixel, 0); 
}

void bubbleShootGame(){ //z=2
  thumbAngle_pixel = map(thumbAngle,0,180,80,0);
  fingerAngle_pixel = map(fingerAngle,0,480,100,0);
  Mouse.move(thumbAngle_pixel, fingerAngle_pixel, 0);
}

The Arduino website mentioned about the fact that the Arduino microcontroller can not take the encoder with high speed and high resolution. But my case is a little different. The Encoder is not directly connected to my Arduino Leonardo. The encoder is connected to the robot computer and I wire my Arduino Leonardo RX TX (serial1) to RS232 of robot computer to get encoder data sent in.

I know I am only picking at little pieces but I don't have a sufficient sense of the whole to do anything else

        gameSelection = 256*datain_Byte[1] + datain_Byte[0];
        fingerAngle = (256*datain_Byte[3] + datain_Byte[2]); //current finger angle
        thumbAngle  = (256*datain_Byte[5] + datain_Byte[4]); //current thumb angle
        Serial.println(gameSelection);
        fingerAngle_prev = fingerAngle;
        thumbAngle_prev = thumbAngle;

I suspect you should have the last pair of lines BEFORE the top line. In other words, save the old value before you get the new value.

The new names are much better :slight_smile:

...R

PS, spend an hour or two writing a Python program to get the habit of good code formatting. In Python precise formatting is essential.

Robin2,

Thanks a lot again for the comment. Yeah, I might need to move the last two lines at the very top to save the old values first. I was actually thinking about learning good formatting habit by picking on some other language. And I have finally found where the problem is . It is inside my Datareading() function. I should use while(Serial1.available()>5) instead of if(Serial1.available()>5). I got the hint somewhere else talking about the different between while loop and if statement for sending data from serial1 to serial. Using if statement in the case will easily cause buffer overflow since only 1 pack of data will send out every time no matter how much data comes in. On the other hand, while loop will send out any data which comes into the buffer.

void dataReading()
{
  if(Serial1.available()>5) { // I should use while loop here. Certainly I need to modify some other 
                                      // places in this part of code.                               

    for (int n = 0; n < 6; n++)
    {
      datain_Byte[n] = Serial1.read();
      value = 1;
    }
    gameSelection = 256*datain_Byte[1] + datain_Byte[0];
    fingerAngle = (256*datain_Byte[3] + datain_Byte[2]); //current finger angle
    thumbAngle  = (256*datain_Byte[5] + datain_Byte[4]); //current thumb angle
    Serial.println(gameSelection);
    fingerAngle_prev = fingerAngle;
    thumbAngle_prev = thumbAngle;     
  }
  else {
    value = 0;
    fingerAngle = fingerAngle_prev;
    thumbAngle = thumbAngle_prev;
  }

Glad to hear it is working.

I wonder should you use both IF and WHILE like this

if(Serial1.available()>5) { 
  while(Serial1.available > 0) {

It does nothing if there are five or fewer characters, but then it reads all that there is.

You might want to look at the examples in serial input basics which read from the serial buffer in the background until all the data has been received.

...R

sure. I am looking at the link now and it is very comprehensive. Great work, Robin2.

Robin2,

Again the link is quite informative. a question to your exemplary code in Serialinput link. How should I operate the serial monitor to see the parsed message of "This is a test, 1234, 45.3". When I upload the code and then open the serial monitor, there is no any text coming out. Should I type This is a test, 1234, 45.3, and then hit Send.
Thanks a lot.

// simple parse demo
char receivedChars[] = "This is a test, 1234, 45.3" ;

char messageFromPC[32] = {0};
int integerFromPC = 0;
float floatFromPC = 0.0;

char recvChar;
char endMarker = '>';
boolean newData = false;


void setup() {
	Serial.begin(9600);
	Serial.println("<Arduino is ready>");
	
	parseData();
	showParsedData();
}


void loop() {

}

	
void parseData() {

    // split the data into its parts
    
  char * strtokIndx; // this is used by strtok() as an index
  
  strtokIndx = strtok(receivedChars,",");      // get the first part - the string
  strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
  
  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  integerFromPC = atoi(strtokIndx);     // convert this part to an integer
  
  strtokIndx = strtok(NULL, ","); 
  floatFromPC = atof(strtokIndx);     // convert this part to a float

}


void showParsedData() {
	Serial.print("Message ");
	Serial.println(messageFromPC);
	Serial.print("Integer ");
	Serial.println(integerFromPC);
	Serial.print("Float ");
	Serial.println(floatFromPC);
}

You don't need to enter any data in the Serial Monitor. Try pressing the reset button on the Arduino (assuming it is NOT a Leonardo) while the Serial Monitor is open.

The code only runs once when the Arduino restarts.

The parse example simulates the situation where you had used one of the other examples to put data into receivedChars[]

Do let me know if you can't get it to work

...R

I See. Thanks. Sorry, unfortunately, I am trying with my Leonardo board. It didn't work that way somehow.