X-Plane 11 Autopilot Rotary Controller with one Arduino Leonardo

Setting the altitude, the speed and the direction for the autopilot is done more often than saying “Welcome Sir / Madam” in an airliner. Good that this action is easy to achive by 3 different hardware controls. But whats with us non-real-pilot guys in our flight simulators? Or better said, how can I do this in X-Plane 11, which I am big fan of. We can use the mouse or assign hotkeys for this action. This is a good thing if you want to use your mouse or keyboard. I am using a Hotas joystick with many different keys, switches and some more cool controlls. Too bad that using my mouse or keyboard once I tell the engines to spin up and the airplane to take off is reducing the pilot immersion quite a lot.

This situation was bugging me quite a lot and I checked my options. One option would be buying such a controller. The other option would be building it on my own. As I am familiar with soldering and I know how to assemble electronic components I was choosing the second option. In the video below you can see how the result looks like. I will also show you how I was building it including the source code I was using for the Arduino.

What to buy before I could fly

It was set to build my own solution but I didn’t know where to start until I talked with a friend of mine about it. As he is shipping more than 5000 units of Arduinos every year accross Germany, he was recommending me an Arduino Leonardo. This model is shipping with an micro USB connector and is recognized as Keyboard device for Windows from the getgo. The Arduino Leonardo has also enough digital and analog input connectors available and is easy to programm. 

In the next step, I was selecting a physical, near to the real plane rotary. I wanted to feel some physical resistance and snap when I spin them.  I ordered three STEC12E08 encoder from ALPS. The STEC12E08 are having also a build in push button function which I really like. Additional to that, I was getting the fitting knobs, four 10k resistors and two 10nF capacitors for every rotary controller.

I was then deciding to buy a standard format circuit board with 100 * 160 mm in size, some cables with plugs and one USB to Micro USB cable. Now I got all the “inside” parts. For the case I picked a black plastic one where the parts could fit well and also where I could realize a good distance between each rotary controller.

Assembling

When I had all parts in my hands I was cutting the circuit board down to a smaller size. Then there was detailed soldering work todo for me. Every rotary knob was getting an debounce capacitor-resistor setup. I also put small connector pins on the board that could be used later on to connect the board with the cable.

X-Plane Autopilot Rotary Controller
X-Plane Autopilot Rotary Controller Board Back Side

It took quite a while to had everything done properly. The tricky part on this was placing the connector pins in a position and direction where I could connect the cables later on. Because the case I was choosing was only slightly bigger than the circuit board. You can see this on other pictures soon.

The next stop was the case. I was drilling in wholes for the rotary controller heads, some holes for ventilation and one for the USB cable. After this was done I connected the circuit board with cables that I connected on the other site with the Ardunio Leonardo board. Now the electric part was done. I did some basic test if the cables are all conneced well and then I fixed the circuit board with some glue to the case. After that I did some cable management, put the Arduino board in place, connected the USB cable and closed the case. But wait, why are 3 holes shown on the back of the case? Yeah, I was not super sure on which side I wanted to put the rotary controllers when I started. Now the case has 3 holes more than needed 😉

X-Plane Autopilot Rotary Controller Board Open
X-Plane Autopilot Rotary Controller Board Top Closed
X-Plane Autopilot Rotary Controller Board Side Closed

Writing some code

Now I was coding a small Arduino C program that reads the rotary positions and responses to it by simulating a keyboard press action. When there is no other rotation in a given time (150ms works good for me) it releases the key. If there is a retrigger it holds the key. I come to this topic soon again. I was picking the keys Q + W for my left rotary. A + S for the one in the middle and Y + X for the right one. 

#include <RotaryEncoder.h>
#include "HID-Project.h"

RotaryEncoder rotaryLeft(8, 9);
RotaryEncoder rotaryMiddle(10, 11);
RotaryEncoder rotaryRight(12, 13);

static unsigned long standardKeyPressTime = 150;
static unsigned long lastTriggerTime = 0;

void setup()
{
  Serial.begin(9600);
  delay(500);
  Keyboard.begin();
  delay(500);
}

void loop()
{
  static int lastPosLeft = 0;
  static int lastPosMiddle = 0;
  static int lastPosRight = 0; 
  
  lastPosLeft = rotaryAction(rotaryLeft, lastPosLeft, 'Q', 'W');
  lastPosMiddle = rotaryAction(rotaryMiddle, lastPosMiddle, 'A', 'S');
  lastPosRight = rotaryAction(rotaryRight, lastPosRight, 'Y', 'X');

  canWeReleaseKeys();
}

int rotaryAction(RotaryEncoder& rotary, int lastPos, char down, char up) {
  rotary.tick();
  int diff = lastPos - rotary.getPosition();

  if(diff < 0) {
    Keyboard.press(down);
    lastTriggerTime = millis();  
  } else if(diff > 0) {
    Keyboard.press(up);
    lastTriggerTime = millis();  
  }

  return rotary.getPosition();
}

void canWeReleaseKeys() {
  if(millis() > (lastTriggerTime + standardKeyPressTime))
      Keyboard.releaseAll();  
}

Configuring X-Plane 11

Here comes the easiest part of it. I was now configuring the X-Plane autopilot keys Q+W, A+S and Y+X for the speed, direction and altitude. Easy.

Windows 10 and X-Plane 11 Magic

How difficult can it be to put the rest all together after having the hardware and software part done? Well, there where some iterations on the software part until I had the code you could see. The reason for this is X-Plane 11 itself. My first implementation was not pressing/holding the key, but simulating that the character was typed. When I moved the rotary controller faster, I got more characters sent to Windows. A simple text editor and 5 other programms where confirming this. But ups, X-Plane 11 was not responding at all. 

I tried delays, different baud rates on the Arduino. Nothing was working. I was almost done with my little project. BUT I could not let the machine win. I tried now with the key press functionality and sometimes I saw a reaction in X-Plane 11. Then I think I figured it all out. X-Plane is not really responding to keyboard interactions like all other progamms. X-Plane 11 seams to have some own logic inside that is not based on the characters that are coming from the keyboard. Only the press action of a keyboard is respected as it looks to me. I have no clue why Laminar Ressearch is doing this. But they are smart so there must be a reason.

To make the story short, keeping the key pressed was the thing that made it work. When you have digged into the code you have seen the 150ms time threshold. I figured this out with pure experimentation.

I hope you enjoyed this little journey,

Your René

Post navigation