Arduino UNO Joystick HID firmware

I've built a basic two button analog joystick driver for the UNO that turns the UNO into a USB joystick. This is based on the joystick demo from the LUFA project which defines X and Y analog input ranging from -100 to +100 and two buttons.

I've defined a serial protocol for sending joystick commands with the following format:
Byte Type Description
0 int8_t X value, -100 to 100
1 int8_t Y value, -100 to 100
2 uint8_t Buttons. Bit 0 = button 1, Bit 1 = button 2
3 uint8_t reserved. Set to 0 for now.

Here is the firmware, source, and sample sketch. The firmware works on both the UNO and the Mega2560.

Download file "Arduino-joystick-0.1.hex"
Download file "arduino-joystick-0.1.tar.gz"
Download file "joystick_usb_demo.pde"

Upload the sketch, then load the hex file using DFU mode as described in my earlier posts (dfu-programmer for Linux/OSX or flip for Windows). Unplug the board and plug it back in and your PC should now recognise an Arduino joystick and start receiving input from the sketch.

Note you'll need to reload the USB Serial firmware via DFU mode whenever you want to change your sketch.
Download file "Arduino-usbserial.hex"
Download file "Arduino-usbserial-mega2560.hex"

Here's a summary of how I created the firmware.
  1. I started with a copy of the arduino-mouse source code, and renamed Arduino-mouse.c to Arduino-joystick.c and Arduino-mouse.h to Arduino-joystick.h. I could have started with the USB Serial driver but the mouse HID driver was already close to what was needed for the joystick code.
  2. I copied in Descriptors.c and Descriptors.h from the LUFA joystick demo (Demos/Device/ClassDriver/Joystick available from the LUFA100807 source from the LUFA Project).
  3. I modified Descriptors.c to change the ManufacturerString to "Arduino" and the ProductString to "Arduino Joystick".
  4. I added a USB_JoystickReport_Data_t data structure typedef to Arduino-joystick.h (based on the definition from the LUFA demo's joystick.h header).
  5. I replaced all references to "MouseReport" in Arduino-joystick.c with "JoystickReport".
  6. I changed the CALLBACK_HID_Device_CreateHIDReport so that it checks the amount of serial data received and whenever there is a full report available (i.e. 4 bytes) it copies it into a global joystick report variable. The function always sends the global joystick report to the PC host, so the effect is that it always sends the most recent report to the host. If there is no new report then the last one received is sent again.
  7. I changed the main loop to only call the HID and USB handlers (since the report handling is now taken care of in the CALLBACK_HID_Device_CreateHIDReport function).
  8. I also bumped the serial baud rate from 9600 up to 115200 to let the UNO send joystick updates as quickly as possible.
  9. And finally I added code to turn on the TX led when a report is received from the serial port (i.e. from the UNO) and to turn it off again after a small amount of time. This means the TX led will flash whenever the UNO sends a joystick command.



Comments

Jani (unauthenticated)
May 13, 2011

Hi! Nice job.
Question: Does Windows own calibration sequence work with this Arduino-joystick? Or do I have implement my own in Arduino sketch, and map those values between -100 and 100?
-Jani

darran
May 13, 2011

Hi Jani,

sorry I'm not familiar with windows calibration (I tested this on a mac). If it works with a normal joystick then it should work with the Arduino-joystick.

Regards,
Darran.

Help figuring this out for windows (unauthenticated)
Jun 13, 2011

So if I'm using windows I first load joystick_usb_demo.pde via arduino IDE? then us (flip?) and load a hex to the arduino
?

i'm using an Arduino Dueilanove (unauthenticated)
Jun 13, 2011

how do i load the hex file.

Irsla (unauthenticated)
Jun 20, 2011

Hi Daran,

I'm trying to do something similar to what you did, but I don't understand how the value are effectively sent.

I was able to upload to the arduino uno, and flash the hex file.

I wrote a simple Linux/C code that reads and outputs what is sent from the hid usb

When I try to simplify the pde code by commenting out most of the cmds (actually only keeping the first 2 serial.write) as follow:

joyReport.buttons = 0;
joyReport.x = 0;
joyReport.y = 0;
joyReport.rfu = 0;

/* Move the joystick in a clockwise direction */
joyReport.x = 100;
Serial.write((uint8_t *)&joyReport, 4);
delay(1000);

joyReport.x = 0;
joyReport.y = 100;
Serial.write((uint8_t *)&joyReport, 4);
delay(1000);

I get as an output:

$ ./a.out
just read 32 chars:
0X06 0XD8 0X7B 0X00 0X00 0X00 0X81 0X00 0X06 0XD8 0X7B 0X00 0X00 0X00 0X81 0X01 0X06 0XD8 0X7B 0X00 0X00 0X00 0X82 0X00 0X06 0XD8 0X7B 0X00 0X00 0X00 0X82 0X01
06 216 123 00 00 00 129 00 06 216 123 00 00 00 129 01 06 216 123 00 00 00 130 00 06 216 123 00 00 00 130 01
just read 8 chars:
0X10 0XD8 0X7B 0X00 0XFF 0X7F 0X02 0X00
16 216 123 00 255 127 02 00
just read 8 chars:
0XA6 0XD8 0X7B 0X00 0X00 0X00 0X02 0X00
166 216 123 00 00 00 02 00
just read 8 chars:
0X8E 0XDC 0X7B 0X00 0XFF 0X7F 0X02 0X00
142 220 123 00 255 127 02 00
just read 8 chars:
0X76 0XE0 0X7B 0X00 0X00 0X00 0X02 0X00
118 224 123 00 00 00 02 00
just read 8 chars:
0X54 0XE4 0X7B 0X00 0XFF 0X7F 0X02 0X00
84 228 123 00 255 127 02 00
just read 8 chars:
0X46 0XE8 0X7B 0X00 0X00 0X00 0X02 0X00
70 232 123 00 00 00 02 00

Now if I keep only the first cmd I only have:

$ ./a.out
just read 32 chars:
0XDC 0X28 0X7D 0X00 0X00 0X00 0X81 0X00 0XDC 0X28 0X7D 0X00 0X00 0X00 0X81 0X01 0XDC 0X28 0X7D 0X00 0X00 0X00 0X82 0X00 0XDC 0X28 0X7D 0X00 0X00 0X00 0X82 0X01
220 40 125 00 00 00 129 00 220 40 125 00 00 00 129 01 220 40 125 00 00 00 130 00 220 40 125 00 00 00 130 01
just read 8 chars:
0XF0 0X28 0X7D 0X00 0XFF 0X7F 0X02 0X00
240 40 125 00 255 127 02 00

I therefor have 2 questions:
- Do you know have any clues why, despite the blinking tx, It seems that no cmds a sent to my linux ?
- I understood that the first 0 bytes are timing request from the hid/usb protocol, but I don't understand how the 4 last are computed, they should be 100 0 0 0 and 0 100 0 0 according to the structure definition ?

Thanks for any answer you can provide.

darran
Jun 21, 2011

hi "Help figuring this out for windows". You can load the hex files from windows using the flip utility from Atmel. More info here: http://andrewmemory.wordpress.com/2011/04/14/upgrading-the-arduino-uno-8u2-using-flip/.

darran
Jun 21, 2011

Hi "I'm using an Arduino Dueilanove". The Duemilanove uses an FTDI chip for its USB interface, and it can only provide a serial interface. Only the Uno and Mega2560 support loading custom hex files.

darran
Jun 21, 2011

Hi Irsla,

I'm not sure what your test application is doing. Have you tested it with a normal joystick? If you can send me the source I might be able to give you some pointers on what is going wrong (you can email me at darran [at] hunt [dot] net [dot] nz).

Cheers,
Darran.

darran
Jun 21, 2011

Hi Irsla, thanks for sending the code.

the relevant linux docs are: http://lxr.linux.no/linux+v2.6.39/Documentation/input/joystick.txt and http://lxr.linux.no/linux+v2.6.39/Documentation/input/joystick-api.txt.

In joystick.txt it says the full range of the axis for the joystick -32767 to 32767. This means that it maps the maximum range of the joystick, in this case -100 to 100, onto the range -32767 to 32767. 32767 is 0x7fff and from the data you printed I can see that value being reported.

just read 8 chars:
0X10 0XD8 0X7B 0X00 0XFF 0X7F 0X02 0X00

In joystick-api.txt you can see that the 8 byte packet is broken down into the following:
uint32_t time; /* event timestamp in milliseconds */
int16_t value;
uint8_t type; /* event type */
uint8_t number; /* axis/button number */

So the from your program output the data is:
time: 0X10 0XD8 0X7B 0X00 = 0x007bd810 = 8116240 msecs
value: 0XFF 0X7F = 0x7fff = 32767 (i.e. +100 from the arduino)
type: 0X02 = JS_EVENT_AXIS
number: 0X00 (Axis 0, presumably the X axis)

Cheers,
Darran.

Seth M (unauthenticated)
Jul 27, 2011

ughhh...im having trouble with the 2 buttons... I just got the 2 analogs working and calibrated, but i can't get the buttons to work. i tried while and if loops and those didnt work so i didnt want to waste any more time. any help is appreciated, im a little rusty.

/* Arduino USB Joystick HID demo */

/* Author: Darran Hunt
* Released into the public domain.
*/

struct {
int8_t x;
int8_t y;
uint8_t buttons;
uint8_t rfu; /* reserved for future use */
} joyReport;

int jx,jy,mx,my,ab,ja;
int ax = A0;
int ay = A1;
int a = 5;

void setup()
{
Serial.begin(115200);
pinMode(ax, INPUT);
pinMode(ay, INPUT);
pinMode(a, INPUT);
}

void loop()
{
delay(100);
jx = analogRead(ax);
jy = analogRead(ay);
ja = digitalRead(a);
ab = 0;

mx = map(jx,0,1024,-100,100);
my = map(jy,0,1024,-100,100);

joyReport.x = mx;
joyReport.y = my;
joyReport.buttons = ab;

Serial.write((uint8_t *)&joyReport, 4);

while (digitalRead(ja) == HIGH) {
ab = 1;
joyReport.buttons = ab;
Serial.write((uint8_t *)&joyReport, 4);
}

}

darran
Jul 29, 2011

Hi Seth,

I'd try something like the following:

void loop()
{
delay(100);
jx = analogRead(ax);
jy = analogRead(ay);
ja = digitalRead(a);
ab = 0;

mx = map(jx,0,1024,-100,100);
my = map(jy,0,1024,-100,100);

if (digitalRead(ja) == HIGH) {
ab = 1;
} else {
ab = 0;
}

joyReport.x = mx;
joyReport.y = my;
joyReport.buttons = ab;

Serial.write((uint8_t *)&joyReport, 4);
}

Norwegian shrubbery (unauthenticated)
Aug 24, 2011

Thanks a lot for doing this work, Darran!

For my plans I need to hook up a lot of buttons, but it seems this firmware only supports two at the moment? I had a look at the source, but it wasn't immediately apparent to me how to go about adding support for multiple buttons. Is there any advice you could give as to the best way to go about it? My C is a bit rusty, but I suppose I need to map some extra bits for the purpose..

I could always switch to the HID keyboard firmware, but I'd prefer it to appear as a joystick and not interfere/overlap with the other keyboard devices I connect..

Norwegian shrubbery (unauthenticated)
Aug 25, 2011

Hi again! I found that you had already answered my question in a thread here: http://arduino.cc/forum/index.php/topic,60391.msg458189.html#msg458189

So I went ahead and applied the patches you suggest, and lo and behold, it worked!

Here is a patch file with the modifications applied to your code: http://www.scheen.no/buzh/arduino-joystick-0.1-thirtybuttons.patch.tar.gz

Again, thanks for you efforts!

That shrub again (unauthenticated)
Aug 25, 2011

Final update - HEX file and full modded source available here:

http://www.scheen.no/buzh/arduino-joystick-0.1-thirtybuttons/

darran
Aug 31, 2011

Hi Norwegian shrubbery - great handle.

Glad that worked for you. Thanks for the link. I've been meaning to add a blog entry with a more advanced joystick example that should be helpful, using the 30 buttons patch and also extending the x and y axis ranges to +/- 512 to match the arduino's analogRead() range. Will post something in the next few weeks.

Cheers,
Darran.

Norwegian shrubbery (unauthenticated)
Sep 1, 2011

That sounds great, Darran! Do you know if it's feasible to do >30 buttons as well, or are we running out of bits?

The next big step in my project is to allow the Arduino to recieve events from the computer, using the framework that's in the USB HID standard for force feedback and such. Is there any reason that this wouldn't work with this USB HID firmware?

DaNDeE (unauthenticated)
Sep 13, 2011

Hi Darran, great work! This will help a lot of Arcadeguys. ;) What I do dream off is and Arduino that emulates an Xbox Controller for the old xbox 1. These boxes are the best that you can get for emulation, with a low price. A proper Joystick is a must to enjoy the games. Hacking and soldering inside these is really not an easy task, so an Arduino that just acts a Xboxcontroller... I like! ;)
A little bit off track, I know, but maybe xmas comes early this year.

