Many axis joystick

What about the 128 buttons from the original version?

Did you actually try using this yet?

All 128 button still exist. This JOYSTICK_SIZE define is the number of bytes for the entire HID report, not the number of any particular type of field within the report.

The 128 buttons use 1 bit each, so they consume only the first 16 of these 64 bytes. The many axes account for most of the report size.
 
Hi Paul, i was searching a lot for the best setup for a 16bit flight controller, i was wondering does Extreme Joystick works with rotary encoders and rotary switches ??
I want to buy the Teensy 3.1 for the project, but i found mmjoy too that uses teensy 2++, so im a bit confused what is the best.
Since this thread is from a very long time, does extreme joystick have had any update ??
and... if i would like to use a bigger resolution like 20bit, can it be done on teensy 3.1 ?

thanks very much
 
i was wondering does Extreme Joystick works with rotary encoders and rotary switches ??

Teensy is about DIY electronics. The USB Joystick function (either standard or extreme) is meant to allow you to create such things.

You write relatively simple code in Arduino which reads whatever encoders or switches you like. When then change, you use the joystick functions to transmit joystick events. You could use pots instead of encoders. Or you could connect a ethernet module and allow network communication to send joystick events.

If you haven't already installed the software, get Arduino & Teensyduino. Select Teensy in the Tools > Boards menu (the other menus update based on the board). Then look at some of the examples, in File > Examples > Teensy > USB_Joystick and File > Examples > Encoder. To accomplish a project like this, you'll be copying bits of code from these examples. You can download the software and look at this code before buying anything, and doing so can give you a much better idea of how this all works. It's not a finished, fixed-function product. It's a system that allows you to create things.
 
Hi Paul,

I am using the USB Joystick Complete example (that comes with Teensyduino) for a custom joystick. The axes are X, Y, Z, Zrotate, sliderLeft, sliderRight. The joystick shows up like the attached pict under Windows 10. The second slider axis won't work in a game (Overload) and I suspect it is because they are both named slider. I have tried renaming sliderLeft and sliderRight to Xrotate and Yrotate in the .ino sketch, usb_joystick.h, and usb_api.h. I also changed joystick_report_desc in usb_desc.c and usb.c as follows:

Changed:
0x09, 0x36, // Usage (Slider)
0x09, 0x36, // Usage (Slider)

To:
0x09, 0x33, // Usage (Rx)
0x09, 0x34, // Usage (Ry)

After uninstalling the joystick under Device Manager and reinstalling it, it still comes up the same way with two sliders. Am I missing something?

Thanks in advance.

Windows_control_panel.JPG
 
It can be tough to get Windows to "forget" the prior info it stores about a USB device.

Usually the best thing is to increment the BCD version number in the USB device descriptor. Windows will see it's a newer version and re-read everything.
 
I did try incrementing the bcdDevice number (usb_desc.c, line 90), as well as the vendor ID and product ID and then flashed the firmware to the Teensy. Nothing made it reinstall the device short of going to device manager and right clicking on the correct USB composite device and uninstalling. In that case, after unplugging and plugging it in again, windows installed it fresh (however sliders still show as in the pict). Are there any other places other than the files I mentioned that need to be changed for the sliders to change to Rx and Ry? Thanks for your help!
 
Last edited:
Ok, I've updated this code and merged it into the official core library.

https://github.com/PaulStoffregen/cores/commit/f5f05e9adee9ab9eca1ca83897e4114bf6e767fa

If you want to play with it now, you can get the updated files from github and put them into your copy of Arduino. Starting with 1.36-beta2 they will always be there by the installer.

To actually use this (after you have the new files installed), edit usb_desc.h. Change JOYSTICK_SIZE from 12 to 64. Remember, there's 4 copies for the different USB Types which use joystick. Edit the one you need, or all of them if unsure. I've set everything else to automatically adapt.

As always, on Windows your old USB device detection might be cached in the Windows Registry. You might need to increase the BCD version number or change the product ID or do other stuff to get Windows to re-detect the device.

Hello Paul, thank you for your work on this project, I am kind of new using the teensy boards since I just got my first one a week ago(teensy ++ 2.0) for a project and was afraid i will not have enough axis for it. Looking this project was from 2014 I was losing hope that i will be able to use it now.

