USB Volume control using Rotary encoder for android

Hi Everyone,

I have a touch screen radio in my truck that has no physical knob to adjust the volume, one of these days I swear I will die trying to adjust it using the touch screen.
The radio runs android, so I figured I could use a rotary encoder to send volume up and down keys through the arduino as an HID, this worked however not exactly how I thought it would.
Turns out, my android radio has 2 separate volumes. When I rotate the rotary encoder, similar to a phone, a volume control pops up, however this does not change the volume level on the bottom fixed bar which stays at a certain volume, turns out it is sending this data directly to the car i.e. no keystroke.

I figured I could rethink my plan and change what would be a keyboard to a mouse, however I am struggling to accurately position the mouse where I need the keypress to happen. I understand absolute positioning goes against the entire concept that a mouse was made for, but the concept of relative positioning is hard to grasp for my use.

I found an example sketch from someone on this forum that would locate the mouse to the bottom left, move up slightly to the right at a diagonal, do a circle with the mouse then return to the same location. No matter if you moved the mouse during that operation, it would always return to the same spot. I would very much like to not have someone just give me the answer, but rather point me in the direction of how I could better understand the code that is written in this example. I really just need to understand how the positioning it always repeating back to a 0 location, my positioning is 720 pixels from the left and my understanding is that I can only travel 127 (not even sure the unit, I dont think pixels).

If anyone could point me in the right direction I would be greatly appreciated!

The code I would like to better understand is below, not so much the circle, but the exact positioning.

/*
  Demo of moving the mouse in a smooth circle without delay
  or blocking of the loop
*/
#include <Mouse.h>
void setup() {
  delay(1000);
}

void loop() {
  static float angle = 100;
  static int x, y;
  static unsigned long counter6;
  static unsigned long counter7;

  if (millis() > 10000 && counter6 < millis() - 10000) {
    counter6 = millis();
    angle = 0.0;
  }

  if (millis() > 20 && counter7 < millis() - 20 && angle < 100) {
    counter7 = millis();
    if (angle < 0.1 ) {
      Mouse.begin();
      // move to the corner of the screen
      for (int counter5 = 0; counter5 <= 100; counter5++) {
        Mouse.move(-127, 127, 0);
      }
      // move to a specific point on the screen
      Mouse.move(20,-30,0);
    }
    // move around a couple of times in a circle
    x = 9 * cos (angle);
    y = 9 * sin (angle);
    angle += .2; // increment the angle
    Mouse.move(x, y, 0);
    if (angle >= 4 * PI) {
      angle = 100;
      Mouse.end();
    }
  }
}
for (int counter5 = 0; counter5 <= 100; counter5++) {
        Mouse.move(-127, 127, 0);
      }

Here it relatively moves the mouse -127, 127, 0 but it does so 100 times. that should make it end up in the corner think.

Deva_Rishi:

for (int counter5 = 0; counter5 <= 100; counter5++) {

Mouse.move(-127, 127, 0);
     }



Here it relatively moves the mouse -127, 127, 0 but it does so 100 times. that should make it end up in the corner think.

Thanks for the breakdown, that got me a ton of progress.
Basically, I now have the program working, coordinates are correct when I turn the rotary encoder left and right.
I attempted to add a Mouse.click(MOUSE_LEFT); function, which is wreaking some havoc.
It would appear that although the mouse.click is to follow the movement to the specified coordinate, I am getting multiple clicks, first one as it moves to the 0 point (inconveniently hits the A/C on button in my truck).
The code I am running is

#include <ClickEncoder.h>
#include <TimerOne.h>
#include <HID-Project.h>

#define ENCODER_CLK A0 // Change A0 to, for example, A5 if you want to use analog pin 5 instead
#define ENCODER_DT A1
#define ENCODER_SW A2

ClickEncoder *encoder; // variable representing the rotary encoder
int16_t last, value; // variables for current and last rotation value

void timerIsr() {
  encoder->service();
}

  void setup() {
  Serial.begin(9600); // Opens the serial connection used for communication with the PC. 
  Consumer.begin(); // Initializes the media keyboard
  encoder = new ClickEncoder(ENCODER_DT, ENCODER_CLK, ENCODER_SW, 4); // Initializes the rotary encoder with the mentioned pins
  Timer1.initialize(1000); // Initializes the timer, which the rotary encoder uses to detect rotation
  Timer1.attachInterrupt(timerIsr); 
  last = -1;
  delay(5000); //just in-case you fucked this up
  Mouse.begin();
}