Information:http://euc.jp/periphs/xbox-controller.ja.html

bless & irie

Electromuis (unauthenticated)
Oct 15, 2011

i am trying to make it work with multipule joysticks and more buttons, but it does not work for some reason! can you help me?

darran
Oct 23, 2011

Hi Electromuis,

I might be able to help if you send me some details.

You could also try posting the the arduino forums at http://arduino.cc/forum/. Plenty of people there willing to help also.

Cheers,
Darran.

Electromuis (unauthenticated)
Nov 4, 2011

Thx dude! this is what i have so far
http://dl.dropbox.com/u/24401380/Arduino-joystick.rar
for some reason the adress of the values change.
but it does work.
any ideas how to fix that?

Electromuis (unauthenticated)
Nov 4, 2011

i want to make it work for ps2 controller ;p
I am already able to data from it.
But i need to make the code right to use as a USB controoler.
i tried simply sending serial data and a vb.net programm made it send keystrokes, but it worked too slow.

Kasper (unauthenticated)
Feb 18, 2012

Hey Darran,

This is awesome! Thank you :)

However, I am wondering, is it possible to add more analogue inputs, e.g. x, y, z-rotation???

Andrew-D (unauthenticated)
May 1, 2012

Very cool project. Where would one begin to do this on a Mega2560 Rev 3 board (has a Mega16U2 doing USB)? What would need to be altered?

