Create a Joystick Using the Arduino Joystick Library 2.0

38,482

146

33

Since I released the original Arduino Joystick Library (see https://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.

Step 1: Arduino Joystick Library 2.0

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

Step 2: 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.

Step 3: 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: 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 this can be done by executing deploy.bat. The library should now appear in the Arduino IDE list of libraries.

Step 4: 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.

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.

Step 5: 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”.

Step 6: Arduino Settings Menu

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.

Step 7: Select the Arduino

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.

Step 8: Testing the Arduino Joystick

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

Step 9: Simple Gamepad Example - Hardware

Once the Arduino Leonardo or Micro has been tested using the JoystickTest example, I suggest making a simple gamepad controller. You will need five buttons to build this simple example. Each button will correspond to one of the following joystick functions: up, down, left, right, and fire.

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

  • Up Button => Pin 2
  • Right Button => Pin 3
  • Down Button => Pin 4
  • Left Button => Pin 5
  • Fire Button => Pin 6

Step 10: Simple Gamepad Example - Sketch File

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

Step 11: Simple Gamepad Example - Testing

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

Step 12: For More Information

More information about the Arduino Joystick Library Version 2.0, including the complete API documentation, can be found at https://github.com/MHeironimus/ArduinoJoystickLibrary/tree/version-2.0.

Share

    Recommendations

    • Comfort Food Challenge

      Comfort Food Challenge
    • Epilog X Contest

      Epilog X Contest
    • Warm and Fuzzy Contest

      Warm and Fuzzy Contest

    33 Discussions

    0
    None
    KevinG256

    Question 13 days ago

    Hello first of all, thank you for the great library.

    I made a controller with a PS2 button layout for my smartphone/PC.

    It works fine on my laptop and old smartphone (android 7), but when I try it on my new phone (android 8) the joysticks don't work correctly. They kind of mix up with each other, as if they were only one. Could it be I'm doing something wrong with the multiple joysticks? I'm not sure I wrote that right, I think it works a little "by chance" on the old phone.

    Here's my code:

    #include <Joystick.h>
    #define JOYSTICK_COUNT 2
    Joystick_ Joystick[JOYSTICK_COUNT] = {
    Joystick_(0x03, JOYSTICK_TYPE_JOYSTICK, 15, 0, true, true, false, false, false, false,false, false, false, false, false),
    Joystick_(0x04, JOYSTICK_TYPE_JOYSTICK, 0, 0, true, true, false, false, false, false, false, false, false, false, false)
    };
    void setup() {
    #if defined (__AVR_ATtiny85__)
    if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
    #endif
    // End of trinket special code
    pixels.begin(); // This initializes the NeoPixel library.
    // Initialize Button Pins
    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);
    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(A0, INPUT);
    pinMode(A1, INPUT);
    pinMode(A2, INPUT);
    pinMode(A3, INPUT);
    Joystick[0].setXAxisRange(-127, 127);
    Joystick[0].setYAxisRange(-127, 127);
    Joystick[1].setXAxisRange(-127, 127);
    Joystick[1].setYAxisRange(-127, 127);
    // Initialize Joystick Library
    Joystick[0].begin();
    Joystick[1].begin();
    }
    // Constant that maps the phyical pin to the joystick button.
    const int pinToButtonMap = 2;
    // Last state of the button
    int lastButtonState[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    void loop() {
    // Read pin values
    for (int index = 0; index < 15; index++)
    {
    int currentButtonState = !digitalRead(index + pinToButtonMap);
    if (currentButtonState != lastButtonState[index])
    {
    Joystick[0].setButton(index, currentButtonState);
    lastButtonState[index] = currentButtonState;
    }
    }
    Joystick[0].setXAxis(map(analogRead(A1),0,1023,-127,127));
    Joystick[0].setYAxis(map(analogRead(A0),0,1023,127,-127));
    Joystick[1].setXAxis(map(analogRead(A2),0,1023,-127,127));
    Joystick[1].setYAxis(map(analogRead(A3),0,1023,127,-127));
    delay(10);

    0
    None
    NickF125

    Question 5 months ago on Step 1

    There are 3.3 and 5V boards on AliExpress, what should I choose?

    1 answer
    0
    None
    G60FORCENickF125

    Answer 27 days ago

    good question did you ever find out?
    how does one choice the correct version for a project?
    I assume 5v would be save since i want to use a already USB device
    but open it up to reconfigure the layout and salvage buttons

    0
    None
    BengtM1

    2 months ago


    Thank you for this library! It really solved a problem for me. I now use it to connect my DX6i radio control transmitter to my flight simulator(s). After some experimenting it now works fine.

    1 reply
    0
    None
    G60FORCEBengtM1

    Reply 27 days ago

    Hi I was actually trying to transform my USB RAILDRIVER (trainsimulator unit) into a Generic gamecontroller since the default driver and software only allow me to map 32/34 buttons but won't allow me to use the 4levers and 2rotary switches, so while I haven't studied how to do this I started reading through the comments, then stumbles onto yours Intresting!! since I also own a Spectrum Dx6i which i have never used since i got it al these years back, but reading your comment realized i might finally have a use for it... could you please share your completed program?? THNX alot!

    0
    None
    OverDhill-56

    5 weeks ago

    I would like to make a 8 axis-32 button joystick controller card. The Joystick library would appear to be able to handle it. I am a beginner to Ardunio and was hoping to find someone that has written a Sketch File to do that as well as a diagram on how they hooked everything up. I have tested out the Ardunio Leonardo card using the gamepad example. Any information or projects you could refer me to would be appreciated. I am a retired guy just trying to stay active with some projects. One of which is to MOD am old joystick and add some axis and buttons to it as well.

    0
    None
    HanutaBube

    Question 6 weeks ago

    Hi iam new to arduino stuff but i wanna build a Controller for my Raspberry pi console. But i dont know how to add more buttons to the simplegamepad scetch, i tried but it didnt worked. Can you please help me and tell me how i can have 5 additional "FIRE" buttons so i have : up down left right A B X Y L R.

    1 answer
    0
    None
    MatthewHHanutaBube

    Answer 5 weeks ago

    There is an example sketch included in the library, called JoystickButton (https://github.com/MHeironimus/ArduinoJoystickLibrary/blob/version-2.0/Joystick/examples/JoystickButton/JoystickButton.ino), that includes 4 buttons. If you take the concepts from this example and combine it with the GamepadExample (https://github.com/MHeironimus/ArduinoJoystickLibrary/blob/version-2.0/Joystick/examples/GamepadExample/GamepadExample.ino), you should be able to accomplish what you desire.

    0
    None
    javiera153

    Question 5 months ago on Introduction

    hi matthew

    i am building an 1-axis-joystick, and i want to move this axis via 2 potentiometer(3 pot at the end)--if we call "pot1" , "pot2" and "pot3" , and we have the range 0-1023:

    - pot3 defines a "cut point"

    -pot1 moves around range 0-pot3

    -pot2 moves around range pot3-1023

    i am using 3 analog pins, and with this little code i can "read" the value as i want, but my knowledge is so basic , i can´t implement this to an axis.

    int pot1 = A0, pot2 = A1, pot3=A2;

    int lectura; // this is the value i need to read

    void setup() {

    Serial.begin(9600);

    }

    void loop() {

    int val=analogRead(A0);

    int val2=analogRead(A1);

    int pot3=analogRead(A2);

    val=map(val,0,1023,0,pot3);

    val2=map(val2,0,1023,pot3,1023);

    if(val >= pot3)

    {

    lectura = val2;

    }

    else

    {

    lectura = val;

    }

    Serial.print("Potenciometro1 = ");Serial.print(val);

    Serial.print(" ---- ");

    Serial.print("Potenciometro2 = ");Serial.print(val2);

    Serial.print(" ---- ");

    Serial.print("Potenciometro3 = ");Serial.println(analogRead(A2));

    Serial.print("Lectura = ");Serial.print(lectura);

    Serial.print(" ---- ");

    delay(500);

    }

    thanks a lot!

    0
    None
    JuriF1

    6 months ago

    Hello Matthew!
    i would like do do a little more complicated project. can i "attack" two digital joystick (up,down,left,right,fire1 and fire2) and a keyboard using only one leonardo chip?
    thanks

    1 reply
    1
    None
    MatthewHJuriF1

    Reply 6 months ago

    Yes. There is a test script included with the library, called MultipleJoystickTest, that configures 4 joysticks with one Arduino Leonardo. You can use the Keyboard feature of the Leonardo with that as well.

    0
    None
    call sign freeze

    Question 8 months ago

    Hello, I was wondering could I run this emulator and the keyboard emulator at the same time on the same Arduino?
    All I need is a two axis(x,y) joystick, I’m still new to Arduino so this is a lot to take in. Not sure how to set this up, any chance that there’s a video explaining how to use the code?

    0
    None
    dylannegri

    Question 10 months ago

    Hi Matthew,

    after placing the joystick folder in my libraries i open the JoystickTest file in my IDE, however when I tried to compile the sketch, I was met with a error and I can't figure out why it's happening. This is what the console is giving me:

    readlink C:\Users\dylan\OneDrive\Documents\ArduinoData\packages: The system cannot find the file specified.

    Error compiling for board Arduino Leonardo.

    any help would be much appreciated! thanks!

    Dylan

    2 answers
    0
    None
    dylannegridylannegri

    Answer 10 months ago

    I tried installing everything but I'm ending up with the same issues when I try to verify the sketch. :/

    readlink C:\Users\dylan\OneDrive\Documents\Arduino\libraries\Joystick\examples\JoystickKeyboard\JoystickKeyboard.ino: The system cannot find the file specified.

    Error compiling for board Arduino Leonardo.

    0
    None
    MatthewHdylannegri

    Answer 10 months ago

    I have never encountered that error before. Are you able to open and compile any of the examples via the following menu option: File -> Examples -> Joystick -> JoystickTest (or any of the others)?

    0
    None
    charleslinquist

    1 year ago

    Matthew,

    I have things mostly working. I have 8 analog channels, but channel 5, in particular seems to have a "range" issue. That is, sometimes my device sees the controller output as 0 to 100 (on a scale of 0 to 100), sometimes it reads it as 50 to 80. The results aren't consistent. Is there something wrong with my setup? Could channel (or any others) be mis-configured?

    My code is below.

    #include <Joystick.h>

    Joystick_ Joystick;

    int8_t joystickType = 0x08;


    float Multiplier = 1.2;

    int Offset = 0;

    float Multiplier2 = .9;

    int Offset2 = -300;



    bool includeXAxis = true;

    bool includeYAxis = true;

    bool includeZAxis = true;

    bool includeRxAxis = true;

    bool includeRyAxis = true;

    bool includeRzAxis = true;

    bool includeThrottle = true; //not really throttle
    bool includeRudder = true; // not really rudder


    const int Analog1 = 0;

    const int Analog2 = 1;

    const int Analog3 = 2;

    const int Analog4 = 3;

    const int Analog5 = 4;

    const int Analog6 = 5;

    const int Analog7 = 6;

    const int Analog8 = 7;



    int XValue = 0;

    int YValue = 0;

    int ZValue = 0;

    int RxValue = 0;

    int RyValue = 0;

    int RzValue = 0;

    int SxValue = 0;

    int SyValue = 0;



    void setup() {

    Joystick.begin();

    delay(1000);

    }

    void loop() {



    XValue = (analogRead(Analog1));

    YValue = (analogRead(Analog2));

    ZValue = (analogRead(Analog3));

    RxValue = (analogRead(Analog4));

    RyValue = (analogRead(Analog5));

    RzValue = (analogRead(Analog6));

    SxValue= (analogRead(Analog7));

    SyValue = (analogRead(Analog8));


    XValue = (XValue * Multiplier2) + Offset2;

    YValue = (YValue * Multiplier2) + Offset2;

    ZValue = (ZValue * Multiplier2) + Offset2;

    RxValue = (RyValue * Multiplier2) + Offset2;

    RyValue = (RyValue * Multiplier2) + Offset2;
    RzValue = (RzValue * Multiplier) + Offset;

    SxValue = (SxValue * Multiplier2) + Offset2;

    SyValue = (SyValue * Multiplier2) + Offset2;

    Joystick.setXAxis(XValue); //YAW

    Joystick.setYAxis(YValue); // Throttle

    Joystick.setZAxis(ZValue); //PITCH

    Joystick.setRxAxis(RxValue); // Roll

    Joystick.setRyAxis(RyValue);// Chan 6

    Joystick.setRzAxis(RzValue);// Chan 5

    Joystick.setThrottle(SxValue);// Slider 1- not really throttle

    Joystick.setRudder(SyValue);//Slider 2 - not really rudder
    }

    Please note that the Joysticks are not being read by Windows. They are instead being read by a program running on a PC called "Mission Planner", which lets me re-map the channels to various functions.

    A picture of the "work in progress is attached.

    IMG_20171112_155030.jpg
    2 replies
    0
    None
    MatthewHcharleslinquist

    Reply 10 months ago

    I am not sure.

    It does appear you are calculating the value of "channel 5" differently from the other channels: RzValue = (RzValue * Multiplier) + Offset;
    vs.
    RxValue = (RyValue * Multiplier2) + Offset2;

    0
    None
    charleslinquistMatthewH

    Reply 10 months ago

    I haven't messed with this for awhile. I gave up and moved on to other things. But I'll get back to it.

    Channel 5 has different values because the program on the "other end" isn't consistently reading that channel properly. I tried to change the values in order to make it work. Sometimes, I get a huge offset. For example, if you assume the normal joystick output is 0 to 100, my computer interprets it as 50 to 80 when I move the stick side to side, so I have to add huge offsets and change the scale factors to make it work. But that doesn't always work either - possibly because of variable overflows. It is as if the library expects channel 5 to be digital and trying to make it analog messes it up.

    It could be that the program I'm running on my computer (Mission Planner) is handling the input improperly.

    0
    None
    GuilhermeR25

    1 year ago

    I made a steering wheel based on this library and a arduino leonardo it works but there is a about 100ms delay from a axis turn and the response on the computer (the buttons are with an apparently satisfactory delay) and there's also an annoying fluctuation on the axis(my best guess is that the arduino is to slow to process all the inputs) i would be grateful for a solution or workaround.

    here's my code:

    #include <Joystick.h>
    Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_GAMEPAD,
    8, 0, // Button Count, Hat Switch Count
    false, false, false, // X , Y, Z Axis
    false, true, false, // Rx, Ry, Rz Axis
    false, false, // rudder , throttle
    true, true, true); // accelerator, brake, steering

    void setup() {
    Joystick.begin();
    Joystick.setSteeringRange(0,1023); //steering
    Joystick.setBrakeRange(110,180); //brakes
    Joystick.setRyAxisRange(25,118); //clutch
    Joystick.setAcceleratorRange(943,1023); //throttle
    pinMode(A0, INPUT_PULLUP);
    pinMode(A1, INPUT_PULLUP);
    pinMode(A2, INPUT_PULLUP);
    pinMode(A3, 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);
    digitalWrite(2,HIGH);
    digitalWrite(3,HIGH);
    digitalWrite(4,HIGH);
    digitalWrite(5,HIGH);
    digitalWrite(6,HIGH);
    digitalWrite(7,HIGH);
    digitalWrite(8,HIGH);
    digitalWrite(9,HIGH);
    }



    void loop() {
    bool gear0 = digitalRead(2),gear1 = digitalRead(3),gear2 = digitalRead(4),
    gear3 = digitalRead(5),gear4 = digitalRead(6),gear5 = digitalRead(7),
    gear6 = digitalRead(8),gear7 = digitalRead(9);
    Joystick.setSteering(analogRead(A0)); //steering
    Joystick.setAccelerator(analogRead(A1)); //throttle
    Joystick.setBrake(analogRead(A2)); //brakes
    Joystick.setRyAxis(analogRead(A3)); //clutch
    Joystick.setButton(0,!gear0); //gear 1
    Joystick.setButton(1,!gear1); //gear 2
    Joystick.setButton(2,!gear2); //gear 3
    Joystick.setButton(3,!gear3); //gear 4
    Joystick.setButton(4,!gear4); //gear 5
    Joystick.setButton(5,!gear5); //gear 6
    Joystick.setButton(6,!gear6); //gear 7
    Joystick.setButton(7,!gear7); //reverse


    }