Skip to content

Gear panel tutorial, part 2 – Position Lights

25 October, 2012

In part 1 we created the three green gear-down-and-locked indicator lights. In Part 2 we’ll add the red gear-out-of-position lights, which go on when the landing gear is not in the position selected by the gear lever, and do some refining. Not many images in this session, it’s mostly altering code.

Let’s get started. Put three red LEDs onto the breadboard along with the green ones:

Again we will test the hardware before adding any new logic. Add the red LEDs to the code and light them up alongside the green ones.

const int greenLeftPin = 10;
const int greenNosePin = 11;
const int greenRightPin = 12;

// our new LEDs
const int redLeftPin = 20;
const int redNosePin = 19;
const int redRightPin = 18;

// Landing gear position datarefs
FlightSimFloat gearDeployLeft;
FlightSimFloat gearDeployNose;
FlightSimFloat gearDeployRight;

void setup() {
  pinMode(greenLeftPin, OUTPUT);
  pinMode(greenNosePin, OUTPUT);
  pinMode(greenRightPin, OUTPUT);

  pinMode(redLeftPin, OUTPUT);
  pinMode(redNosePin, OUTPUT);
  pinMode(redRightPin, OUTPUT);

  gearDeployLeft = XPlaneRef("sim/flightmodel2/gear/deploy_ratio[1]");
  gearDeployLeft.onChange(updateGearDeployLeft);
  gearDeployNose = XPlaneRef("sim/flightmodel2/gear/deploy_ratio[0]");
  gearDeployNose.onChange(updateGearDeployNose);
  gearDeployRight = XPlaneRef("sim/flightmodel2/gear/deploy_ratio[2]");
  gearDeployRight.onChange(updateGearDeployRight);
}

void loop() {
  FlightSim.update();
}

void updateGearDeployLeft(float pos) {
  digitalWrite(greenLeftPin, (pos == 1.0));
  digitalWrite(redLeftPin, (pos == 1.0));
}
void updateGearDeployNose(float pos) {
  digitalWrite(greenNosePin, (pos == 1.0));
  digitalWrite(redNosePin, (pos == 1.0));
}
void updateGearDeployRight(float pos) {
  digitalWrite(greenRightPin, (pos == 1.0));
  digitalWrite(redRightPin, (pos == 1.0));
}

You should see each red LED lighting up alongside the green ones. It’s a simple way to check we’ve got the numbers right and the LEDs the right way round, connected to the right holes in the breadboard, etc.

There’s no ‘gear out of position’ dataref, so we’ll need to write our own mini-simulator to decide when these LEDs should light. A brief search through DataRefEditor brings up sim/cockpit2/controls/gear_handle_down, which is 0 for Up and 1 for Down. Comparing gear_handle_down with gear_deploy_ratio should do it:

...
FlightSimInteger gearHandleDown;

void setup() {
  ...
  gearHandleDown = XPlaneRef("sim/cockpit2/controls/gear_handle_down");  
}

void loop() {
  FlightSim.update();

  // if gear handle doesn't match nose gear position
  if (gearHandleDown != gearDeployNose) {
    // light red nose LED (the Rudolph LED?)
    digitalWrite(redNosePin, HIGH);
  } else {
    // otherwise extinguish this LED
    digitalWrite(redNosePin, LOW);
  }
}

void updateGearDeployLeft(float pos) {
  digitalWrite(greenLeftPin, (pos == 1.0));
}
void updateGearDeployNose(float pos) {
  digitalWrite(greenNosePin, (pos == 1.0));
}
void updateGearDeployRight(float pos) {
  digitalWrite(greenRightPin, (pos == 1.0));
}

That works, but we can make it a bit less verbose:

  // light red nose LED if gear handle and nose gear disagree
  digitalWrite(redNosePin, (gearHandleDown != gearDeployNose));