void loop() {

    value += encoder->getValue();
  // This part of the code is responsible for the actions when you rotate the encoder
  if (value != last) { // New value is different than the last one, that means to encoder was rotated
    if(last<value) // Detecting the direction of rotation        
            // move to the corner of the screen
      {{for (int counter5 = 0; counter5 <= 100; counter5++) {
        Mouse.move(-120, 120, 0);
        delay(10);}
      // move to a specific point on the screen
      for (int counter6 = 0; counter6 <= 2; counter6++) {
        Mouse.move(79,-11,0); // left-right, top-bottom, keep at 0
        delay(5);
        Mouse.press(MOUSE_LEFT);
        delay(5);
        Mouse.release(MOUSE_LEFT);
        Mouse.end();
      }
  }}      else
            {{for (int counter5 = 0; counter5 <= 100; counter5++) {
        Mouse.move(-120, 120, 0);
        delay(10);}
      // move to a specific point on the screen
      for (int counter6 = 0; counter6 <= 2; counter6++) {
        Mouse.move(79,-3,0); // left-right, top-bottom, keep at 0
        delay(5);
        Mouse.press(MOUSE_LEFT);
        delay(5);
        Mouse.release(MOUSE_LEFT);
        Mouse.end();
      }}}}
      last = value;
      
      
      delay(50);
      

  delay(10); // Wait 10 milliseconds, we definitely don't need to detect the rotary encoder any faster than that
  // The end of the loop() function, it will start again from the beggining (the begginging of the loop function, not the whole document)
  }

Does anyone have any guidance for this issue?
Greatly appreciated.

Does anyone have any guidance for this issue?

If you want me (and others as well) to keep sifting through your code, then don't do stuff like this :

{{for (int counter5 = 0; counter5 <= 100; counter5++) {
        Mouse.move(-120, 120, 0);
        delay(10);}

or this :

 Mouse.end();
      }}}}
      last = value;

please indent your code properly (using ctrl-t is a way) and put closing braces on a line by them self. Like that it is a lot easier to read and see what is part of what loop or conditional execution. Delete unneeded white lines (they don't do anything but a few in a row just removes lines from view)
Please Change your code accordingly. I suspect you are looping the pressing and releasing, but it is just to hard to tell without counting braces, hence the indenting.

Thanks for the help, I had seen people's code written like that before but really didn't see the purpose, I get that now and have made the adjustments.

#include <ClickEncoder.h>
#include <TimerOne.h>
#include <HID-Project.h>

#define ENCODER_CLK A0 // Change A0 to, for example, A5 if you want to use analog pin 5 instead
#define ENCODER_DT A1
#define ENCODER_SW A2

ClickEncoder *encoder; // variable representing the rotary encoder
int16_t last, value; // variables for current and last rotation value

void timerIsr() {
  encoder->service();
}

void setup() {
  Serial.begin(9600); // Opens the serial connection used for communication with the PC.
  Consumer.begin(); // Initializes the media keyboard
  encoder = new ClickEncoder(ENCODER_DT, ENCODER_CLK, ENCODER_SW, 4); // Initializes the rotary encoder with the mentioned pins
  Timer1.initialize(1000); // Initializes the timer, which the rotary encoder uses to detect rotation
  Timer1.attachInterrupt(timerIsr);
  last = -1;
  delay(5000); //just in-case you fucked this up
  Mouse.begin();
}

void loop() {

  value += encoder->getValue();
  // This part of the code is responsible for the actions when you rotate the encoder
  if (value != last) { // New value is different than the last one, that means to encoder was rotated
    if (last < value) // Detecting the direction of rotation
      // move to the corner of the screen
    {{ for (int counter5 = 0; counter5 <= 100; counter5++) {
          Mouse.move(-120, 120, 0);
          delay(10);
        }
        for (int counter6 = 0; counter6 <= 2; counter6++) {
          Mouse.move(79, -11, 0); // left-right, top-bottom, keep at 0
          delay(5);
          Mouse.press(MOUSE_LEFT);
          delay(5);
          Mouse.release(MOUSE_LEFT);
          Mouse.end();
        }
      }
    }      else
    {{ for (int counter5 = 0; counter5 <= 100; counter5++) {
          Mouse.move(-120, 120, 0);
          delay(10);
        }
        for (int counter6 = 0; counter6 <= 2; counter6++) {
          Mouse.move(79, -3, 0); // left-right, top-bottom, keep at 0
          delay(5);
          Mouse.press(MOUSE_LEFT);
          delay(5);
          Mouse.release(MOUSE_LEFT);
          Mouse.end();
        }
      }
    }
  }
  last = value;
  delay(10);
}

Hopefully that is written in a way that is more understandable (although still likely not written in the ideal way)

(although still likely not written in the ideal way)

No that not, most people here have nothing on a line following an opening brace, and i fail to see what could be the purpose of 2 consecutive opening braces. anyway.

for (int counter6 = 0; counter6 <= 2; counter6++) {
          Mouse.move(79, -11, 0); // left-right, top-bottom, keep at 0
          delay(5);
          Mouse.press(MOUSE_LEFT);
          delay(5);
          Mouse.release(MOUSE_LEFT);
          Mouse.end();
        }

In this loop which runs 3 times, you move the mouse (relatively), press it, and release it. 3 times. is that the plan ? i mean you got tot the zero position, and then you move just a little and click. move a little more and click again and then once more.