Friday, November 25, 2016

Arduino Joystick Library - Version 2.0

Introduction

Since I released the original Arduino Joystick Library (see http://mheironimus.blogspot.com/2015/11/arduino-joystick-library.html or http://www.instructables.com/id/Arduino-LeonardoMicro-as-Game-ControllerJoystick/ for more details) I have received numerous requests for enhancements. Most of these requests fall into the following two categories:

  • Increase the precision of the axes.
  • Make a version with only a specified set of features.
To accommodate these requests (and a few others) I have release Version 2.0 of the Arduino Joystick Library.

Out of the box the Arduino Leonardo and the Arduino Micro appear to the host computer as a generic keyboard and mouse. This article discusses how the Arduino Leonardo and the Arduino Micro can also appear as one or more generic Game Controllers or Joysticks. The Arduino Joystick Library Version 2.0 can be used with Arduino IDE 1.6.6 (or above) to add one or more joysticks (or gamepads) to the list of HID devices an Arduino Leonardo or Arduino Micro (or any Arduino clone that is based on the ATmega32u4) can support. This will not work with Arduino IDE 1.6.5 (or below) or with non-32u4 based Arduino devices (e.g. Arduino UNO, Arduino MEGA, etc.).

Features


The joystick or gamepad can have the following features:
  • Buttons (default: 32)
  • Up to 2 Hat Switches
  • X, Y, and/or Z Axis (up to 16-bit precision)
  • X, Y, and/or Z Axis Rotation (up to 16-bit precision)
  • Rudder (up to 16-bit precision)
  • Throttle (up to 16-bit precision)
  • Accelerator (up to 16-bit precision)
  • Brake (up to 16-bit precision)
  • Steering (up to 16-bit precision)
These features are configured using the Joystick_ class’s constructor.

Installation


The latest build of Version 2.0 of the Arduino Joystick Library can be downloaded from the following GitHub repository:
https://github.com/MHeironimus/ArduinoJoystickLibrary/tree/version-2.0

The library can also be downloaded directly using the following URL:
https://github.com/MHeironimus/ArduinoJoystickLibrary/archive/version-2.0.zip

Copy the Joystick folder to the Arduino Libraries folder (typically located at %userprofile%\Documents\Arduino\libraries on Microsoft Windows machines). On Microsoft Windows machines, only, this can be done by executing deploy.bat. The library should now appear in the Arduino IDE list of libraries.

Included Examples


The example Arduino sketch files listed below are included in this library. These will appear in the Arduino Example menu when the Arduino Joystick Library is installed.

Example Description
JoystickTest Simple test of the Joystick library. It exercises many of the Joystick library’s functions when pin A0 is grounded.
MultipleJoystickTest Creates 4 Joysticks using the library and exercises the first 16 buttons, the X axis, and the Y axis of each joystick when pin A0 is grounded.
JoystickButton Creates a Joystick and maps pin 9 to button 0 of the joystick, pin 10 to button 1, pin 11 to button 2, and pin 12 to button 3.
JoystickKeyboard Creates a Joystick and a Keyboard. Maps pin 9 to Joystick Button 0, pin 10 to Joystick Button 1, pin 11 to Keyboard key 1, and pin 12 to Keyboard key 2.
GamepadExample Creates a simple Gamepad with an Up, Down, Left, Right, and Fire button.
DrivingControllerTest Creates a Driving Controller and tests 4 buttons, the Steering, Brake, and Accelerator when pin A0 is grounded.
FlightControllerTest Creates a Flight Controller and tests 32 buttons, the X and Y axis, the Throttle, and the Rudder when pin A0 is grounded.
HatSwitchTest Creates a joystick with two hat switches. Grounding pins 4 - 11 cause the hat switches to change position.

Running the JoystickTest Example



The JoystickTest example sketch is included with the library. I recommend using this example to verify everything is working properly before beginning to write your own sketch files. Load, compile, and upload this example sketch file to an Arduino Leonardo or Micro using the Arduino IDE (version 1.6.6 or above).


Once you have uploaded the JoystickTest sketch file to the Arduino Leonardo or Micro, perform the following steps to verify everything is working properly. Note: the following steps are for Windows 10. If you have a different version of Windows or a different operating system, these steps may differ. Open the “Devices and Printers” window. This can be done by clicking the Start menu or pressing the Windows Key and typing “Devices and Printers”.

The Arduino Leonardo or Arduino Micro should appear in the list of devices.


Right mouse click on the Arduino Leonardo or Arduino Micro to display the settings menu.


Select “Game controller settings” to get to the “Game Controllers” dialog.



The Arduino Leonardo or Micro should appear in the list of installed game controllers. Select the Arduino Leonardo or Micro and click the Properties button to display the game controller test dialog.



While this dialog has focus, ground pin A0 on the Arduino to activate the test script. The test script will test the game controller functionality in the following order:
  • 32 buttons
  • throttle and rudder
  • X and Y Axis
  • Z Axis
  • 2 Hat Switches
  • X, Y, and Z Axis Rotation

Simple Gamepad Example


Once the Arduino Leonardo or Micro has been tested using the JoystickTest example, I suggest making a simple gamepad controller. This controller will have five buttons: up, down, left, right, and fire.

Connecting the Buttons


Connect one end of each button to the ground pin. Connect the other end of each button as indicated below:

Arduino Pin Description
2
Up
3
Right
4
Down
5
Left
6
Fire

Sketch File


Upload the GamepadExample example sketch file to the Arduino Leonardo or Micro. This example is included with the Arduino Joystick Library.


Test


Open the game controller properties or use the joystick testing application of your choice to test the behavior of your gamepad.



Joystick Library API


The complete documentation for the Arduino Joystick Library can be found at https://github.com/MHeironimus/ArduinoJoystickLibrary/tree/version-2.0.



66 comments:

Matti Virta said...

you have good site how to do it

32 buttons
throttle and rudder
X and Y Axis
Z Axis
2 Hat Switches
X, Y, and Z Axis Rotation
BUT how i add arduino micro trimm wheel too rudder and pitch ?
i no need all button but need all micro analog input use to my game controller.
add example tutorial how made , X,Y,trottle,propell,mix,rudder,2x trimm wheel,1x hat switch,and all other potentiometers/slider what want add too.
buttons i not need, i no understand how i add all analog input can use to game controller. micro have 12 analog.but if 8-9 input can then i can made my cessna simulator cocpit ready. send help to me mail, please.

Ken Bou said...

how Can i use 8axis ?
i can use only 7axis now, just like this.
https://3.bp.blogspot.com/-OvR4Bjnt9WY/WDiqBoSzz1I/AAAAAAAABsQ/SHZiHbWQnewi0o2H6BZsOA8DRLpVhc63wCLcB/s320/Arduino%2BJoystick%2BProperties.png


Matthew Heironimus said...

@Ken Bou - The Windows Game Controller Test dialog only shows 7 axis, but there can be more than that (for games and applications that support it). You will need to use a third-party joystick test application to see over 7 axis. One I have used in the past can be found at http://www.planetpointy.co.uk/joystick-test-application/.

Matthew Heironimus said...

@Matti Virta

Here is a simple sketch file that reads an analog input from a potentiometor that is wired to pin A0:

#include <DynamicHID.h>
#include <Joystick.h>

/*
  AnalogReadSerial
  Reads an analog input on pin 0, prints the result to the serial monitor.
  Graphical representation is available using serial plotter (Tools > Serial Plotter menu)
  Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

  This example code is in the public domain.
*/

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_JOYSTICK, 4, 0,
  false, false, false, false, false, false,
  false, false, false, false, true);

