Joystick Arduino Programming Help

Hi all, I am totally new to programming and to Arduino! I am into flight sims and Elite Dangerous, and I need some help if you would like to consider. I am naturally a left hander, I have a Saitek X-56 HOTAS flightstick, which means I use the stick - intended for the right hand - in my left hand.

I therefore miss some controls that right handed people can reach. I would like to attach some additional controls to the flight stick, essentially two analogue 2-axis PSP-1000 thumbsticks, and 3 momentary pushbuttons. I plan to attach these with Sugru.

I think I have the wiring diagram sorted out - see below. I am using the ATmega32U4 Pro Micro.

However, I have no knowledge on programming at all. I have seen some example code that shows how to connect the thumbstick, or the buttons, but not both at the same time, and I do not feel confident trying to combine these examples myself. Is anyone able to provide some code or help me code the set up?

Thanks :slight_smile:

Alex

I plan to attach these with Sugru.

With what?

However, I have no knowledge on programming at all.

Are you interested in learning? If not, get your wallet out, and ask the moderators to move your post to Gigs and Collaboration.

If you are, look at the examples for reading switches. Learn about debouncing and about pullup and pulldown resistors, including the internal pullup resistors, since you do not have external resistors.

Learn about reading potentiometer data, since that is what a joystick really is.

The real challenge, though, is going to be figuring out how to send the data to the serial port that the game is listening to, in the format that it expects.

Thanks for response. Sugru is like a moudable rubber product that sets into any shape you want, google it, it’s impressive stuff.

Ok so I have attempted some code based on some examples found on the net, which utilise the pro micro board as a USB HID, specifically here: http://www.instructables.com/id/Add-a-little-two-analog-axis-thumb-joystick-to-you/

But am attempting to adapt it to utilise joystick instead of thumbstick - so as to use 4 axes, not 2 - and adding some momentary contact buttons. Here is the code for the INO file. Am not sure I have the buttons done correctly.

JoyState_t joySt;

const bool DEBUG = false;  // set to true to debug the raw values

int ButPin1 = 2;
int ButPin2 = 3;
int ButPin3 = 4;
int ButPin4 = 5;
int x1Pin = A0;
int y1Pin = A1;
int xPin = A2;
int yPin = A3;
int x1Zero, y1Zero;
int x1Value, y1Value;
int xZero, yZero;
int xValue, yValue;
int deadzone = 5;  // smaller values will be set to 0

void setup(){
  pinMode(x1Pin, INPUT);
  pinMode(y1Pin, INPUT);
  pinMode(xPin, INPUT);
  pinMode(yPin, INPUT);
  pinMode(ButPin1, INPUT);
  pinMode(ButPin2, INPUT);
  pinMode(ButPin3, INPUT);
  pinMode(ButPin4, INPUT);
  digitalWrite(ButPin1, HIGH);
  digitalWrite(ButPin2, HIGH);
  digitalWrite(ButPin3, HIGH);
  digitalWrite(ButPin4, HIGH);

  if(DEBUG) {
    Serial.begin(9600);
  }

  // calculate neutral position
  x1Zero = analogRead(x1Pin);
  y1Zero = analogRead(y1Pin);
  xZero = analogRead(xPin);
  yZero = analogRead(yPin);

  joySt.xAxis = 0;
  joySt.yAxis = 0;
  joySt.xRotAxis = 0;
  joySt.yRotAxis = 0;
}

void loop(){
  x1Value = analogRead(x1Pin) - x1Zero;
  y1Value = analogRead(y1Pin) - y1Zero;
  xValue = analogRead(xPin) - xZero;
  yValue = analogRead(yPin) - yZero;

  if(abs(x1Value) < deadzone) {
    x1Value = 0;
  }
  if(abs(y1Value) < deadzone) {
    y1Value = 0;
  }
  if(abs(xValue) < deadzone) {
    xValue = 0;
  }
  if(abs(yValue) < deadzone) {
    yValue = 0;
  }

  joySt.xAxis = map(xValue, 400, -400, -32768, 32768);  // here the axis is inverted
  joySt.yAxis = map(yValue, -400, 400, -32768, 32768);
  joySt.xRotAxis = map(yValue, -400, 400, -32768, 32768);
  joySt.yRotAxis = map(yValue, -400, 400, -32768, 32768);

  if(DEBUG) {
    Serial.print("X1: ");
    Serial.println(x1Value);
    Serial.print("Y1: ");
    Serial.println(y1Value);
    Serial.print("X: ");
    Serial.println(xValue);
    Serial.print("Y: ");
    Serial.println(yValue);
    Serial.print("Button1:  ");
    Serial.print(digitalRead(ButPin1));
    Serial.print("Button2:  ");
    Serial.print(digitalRead(ButPin2));
    Serial.print("Button3:  ");
    Serial.print(digitalRead(ButPin3));
    Serial.print("Button4:  ");
    Serial.print(digitalRead(ButPin4));
  }

  // Send to USB
  Joystick.setState(&joySt);
}

