HID Joystick with just Rotaries

I think what I'm trying to do is create a HID joystick with a few rotaries.

The idea is to have a few rotaries to control Radar Horizontal/Vertical/Range on various aircraft in DCS World, since the HOTAS Warthog has none of these. If I can make it work I think I'd like to 3d print something to put this all in to attach to the back of the hotas by attaching it where a couple screws are located. But anyway, for me the hard part first:

I've never done anything like this whatsoever, but it seems the Arduino Uno can behave as a HID Joystick, from reading. Is this correct?

Would something like this work? Rotary Encoder - Illuminated (RGB) - COM-15141 - SparkFun Electronics
I'm not really concerned with the LED stuff right now, but maybe I will play with it later after everything else is set up to learn more.

And finally, I see some tutorials for joysticks with a couple potentiometer and a couples buttons, but not so much for rotaries. The rotary examples are incomplete, and being an utter newb I'm getting lost quick. Maybe just because I don't even know what I'm searching for. Does anyone know of a detailed tutorial or example using rotaries in this manner?

1 Like

I don't understand those many abbreviations.

With HID do you mean an USB HID? This would be hard to achieve with an Uno.

You should get better results when searching for (rotary) "encoder" instead of "rotary".

Yes, USB HID. It seems like there are people doing it:
http://www.imaginaryindustries.com/blog/?p=80&cpage=1

https://code.google.com/p/unojoy/wiki/GettingStarted

They seem to assume some knowledge about doing this kind of stuff and I see little about rotary encoder examples. Again most are buttons and or potentiometers.

Hi,
HID Human Interface Device, ie the joystick to ardunio to USB.

The joysticks usually are potentiometers, apart from cheap over priced games joysticks which can be just 4 tactile switches under a joystick lever.

Yes the arduino can input the joystick analog values.
Now in plain English, what do you want to interface it with.
What do you want to connect the arduino to?
The arduino will have a digital value for each of the joystick positions.

Remember we are not all gamers, so forget using all the pseudonyms and read back what you have written before posting.

Thanks......Tom...... :slight_smile:

A Leonardo can act as a keyboard or mouse for a PC.

If you have an external device connected to the Leonardo a program can convert its inputs into suitable values to send to the PC

...R

Your best and cheapest bet is to use a Arduino Micro or Pro Micro (Leonardo clone) to act as a HID.

Then use this fantastic script by Nicohood so your PC recognises your Arduino as a joystick/gamepad.

Everything you need is on his Github page.

I added an analogue thumbstick + button to my T16000m using it.

Now as for doing the rotaries, as you are using them for radar scale etc I would try getting your Arduino/Promicro to read them as analogue.

I have attached the script I use for reference. You maybe able to use it or at least glean something from it.

Good luck

T16000M.ino (858 Bytes)

MrGingerwig:
Now as for doing the rotaries, as you are using them for radar scale etc I would try getting your Arduino/Promicro to read them as analogue.

How can you read the digital output of a rotary encoder "as analogue" ?

...R

I emphasize the "I would try" as I figured, as @xaoslaad was talking about using them on a joystick for controlling radar he was talking more about a rotary wheel that you find on some joysticks to control throttle or trim axis. These are read as an analog axis as opposed to digital positions of a switch.

If like you said he is going to use rotary switches that have a set number of positions then yes, he won't be able to use analogRead().

How the game allows you to change these settings is also important as I know games like Elite:Dangerous allow for an axis to change "radar zoom" in which case you wouldn't be able to make it recognise a digital input such as a rotary switch OR it allows two keybindings, one for increase zoom and one for decrease. Again, I'm not sure how the game would deal with a rotary switch as it only wants two separate inputs.

All in all I think the OP would be best with some kind of rotary wheel that reads as analog, as opposed to a rotary switch....all in my opinion of course.

I think you can get potentiometer thumbwheels on Ebay for peanuts and that would make the coding much easier.

MrGingerwig:
If like you said he is going to use rotary switches that have a set number of positions then yes, he won't be able to use analogRead().

I was just going by the link he included in his Original Post.

...R

Robin2:
I was just going by the link he included in his Original Post.

...R

My apologies, I had totally missed that link.

So it works by measuring the difference between two channels and the output will depend on whether it is going clockwise or counter-clockwise.

//From bildr article: http://bildr.org/2012/08/rotary-encoder-arduino/

//these pins can not be changed 2/3 are special pins
int encoderPin1 = 2;
int encoderPin2 = 3;
int encoderSwitchPin = 4; //push button switch

volatile int lastEncoded = 0;
volatile long encoderValue = 0;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

boolean buttonPushed = false;

void setup() {
  Serial.begin (9600);

  pinMode(encoderPin1, INPUT); 
  pinMode(encoderPin2, INPUT);

  pinMode(encoderSwitchPin, INPUT);


  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  digitalWrite(encoderPin2, HIGH); //turn pullup resistor on

  digitalWrite(encoderSwitchPin, HIGH); //turn pullup resistor on


  //call updateEncoder() when any high/low changed seen
  //on interrupt 0 (pin 2), or interrupt 1 (pin 3) 
  attachInterrupt(0, updateEncoder, CHANGE); 
  attachInterrupt(1, updateEncoder, CHANGE);

}