This might be a dumb question but will this work with the teensy ++ 2.0? (I ask since the project was for the teensy 3.1 originally)
 
but will this work with the teensy ++ 2.0?

No, sorry, it's written for the new USB stack in Teensy LC & 3.x.

In theory, with enough work someone skilled with the USB code could rewrite it all for the older Teensy 2.x USB code. But in practice, that's very unlikely to ever happen...
 
Well that's unfortunate, but thank you for your honest reply. Since Teensy boards arent sold here its kind of difficult to get one, and was only able to get a ++ 2.0. The cheapest Teensy 3.x seems to be at least close to 50$ so I think i will need to stay with the ++2.0 for some time, if the project goes well maybe i will be able to get another teensy and try this. If you dont mind me asking for future reference, if I would like to modify the files, what will be the hardest part? Modifying the HID descriptor?
 
Where is "here"? None of these distributors are close?

https://forum.pjrc.com/threads/23601-Official-Distributors

On porting, modifying the code is fairly easy. Getting it to actually work is the hard part! It'd be particularly difficult without a known-good board for comparison and a USB protocol analyzer so you can see what's actually communicated over the USB lines.

Thank you for the reply. Seems like its not an easy job for a noob like me, but fortunately i think i can get enough axis and buttons with the teensy ++ 2.0 for my project.
I am from Peru (South America). Doesnt seems like my region is supported, so best case I need to import from USA. But i think one of my friends is going to travel to USA so maybe I will be able to get a Teensy 3.2 from him.
 
I have not worked much with T2s, mostly know trying to add T3.6 host support... Including plugging in another Teensy... Including Joystick support.

But For the 3.x I would look in the file: D:\arduino-1.8.5\hardware\teensy\avr\cores\teensy3\usb_desc.c
Most likely your path will be different...
For this section:
Code:
#ifdef JOYSTICK_INTERFACE
#if JOYSTICK_SIZE == 12
static uint8_t joystick_report_desc[] = {
        0x05, 0x01,                     // Usage Page (Generic Desktop)
        0x09, 0x04,                     // Usage (Joystick)
        0xA1, 0x01,                     // Collection (Application)
        0x15, 0x00,                     //   Logical Minimum (0)
        0x25, 0x01,                     //   Logical Maximum (1)
        0x75, 0x01,                     //   Report Size (1)
        [COLOR="#FF0000"]0x95, 0x20,                     //   Report Count (32)[/COLOR]
        0x05, 0x09,                     //   Usage Page (Button)
        0x19, 0x01,                     //   Usage Minimum (Button #1)
        [COLOR="#FF0000"]0x29, 0x20,                     //   Usage Maximum (Button #32)[/COLOR]
        0x81, 0x02,                     //   Input (variable,absolute)
        0x15, 0x00,                     //   Logical Minimum (0)
        0x25, 0x07,                     //   Logical Maximum (7)
        0x35, 0x00,                     //   Physical Minimum (0)
        0x46, 0x3B, 0x01,               //   Physical Maximum (315)
        0x75, 0x04,                     //   Report Size (4)
        0x95, 0x01,                     //   Report Count (1)
        0x65, 0x14,                     //   Unit (20)
        0x05, 0x01,                     //   Usage Page (Generic Desktop)
        0x09, 0x39,                     //   Usage (Hat switch)
        0x81, 0x42,                     //   Input (variable,absolute,null_state)
        0x05, 0x01,                     //   Usage Page (Generic Desktop)
        0x09, 0x01,                     //   Usage (Pointer)
        0xA1, 0x00,                     //   Collection ()
        0x15, 0x00,                     //     Logical Minimum (0)
        0x26, 0xFF, 0x03,               //     Logical Maximum (1023)
        0x75, 0x0A,                     //     Report Size (10)
        [COLOR="#008000"]0x95, 0x04,                     //     Report Count (4)
        0x09, 0x30,                     //     Usage (X)
        0x09, 0x31,                     //     Usage (Y)
        0x09, 0x32,                     //     Usage (Z)
        0x09, 0x35,                     //     Usage (Rz)[/COLOR]
        0x81, 0x02,                     //     Input (variable,absolute)
        0xC0,                           //   End Collection
        0x15, 0x00,                     //   Logical Minimum (0)
        0x26, 0xFF, 0x03,               //   Logical Maximum (1023)
        0x75, 0x0A,                     //   Report Size (10)
        [COLOR="#008000"]0x95, 0x02,                     //   Report Count (2)
        0x09, 0x36,                     //   Usage (Slider)
        0x09, 0x36,                     //   Usage (Slider)
        0x81, 0x02,                     //   Input (variable,absolute)[/COLOR]
        0xC0                            // End Collection
};
I believe the line I put in RED above controls the number of buttons: in particular the 0x20 (which is 32)