I haven’t hooked it up as of yet, just wanted to get some comment on my first attempt at coding :slight_smile:

EDIT: Formatting, to conform to Forum rules (thanks Tom!)

Thanks

Hi,
Welcome to the forum.

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Thanks.. Tom.. :slight_smile:

Thanks Tom, adjusted. Is this the right part of the forum to ask my query above?

Thanks.

Since "Joystate_t" is used but not declared I suspect you forgot to include a library.

Your indentation is a little ragged. Use "Tools->Auto Format" to clean up your formatting before posting to make the code easier to read.

The proof will be in the running. Until you hook things up and try to use the code it will be very hard to tell if it is going to work the way you expect. For example it is hard to say if the magic number '400' is right without testing.

Thanks John for the feedback. I have re-run the Auto-format and modified the post above, hopefully it's now better, was not sure why it was doing that. Yes you're right about hooking up and getting in there to see how it works, I guess I was after some sort of feedback on whether the code made sense and appeared correct prior to testing for real... I really do mean it when I say this is my first foray into coding so am just trying to learn whilst "reverse engineering" if that makes sense!

Having read some more on the coding, I suspect I have a rather simplified code. As PaulS suggests above, it appears I will need to implement debounce code and pull up resistor code (now that I understand what these mean).

I have now found a few additional tutorials which are of immense use, I am currently studying these and their code to better understand how to implement my project. An extremely relevant tutorial found here: http://www.instructables.com/id/Add-buttons-to-your-X52-Pro-Joystick-with-an-Ardui/

What I don't yet fully understand is why some people have more simplified code than others, for what is apparently the same task. I.e., some code I have studied does not have pull up resistor, or de-bouncing, nor Arrays for multiple pins.

Thanks.

You still don't have a declaration of the type "JoyState_t".

Ok, have done some further research and reading online. I have found and studied this relevant tutorial here:

Thanks to RussPitcher for posting that code.

I have spliced the relevant pieces of code that manage the buttons, with the code I had in my previous entry which controls the analogue axes. The new code from RussPitcher contains control for debouncing and pull up resistors.

I plan to wire this up for testing over the next few days.

#include <Bounce2.h>    // http://playground.arduino.cc/Code/Bounce

const bool DEBUG = false;  // set to true to debug the raw values
const int switchCount = 3;
byte buttonLastState[switchCount];
Bounce Bouncers[switchCount];
JoyState_t joySt;
boolean initial = true;
int x1Pin = A0;
int y1Pin = A1;
int xPin = A2;
int yPin = A3;
int x1Zero, y1Zero;
int x1Value, y1Value;
int xZero, yZero;
int xValue, yValue;
int deadzone = 5;  // smaller values will be set to 0


void setup() {
  pinMode(x1Pin, INPUT);
  pinMode(y1Pin, INPUT);
  pinMode(xPin, INPUT);
  pinMode(yPin, INPUT);

  if(DEBUG) {
    Serial.begin(9600);
  }

  // Joysticks - calculate neutral position
  x1Zero = analogRead(x1Pin);
  y1Zero = analogRead(y1Pin);
  xZero = analogRead(xPin);
  yZero = analogRead(yPin);

  joySt.xAxis = 0;
  joySt.yAxis = 0;
  joySt.xRotAxis = 0;
  joySt.yRotAxis = 0;

  //Buttons
  for (int i=0; i <= (switchCount -1); i++){
    // make the pushButton pin an input:
    pinMode(i, INPUT_PULLUP);
    // create a bouncer object and add it to the Bouncers array
    Bounce tempBouncer = Bounce();
    tempBouncer.attach(i);
    tempBouncer.interval(10);
    Bouncers[i] = tempBouncer;
    buttonLastState[i] = tempBouncer.read();
  }

  Serial.println("----  INITIAL SETUP ----");
  pinMode(3, OUTPUT);
  joySt.buttons = 0;
}

