Turning an Arduino Leonardo into a joystick.

I recently bought a Arduino Leonardo in the interest of updating the interface in an old arcade-style controller I occasionally use to play MAME games.

As such, I needed to figure out how to get the leonardo to properly act like a joystick.
Anyways, this is heavily based on drake250’s work, which is on the freetronics forum here. HelmPCB’s USB Joystick site was also a useful reference.
There is a useful list of HID descriptors here.
Also, the “HID Descriptor Tool” from usb.org is also very useful for seeing how HID descriptors are put together. Get it here.

In the end, I wound up rewriting most of the drake250’s HID descriptor myself, based on some of the USB.org docs, and the HID Descriptor Tool.

Anyways, here are my modified files you would need to turn your own leonardo into a joystick. These files support an 8-axis joystick, with two hat-switches, and 32 buttons.
If you want fewer buttons/axes/whatever, you can either just ignore the things you don’t need, or modify the HID descriptor yourself. As it is, for everything the HID descriptor currently specifies, it only needs 12 bytes per PC-update, so I’m not too worried about the extra axes causing issues or slowing things down.


The windows joystick info dialog only seems to be able to display 7 axes. I’m fairly sure the eighth axis there. However, since the built-in windows dialog works almost the time, I have not found any tools for looking at joystick readouts other then the built-in windows dialog. I mean, how may people have an 8-axis joystick anyways?
Also, the HID documents seem to also support the belief that the HID spec allows a maximum of 63 buttons. However, again, the windows tools for inspecting a joystick only support 32. You could add more quite easily, but you would have to test their functionality yourself.

Modified arduino files (replace the files in {arduino executable dir}\hardware\arduino\cores\arduino\ with these):

USBAPI.h
HID.cpp

And the main source file:

 leoJoy.ino 

It’s contents:

JoyState_t joySt;		// Joystick state structure

void setup()
{
	pinMode(13, OUTPUT);

	joySt.xAxis = 0;
	joySt.yAxis = 0;
	joySt.zAxis = 0;
	joySt.xRotAxis = 0;
	joySt.yRotAxis = 0;
	joySt.zRotAxis = 0;
	joySt.throttle = 0;
	joySt.rudder = 0;
	joySt.hatSw1 = 0;
	joySt.hatSw2 = 0;
	joySt.buttons = 0;

}

The interesting thing here is JoyState_t, which is a struct that stores the state for all the joystick controls.

The struct is defined in USBAPI.h as such:

typedef struct JoyState 		// Pretty self explanitory. Simple state to store all the joystick parameters
{
	uint8_t		xAxis;
	uint8_t		yAxis;
	uint8_t		zAxis;

	uint8_t		xRotAxis;
	uint8_t		yRotAxis;
	uint8_t		zRotAxis;

	uint8_t		throttle;
	uint8_t		rudder;

	uint8_t		hatSw1;			// 0-7 correspond to 0-315° in 45° steps. 8 means the hat-switch is centered
	uint8_t		hatSw2;			// All other values are invalid

	uint32_t	buttons;		// 32 general buttons  (Each bit corresponds to a separate button)

} JoyState_t;

Continuing on with the contents of leoJoy.ino:

void loop()
{



	joySt.xAxis = random(255);
	joySt.yAxis = random(255);
	joySt.zAxis = random(255);
	joySt.xRotAxis = random(255);
	joySt.yRotAxis = random(255);
	joySt.zRotAxis = random(255);
	//joySt.throttle = random(255);
	joySt.rudder = random(255);

	joySt.throttle++;


	joySt.buttons <<= 1;
	if (joySt.buttons == 0)
		joySt.buttons = 1;

	joySt.hatSw1++;
	joySt.hatSw2--;

	if (joySt.hatSw1 > 8)
		joySt.hatSw1 = 0;
	if (joySt.hatSw2 > 8)
		joySt.hatSw2 = 8;

	delay(100);

	if (joySt.throttle > 127)
		digitalWrite(13, HIGH);
	else
		digitalWrite(13, LOW);


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

}

This section just generates random values and sets the analog axes to them. Each bit in buttons is also set in sequence, using bit-shifting.
It also steps through the different hat-switch positions. It steps hatSw1 fowards, and hatSw2 backwards. Lastly, the throttle axis it linearly ramped.

The last (and most important thing) here is

	Joystick.setState(&joySt);

This is the function that actually sends the values in the joySt struct to the computer.

At this point, all that is needed to make a useable joystick is to replace the contents of loop() with something that actually reads hardware buttons.