The Number of Axis is a little more complicated, Some of the lines associated with it are in Green
That is for example you have the section, that defines X, Y, Z, Rz which there are 4 of them. (report count).

Likewise with sliders. Note: The HAT fields earlier in the report also probably show up as axis.

Again I have not looked at where it is defined for Teensy 2.0, but I would suspect it would be something similar.
On my system I believe it is in the file: D:\arduino-1.8.5\hardware\teensy\avr\cores\usb_hid\usb.c
 
Last edited:
Thanks,

The path on my machine is: '/usr/share/arduino/hardware/teensy/avr/cores/teensy3/'.
That file exists in the teensy3 directory, however there is no teensy2 directory.
Perhaps it defaults to the teensy directory, but the file is not in that directory.
Is it possible that the file in teeny3 is being used?
I'll make changes to the file, then flash a teensy 2 and see if it makes a difference.

Edit:

Okay, so I tried that, but I think I messed something up.
I think what I really want to do now, is peal back this obtuse layer of arduino abstraction and get a real sense of what is actually going on.
What is the bare minimum that I would need to compile and flash the teensy2 from a terminal?
What compiler do I need, what library files do I need?
What utility do I need to flash the compiled hex?
Again the goal is still to make a joystick, but I just want to understand what is going on and what files are absolutely necessary.
 
Last edited:
On my linux box: My arduino Installation is similar: kurt@kurt-UP-CHT01:~/Desktop/arduino-1.8.5/hardware/teensy/avr/cores$
Under that directory is teensy3 for the stuff I mentioned.

For a Teensy2, the sources are in the directory: teensy
As I mentioned in the first post, some of the USB code (usb.c) includes code from other directories for the different USB configurations. The code I mentioned associated with the joystick is in the directory: kurt@kurt-UP-CHT01:~/Desktop/arduino-1.8.5/hardware/teensy/avr/cores/usb_hid$
If you look in usb.c you will find the joystick HID descriptor.

However just changing the descriptors will not be sufficient. This tells the other side how the data is packed on the messages that follow from the logical joystick.
You then also need to update the usb_joystick_class which is in the usb_api.h and usb_api.cpp files in that directory to make the data match the format that you describe in the descriptor.