// the setup routine runs once when you press reset:
void setup() {
  
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB
  }

  Joystick.setSteeringRange(0, 800);
  Joystick.begin();

  // Init Pins
  pinMode(A0, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);

  Joystick.setSteering(sensorValue);
  
  // print out the value you read:
  Serial.println(sensorValue);
  delay(200);        // delay in between reads for stability
}

Not sure if that will help you or not, but it shows how to read a value from A0 and send it to the Joystick library.

Matti Virta said...

thanks, what mean all many false,false,true, were mean this do ?
i must test you code how work after i can orden new micro, old has bro0ken now i try burn mmjoy hex file and now all micro no working and not found any port. and software

Matthew Heironimus said...

@Matti Virta - The mean of the Constructor arguments is documented at https://github.com/MHeironimus/ArduinoJoystickLibrary/tree/version-2.0#joystick_

Unknown said...


Good morning
it is possible to have a code example on how to operate the analog sticks?
Thanks in advance

Kuba Tatara said...

Hey. J have this code
------------------------------------------------------------------------------------------
//#include DynamicHID.h
#include Joystick.h

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_JOYSTICK, 4, 0,
false, false, false, false, false, false,
false, false, false, true, true);

// the setup routine runs once when you press reset:
void setup() {

// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB
}

Joystick.setBrakeRange(0, 1023);
Joystick.begin();

// Init Pins
pinMode(A0, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {

// read the input on analog pin 0:
int sensorValue = analogRead(A0);
Joystick.setBrake(sensorValue);

// print out the value you read:
Serial.println(sensorValue);
//delay(200); // delay in between reads for stability
}
----------------------------------------------------------------------------------------
DynamicHID.h - what for is this ?
I use Brake analog and in serial monitor is working fine, i got range 0-1023. But in joystick properties in windows i get only value min and max, no range. Any ideas why??

Ben P said...

Matt, sorry to comment on an older post, but I've been at this a few days and am stuck. My first problem was I was using version 1 of your sketch, but that's fixed now. :)

Pretty much what I want to do is disable all the axis and hat so I can have 20 buttons. I can petty much do that, except whenever I press any button the "16" button presses and remains pressed. Also, the X, Y and Throttle move from 100% to 0 and the x/y axis moves back to 0 from center. I can turn all these off in joystick.h as you described with the true/false statements, only I still have the button 16 problem. It looks like my buttons are showing up as 1-15 and then 19-20.

I don't recall having this issue in version 1 but, I couldn't get the axis and hat to disable.

Can you get me pointed into the right direction? Thanks! (Leonardo R3, if it matters)

Ben P said...

Ok, I had to get creative. I figured it out though. I used the Gamepad Example and did this:

// Simple gamepad example that demonstraits how to read five Arduino
// digital pins and map them to the Arduino Joystick library.
//
// The digital pins 2 - 6 are grounded when they are pressed.
// Pin 2 = UP
// Pin 3 = RIGHT
// Pin 4 = DOWN
// Pin 5 = LEFT
// Pin 6 = FIRE
//
// NOTE: This sketch file is for use with Arduino Leonardo and
// Arduino Micro only.
//
// by Matthew Heironimus
// 2016-11-24
//--------------------------------------------------------------------

#include

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_GAMEPAD,
24, 0, // Button Count, Hat Switch Count
false, false, false, // X and Y, but no Z Axis
false, false, false, // No Rx, Ry, or Rz
false, false, // No rudder or throttle
false, false, false); // No accelerator, brake, or steering