(gearHandleDown != gearDeployNose) is evaluated as a true/false condition by C++. If the two numbers are not exactly the same, we get a true result, which is equivalent to 1 or HIGH here, and so the LED will light. Otherwise we get false/zero/LOW and the light goes out. Of course the numbers are only the same when the gear’s fully up or down and and the handle is up or down in the same position.

After testing it to see that it works, let’s extend this to all the red LEDs:

void loop() {
  FlightSim.update();

  // light red LEDs if gear handle and gear position disagree
  digitalWrite(redLeftPin, (gearHandleDown != gearDeployLeft));
  digitalWrite(redNosePin, (gearHandleDown != gearDeployNose));
  digitalWrite(redRightPin, (gearHandleDown != gearDeployRight));
}

This is working, but not very sophisticated. What is supposed to be powering these indicators? In reality, they’re fed off your computer’s USB power supply, but in an aircraft, they’re fed from one of the electrical busses. We can use the sim/cockpit2/electrical/bus_volts[0] dataref – there’s no explicit ‘essential power bus’ dataref in default X-Plane.

We’ll create a new FlightSimFloat for the voltage dataref – let’s call it supplyVolts. And let’s say that we need 10V to light our indicators. Now we could put && (supplyVolts > 10.0) into all of the lighting checks, but it is neater (and easier to amend) if we create a bool flag to store this information and then check against that. Let’s name it hasPower.

// Aircraft essential bus voltage
FlightSimFloat supplyVolts;

// flag to show whether our indicators can light
bool hasPower = false;

void setup() {
  ...
  supplyVolts = XPlaneRef("sim/cockpit2/electrical/bus_volts[0]");
}

void loop() {
  FlightSim.update();

  // let's say we need 10V to run the lights
  hasPower = (supplyVolts > 10.0);
  //hasPower is true if we have at least 10V, otherwise it is false.

  // light red LEDs if gear handle and gear position disagree and we have power
  digitalWrite(redLeftPin, (gearHandleDown != gearDeployLeft) && hasPower);
  // test on only one light first
  digitalWrite(redNosePin, (gearHandleDown != gearDeployNose));
  digitalWrite(redRightPin, (gearHandleDown != gearDeployRight));
}

// light green LEDs if gear down and locked and we have power
void updateGearDeployLeft(float pos) {
  digitalWrite(greenLeftPin, (pos == 1.0) && hasPower);
}
...

Turn off the engines and the battery supply, and… uh-oh! The red LED is behaving correctly, not lighting if the voltage is low, but the green LED isn’t lighting at all.

I scratched my head for a little while before seeing the reason: updateGearDeployLeft only runs when the gear position changes. If the supply voltage drops while the LED is lit, the LED stays lit until the gear position changes.

We could call the updateGearDeploy functions explicitly whenever supplyVolts passes 10V, or we could bring the green LED lighting code up into the loop() function. Both would work. I’ll choose the second option; it will make the green LED code consistent with the red LEDs. It’s a matter of taste, but I think it also makes the code simpler.

// I haven't shown it, but you should remove
// the onChange lines from setup() too.
...
void loop() {
  FlightSim.update();

  // let's say we need 10V to run the lights
  hasPower = (supplyVolts > 10.0);

  // light red LEDs if gear handle and position disagree and we have power
  digitalWrite(redLeftPin,  (gearHandleDown != gearDeployLeft)  && hasPower);
  digitalWrite(redNosePin,  (gearHandleDown != gearDeployNose)  && hasPower);
  digitalWrite(redRightPin, (gearHandleDown != gearDeployRight) && hasPower);

  // light green LEDs if gear down and we have power
  digitalWrite(greenLeftPin,  (gearDeployLeft == 1.0)  && hasPower);
  digitalWrite(greenNosePin,  (gearDeployNose == 1.0)  && hasPower);
  digitalWrite(greenRightPin, (gearDeployRight == 1.0) && hasPower);
}