So again currently in the usb.c you have:
Code:
static const uint8_t PROGMEM joystick_hid_report_desc[] = {
        0x05, 0x01,                     // Usage Page (Generic Desktop)
        0x09, 0x04,                     // Usage (Joystick)
        0xA1, 0x01,                     // Collection (Application)
	0x15, 0x00,			// Logical Minimum (0)
	0x25, 0x01,			// Logical Maximum (1)
	0x75, 0x01,			// Report Size (1)
	0x95, 0x20,			// Report Count (32)
	0x05, 0x09,			// Usage Page (Button)
	0x19, 0x01,			// Usage Minimum (Button #1)
	0x29, 0x20,			// Usage Maximum (Button #32)
	0x81, 0x02,			// Input (variable,absolute)
	0x15, 0x00,			// Logical Minimum (0)
	0x25, 0x07,			// Logical Maximum (7)
	0x35, 0x00,			// Physical Minimum (0)
	0x46, 0x3B, 0x01,		// Physical Maximum (315)
	0x75, 0x04,			// Report Size (4)
	0x95, 0x01,			// Report Count (1)
	0x65, 0x14,			// Unit (20)
        0x05, 0x01,                     // Usage Page (Generic Desktop)
	0x09, 0x39,			// Usage (Hat switch)
	0x81, 0x42,			// Input (variable,absolute,null_state)
        0x05, 0x01,                     // Usage Page (Generic Desktop)
	0x09, 0x01,			// Usage (Pointer)
        0xA1, 0x00,                     // Collection ()
	0x15, 0x00,			//   Logical Minimum (0)
	0x26, 0xFF, 0x03,		//   Logical Maximum (1023)
	0x75, 0x0A,			//   Report Size (10)
	0x95, 0x04,			//   Report Count (4)
	0x09, 0x30,			//   Usage (X)
	0x09, 0x31,			//   Usage (Y)
	0x09, 0x32,			//   Usage (Z)
	0x09, 0x35,			//   Usage (Rz)
	0x81, 0x02,			//   Input (variable,absolute)
        0xC0,                           // End Collection
	0x15, 0x00,			// Logical Minimum (0)
	0x26, 0xFF, 0x03,		// Logical Maximum (1023)
	0x75, 0x0A,			// Report Size (10)
	0x95, 0x02,			// Report Count (2)
	0x09, 0x36,			// Usage (Slider)
	0x09, 0x36,			// Usage (Slider)
	0x81, 0x02,			// Input (variable,absolute)
        0xC0                            // End Collection
};
This translates into:
32 bits - Buttons
4 bits - Hat switch
10 bits for X (axis)
10 bits for y (axis)
10 bits for Z (axis)
10 bits for RZ (axis)
10 bits for Slider
10 bits for Slider
= 96 bits of data or 12 bytes.

So if you look at the usb_joystick_class you will see how it is packing all of the data into the appropriate areas of the report on a bit boundary. So if you change the report descriptor, you will need to pack the data in your new format...

Now as to the minimal stuff needed to build and program. There are several threads on forum on how to program using bare metal. You might do a search. I typically just install Arduino and Teensyduino and use it that way
 
...snip...

However just changing the descriptors will not be sufficient. This tells the other side how the data is packed on the messages that follow from the logical joystick.
You then also need to update the usb_joystick_class which is in the usb_api.h and usb_api.cpp files in that directory to make the data match the format that you describe in the descriptor.
...snip...

I'm using a Teensy 2.0 and would dearly love 37 buttons. Could I add a byte to the buttons by:

  • Editing the descriptor
  • Editing usb_api.h by changing
    Code:
    extern uint8_t joystick_report_data[12];
    to
    Code:
    extern uint8_t joystick_report_data[13];
    and adding conditional code in the usb_joystick_class
    Code:
    else if (button < 40) joystick_report_data[4] |= mask;
  • Editing usb_api.cpp
    Code:
    UEDATX = joystick_report_data[12];
    after line 662


Is that really all there is to it?
 
That's most of it. But you'll also need to alter all the writes to joystick_report_data[4] to joystick_report_data[11] to one index farther in the array, since you'll now be using joystick_report_data[4] for something else. Of course, if you add fewer than 8 buttons, you'll need to add a const field to the descriptor to fill up the rest of joystick_report_data[4] with bits the HID parser will ignore. Adding exactly 8 more is easiest.

If using Windows, don't forget to increment the BCD version. Windows loves to cache USB info in the Windows Registry, even when it's silly to do so because it has to read all that stuff anyway as it detects the device. If you don't increment the BCD version or change the VID or PID, Windows may happily ignore your changes and use the stale info from its registry.
 
Okay so I must be missing something or totally inept.

I have a 3.5 and trying to use the Extreme Joystick sample but it will not compile. I have updated to the most current Teensy software and also the current 1.8.5 IDE.

My guess is that I somehow now need to declare the joystick to be 64?? for it to use the correct portion of the USB Joystick. However where in the Extreme example that was posted many many moons ago do I put this and what is the correct syntax?

Again I am asking if I am missing something -- ie is there documentation besides the examples that come with Teensy that I am missing. Second would it be possible in the future updates to the Teensy to add the Extreme example that seems to now be working by others into the examples? So inanition to the Complete that works having an EXTREME as a 4th option?

