Joystick mouse moving on its own

I'm making a joystick controlled mouse on an Arduino Nano ESP32. it works perfectly, but the thing is that it is also causing the mouse to constantly move down and to the right at a 45 degree angle, anyone know a fix for this? here is the code I'm using

int Xaxis = analogRead(A0);
int Yaxis = analogRead(A1);
  int offsetX = Xaxis - centerX;
  int offsetY = Yaxis - centerY;
  if (abs(offsetX) < deadZone){
    offsetX = 0;
  }
  if (abs(offsetY) < deadZone){
    offsetY = 0;
  }
  int deltaX = map(offsetX, 2048, -2048, 5, -5);
  int deltaY = map(offsetY, 2048, -2048, 5, -5);
  if (deltaX != 0 || deltaY != 0) {
    Mouse.move(deltaX, deltaY);
  }

It does not work perfectly.

This is called drift. To eliminate drift when the joystick is centered, there needs to be a "deadband" which does not cause the "mouse" to move. You need to increase your deadband.

Also, you should always post the full sketch, not just a chunk you think is broken.

Are you aware, that the arduino map is slighly off?

Also I would apply the dead zone to the final result rather, than for input, like this:

Follow @xfpd 's post and increase the value of deadZone (unfortunately the actual value is not disclosed, again a case for the magic crystal ball ... :wink:)

A hint for the future:

  • Print the interesting values (here: Xaxis, Yaxis, offsetX, offsetY, deltaX and deltaY) to Serial
  • Test the application thoroughly, especially at its limits and where you have encountered problems
  • Evaluate the results and apply appropriate solutions
  • Remove the print commands

in this case you will see that the final values are floating while your input device seems to be in a centered position. Give it a try and play around with the value of deadZone to get a feeling for your specific hardware ... It will be worth for future projects!

Good luck!
ec2021

I can confirm that the deadband isn't the issue, I tried it without the stick connected (that means nothing was connected to the microcontroller) and it still had the same thing, also here is the entire sketch (a lot of it is for buttons so that's why i refrained from showing them)

#if ARDUINO_USB_MODE
#warning This sketch should be used when USB is in OTG mode
void setup(){}
void loop(){}
#else

#include "USB.h"
#include "USBHIDMouse.h"
#include "USBHIDKeyboard.h"
USBHIDMouse Mouse;
USBHIDKeyboard Keyboard;

// set pin numbers for the buttons:
const int upButton = D1;
const int downButton = D2;
const int leftButton = D3;
const int rightButton = D4;
const int mouseButtonL = D0;
const int mouseButtonR = D5;
const int AButton = D6;
const int centerX = 2048;
const int centerY = 2048;
const int deadZone = 200;
void setup() {
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);
  pinMode(leftButton, INPUT_PULLUP);
  pinMode(rightButton, INPUT_PULLUP);
  pinMode(mouseButtonL, INPUT_PULLUP);
  pinMode(mouseButtonR, INPUT_PULLUP);
  pinMode(AButton, INPUT_PULLUP);

  Serial.begin(115200);
  // initialize mouse control:
  Mouse.begin();
  Keyboard.begin();
  USB.begin();
}

void loop() {
int Xaxis = analogRead(A0);
int Yaxis = analogRead(A1);

  //set the offset of the joystick
  int offsetX = Xaxis - centerX;
  int offsetY = Yaxis - centerY;
  if (abs(offsetX) < deadZone){
    offsetX = 0;
  }
  if (abs(offsetY) < deadZone){
    offsetY = 0;
  }
  //calculate the position of the stick
  int deltaX = map(offsetX, 2048, -2048, 5, -5);
  int deltaY = map(offsetY, 2048, -2048, 5, -5);
  if (deltaX != 0 || deltaY != 0) {
    Mouse.move(deltaX, deltaY);
  }

  // use the pushbuttons to control the keyboard:
  if (digitalRead(upButton) == LOW) { 
    Keyboard.press('w');
  }
  if (digitalRead(upButton) == HIGH) { 
    Keyboard.release('w');
  }
  if (digitalRead(downButton) == LOW) {
    Keyboard.press('s');
  }
  if (digitalRead(downButton) == HIGH) {
    Keyboard.release('s');
  }
  if (digitalRead(leftButton) == LOW) {
    Keyboard.press('a');
  }
  if (digitalRead(leftButton) == HIGH) {
    Keyboard.release('a');
  }
  if (digitalRead(rightButton) == LOW) {
    Keyboard.press('d');
  }
  if (digitalRead(rightButton) == HIGH) {
    Keyboard.release('d');
  }
  if (digitalRead(mouseButtonL) == LOW) {
    Mouse.press(MOUSE_LEFT);
  }
  if (digitalRead(mouseButtonL) == HIGH) {
    Mouse.release(MOUSE_LEFT);
  }
  if (digitalRead(mouseButtonR) == LOW) {
    Mouse.press(MOUSE_RIGHT);
  }
  if (digitalRead(mouseButtonR) == HIGH) {
    Mouse.release(MOUSE_RIGHT);
  }
  if (digitalRead(AButton) == LOW) {
    Keyboard.press(' ');
  }
  if (digitalRead(AButton) == HIGH) {
    Keyboard.release(' ');
  }
}
#endif /* ARDUINO_USB_MODE */