void setup() {
// Initialize Button Pins
pinMode(1, INPUT_PULLUP);
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);
pinMode(11, INPUT_PULLUP);
pinMode(12, INPUT_PULLUP);
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
pinMode(15, INPUT_PULLUP);
pinMode(16, INPUT_PULLUP);
pinMode(17, INPUT_PULLUP);
pinMode(A0, INPUT_PULLUP);
pinMode(A1, INPUT_PULLUP);
pinMode(A2, INPUT_PULLUP);
pinMode(A3, INPUT_PULLUP);
pinMode(A4, INPUT_PULLUP);
pinMode(A5, INPUT_PULLUP);

// Initialize Joystick Library
Joystick.begin();
//Joystick.setXAxisRange(-1, 1);
//Joystick.setYAxisRange(-1, 1);
}

// I added this
const int pinToButtonMap = 0;

// Last state of the button
int lastButtonState[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0};

void loop() {

// Read pin values
//for (int index = 0; index < 24; index++)
//{
// int currentButtonState = !digitalRead(index + 2);
// if (currentButtonState != lastButtonState[index])
//{
// switch (index) {
// case 0: // UP
// if (currentButtonState == 1) {
// Joystick.setYAxis(-1);
// } else {
// Joystick.setYAxis(0);
// }
// break;
// case 1: // RIGHT
// if (currentButtonState == 1) {
// Joystick.setXAxis(1);
// } else {
// Joystick.setXAxis(0);
// }
// break;
// case 2: // DOWN
// if (currentButtonState == 1) {
// Joystick.setYAxis(1);
// } else {
// Joystick.setYAxis(0);
// }
// break;
// case 3: // LEFT
// if (currentButtonState == 1) {
// Joystick.setXAxis(-1);
// } else {
// Joystick.setXAxis(0);
// }
// break;
// case 4: // FIRE
// Joystick.setButton(0, currentButtonState);
// break;
// }
// lastButtonState[index] = currentButtonState;
// }
// }
for (int index = 0; index < 24; index++)
{
int currentButtonState = !digitalRead(index + pinToButtonMap);
if (currentButtonState != lastButtonState[index])
{
Joystick.setButton(index, currentButtonState);
lastButtonState[index] = currentButtonState;
}
}
delay(50);
}

Matthew Heironimus said...

@Ben P - Glad you were able to get something working. Sorry for the delay in getting to your comment. I have been falling behind in answering requests.

DeAnander said...

Hi Matthew and many thanks for the Joystick Library v2.0

Rather than waffle on at length here, I will post a link to my unanswered question on Arduino forum

http://forum.arduino.cc/index.php?topic=468358.0

I have almost -- but not quite -- got the hang of HID joystick emulation :-) I can make my Arduino actuate a selected axis, no problem; but I have not figured out how to expose all the axes to the application level, or how to make them map to the axes that any given game is expecting to find when the user configures input devices. I think I'm just one key concept away from enlightenment here... can you point me at an article or document that will make that last connection for me?

Matthew Heironimus said...

@Kuba Tatara - I uploaded your sketch file to my Leonardo and it worked fine for me. As I adjusted my variable resister, both the value on the serial monitor and the value of the brake on the Window's game controller test dialog seemed to match. One thing to note: it has been my observation that the Window's game controller test dialog must have focus or it will not update. The Serial Monitor can be running in the background, however.

Matthew Heironimus said...

@Kuba Tatara - You can ignore the DynamicHID.h. It is used internally, but does not have to be included in your sketch file. It was being incorrectly included in early versions of 2.0.x, but the current version 2.0.3 this issue has been corrected.

Yves Maurischat said...

Hi Matthew, I'm in the process of building my own little Raspberry Pi based retro gaming console and your library will be of great help. Awesome work!
I've got one question though: The standard joystick constructor has 32 buttons. How would I get 32 buttons from the pins of an Arduino (Micro) (or a Pro Micro)? The only way I can think of would be to map multi-button-pushes/pin activations to single (API-level) buttons. Or am I missing something?
Also, let's assume I would like to switch between Joystick and Mouse input using the same controller (and thus the same buttons and joysticks/d-pads). Would it suffice to just send different commands/call the right functions (like Mouse.move(...), Mouse.press(...)) instead of the Joystick commands? Or is there something that has to be done with the HIDs?

Yves Maurischat said...

Ps.: I also noticed that Joystick.end() is empty and does nothing. Is this by design? If so, would there be any reason to call it?

Matthew Heironimus said...

@Yves Maurischat

> How would I get 32 buttons from the pins of an Arduino (Micro) (or a Pro Micro)?
There are various techniques one can use to do this. I have listed a few for your reference:
- https://www.instructables.com/id/How-to-Multiple-Buttons-on-1-Analog-Pin-Arduino-Tu/
- http://www.instructables.com/id/How-to-access-5-buttons-through-1-Arduino-input/
- https://www.arduino.cc/en/Tutorial/ShiftIn


> Would it suffice to just send different commands/call the right functions (like Mouse.move(...), Mouse.press(...)) instead of the Joystick commands?
Yes

> Or is there something that has to be done with the HIDs?
No. The Arduino Micro can appear as multiple USB devices at the same time (e.g. Keyboard, Mouse, and Joysticks)

Matthew Heironimus said...

@Yves Maurischat