darran
May 6, 2012

Hey Andrew-D,

nothing should need to be altered. In the makefile, set the following:

MCU = atmega16u2
MCU_AVRDUDE = at90usb82
MCU_DFU = atmega16u2

Andrew-D (unauthenticated)
May 23, 2012

Thank you Darren. Trying now.

xeightysixer (unauthenticated)
Aug 2, 2012

Hello, I'm hoping to get 30 a buttons joystick working on a mega 2560 with a atmega8u2. I'm pretty new to programming and am having trouble learning Processing to understand the example sketch. Can you tell me where I can get a copy of the 30-button sketch? Or if someone has it working, please email me a copy at xeightysixer at gmail? Thanks.

carmic_end (unauthenticated)
Nov 14, 2012

Very nice project u got here Darran but
how about 32 pins assigned to 32 buttons in order to work as gamepad ?

Dreded (unauthenticated)
Dec 16, 2012

your demo works great! but since its rather limited I need to compile the source so I downloaded lufa-120730 and your source did a make clean then make in the arduino-joystick folder and it gives me the following error:

make
grep: Version.h: No such file or directory
../../LUFA/makefile:30: ../../LUFA/Build/lufa.sources.in: No such file or directory
make: *** No rule to make target `../../LUFA/Build/lufa.sources.in'. Stop.

so then I decided it might be a LUFA version problem so i downloaded LUFA-100807(version you used) and the error I get from that is...

Descriptors.c: At top level:
Descriptors.c:46:45: error: variable ‘JoystickReport’ must be const in order to be put into read-only section by means of ‘__attribute__((progmem))’
Descriptors.c:81:33: error: variable ‘DeviceDescriptor’ must be const in order to be put into read-only section by means of ‘__attribute__((progmem))’
Descriptors.c:108:40: error: variable ‘ConfigurationDescriptor’ must be const in order to be put into read-only section by means of ‘__attribute__((progmem))’
Descriptors.c:167:33: error: variable ‘LanguageString’ must be const in order to be put into read-only section by means of ‘__attribute__((progmem))’
Descriptors.c:178:33: error: variable ‘ManufacturerString’ must be const in order to be put into read-only section by means of ‘__attribute__((progmem))’
Descriptors.c:189:33: error: variable ‘ProductString’ must be const in order to be put into read-only section by means of ‘__attribute__((progmem))’
make: *** [Descriptors.o] Error 1

any ideas?

Nitin (unauthenticated)
Dec 19, 2012

I am getting the same error as Dreded up there.

../../LUFA/makefile:30: ../../LUFA/Build/lufa.sources.in: No such file or direct
ory
make: *** No rule to make target `../../LUFA/Build/lufa.sources.in'. Stop.