void loop() {

  x1Value = analogRead(x1Pin) - x1Zero;
  y1Value = analogRead(y1Pin) - y1Zero;
  xValue = analogRead(xPin) - xZero;
  yValue = analogRead(yPin) - yZero;

  if(abs(x1Value) < deadzone) {
    x1Value = 0;
  }
  if(abs(y1Value) < deadzone) {
    y1Value = 0;
  }
  if(abs(xValue) < deadzone) {
    xValue = 0;
  }
  if(abs(yValue) < deadzone) {
    yValue = 0;
  }

  joySt.xAxis = map(xValue, 400, -400, -32768, 32768);  // here the axis is inverted
  joySt.yAxis = map(yValue, -400, 400, -32768, 32768);
  joySt.xRotAxis = map(yValue, -400, 400, -32768, 32768);
  joySt.yRotAxis = map(yValue, -400, 400, -32768, 32768);



  // Now to read the button states
  for (int i=0; i <= (switchCount -1); i++){
    // read the pushbutton:
    Bouncers[i].update();
    int buttonState = Bouncers[i].read();
    if (i < 3) {
      // We're looking at the buttons
      if ((buttonState != buttonLastState[i]) && (buttonState == LOW)) {
        // if the button state has changed and it's currently pressed
        Serial.print("LOW button ");
        Serial.print(i);
        // Set the buttons 
        joySt.buttons = bitSet(joySt.buttons, i);
        Serial.print("== joySt.buttons = ");
        Serial.println(joySt.buttons);
      }
      if ((buttonState != buttonLastState[i]) && (buttonState == HIGH)) {
        // if the button state has changed and it's currently released
        Serial.print("HIGH button ");
        Serial.print(i);
        // Unset the buttons
        joySt.buttons = bitClear(joySt.buttons, i);
        Serial.print("== joySt.buttons = ");
        Serial.println(joySt.buttons);
      }
      // save the current button state for comparison next time:
      buttonLastState[i] = buttonState;
    } 


  }

  if(DEBUG) {
    Serial.print("X1: ");
    Serial.println(x1Value);
    Serial.print("Y1: ");
    Serial.println(y1Value);
    Serial.print("X: ");
    Serial.println(xValue);
    Serial.print("Y: ");
    Serial.println(yValue);
    
  }


  // Call Joystick.setState
  Joystick.setState(&joySt);


}

The sketch Verifies/Compiles successfully, however currently ‘Bounce’ does not name a type.

OK, have wired up, I get the below error when uploading the sketch to the Pro Micro. Am not sure what this means at all. Any advice much appreciated! :slight_smile:

In file included from GamePad_Sketch_AK.ino:1:
C:\Program Files (x86)\Arduino\hardware\arduino\cores\arduino/Bounce2.h: In constructor 'Bounce::Bounce(uint8_t, long unsigned int)':
C:\Program Files (x86)\Arduino\hardware\arduino\cores\arduino/Bounce2.h:76: error: type 'Bounce' is not a direct base of 'Bounce'

C:\Program Files (x86)\Arduino\hardware\arduino\cores\arduino/Bounce2.h: In constructor 'Bounce::Bounce(uint8_t, long unsigned int)':

The Bounce library is not a core library. Why on earth did you put the library there?

Hi PaulS, I put it there because I saw other libraries there, having originally tried locating it in the Arduino\Libraries folder, as per the Library author's instructions. However I received exactly the same error as posted below.

At the time I didn't realise the implication of putting it in Cores\Arduino.... stoopid mistake on my behalf. I don't yet know why this error is occurring but am endeavouring to find out.

Thanks.

I looked at the Bounce class. Really bizarre design, as far as I'm concerned. The constructor that takes arguments tries to invoke the version that doesn't. I would never have written code like that. I really don't know how anyone gets it to compile.