void loop(){ 
  //Do stuff here
  if(digitalRead(encoderSwitchPin)){
    //button is not being pushed
  }else{
    //button is being pushed
    Serial.println("button pushed");
    buttonPushed = true;
  }
 
  Serial.println(encoderValue);
  delay(1000); //just here to slow down the output, and show it will work  even during a delay
}


void updateEncoder(){
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;

  lastEncoded = encoded; //store this value for next time
}

Found this code on this page:

http://bildr.org/2012/08/rotary-encoder-arduino/

I am a little confused by the end of the code though as it doesn't seem to make use of encoderValue or the unused long lastencoderValue = 0.

Perhaps if there was an if statement before the last line (using the Gamepad code from Nicohood):

if(encoderValue < lastencoderValue)
   Gamepad.press(1);
   else
      Gamepad.release(1);      //counter-clockwise activates DX1

if(encoderValue > lastencoderValue)
   Gamepad.press(2);
   else
      Gamepad.release(2);      //clockwise turn activates DX2

encoderValue = 0; //reset encoderValue to zero

That would give him a DX press for clockwise and counter-clockwise.

Apologies again for mistakes or errors as I'm an extreme beginner.

I wrote it out in Arduino and it compiles OK but I have no rotary switch to try it.

//these pins can not be changed 2/3 are special pins
int encoderPin1 = 2;
int encoderPin2 = 3;
int encoderSwitchPin = 4; //push button switch

volatile int lastEncoded = 0;
volatile long encoderValue = 0;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

boolean buttonPushed = false;

void setup() {
  // put your setup code here, to run once:
Serial.begin (9600);

  pinMode(encoderPin1, INPUT); 
  pinMode(encoderPin2, INPUT);

  pinMode(encoderSwitchPin, INPUT);


  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  digitalWrite(encoderPin2, HIGH); //turn pullup resistor on

  digitalWrite(encoderSwitchPin, HIGH); //turn pullup resistor on


  //call updateEncoder() when any high/low changed seen
  //on interrupt 0 (pin 2), or interrupt 1 (pin 3) 
  attachInterrupt(0, updateEncoder, CHANGE); 
  attachInterrupt(1, updateEncoder, CHANGE);
  
   Gamepad.begin();
}

void loop()
{
if (!digitalRead(encoderSwitchPin))
    Gamepad.press(3);
  else
    Gamepad.release(3);

 
  Serial.println(encoderValue);
  delay(1000); //just here to slow down the output, and show it will work  even during a delay
}


void updateEncoder()
{
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;

  if(encoderValue < lastencoderValue)
    Gamepad.press(1);
     else
       Gamepad.release(1);      //counter-clockwise activates DX1

  if(encoderValue > lastencoderValue)
    Gamepad.press(2);
      else
        Gamepad.release(2);      //clockwise turn activates DX2

  encoderValue = 0; //reset encoderValue to zero

  lastEncoded = encoded; //store this value for next time
}

@ MrGingerwig, please use the code button </> rather that the quote button. Code should look like this and be easy to select

...R

If anyone is curious how I am trying to attempt this, I am doing it first with a Leonardo and breadboard and once I figure out how to do that I will use a Pro Micro and do some soldering work.

The software is MMJoy2 which allows you to flash a firmware that presents the device as a game controller. From here you can program buttons, encoders, axes, etc.

Here's a view of the software and a Leonardo configured to look like a game controller.

I just have it set up as a single button controller at the moment as the breadboard, wires, resistors, capacitors, etc. are in a second package I'll probably get tomorrow, so maybe over the weekend I can get it working as a prototype.

( http://i1156.photobucket.com/albums/p562/xaoslaad/mmjoy2_zpstfnjxm47.png to see the larger version)

xaoslaad:
If anyone is curious how I am trying to attempt this, I am doing it first with a Leonardo and breadboard and once I figure out how to do that I will use a Pro Micro and do some soldering work.

The software is MMJoy2 which allows you to flash a firmware that presents the device as a game controller. From here you can program buttons, encoders, axes, etc.

Here's a view of the software and a Leonardo configured to look like a game controller.

I just have it set up as a single button controller at the moment as the breadboard, wires, resistors, capacitors, etc. are in a second package I'll probably get tomorrow, so maybe over the weekend I can get it working as a prototype.

( http://i1156.photobucket.com/albums/p562/xaoslaad/mmjoy2_zpstfnjxm47.png to see the larger version)

I've seen MMJoy2 before but never needed to use it as I was using T.A.R.G.E.T. from Thrustmaster. I didn't realise it could work with Arduino.

Good to know, thanks @xaoslaad.

I've got it more or less working with one rotary. Adding more should be no problem. I'm going to start doing some of the soldering so I can clean up once some additional parts get here.

This SimHQ post shows that I should have diodes in place, which I have not received yet. So for now it only work OK if I turn the knob at a steady and deliberate pace.

The software also lets you optionally configure a button to re-center the access.

Here is a brief video showing it work in a game while I play with the control.
Encoder Virtual Axis with Push to Center

Works pretty good :slight_smile:
Rotary Box

I designed a case to print with a 3d printer to attach to my throttle, but I don't own one so I'll have to barter for it.

Final build connected to the back of the throttle. Inside is just a Arduino Leonardo and a mini-breadboard. Can add more controls in the future if I choose.