You did not try. You went off on your own guesswork.

Unless you tied those pins HIGH or LOW, those pins will yield random reading.

You should read about arrays. It will put more control in the microcontroller, and less in typographical correctness.

I sense (see) that you do not want to be told anything. Have fun.

yeah I'm a complete beginner when it comes to this stuff, but I'll make sure to look into arrays. thank you for telling me about that.

having the dead zone be applied to the output helped, but it didn't completely solve the issue. the cursor doesn't move on its own anymore, but now the inputs don't work as intended, now the left and right inputs cause the the cursor to also go down, and inputs for the cursor to go up and down make it also go to the right. I'm still unable to find a solution to this unfortunately.

See my Post No 4.

If the result of several functions that convert raw data to other values does not provide what you expect there is a problem in the chain that starts with raw data, offset values, dead zone filtering and finally mapping.

One method is to feed the algorithms with known values instead of arbitrary joystick data. Put the algorithm in a separate function and use a for loop that goes from 0 to maximum value, Print the input value and intermediate results to Serial. You can use steps of 100 in the first run. Then 10, finally 1.

Do the algorithms do what you expect?

If yes there must be an issue with your raw data. If not: Rethink your calculation chain.

I'm slowly starting to figure things out, I have no idea why this is happening, but when printing out the offset of the stick to serial, I suddenly start getting messed up data as seen in the image, I'm still trying to find my way around this system due to me being completely new to Arduino (this is my first ever project using arduino)

Your sketch in Post #5 shows no Serial.print()... Did you change to an old sketch that was causing the problem?

no, that was the code i had at the time, I just today added the serial print, while printing the raw input value I've notice that it is constantly changing, I here is a screenshot of some serial readings I have got. I'm not sure why my raw data of all things is moving, but I assume that this is the core root of my problem, any ideas on how I can fix it?

The image shows COM5 not connected.

Verify sketch and IDE Serial Monitor use the same baud.

That was because I unplugged the Arduino to change the circuitry. The baud is fine, should be set to 9600.

​

​

​

​

​

​

​

​

​

​

The cause of "special characters" in your post 10 was this line

image

The use of Serial.println() is defined as follows


