Saturday, April 25, 2015

Add Up To 3 USB Game Controllers to Arduino Leonardo or Micro

IMPORTANT NOTE: This article is for Arduino IDE version 1.6.5 (or below). To add a USB Game Controller to an Arduino Leonardo or Micro using Arduino IDE version 1.6.6 (or above) see the Arduino Joystick Library post.

ArduinoLeonardoFrontThis is a follow-up to the article I posted last month, called Add USB Game Controller to Arduino Leonardo or Micro.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 two or three generic Game Controllers. This project will only work with Arduino products based on the ATmega32u4 microcontroller (i.e. the Arduino Leonardo and the Arduino Micro). It will not work with the Arduino Uno, because it is based on the ATmega328 microcontroller.

ArduinoMicroFrontFor this project the USB game controllers provided by the Arduino Leonardo or Micro only provide the following:

  • X and Y Axis
  • 16 Buttons

If more complex USB game controllers are desired, refer to the USBAPI.h and HID.cpp files in the Add USB Game Controller to Arduino Leonardo or Micro article.

Updating the Arduino Code

First make a backup copy of the following two files in the “%PROGRAMFILES%\Arduino\hardware\arduino\avr\cores\arduino” folder:

  • USBAPI.h
  • HID.cpp

Two Game Controllers

Replace these two files with the following to add a two generic Game Controllers to the Arduino Leonardo and the Arduino Micro:

Three Game Controllers

Replace these two files with the following to add a three generic Game Controllers to the Arduino Leonardo and the Arduino Micro:

Running the Test Sketch

Compile and upload either the UsbDualJoystickTest.ino (http://bit.ly/1DnxZSW) or UsbTriJoystickTest.ino (http://bit.ly/1IaFgfM) sketch file onto the Arduino Leonardo or the Arduino Micro using the Arduino Software (IDE). I have tested this using version 1.6.1 through 1.6.5 of the software.

NOTE (added 11/19/2015): Due to a change in how the USB functionality is implemented in version 1.6.6 and above, please see Arduino Joystick Library if you are using Arduino IDE version 1.6.6 and above.

The following steps are for Windows 7. If you have a different version of Windows or a different operating system, these steps may differ.

Go to the Windows Control Panel and select “Hardware and Sound”.

Control Panel

Then select “Devices and Printers”.

Hardware and Sound

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

Devices

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

Drop Down Settings

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

Game Controllers 1
[if the Two Game Controller files were used]

Game Controllers 3
[if the Three Game Controller files were used]

Either two or three Arduino Micros or Arduino Leonardos should appear in the list of installed game controllers. Select the first Arduino Micro or Arduino Leonardo and click the Properties button to display the game controller test dialog.

Game Controller Properties

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:

  • 16 Buttons
  • X and Y Axis

After testing the first game controller, the test script will perform the same test on the second game controller. Click the second Arduino Micro or Arduino Leonardo and click the Properties button to display the game controller test dialog and observe the test running against the second game controller. If the three game controller version of the files were used, the third game controller will be tested after the second.

Joystick Library

Now that the Arduino Leonardo or Arduino Micro has the Joystick library, the Arduino can be used for custom game controller projects. The following describes the Joystick library that is included in the updated USBAPI.h and HID.cpp files. The joystickIndex is 0-based (i.e. the first game controller has a joystickIndex of 0, the second has a joystickIndex of 1, and the third has a joystickIndex of 2).

Joystick[joystickIndex].begin(bool initAutoSendState)

Starts emulating a game controller connected to a computer. By default all methods update the game controller state immediately. If initAutoSendState is set to false, the Joystick[joystickIndex].sendState method must be called to update the game controller state.

Joystick[joystickIndex].end()

Stops the game controller emulation to a connected computer.

Joystick[joystickIndex].setXAxis(byte value)

Sets the X axis value. Range -127 to 127 (0 is center).

Joystick[joystickIndex].setYAxis(byte value)

Sets the Y axis value. Range -127 to 127 (0 is center).

Joystick[joystickIndex].setButton(byte button, byte value)

Sets the state of the specified button. The button is the 0-based button number (i.e. button #1 is 0, button #2 is 1, etc.). The value is 1 if the button is pressed and 0 if the button is released.

Joystick[joystickIndex].pressButton(byte button)

Press the indicated button. The button is the 0-based button number (i.e. button #1 is 0, button #2 is 1, etc.).

Joystick[joystickIndex].releaseButton(byte button)

Release the indicated button. The button is the 0-based button number (i.e. button #1 is 0, button #2 is 1, etc.).

Joystick[joystickIndex].sendState()

Sends the updated joystick state to the host computer. Only needs to be called if AutoSendState is false (see Joystick[joystickIndex].begin for more details).

3 comments:

Matthew Heironimus said...

See this article for instructions on how to get this to work in Linux.

stefan Gemeinert said...

Hello Matthew,

sorry for my english. I'm come from germany. Very interesting project.
I have a rotary encoder build in the programm for the X Axis. The problem is that the valve
only + or - 127 in the x axis.
Can you me help for the HID descriptor that the valve over +-127 is?

mail please on: stefangem@gmx.de

regards
Stefan

Matthew Heironimus said...

Stefan - I am currently working on a version of the library that will let you have 16-bit precision for the axis values (i.e. -32767 to +32767). I will post a new article to this blog when it is ready.