> I also noticed that Joystick.end() is empty and does nothing. Is this by design? If so, would there be any reason to call it?
You do not need to call it. It was just added so the interface of the Joystick would be similar to the Mouse and Keyboard.

Yves Maurischat said...

Thank you! That helped a lot! :)

Shawn Roelofsen said...

Thank you for the sample code it was very helpful! how could I go about mapping the value from the potentiometer to the X axis to make a game character turn left or right?

Bryan Davidson said...

All of this is daunting to me Matthew. My goal is to use this in my button box creation. Is it possible to have 28 - 30 button presses and 2 analogue stick using an arduino pro micro? And how do I best go about learning what I need to accomplish?

Matthew Heironimus said...

@Bryan Davidson - In order to get that many buttons on a Arduino Pro Micro, you will need to use some extra circuitry. There are various techniques you can use to read more that one button with a single Arduino pin. The following are a few techniques one can use to do this:
- https://www.instructables.com/id/How-to-Multiple-Buttons-on-1-Analog-Pin-Arduino-Tu/
- http://www.instructables.com/id/How-to-access-5-buttons-through-1-Arduino-input/
- https://www.arduino.cc/en/Tutorial/ShiftIn

Matthew Heironimus said...

@Shawn Roelofsen - To map a potentiometer value to the X or Y axis all you need to do is read in the value and call the appropriate Joystick function (e.g. Joystick.setXAxis or Joystick.setYAxis). The following is a sketch that shows how to read A0 and set the steering. This could be modified to set X instead.

#include <Joystick.h>

/*
AnalogReadSerial
Reads an analog input on pin 0, prints the result to the serial monitor.
Graphical representation is available using serial plotter (Tools > Serial Plotter menu)
Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

This example code is in the public domain.
*/

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_JOYSTICK, 4, 0,
false, false, false, false, false, false,
false, false, false, false, true);

// the setup routine runs once when you press reset:
void setup() {

// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB
}

Joystick.setSteeringRange(1000, 50);
Joystick.begin();

// Init Pins
pinMode(A0, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {

// read the input on analog pin 0:
int sensorValue = analogRead(A0);

Joystick.setSteering(sensorValue);

// print out the value you read:
Serial.println(sensorValue);
delay(200); // delay in between reads for stability
}

Eli Cherem said...

will this code press a the joystick button when i press a button connected to pin 13?

am i missing something here?



//Testing the joystick button connected to pin 13
#include

//buttons
const int ALT_UP = 13;

int ALT_Upstate = 0;

void setup() {

Serial.begin(57600);
pinMode(ALT_UP , INPUT_PULLUP);
Joystick.begin();

}

void loop() {


// checks if a button is being pressed
ALT_Upstate = digitalRead(ALT_UP);

if ( ALT_Upstate == LOW) {

Joystick.pressButton(ALT_UP);
delay(10);
Joystick.releaseButton(ALT_UP);
delay(120);
}
}

Matthew Heironimus said...

@Eli Cherem - It looks like your code will press button 14 (or thirteen if you consider the first button #0) for 10 milliseconds and then release it. I suspect you will not be able to see a button press that is that short. I recommend you look at the example at https://github.com/MHeironimus/ArduinoJoystickLibrary#simple-example. This is a simple push button example.

Marc said...

Hi Matthew.

How would I go about changing the device name from "Arduino Leonardo" to one of my own choosing?

Matthew Heironimus said...

@Marc - There is a long discussion about this at https://github.com/MHeironimus/ArduinoJoystickLibrary/issues/14. This is not currently supported, but can be done by following some of the instructions provided in the discussion.

Marc said...

@Matthew Thanks for the link. I know you can change the name in the USB core source files, I was able to do it with STM32 boards, and using the STM32Cube profiler its a simple config change for the board your programming, but Arduino is not so straight forward it would seem.

Ashley Webb said...

Hi Matthew!

Which pins do we use on the Arduino for the x and y data from the potentiometers? I'm not seeing it in the code but I'm probably overlooking something...

Matthew Heironimus said...

@Ashley Webb

You can use any of the analog pins you like (A0 - A5). You read the analog value from the pin and then call the appropriate set?Axis function (i.e. setXAxis, setYAxis, or setZAxis).

Dennie Theissen said...

Dear Matthew,

I really Need help now. I use the following sketch to use digital and analog pins as Joystick Buttons. It works very well and I can use 20 pins. But now I Need the analog pins for potentionmeters as I will use it as throttle. I Need 3 Rotation axis. How to modify this sketch to have 17 Buttons and 3 rotation axis?
Highly appreciate any help!

// Simple gamepad example that demonstraits how to read five Arduino
// digital pins and map them to the Arduino Joystick library.
//
// The digital pins 2 - 6 are grounded when they are pressed.
// Pin 2 = UP
// Pin 3 = RIGHT
// Pin 4 = DOWN
// Pin 5 = LEFT
// Pin 6 = FIRE
//
// NOTE: This sketch file is for use with Arduino Leonardo and
// Arduino Micro only.
//
// by Matthew Heironimus
// 2016-11-24
//--------------------------------------------------------------------

#include

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_GAMEPAD,
24, 0, // Button Count, Hat Switch Count
false, false, false, // X and Y, but no Z Axis
false, false, false, // No Rx, Ry, or Rz
false, false, // No rudder or throttle
false, false, false); // No accelerator, brake, or steering

void setup() {
// Initialize Button Pins
pinMode(1, INPUT_PULLUP);
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);
pinMode(11, INPUT_PULLUP);
pinMode(12, INPUT_PULLUP);
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
pinMode(15, INPUT_PULLUP);
pinMode(16, INPUT_PULLUP);
pinMode(17, INPUT_PULLUP);
pinMode(A0, INPUT_PULLUP);
pinMode(A1, INPUT_PULLUP);
pinMode(A2, INPUT_PULLUP);
pinMode(A3, INPUT_PULLUP);
pinMode(A4, INPUT_PULLUP);
pinMode(A5, INPUT_PULLUP);

// Initialize Joystick Library
Joystick.begin();
//Joystick.setXAxisRange(-1, 1);
//Joystick.setYAxisRange(-1, 1);
}

