Go Down

Topic: Need help with Arduino joystick! (Read 532 times) previous topic - next topic

vonNeustadt

Greetings Arduino community,

I have just finished hooking up an Arduino DUE to the Honeycomb yoke (flight controls) in order to get rid of the huge deadzone the default firmware has and increase the granularity of the axis inputs.

When I first opened up the Windows 'Set up USB game controllers' program I noticed both axis readings barely moved whenever I moved the yoke itself. Everything seems fine once I calibrate the device using the same program except when I try to calibrate it in X-Plane 11 (which uses its own calibration software and totally ignores the Windows calibration).

When trying to calibrate it in X-Plane, I start moving both axis and again they're barely moving in the software (just like Windows did before calibration), so I'm unable to complete the calibration.

I tried to check the windows calibration using another joystick program and it seems the 'default' axis scale is from 0 to 65535 but before calibration it outputs values between 0 and 1024 which seems extremely small on the larger scale. The problem is I can't seem to get rid of that scale problem in X-Plane and I would like for the 'scale' to be correct 'out of the box' when I plug in the yoke.

The problem seems to be the code (which I did not write myself), I will post it here so maybe you guys can help... Many thanks in advance!

Code :

//#include "HID.h"  //uncomment for arduino due
//note that for the due the hid controller only works through the native port
#include "Joystick.h"

void setup() {
  //zero out the joystick state
  Joystick.clearState();
  //set pins as input (sparkfun joystick shield config)
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  //enable pullups
  digitalWrite(2, HIGH);
  digitalWrite(3, HIGH);
  digitalWrite(4, HIGH);
  digitalWrite(5, HIGH);
  digitalWrite(6, HIGH);
//  Serial.begin(9600);
  analogReadResolution(10);
}

void loop() {
 // Serial.println(analogRead(0));
  //clear
  Joystick.clearState();
  //tweak the joystick state (see joystick.h for all possible fields)
  Joystick.state.x.axis = map(analogRead(0), 53, 998, 0, 1024);
  Joystick.state.y.axis = map(analogRead(1), 49, 955, 0, 1024);
  Joystick.state.buttons.b00 = !digitalRead(2);
  Joystick.state.buttons.b01 = !digitalRead(3);
  Joystick.state.buttons.b02 = !digitalRead(4);
  Joystick.state.buttons.b03 = !digitalRead(5);
  Joystick.state.buttons.b04 = !digitalRead(6);
  Joystick.state.hats.switch1 = HAT_LEFT;
  Joystick.state.hats.switch2 = HAT_UP;
  //call send state to pack and send the current state over usb
  Joystick.sendState();
 // Serial.print("Output ");
  //Serial.println(Joystick.state.x.axis);

  delay(50);


}

pert

before calibration it outputs values between 0 and 1024
That's because in your code you are mapping the analogRead value between 0 and 1024:
Code: [Select]
  Joystick.state.x.axis = map(analogRead(0), 53, 998, 0, 1024);
  Joystick.state.y.axis = map(analogRead(1), 49, 955, 0, 1024);
More information:
https://www.arduino.cc/reference/en/language/functions/math/map/

vonNeustadt

Thank you for clarifying! I will set the toHigh value to 65535 instead and see if the 'range' gets adjusted properly. Do I also need to adjust the fromLow and fromHigh values? What do they represent?

Don't really understand what 'current range' means in this context. Does it have anything to do with center or neutral value?

pert

Let's say you have this code:
Code: [Select]
Joystick.state.x.axis = map(analogRead(0), 53, 998, 0, 65535);
This means that if analogRead(0) returns 53, Joystick.state.x.axis will be set to 0. If analogRead(0) returns 998, Joystick.state.x.axis will be set to 65535. All other return values of analogRead(0) results in Joystick.state.x.axis being set to a value following that linear relationship.

analogRead(0) will return 0 if the voltage on the Due's pin A0 is 0 V and 1023 if the voltage on the Due's pin A0 is 3.3 V. The 53/998 and 49/955 numbers used were probably determined empirically by checking what analogRead() returned after moving the joystick to the limits of each axis. You may find that each joystick has slightly different numbers. You could check it using this simple sketch:
Code: [Select]
void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.print("X axis: ");
  Serial.println(analogRead(0));
  Serial.print("Y axis: ");
  Serial.println(analogRead(1));
  delay(500);
}

Open Tools > Serial Monitor and then watch the values printed on the screen when you move the  joystick to the limits of each axis.

That sketch is written for use with the Due connected to the computer with the Programming Port. If it's connected with the Native USB Port, change all the instances of Serial in the sketch to SerialUSB.

vonNeustadt

Thank you for the very useful code! Unfortunately, changing the 'toHigh' value to 65535 for both axis does not seem to be the solution. I messes my axes up big time (jump from negative to positive suddenly, unstable, etc.)