Second -- sorry. How do you declare what pins are connected for the HAT? In the complete we just have auto updating data, but nothing explains how to setup Pins for a HAT.

Third -- yes again really sorry. When using the 3.5 the analog pins get setup where buttons would be (also pin 13 does not really work well as a button) Does anyone have an idea of what happens to pins above the Analog that are used? I can't seem to make Pins 24 and up into buttons.
 
You need to edit hardware/teensy/avr/cores/teensy3/usb_desc.h, within the Arduino folder. If using a Mac, control-click Arduino and "show package contents" to access the folder. On Windows and Linux, Arduino is just an ordinary folder. If you used the Windows installer, the default install location is C:\Program File (x86)\Arduino.

Find this line within the file.

Code:
  #define JOYSTICK_SIZE         12      //  12 = normal, 64 = extreme joystick

This line is actually repeated several times, for the different choices in Tools > USB Type which have Joystick. If you're unsure, edit ALL of them.

Just change 12 to 64 and save the file. Your next upload will build as the extreme joystick.
 
Okay thanks -- that was exactly the part I could not seem to sort out.

When I started "hacking" at the files I can say that I am getting it a little better.

On the 3.5 trying to figure out what decides the buttons and hat connections? I thought I found an example else where on how to "remap" the buttons but that did not seem to work. Basically I want to skip PIN 13 and have the buttons be from 0-12 then 14-32.

Thanks for the Info thus far
 
I've recently started looking at using one of my Teensy 3.5 boards to build a game controller switch panel to supplement my T.Flight HOTAS X in Elite Dangerous.

When I first started entertaining the idea of custom switches I thought I might just make a simple switch panel for handling secondary (non-combat) commands much like many people before have already done, but now I'm starting to consider integrating it further with the T.Flight to opportunistically fix some of its design issues as well. The T.Flight has non-linear behaviour on the axes, with some pretty heinous deadzones around the neutral points. I've used vJoy to partially rectify the non-linearity but the only real fix for the deadzones will be to transfer the worst offending analog signals over to the Teensy so I can have full control over what's going on and leave the existing T.Flight factory electronics to continue handling what remains of the joystick (buttons, hats, etc), with both the T.Flight and the Teensy plugged into the PC over their own USB cables. This is not new ground, this forum post shows me I won't be the first person to fix a T.Flight with a Teensy so it feels pretty safe so far. In fact I will most likely start here and build on DogP's work to adapt it for my own approach.

My question is this; If I set Tools > USB Type to "Serial + Keyboard + Mouse + Joystick" can I get a bit radical and add something like a rotary encoder into the mix and have the Teensy handle it with a Mouse.scroll() routine on top of the required joystick features? I have been starting to consider extra controls like adding an analog hat joystick for vertical and lateral thrusters alongside the existing joystick axes. If a rotary encoder will work I can think of some useful things to do with it so I might add that in as well. Before I go to the trouble of laying out a full design based on hopes and dreams, can anyone confirm that what I'm thinking would / would not be possible at the Teensy level? Elite Dangerous itself seems to be pretty flexible with control definitions, I've got the T.Flight set for all the obvious stuff (some through vJoy) but I also have a PS4 gamepad, mouse and keyboard defined simultaneously alongside for certain aspects of the control scheme and ED seems to just work with no real trouble. If the Teensy side can pass it to the PC I think(?) ED might simply be OK with it.


TLDR; Can anyone see any problems with trying to use a rotary encoder to act as a Mouse.scroll() wheel in a Teensy build of a hybrid mouse-keyboard-gamepad-mega-joystick with more than 8 axes?
 
You should be able to use mousewheel or other keyboard or mouse inputs this way. The limitations happen when you use an absolute UI element (like a pot) for scroll or a toggle switch for a button where you need output from the game about where it thinks UI elements are.
 
Thanks GremlinWrangler, much appreciate the fast reply. Sounds like an understandable limitation.

I just fired up ED to confirm it will accept the traditional mouse scrollwheel for the inputs I'm considering using it on, so I might go ahead now and build a quick proof of concept Teensy + Encoder and test it out with that next. Before any holes get drilled in anything...
 
Back
Top