// I added this
const int pinToButtonMap = 0;

// Last state of the button
int lastButtonState[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0};

void loop() {

// Read pin values
//for (int index = 0; index < 24; index++)
//{
// int currentButtonState = !digitalRead(index + 2);
// if (currentButtonState != lastButtonState[index])
//{
// switch (index) {
// case 0: // UP
// if (currentButtonState == 1) {
// Joystick.setYAxis(-1);
// } else {
// Joystick.setYAxis(0);
// }
// break;
// case 1: // RIGHT
// if (currentButtonState == 1) {
// Joystick.setXAxis(1);
// } else {
// Joystick.setXAxis(0);
// }
// break;
// case 2: // DOWN
// if (currentButtonState == 1) {
// Joystick.setYAxis(1);
// } else {
// Joystick.setYAxis(0);
// }
// break;
// case 3: // LEFT
// if (currentButtonState == 1) {
// Joystick.setXAxis(-1);
// } else {
// Joystick.setXAxis(0);
// }
// break;
// case 4: // FIRE
// Joystick.setButton(0, currentButtonState);
// break;
// }
// lastButtonState[index] = currentButtonState;
// }
// }
for (int index = 0; index < 24; index++)
{
int currentButtonState = !digitalRead(index + pinToButtonMap);
if (currentButtonState != lastButtonState[index])
{
Joystick.setButton(index, currentButtonState);
lastButtonState[index] = currentButtonState;
}
}
delay(50);
}

Greetings Danny

Dennie Theissen said...

Please help...

Matthew Heironimus said...

@Dennie Theissen - What you need to do is as follows:

Reconfigure three of the analog pins to be INPUT, rather than INPUT_PULLUP.

Wire each of your potentionmeters to these analog pins.

In the loop function, remove the existing UP, DOWN, LEFT, RIGHT logic.

In your loop function, read the value of each pin (using the analogRead function) and send it to the Joystick.setXAxis (or Y or Z) functions.

Hope this helps.

Unknown said...
This comment has been removed by the author.
Unknown said...

Hi Matthew.

I have been pondering a lot lately.
I am trying to get a cd4021 shiftregister to work with the jostick.h.
Is there an example somewhere to be downloaded ?

Somehow i can not get it to work, have been reading the above links.
So an example would be very helpful.
Thanks

Unknown said...
This comment has been removed by the author.
Martijn Hoving said...

Hi Matthew
Is there an example code somewhere with the shiftin register code (cd4021) somewhere to be found.
Been reading a lot of links but couldn't find a link with the shiftin and jostick.h merged.
thanks in advance

Patrick McEnaney said...

Hi Matthew,

I'd like to start by saying I think it's great you're still supporting this library so well, and helping users get it working for them. I've got a fair bit of experience in C# and VB.net, but this is my first foray into Arduino, so forgive the rookie mistakes...

I'm trying to get a simple 2-Axis, 2-Button joystick working using your library, but can't seem to figure out exactly where my issue is. I've got it showing up correctly in my devices, and get no errors compiling/uploading to my board, but none of the inputs seem to be doing anything. I'm using an off-brand Arduino Micro, and it shows up in devices as "Arduino Leonardo".

Here's the sketch I'm trying to get working:

// Pin A2 = X Axis
// Pin A3 = Y Axis
// Pin 10 = Button 1
// Pin 16 = Button 2
//
//--------------------------------------------------------------

#include "Joystick.h"

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_JOYSTICK, 2, 0, true, true, false, false, false, false, false, false, false, false, false);

void setup() {

Serial.begin(9600);
while (!Serial) {
;
}

pinMode(A2, INPUT);
pinMode(A3, INPUT);
pinMode(10, INPUT_PULLUP);
pinMode(16, INPUT_PULLUP);

Joystick.begin();
Joystick.setXAxisRange(-512, 512);
Joystick.setYAxisRange(-512, 512);
}

void loop() {

// X-Axis
int xAxis = analogRead(A2);
Joystick.setXAxis(xAxis);
Serial.println(xAxis);

// Y-Axis
int yAxis = analogRead(A3);
Joystick.setYAxis(yAxis);
Serial.println(yAxis);

// Button 1
int button1State = !digitalRead(10);
if (button1State = 1)
{
Joystick.pressButton(0);
}

// Button 2
int button2State = !digitalRead(16);
if (button2State = 1)
{
Joystick.pressButton(1);
}
}


Thanks in advance,

Patrick

Patrick McEnaney said...

A found one of those rookie mistakes I mentioned... I didn't check the serial monitor...

So it seems My joystick is outputting X and Y axis as intended to the serial monitor, but what do I need to change so that I can see my actions on the Windows game controller settings panel?

Matthew Heironimus said...

@Patrick McEnaney

One thing I have noticed is you set the X and Y axis range to go from -512 to 512, but Arduino analog pins go from 0 to 1023 by default. This happens to be the default for the Joystick library, so you should be able to remove those lines.