I will have to try and find a different solution. A calibration software that would override X-Plane's would be useful in my case.

vonNeustadt

I would like to simplify the code to make sure it is not the reason my project is not working. Could this one work for a simple joystick (two axes, X and Y. So only two pots connected to the DUE)?

Code :

#include "Joystick.h"

void setup() {
 Joystick.clearState();
 Serial.begin(9600);
 analogReadResolution(10);
}

void loop() {
 Joystick.clearState();
 Joystick.state.x.axis = map(analogRead(0), 53, 998, 0, 1024);
 delay(50);
 Joystick.state.y.axis = map(analogRead(1), 49, 955, 0, 1024);
 Joystick.sendState();
}


I am using the Joystick library. The previous code, which I did not write, said to uncomment ' #include "HID.h" ' at the beginning but I cannot seem to find the HID.h file anywhere in the provided library.

Also, I notice Serial.begin(9600) still had slashes in front of the line in the previous code (was not activated).

One last question, is it okay to put delay(50) between the analogRead lines instead of after? I read in this tutorial (https://www.arduino.cc/en/Tutorial/JoyStick) that a pause is needed between reading analog pins to prevent getting the same value twice...

Any help is greatly appreciated!

pert

Unfortunately, changing the 'toHigh' value to 65535 for both axis does not seem to be the solution. I messes my axes up big time (jump from negative to positive suddenly, unstable, etc.)
It could be caused by a limitation imposed by the data types used by the Joystick library. Please post a link to where you downloaded the library from.

I am using the Joystick library. The previous code, which I did not write, said to uncomment ' #include "HID.h" ' at the beginning but I cannot seem to find the HID.h file anywhere in the provided library.
It's part of a separate library, that comes with the Arduino SAM Boards support package you installed to be able to use your Due with the Arduino IDE:
https://github.com/arduino/ArduinoCore-sam/tree/master/libraries/HID/src

Also, I notice Serial.begin(9600) still had slashes in front of the line in the previous code (was not activated).
It is used for debug output, to be able to see how the program is working from the output in Serial Monitor. During normal operation, you don't need the serial output. This is the reason why it was commented out, along with the lines that provide the debug output:
Code: [Select]
// Serial.print("Output ");
  //Serial.println(Joystick.state.x.axis);


In your simplified code, you don't have any serial output, so that Serial.begin(9600) has no purpose. However, since you are trying to figure out what is going wrong, you might want to leave it in and also add some output. Then run the program with Serial Monitor open so you can see what is happening.

One last question, is it okay to put delay(50) between the analogRead lines instead of after?
Probably. But it's not going to help with your problem.

I read in this tutorial (https://www.arduino.cc/en/Tutorial/JoyStick) that a pause is needed between reading analog pins to prevent getting the same value twice...
I think the reason for the delay in that tutorial is because without it you will get a very fast stream of number in Serial Monitor that will be hard to read. In a real application where you are actually using your joystick to control a game, likely you would not want any delay, since this will be harmful to the responsiveness of the joystick. I suppose it's possible there is some limitation of data rate imposed by the application on the computer, but I doubt it.

In the case of debugging with the Serial Monitor, it may be helpful to have a delay.

vonNeustadt

This is where I picked up the joystick library : https://github.com/LordNuke/ArduinoLibs

The 'original' code I picked up says to include HID.h at the beginning for DUE boards so I will add it to my new code just in case...

Also, is it useful to add a small delay at the end of the loop code? How does one choose how much delay to add?

Again, many thanks for your help!

pert

This is where I picked up the joystick library : https://github.com/LordNuke/ArduinoLibs
From looking at the source code, I can see that the Joystick.state.x.axis and Joystick.state.y.axis variables are signed 16 bit variables. That means they can store values from -32768 to 32767. When you try to store a number greater than 32767 in the variable, it overflows. For example, if you do this:
Code: [Select]
Joystick.state.x.axis = 32769;
Serial.println(Joystick.state.x.axis);

You'll see in Serial Monitor: -32767

The 'original' code I picked up says to include HID.h at the beginning for DUE boards so I will add it to my new code just in case...
That's only necessary if you're using an old version of the Arduino IDE, 1.6.5 or older. With any modern version of the Arduino IDE, it's not necessary. The Joystick library does that for you.

Also, is it useful to add a small delay at the end of the loop code?
I already answered that in my last reply.

vonNeustadt

I have managed to get everything to work properly code wise but when I connect my joystick some kind of noise on the potentiometers gets really noticeable, I can see the virtual yoke jittering mildly in X-Plane without any physical movement from the joystick.

Could this problem by related to anything other than bad connections? Do I need to deactivate unused analog inputs in order to get rid of the noise? Could this be caused by the removal of the delay() function in the loop?

Thank you for your help!

Go Up