You are on page 1of 17

Interfacing a VOR/LOC/Glideslope Indicator

So today, we are going to make a fully functional VOR/LOC/Glideslope Indicator

What do we need?
An IN-386A instrument or similar
A Teensy Arduino board (compatible with xPlane)
The Teensy software and plugin for xPlane, the Arduino software
Four 5K trim potentiomenters (10 turn or more)
One 5K potentionmeter (linear)
Four 5K resistors, a 470 Ohm resistor and 3 to-be-determined resistors
Some gears

A $4 bag of different gears (Ebay)

A small diameter shaft 5K pot and 4 multi-turn trim pots

Testing the gauges

a positive voltage moves the NAV needle to the left (approx. 0.3Vdc)
a negative voltage moves the NAV needle to the right (approx. -0.3Vdc)
As you correctly guessed, we need to use voltage dividers to create the small voltages needed

Now that is a problem!

Arduino boards can not generate a negative voltage
Arduino boards can not generate a variable voltage

Let's talk about the variable voltage output first

Ever heard about PWM?
It does not mean Plane Widow Maker but Pulse Width Modulation
As you can see, the pulses are 5v “tall”
So how does that give us a voltage other than 5vdc?

In the above example we filled up the buckets with Blue de Curacao, some good tasting liqueur ...
at a 100% duty cycle we have plain 5vdc or 5 Liter per time-frame
at a 25% duty cycle we have simulated 1.25vdc or 1.25 Liter per time-frame
at a 50% duty cycle we have simulated 2.5vdc or 2.5 Liter per time-frame
So although, the pulses are 5v high, the width will determine our output voltage

Now that solves one issue but how are we going to create a NEGATIVE voltage?
Thus by using 2 voltage sources, we can create a positive or negative signal !

If we hook up our instrument in-between 2 PWM pins, we can vary from negative to positive voltages
Thus if the PWM signal on C4 > C5 we have a negative voltage
Thus if the PWM signal on C5 > C4 we have a negative voltage

But WAIT, do not connect it yet!!!!

Without current limiting resistors, we might fry our board

Below is the complete schematic

OK let's start....

Remove the PCB boards, 2 brass gears and the resolver

Remove the 25 pin connector and ground lug
We are going to re-use the wiring
Some of the items we removed
We need to replace the resolver with a 5K potentiometer
Pots usually have a turning range of 270 degrees

The pot has to be geared so that we can (at least) turn the OBS dial from 0 degrees to 360 degrees without hitting the
potentiometer's limit

I mounted the pot on a piece of scarp PCB and made the mounting holes slightly oblong so I can perfectly align the
If you want to save money, you could mount the voltage dividers (trim pots) on a test board, calibrate the
NAV and GS needles, write down the resistor values and use regular resistors

The Code:

FlightSimInteger BackCourse; // Special variable to access the BC led

FlightSimInteger OBS; // Special variable to access the OBS dataref
FlightSimInteger ToFrom; // Special variable to access the OBS dataref
FlightSimFloat NAV; // Special variable to access the NAV needle dataref
FlightSimFloat GS; // Special variable to access the NAV needle dataref
FlightSimInteger GSflag; // Special variable to access the GS-flag dataref

const int OBSpin = A7; // input pin OBS potentiometer

int OBSprevious = 0; // create variable to store previous OBS potentiometer value
int Pin_ToFromLow = 25; //reserve the pin for negative PWM ToFrom signal
int Pin_ToFromHigh = 24; //reserve the pin for positive PWM ToFrom signal
int Pin_NAVLow = 14; //reserve the pin for negative PWM NAV needle
int Pin_NAVHigh = 15; //reserve the pin for positive PWM NAV needle
int Pin_GSLow = 26; //reserve the pin for negative PWM GS needle
int Pin_GSHigh = 16; //reserve the pin for positive PWM GS needle