Another thing to watch for is you need to have a delay in your loop or you can "overload" things. Adding a delay(50); might be a good idea.

Note: The Windows Game Controller Settings panel will only update if it has focus.

Have you tried using any of the example projects that come with the library?

Patrick McEnaney said...

Thanks for the reply.

I'll remove the axis range, since I guess it isn't needed, but being new to this, where exactly should I add the delay in my code?

And yes, I've fooled around with the example files, and had them working just fine in the Game Controller Dialog (except for some reason the button set to PIN 10 isn't working, and I'm not sure why; I've tried with two different joysticks, so my next step is to try a different pin, in case PIN 10 might by faulty on my board), but couldn't figure out how to adapt them to my use-case, so I figured starting from scratch was my best bet. I'm not sure what I'm missing that's causing my sketch to not work in the dialog though...

Patrick McEnaney said...

Adding a delay seems to have fixed my joystick axis (although I still don't exactly understand why, lol). But now my issue is that both of my buttons are stuck in the "ON" state, and pressing them doesn't do anything. I tried switching `if (button1State = 1)` to "0", but that just makes them stuck in the "OFF" state. Where am I going wrong with this part?

Also, I added a delay on the buttons too, is this necessary?

Thanks

Dennie Theissen said...

Dear Patrick,

Use the following Sketch.
Then you have 6 axis and 14 buttons

#include "Joystick.h"

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_GAMEPAD,
14, 0, // Button Count, Hat Switch Count
false, false, true, // X and Y, but no Z Axis
true, true, true, // Rx, Ry, or Rz
false, true, // rudder or throttle
true, false, false); // accelerator, brake, or steering

// declare variables
int axe1Value;
int axe2Value;
int axe3Value;
int axe4Value;
int axe5Value;
int axe6Value;


// init joystick libary
void setup() {
// Initialize Button Pins
pinMode(0, INPUT_PULLUP);
pinMode(1, INPUT_PULLUP);
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);
pinMode(11, INPUT_PULLUP);
pinMode(12, INPUT_PULLUP);
pinMode(13, INPUT_PULLUP);
pinMode(A0, INPUT_PULLUP);
pinMode(A1, INPUT_PULLUP);
pinMode(A2, INPUT_PULLUP);
pinMode(A3, INPUT_PULLUP);
pinMode(A4, INPUT_PULLUP);
pinMode(A5, INPUT_PULLUP);

// Initialize Joystick Library
Joystick.begin();
}

// Constant that maps the phyical pin to the joystick button.
const int pinToButtonMap = 0;

// Last state of the button
int lastButtonState[14] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0};

void loop() {
// Axe 1
axe1Value = analogRead(A0);
Joystick.setThrottle(axe1Value);
delay(1);

// Axe 2
axe2Value = analogRead(A1);
Joystick.setZAxis(axe2Value);
delay(1);

// Axe 3
axe3Value = analogRead(A2);
Joystick.setRxAxis(axe3Value);
delay(1);

// Axe 4
axe4Value = analogRead(A3);
Joystick.setRyAxis(axe4Value);
delay(1);

// Axe 5
axe5Value = analogRead(A4);
Joystick.setRzAxis(axe5Value);
delay(1);

// Axe 6
axe6Value = analogRead(A5);
Joystick.setAccelerator(axe6Value);
delay(1);


// Read pin values
for (int index = 0; index < 14; index++)
{
int currentButtonState = !digitalRead(index + pinToButtonMap);
if (currentButtonState != lastButtonState[index])
{
Joystick.setButton(index, currentButtonState);
lastButtonState[index] = currentButtonState;
}
}

delay(50);
}

Patrick McEnaney said...

Turns out something was wrong with the serial communication I had set up. I removed it, and now everything is working fine (except for one button, but I think it may be a faulty pin).

Here is what I ended up with incase it helps someone else in the future:

// Pin A2 = X Axis
// Pin A3 = Y Axis
// Pin 16 = Button 1
// Pin 10 = Button 2
//
//--------------------------------------------------------------

#include "Joystick.h"

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_JOYSTICK, 2, 0, true, true, false, false, false, false, false, false, false, false, false);

void setup() {

pinMode(A2, INPUT);
pinMode(A3, INPUT);
pinMode(16, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);

Joystick.begin();
}

void loop() {

// X-Axis
int xAxis = analogRead(A2);
Joystick.setXAxis(xAxis);

// Y-Axis
int yAxis = analogRead(A3);
Joystick.setYAxis(yAxis);

// Button 1
int button1State = !digitalRead(16);
if (button1State == 1)
{
Joystick.pressButton(0);
}
else
{
Joystick.releaseButton(0);
}

// Button 2
int button2State = !digitalRead(10);
if (button2State == 1)
{
Joystick.pressButton(1);
}
else
{
Joystick.releaseButton(1);
}

delay(50);
}

Thanks for the help!

Matthew Heironimus said...

@Patrick McEnaney - Glad to hear you got it working.

Patrick McEnaney said...

Hi Matthew, I've got my simple joystick working but now I'm having issues with my 2nd project with your library. I'm using the same code that I got working with my joystick, but modified it to have a total of 8 buttons and 2 axis for a custom gamepad I've made. Everything worked exactly as planned at first, but the 2nd time I plugged it in I'm getting random twitchy movements on the thumbstick (which seems to favor the bottom-right corner) and most of the time "button 8" is stuck in the "ON" position, with 3 other buttons behaving erratically. "Button 8" is also stuck "ON" if I power up the board without even connecting my buttons to it.

