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

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

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>