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.



25 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.