need help

Darran help (unauthenticated)
Dec 21, 2012

I purchased the Arduino uno R3 I have no programming experience. thought it was plug and play.
I am trying to use this to work a gaming wheel.
I have 10K pot for the steering and 3 10K pots for pedals (clutch brake gas)
I have 14 buttons for the DO to oprerate functions in the game usually done by keys

Am I out to luch with this or can it be done. I will need step by step instructions.

Thanks Joey

Kocmo (unauthenticated)
Jan 5, 2013

Hi darran,

your works have really inspired us to do unthinkable projects with our arduino unos. We're trying to make this huge controller for a game and we rely on your keyboard.hex, but now we understood that we need your joystick.hex to make all the potentiometers to work well. But the problem is that it supports two axis and two buttons. Is there any possible way to get wide range of joysticks and buttons?

We're trying to build two-axis joystick, throttle and few other controls with potentiometers - all with one uno. Not to mention all 40 buttons, that we now have working on your keyboard.hex. So is there any chance that you could get this kind of a support into your joystick.hex?

Nitin (unauthenticated)
Jan 5, 2013

I DFU'ed your .hex file and was able to turn my UNO R3 into the joystick. However, when I compiled your sources, the resulting .hex file does not match the one you posted and I cannot make it work when I DFU that file to 16u2 chip.