void setup() {
BackCourse = XPlaneRef("sim/cockpit2/autopilot/backcourse_on"); //set Backcourse dataref
BackCourse.onChange(updateBackCourse); //only do things when BackCourse changes
pinMode(5, OUTPUT); // set the BackCourse LED pin

OBS = XPlaneRef("sim/cockpit2/radios/actuators/nav1_obs_deg_mag_pilot"); //set OBS dataref

ToFrom = XPlaneRef("sim/cockpit2/radios/indicators/nav1_flag_from_to_pilot"); //set ToFrom dataref

ToFrom.onChange (updateToFrom); //only do things when ToFrom flag changes

NAV = XPlaneRef("sim/cockpit2/radios/indicators/nav1_hdef_dots_pilot"); //set NAV needle dataref

NAV.onChange (updateNAV); //only do things when NAV needle changes

GS = XPlaneRef("sim/cockpit2/radios/indicators/nav1_vdef_dots_pilot"); //set GS needle dataref

GS.onChange (updateGS); //only do things when GS needle changes

GSflag = XPlaneRef("sim/cockpit2/radios/indicators/nav1_flag_glideslope"); //set GS dataref

GSflag.onChange(updateGSflag); //only do things when GS flag changes
pinMode(4, OUTPUT); // set the GS flag pin

// loop runs repetitively, as long as power is on

void loop() {
FlightSim.update(); // causes X-Plane's changes to be received

// calculate and convert OBS data

int OBSanalog = analogRead(OBSpin);
int OBSmap = map(OBSanalog, 0, 1012, 360, 0);
if (OBSmap > 360) {
OBSmap = 360;
if (OBSmap < 0) {
OBSmap = 0;

// change only if more then one and send OBS data to XPlane
if (OBSanalog < OBSprevious - 1 || OBSanalog > OBSprevious + 1) {
OBS = OBSmap;
OBSprevious = OBSanalog;

// update runs only when X-Plane changes backcourse

void updateBackCourse(long value) {
if (value == 0) {
digitalWrite(5, LOW);
} else {
digitalWrite(5, HIGH);

// update runs only when X-Plane changes ToFrom flag

void updateToFrom(long value) {
if (value == 0) { // NAV1 off-line
analogWrite(Pin_ToFromLow, 0);
analogWrite(Pin_ToFromHigh, 0) ;
if (value == 1) { //NAV1 TO
analogWrite(Pin_ToFromLow, 255);
analogWrite(Pin_ToFromHigh, 0) ;
if (value == 2) { //NAV1 FROM
analogWrite(Pin_ToFromLow, 0);
analogWrite(Pin_ToFromHigh, 255) ;

// update runs only when X-Plane changes NAV needle pos.

void updateNAV(float value) {
int NAVmap =value * 100;
if (NAVmap > 255) {
NAVmap = 255;

if (NAVmap > 0) {
} else {
NAVmap = NAVmap * -1;
analogWrite(Pin_NAVHigh, NAVmap);

// update runs only when X-Plane changes GS needle pos.

void updateGS(float value) {
int GSmap =value * 100;
GSmap = GSmap - 10; //calibrate needle (note in the picture that my GS needle does not sit fully horizontal)
if (GSmap > 255) { //prevent damage
GSmap = 255;

if (GSmap > 0) {
analogWrite(Pin_GSHigh, GSmap);
} else {
GSmap = GSmap * -1; //convert negative number to positive

// update runs only when X-Plane changes GS flag

void updateGSflag(long value) {
if (value == 0) {
digitalWrite(4, HIGH);
} else {
digitalWrite(4, LOW);

Note that Arduino is case sensitive !!!

So where do I get my parts?

Ebay … but a little warning here
It is not uncommon that the same item is listed for per example for $59 and another seller wants $2000
Then you would think that the extravagant prices would mean quality?
Further from the truth, I received expensive gear that was indeed “like new” but must have been stored for years in a
damp warehouse. Thus bad contacts, corroded switches etc.

I rarely endorse a seller but whatever I purchased from swift46 was in pristine condition and dirt cheap!!!
Snap Lemon (aka swift46) is a pleasant and knowledgeable person to deal with
And by the way, most of his gear comes with the certificates!

Look at the SAME item!

Listed for:
Yes indeed, this gorgeous trim indicator panel was only $24.95
My Trim indicator panel was installed in an SAS DC8 in 1963
Was sold to AeroPeru in 1991 and sold to AeroMexico on 1993
Plane was scrapped this year
Enjoy !!!!