I know my code is fine, because it worked exactly as intended at first, but all of a sudden it's behaving very erratically.

If I plug my joystick into the board, and reupload my original code for the joystick it works fine. It just seems to behave this way when I switch to my 8-button/2-axis sketch.

Any ideas? I've triple-checked my code, and there shouldn't be any issues there (as I said, it was working at first and I've made no changes to the code since).

Thanks,

Patrick

Matthew Heironimus said...

@Patrick McEnaney - I would go ahead and submit an issue on the GitHub site (https://github.com/MHeironimus/ArduinoJoystickLibrary). Someone in the community may have an idea what is going on.

These kinds of issues do sometimes turn out to be code related, so I would be sure to include a copy of your sketch file in your issue submission.

Patrick McEnaney said...
This comment has been removed by the author.
Patrick McEnaney said...
This comment has been removed by the author.
Patrick McEnaney said...

Yet another question Matthew...

I didn't see it listed anywhere on GitHub, but I'd like to add a deadzone to my joystick (same sketch as listed above), but I'm not sure if it's possible with your library or not.

My theory was that if I set 'autosendstate' to 'false' and wrote an 'if' statement that would poll my joystick to see if either axis was outside of my desired deadzone and 'then' either 'Joystick.begin()' or 'Joystick.sendState()' else 'break' or something similar.

Am I on the right track?

Thanks.

Umberto said...

Dennie Theissen, I'm interested in your code, but how do you use pins 0 and 1, does not it conflict with serial communication? How did you solve it?

Mik said...

I don't know if this is related to your work, but I've come across some Arduino-based joysticks/adapters where in DirectInput the reported X axis range is 0-0 for buttons (instead of, say, 0-65535). That is not considered a valid range by some apps.

I am trying to establish whether there is an issue in interpretation, in hardware or in drivers. Any thoughts?

Unknown said...

Hi Matthew
I am looking to create my own rudder pedal set and your code looks ideal (I'm definitely not a programmer, simply a user/adaptor). I have loaded your code and tried to compile the test programmes but get an error that the #include cannot be found. I note that the dynamicHID.h is not included in the joystick sketch code but is referenced in the Joystick.h file. I also note that the dynamicHID.h file is included as part of the download from GitHub. I've tried relocating the dynamicHID.h file into different folders to see if the compiler picks it up without success.
Any guidance would be appreciated.
Martin

Matthew Heironimus said...

Martin,

The error you describe usually is a result of the library not being installed correctly. When you open the Arduino IDE, click on File -> Examples and scroll to the bottom of the list. You should see an entry in the "Examples from custom libraries" section called Joystick. Another thing to check is the "Library Manager" (Sketch -> Include Library -> Manage Libraries...). If the library is installed correctly, you should see an entry called Joystick by Matthew Heironimus Version 2.0.5 INSTALLED. If either of these things are not present, the library was not installed correctly. Installation instructions can be found at https://github.com/MHeironimus/ArduinoJoystickLibrary/#installation-instructions.

Hope this helps,
Matt

Unknown said...

Hi again Matthew
I'm not a blogger so please forgive my poor protocol and appearing as unknown.
My first comment this morning referred to the compiler not being able to find the dynamicHID.h file - the posted message seems to have been corrupted during the upload.
I have a second question - could you please confirm that your code support 12-bit resolution (i.e. two 8-bit bytes to send a signed integer) for joystick/analogue inputs?
Many thanks
Martin

Unknown said...

Hi Matt
Re-installation - all now good - I'd made a numpty error. Sorry to have wasted your time a school boy mistake.
Many thanks
Martin

Matthew Heironimus said...

Martin,

DynamicHID.h is included in the Joystick\src\DynamicHID folder and should have been installed when the deploy.bat (or deploy.sh if you are on Linux) was executed.

The library supports up to 16 bits of precision. That being said, the analog pins on most Arduino boards (at least the ones I have worked with) are only 10-bits in resolution. That is why the library defaults axis from 0 to 1024. If you are using some other mechanism to read in analog values, then you can get up to 16-bits (or -32,768 to 32,767).

Matt

Unknown said...

Matthew,
Many thanks for your timely responses.
Best regards,
Martin

Unknown said...

Matthew
Re precision/resolution of analogue inputs.
The API documentation refers to, typically, .setXAxis(byte value) and a range of -127 to +127. This implies 8-bit (i.e. one byte) resolution over the USB interface. How does the code handle 10-bit (-512 to +512) or higher resolution (implying two 8-bit bytes to hold the digital representation of the analogue value)?
I suspect I'm missing something obvious but can't see any references anywhere else to greater than 8-bit resolution.
Kind Regards,
Martin

Matthew Heironimus said...

Martin,

You may be refering to older documentation (i.e. version 1.0). The current version shows Joystick.setXAxis(int16_t value) having a 16-bit value. See https://github.com/MHeironimus/ArduinoJoystickLibrary#joysticksetxaxisint16_t-value for more details.

Matt

Unknown said...

Hi Matthew,

That will be the reason! I'm not sure how I managed to get an older version, but many thanks for persevering with me.

Kind regards,
Martin

Unknown said...

Hi Matthew,

The ‘bad penny’ has turned up again.
With your previous help I have a sketch that compiles and loads successfully to my Arduino Micro.

However, it does not appear as a HID. I have tried a couple of the test examples from the joystick library (without inserting any changes!), but the result is always the same.

In Device Manager I can see the Micro as a USB device (on Com 8) and I can see that there are 2 entries in the Device Manager/HID list that relate to the Micro - one as a "HID-compliant device" and one as a "USB Input Device" (the HID entries are not explicitly identified as the Micro but by inserting/removing the Micro and recording differences in the Device Manager's HID list I have been able to isolate which entries appear/disappear when the Micro is connected/not connected). If I double click either of these [HID list] entries the HID-compliant device properties dialogue opens where everything looks OK, except on the Events tab where there are 3 Events listed, all with the same timestamp. The descriptions of these events are:
"Device not migrated"
"Device configured (input inf)"
"Device started (HIBUsb)"

The information text box (on the HID-compliant device properties dialogue) for the "Device not migrated" event reads:
"Device USB\VID_2341&PID_8037&MI_02\6&1163e5c6&0&0002 was not migrated due to partial or ambiguous match.
Last Device Instance Id: USB\VID_04D9&PID_1603&MI_01\6&34E0FEB6&0&0001
Class Guid: {745A17A0-74D3-11D0-B6FE-00A0C90F57DA}
Location Path:
Migration Rank: 0xF000FFFF0000F120
Present: false
Status: 0xC0000719"

I have Googled (a lot today) finding many references/’resolutions’ to "Device not migrated" issues and problems associated with corrupt/’bad’ drivers. I have tried several of the recovery methods (such as deleting/re-installing new/updated drivers) but, despite all efforts, I remain in a "Device not migrated" situation. (The issue only affects the HID configuration as the serial comms still works because I can update the sketch on the Micro.)

I'm using Windows 10 (ver 1803, OS build 17134.407) and Arduino IDE v 1.8.5.

I appreciate with is not directly involved with the Joystick library but any thoughts/advice would be appreciated (hopefully it's just another simple issue).

Kind regards,
Martin

Unknown said...

Hi Matthew,
Further investigation indicates my previous missive may be a red herring (after great effort to eliminate fish)! "Events" in device/properties are entered as last at the bottom (not at the top as I thought previously), which puts a different spin on things. It seems the drivers are correctly installed and running. However this still leaves the basic problem of the Micro not being seen as a joystick/game controller (as well as a serial device).
I have now tried the Micro on 2 other Windows 10 machines and get exactly the same results - it appears in Device Manager in the following areas:
HID list as a HID-compliant device and USB Input Device;
Ports (COM & LPT) list as Arduino Micro (COMx); and
USB Controllers list as USB Composite Device.

(I've assumed the Micro can operate simultaneously as a serial device and a joystick.... or does it have to be somehow 'switched' between functions?).

Any thoughts/guidance would be appreciated.

Kind Regards,
Martin

Matthew Heironimus said...

Martin,

The Micro can appear as a Joystick, Mouse, and Keyboard all at once if the correct header files (e.g. Mouse.h, Keyboard.h, and Joystick.h) are included in the sketch file. The JoystickKeyboard example that is include with the library demonstrates this ability. It will always appear as a serial port as well.

I will have to investigate your issue further to provide any more information.

Matt

Unknown said...

Hi Matt,

Thanks for your reply.

I have good news - I have tried several other things today without success then, in desperation, I removed and reloaded IDE (now ver 1.8.7). After this I loaded the flightcontroller example (twice) without any change in outcomes. I then loaded the JoystickTest example which worked instantly. I then retried flightcontroller example, my developmental version of flightcontroller and joystick where all worked instantly. I have removed and re-inserted the micro several times with one or other of the 3 sketches loaded and it seems rock solid.

I have noted that sometimes the Micro comes up on COM4 and other times on COM6 (seems to be a random selection at this point of investigation). I also note that in the programme load progress/report window at the bottom of the IDE window it always seems to refer to "Using COM port 5". I'm not sure if this apparent discrepancy is a predictable situation or error.

Anyway - for now at least, the Micro is doing what I want (albeit I haven't contributed anything to the functionality yet) and, assuming it remains stable/predictable, provides a good reference point where any problems are due to my code [in]ability.

Thanks for your support on what has been a frustrating rather than challenging issue.

Best regards,
Martin

Unknown said...

Hi Matthew,

This time I have some real observations(!).

As I noted yesterday, the sketch seems to be working as it should, I even get the data appearing in my target application DCS World, so all good - except:
I have 7 axis active in Joystick namely X, Y, Z, Rudder, Throttle, Brake, Steering (I appreciate Z, rudder and steering are synonymous but they do get used differently as rudder, left wheel brake and view zoom; brake is used as right wheel brake). However, only 5 of the 6 axis show in Microsoft's Game Controller and in DCS (rudder & steering do not shown).

I then changed the Rudder data to be on AxisRz and Steering data to be on AxisRy. In Game Controller and DCS the 2 new channels appear but Brake disappears (now a total of 6 axis).

I then tried all examples in the Joystick library and noted:
Driving Controller only displayed Brake - Accelerator and Steering were not displayed.
Flight Controller Test had all 3 axis and 32 buttons displayed.
Gamepad had all 2 axis and 1 button.
HAT Switch Test had 4 buttons but only 1 of the 2 HATs (maybe a limitation of Game Controller)
Analysis of the 3 remaining examples were inconclusive as Game Controller might have limited capacity.

I have also increased the delay between Axis reports to 10 (from 1) without improvement.

Is there any reason why Joystick might limit the numbers of axis reported?

I will try further testing with Planet Pointy but wondered if you had any thoughts that might be related to the issue.

Best regards,

Martin