I searched high and low on the internet but haven't found any solution.

Please help !!!

darran
Jan 13, 2013

Hi Kocmo,

yes I posted a patch quite a while ago to increase the joystick driver to 30 buttons and I started on a "big controller" with multiple axes and 30 buttons, and a resolution of 1024 for the analog inputs instead of 200. I'll dust it off and see if I can finish it in the next couple of weeks.

darran
Jan 13, 2013

Hi Nitin,

can you confirm that you have the LUFA100807 version of LUFA and not the latest? With the versions after 100807 the hex can be too big to load.

I've successfully loaded the hex file on my new rev UNO which has a 16U2, no changes needed to the makefile or source code.

What kind of errors are you seeing when it fails to load?

Andy (unauthenticated)
Jan 17, 2013

Hi Darran, thanks so much for making this post. It was very helpful.

I was wondering if you could help me figure out how to add more axes to this firmware. I'm trying to create a device which has an accelerometer as well as a physical joystick. Any ideas?

Thanks!

darran
Jan 22, 2013

Hi Andy, Kocmo,

I've posted firmware for a bigger joystick with 8 16-bit axes (-32768 to 32767) and 40 buttons. http://hunt.net.nz/users/darran/weblog/15f92/Arduino_UNO_Big_Joystick_HID_firmware.html

Kocmo (unauthenticated)
Apr 7, 2013

Thank you darran, you really know your business. We truly appreciate your help and devotion! We'll keep you updated!

bdor (unauthenticated)
Oct 1, 2013

Hey,
I am new to flashing new firmware to the arduino but I got the process down well.
My first project is to control a video game steering wheel using my arduino.
Can anyone help me out with this project?
The wheel has 1 pot that controls the turning direction, 2 more pots that control speed and brake, and a bunch of buttons for various uses.
I need to get all 3 pots and most of the 14 buttons working.
Does anyone know what firmware I should use to make this happen?
if anyone wants to help me you can contact me on Skype: bridor5285

locodog (unauthenticated)
Jan 3, 2014

Hi darran, thanks for the detailed tutorial, I am at the very beginning of my prototyping journey, could you please explain how I could switch from your automated joystick demo to analogue input on (A0 for X and A1 for Y)

locodog (unauthenticated)
Jan 4, 2014

Not really required any more thanks.

locodog (unauthenticated)
Jan 8, 2014

Back again, what are the limits to inputs with HID? I have seen that the maximum report size is 64Bytes so could I have 64*8bit analogue inputs? or 512 bit sized buttons? (theoretical, although I do want a combination 48 analogue and 128 buttons)

locodog (unauthenticated)
Jan 10, 2014

I've resolved my own problem again, 512 single bit inputs are possible (perhaps not as a joystick) could you do a full detailed break down of how to write firmware. I am picking up bits here and there but some parts are still a mystery.

I'm wanting to make a generic device.

(unauthenticated)
Mar 5, 2014

Hi locodog, writing code takes a bit of time to learn. You're best off starting with some easy examples like some of the Arduino examples and then building up to more advanced development. Find some tutorials on USB HID development to understand the descriptors that would allow you to attempt 512 inputs. The HID spec does describe how to do this, or if you compare the small joystick example on this site with the big joystick example then you can see the key differences.

locodog (unauthenticated)
Mar 10, 2014

Many thanks for that reply, I now have a working joystick based device with 64 bytes worth of output (128 buttons & 48 * 8bit pots) I'm now trying for 128 bytes, 2 months ago I knew nothing of HID or very little coding, so whilst my goal is ambitious for a noob I'm confident, but I might go on a killing spree if I have to read the HID spec again. :)

IceMakeR (unauthenticated)
Mar 27, 2014

Hello,
Nice work very usefull for me!
I'm workin in with AT MEGA 2560 R3 the joystock works fine with 40 buttons but i need something special : i need to manage some arduinos led output with an external program who communicates with COM Ports.
So i need Both Joystick AND com port when i merge serial and joystick my arduino bring up joystick but windows says something goes wrong and COM port doesn't work.
Can you give me some clues on merging HID Joystik and Serial com port interface?

Nitin (unauthenticated)
May 1, 2014

USB HID spec allows for the data to be sent in both directions. I am trying to implement something like the force feedback joystick. Is it possible to use the generic windows driver to send the data out to the HID device from the computer (USB Host)?