(see here https://docs.arduino.cc/language-reference/en/functions/communication/serial/println/

But please post code inside code tags (also longer data columns). It makes reading and copying much easier for other forum members ... You find the code tags in the post editor menu

image

And preferably post the full code! In a lot of cases the reason for problems is somewhere else in the sketch.

A code snippet of your screenshot would look like this (thanks to AI OCR):

//set the offset of the joystick
int offsetX = Xaxis - centerX;
int offsetY = Yaxis - centerY;
//calculate the position of the stick
int deltaX = map(offsetX, 4096, -4096, 5, -5);
int deltaY = map(offsetY, 4096, -4096, 5, -5);
if (abs(deltaX) > deadZone || abs(deltaY) > deadZone) {
  Mouse.move(deltaX, deltaY);
  Serial.print(Xaxis);
  Serial.print(",");
  Serial.println(Yaxis);
}

Here the data

09:44:35.702 -> 3013,3739
09:44:35.702 -> 3003,3752
09:44:35.702 -> 3003,3757
09:44:35.702 -> 3003,3743
09:44:35.702 -> 3004,3743
09:44:35.702 -> 3007,3748
09:44:35.702 -> 3017,3765
09:44:35.702 -> 3008,3758
09:44:35.702 -> 3019,3739
09:44:35.702 -> 3011,3747
09:44:35.702 -> 3007,3753
09:44:35.702 -> 3018,3771
09:44:35.702 -> 2995,3719
09:44:35.702 -> 3019,3763
09:44:35.702 -> 2985,3743
09:44:35.702 -> 3003,3695
09:44:35.702 -> 3020,3753
09:44:35.702 -> 3013,3748
09:44:35.702 -> 3002,3740
09:44:35.735 -> 3015,3769
09:44:35.735 -> 3023,3777
09:44:35.735 -> 3017,3743
09:44:35.735 -> 3013,3756

If you copy your data into a spreadsheet and let it check for minimum and maximum you can calculate the difference (and also the percentage the data are floating):

  • Xaxis floats less than one percent of the full range (0 ...4095),
  • Yaxis about 2 percent.

That's not bad at all - quite the opposite!

Both raw data are not centered if we assume that this should be around 2048.

  • Xaxis is more or less around 3000
  • Yaxis is around 3740

To get rid of the "movement" you can average the raw data over a certain number of measurements.

Any method will have an influence on reactivity, but give it a try ... as long as human interaction is involved there is some reasonable space (in time)!

If you are more interested in an existing solution rather than create your own than have a look at this library
https://github.com/dxinteractive/ResponsiveAnalogRead

BTW: You still may have to check what interim output you get from your code! But it#s much easier if the raw data perform as expected!

Verify.

(Looks like i posted whil you were posting)

What's up with the whitespace?

@ec2021

Is this map() input correct? 2^13 bits?

Thank you for the info, I'll download the library and implement it into the sketch. The center for both being 3000 and 3740 could possibly be caused by my joystick, I'm simply using a ps2 joystick module to test the code, the fully finished project is planned to use a hall effect joystick, is that going to change the values I'll have to put in or no. I'll add a picture of the joystick I plan to implement.

It's the part of the sketch that the TO posted in the screenshot from post 12...

This looked different in post 1

int deltaX = map(offsetX, 2048, -2048, 5, -5);
int deltaY = map(offsetY, 2048, -2048, 5, -5);

with

const int centerX = 2048;
const int centerY = 2048;

from post 5 and a Nano ESP with 12 bit resolution (0 ...4095) the offsetX and -Y values could be minimum -2048 to maximum 2047.

Mapping with input borders of -4096 to 4096 will use only about 50 percent of the available space from -5 to 5.

And mapping these values to a scale from -5 ... 5 makes averaging less effective as jitter would only appear at the borders between the output values -5 to -4, -4 to -3, etc.

Simple test:



void setup() {
 Serial.begin(115200);
 for (int i=-20;i<21;i++){
  int m1 = map(i*100,-2028,2028,-5,5);
  int m2 = map(i*100,-4096,4096,-5,5);
  Serial.print(i*100);
  Serial.print("\t");
  Serial.print(m1);
  Serial.print("\t");
  Serial.println(m2);
 }
}

void loop() {
 }

Results:

-2000	-5	-3
-1900	-5	-3
-1800	-5	-3
-1700	-5	-3
-1600	-4	-2
-1500	-4	-2
-1400	-4	-2
-1300	-4	-2
-1200	-3	-2
-1100	-3	-2
-1000	-3	-2
-900	-3	-2
-800	-2	-1
-700	-2	-1
-600	-2	-1
-500	-2	-1
-400	-1	-1
-300	-1	-1
-200	-1	-1
-100	-1	-1
   0	0	0
 100	0	0
 200	0	0
 300	0	0
 400	0	0
 500	1	0
 600	1	0
 700	1	0
 800	1	0
 900	2	1
1000	2	1
1100	2	1
1200	2	1
1300	3	1
1400	3	1
1500	3	1
1600	3	1
1700	4	2
1800	4	2
1900	4	2
2000	4	2

Edit: But some averaging would still be required to avoid the jitter ...

Great news!! I was able to fix the issue. this post was able to help me figure out my issue and how i could fix it, instead of changing the center value of the stick in the code, I simply changed the stick to a hall effect stick I have that has the values I already had in my code as its center value. I'm currently applying the library you showed me in post 15.

That's good news!

You may mark the post that helped you as "solution" so that your thread is no longer listed as an open issue.

If you apply the measures as shown above in future projects it will help to reduce time and work to achieve the goal... Mastering the way from raw data to final output is crucial.

Good luck!
ec2021