One last refinement. Let’s make the lights always extinguish when X-Plane isn’t running. We can do this with the FlightSim.isEnabled() function. It is true when X-Plane’s running and ready to talk to the Teensy boards, and false otherwise.

We might as well use hasPower for this as well as the electrical power:

hasPower = (supplyVolts > 10.0) && FlightSim.isEnabled();

But now the name’s misleading. If you’re using Qt Creator, you can right-click on hasPower and use Refactor >> Rename Symbol Under Cursor to change the name to canLight intelligently. If you’re using the Arduino IDE to edit your code, change the name manually or with Find/Replace. Then read my guide to using a sensible IDE for writing Arduino/Teensy code.

Here’s the complete code listing:

const int greenLeftPin  = 10;
const int greenNosePin  = 11;
const int greenRightPin = 12;

const int redLeftPin    = 20;
const int redNosePin    = 19;
const int redRightPin   = 18;

// Landing gear position datarefs
FlightSimFloat gearDeployLeft;
FlightSimFloat gearDeployNose;
FlightSimFloat gearDeployRight;

// Landing gear control dataref
FlightSimInteger gearHandleDown;

// Aircraft essential bus voltage
FlightSimFloat supplyVolts;

// flag to show whether our indicators can light
bool canLight = false;

void setup() {
  pinMode(greenLeftPin,  OUTPUT);
  pinMode(greenNosePin,  OUTPUT);
  pinMode(greenRightPin, OUTPUT);

  pinMode(redLeftPin,    OUTPUT);
  pinMode(redNosePin,    OUTPUT);
  pinMode(redRightPin,   OUTPUT);

  gearDeployLeft =  XPlaneRef("sim/flightmodel2/gear/deploy_ratio[1]");
  gearDeployNose =  XPlaneRef("sim/flightmodel2/gear/deploy_ratio[0]");
  gearDeployRight = XPlaneRef("sim/flightmodel2/gear/deploy_ratio[2]");

  gearHandleDown =  XPlaneRef("sim/cockpit2/controls/gear_handle_down");  

  supplyVolts =     XPlaneRef("sim/cockpit2/electrical/bus_volts[0]");
}

void loop() {
  FlightSim.update();

  // we need 10V and the sim to be running to light the LEDs
  canLight = (supplyVolts > 10.0) && FlightSim.isEnabled();

  // light red LEDs if gear handle and position disagree and we have power
  digitalWrite(redLeftPin,  (gearHandleDown != gearDeployLeft)  && canLight);
  digitalWrite(redNosePin,  (gearHandleDown != gearDeployNose)  && canLight);
  digitalWrite(redRightPin, (gearHandleDown != gearDeployRight) && canLight);

  // light green LEDs if gear down and we have power
  digitalWrite(greenLeftPin,  (gearDeployLeft  == 1.0) && canLight);
  digitalWrite(greenNosePin,  (gearDeployNose  == 1.0) && canLight);
  digitalWrite(greenRightPin, (gearDeployRight == 1.0) && canLight);
}

With all these changes, we now have a complete set of gear indicator lights, which don’t light when the sim’s not running or when the aircraft has no power. Next time, we’ll add a gear lever!

– Jack 25/Oct/2012

Advertisements
2 Comments
  1. Dave Morley permalink

    This is great, but it would be really cool if you could use 2 coloured LEDs, leaving just the clear diffusers on the panel, turning green or red depending which switch is triggered by the lever.
    Looking at the tutorials on pjrc it seems do-able … please ?

    • Definitely doable. I can’t demonstrate it because I don’t have any multicolour LEDs to hand. The multicolour LEDs that come with the Teensy tutorial kit are basically three LEDs in one package with a common return pin, so in this case the code would be almost identical.

      You’d need to change the logic though, because lighting green and red at the same time would show as yellow. Some aircraft use red for ‘landing gear not fully down or fully up’ so it never lights when the green ‘gear fully down’ light is on – you’d need to use this logic.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s