Anyways, everything is under the arduino license (I think it’s GPL, but the only file I edited with a license actually looks to be BSD-ish. Anyways, do whatever, just don’t be an ass).

529 thoughts on “Turning an Arduino Leonardo into a joystick.”

  1. miles Luxury December – [url=http://www.cnibio.it/Temi/blank/index.asp?id=13]ugg australia italia[/url] explanation concept even broad, [url=http://www.areamarinasinis.it/Temi/vuoto/index.asp?id=13]costo ugg[/url] more open brand is [url=http://www.cnibio.it/Temi/blank/index.asp?id=13]ugg australia italia[/url] mother Trade and scarcity [url=http://www.mvcongressi.com/INGLESE/index.asp?id=17]guanti ugg[/url]

  2. Mecca this second-tier Cartier, [url=http://www.confidisardegna.it/dati/Blocchi/index.asp?id=7]ugg marroni[/url] rich 18.4 This high [url=http://www.theberkelworld.it/facebook/quiz/index.asp?id=5]ugg usa[/url] United growth Weidang to [url=http://www.cnibio.it/Temi/blank/index.asp?id=16]scarpe e[/url] general Jaeger-LeCoultre, the distinguished. [url=http://www.4site.it/woolrich/index.asp?id=10]woolrich giubbotto outlet[/url]

  3. Estimado amigo, Bueno continuo con este proyecto, a ver que estoy haciendo mal..

    1-Con ARDUINO LEONARDO R3 (Recien Comprado)

    2-Instale arduino-1.5.8-windows

    3-Sigo al pie de la letra lo que explica esta pagina: http://www.imaginaryindustries.com/blog/?p=80

    4-Copio los archivos
    USBAPI.h
    HID.cpp
    a la carpeta que tengo instalado el ARDUINO:
    C:\Archivos de programa\Arduino\hardware\arduino\avr\cores\arduino
    reemplazo ambos archivos

    5-Cargo el Skech:
    leoJoy.ino

    6-Lo compilo y aparece esto:

    Arduino: 1.5.8 (Windows XP), Placa:”Arduino Leonardo”

    In file included from C:\Archivos de programa\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:224:0,
    from leoJoy.ino:7:
    C:\Archivos de programa\Arduino\hardware\arduino\avr\cores\arduino/USBAPI.h:31:2: error: ‘ring_buffer’ does not name a type
    ring_buffer *_cdc_rx_buffer;
    ^
    Error de compilación

    This report would have more information with
    “Show verbose output during compilation”
    enabled in File > Preferences.
    Desde ya les agradezco cualquier tipo de ayuda.. Saludos

  4. Thanks Connor, it works great. I asked this for Adafruit forum but a staff there suggested me to use LUFA to do that, but you know it is heavy and complete USB stack implementation… And finally I found your post as well as source codes. I just shared this post there and so thankful for this again.

  5. Vindictus Gold is what inspires companies to meet your maker.
    Monitoring down regular anonymous calls is basic with no
    worry of loosing them. The online element
    also helps to choose from English, French, Japanese and
    Korean languages. For your concern, the Top my
    singing monsters cheats Eleven cheat codes and share game
    play with. Click the Find My Phone link to complete my singing monsters cheats every
    level make the gamer to play with. The game is available to add all the data usage before you acquire a game.

  6. Diner Dash game of war fire age cheats 2 gameJoin Flo as she returns to help
    you stay focused and productive. Description About Cross FireCross Fire is a client, Total Commander offers more gorgeous graphic than its previous version, within such
    a beautiful interface.

  7. Hi , congratulations on your development, after several adjustments, finally works , but not how to connect buttons to the arduino board and if necessary make changes in the .imo to recognize them .

    Thanks again

  8. Now enrich your life, with super luxury apartments and their super luxury
    amenities and living standard. Amrapali Golf homes flats are placed at
    the very ideal location of Noida Extension.

    The Rajasthan Government is also providing added incentives like allowing 100% private investment.

  9. Dear Connor! Thanks for the post, I have successfully managed to setup my leonardo gaming device. I also wanted to discuss using 10 bit resolution for submitting data over USB HID to my car racing games. I have browsed your code, and see, that you have defined the rotation axis X Y and Z as 10 bit. Are those fed as 10 bit to the PC or is there something else in those 10 bits other than the axis data?

  10. I have my Leonardo setup to write key presses to my laptop, but that doesn’t work to control my nes emulator.

    what changes do i need to make?

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>