Welcome to Cockpitbuilders.com. Please login or sign up.

May 23, 2022, 10:13:06 PM

Login with username, password and session length


Fly Elise-ng
9 Guests, 0 Users
  • Total Posts: 58873
  • Total Topics: 7789
  • Online Today: 21
  • Online Ever: 582
  • (January 22, 2020, 08:44:01 AM)
Users Online
Users: 0
Guests: 9
Total: 9



Will Depart in...



X-Plane AP Servo Command?

Started by racer_x, January 15, 2022, 04:45:44 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.


I've been recently updating my X-Plane setup with cleaner code that is updated for 11.55 (all Teensy driven) and am having a problem with the autopilot. I can't seem to find the proper command to activate the AP servos and have it stay on.

In PlaneMaker, the AP setup is using "XP Custom" which is for legacy purposes because I started with the old Carenado B200 so this is a true Frankenstein (virtually all the original scripts are gone or re-coded). Should I use a different preconfigured AP option?

I've used the commands:

It looks like the servos come on for a brief moment (although the dataref "sim/cockpit2/autopilot/servos_on" never goes to "1") but never long enough for the plane to make any moves.

FD activation works and all the arming of options (heading, vs, alt, etc) work as well, I just can't get the servos to stay on.

I'm a bit stumped. Any ideas where to start looking/troubleshooting?  :-\




Cannot help you with your question but just want to compliment you on your sim.  Really nice work.



My Autopilot code for a Teensy 3.2:

#include <Wire.h>  // Comes with Arduino IDE
#include <Encoder.h>
#include <Bounce.h>

FlightSimInteger AVIONICS_MODE; // More to come here
FlightSimInteger AP_MODE; // More to come here
FlightSimInteger FD_MODE; // More to come here
FlightSimInteger HDG_MODE; // More to come here
FlightSimInteger IAS_MODE; // More to come here
FlightSimInteger AT_MODE;
FlightSimInteger ALT_MODE; // More to come here
FlightSimInteger VS_MODE; // More to come here
FlightSimInteger GS_MODE; // More to come here
FlightSimFloat   AP_AIRSPEED; // For IAS Adjustment
FlightSimFloat   AP_VS;       // For VS Adjustment
FlightSimInteger NAV_MODE;       // For VS Adjustment
FlightSimInteger APPR_MODE;       // For VS Adjustment
FlightSimInteger AUTOPILOT_STATE;  //Sim/cockpit/autopilot/autopilot state
FlightSimInteger AP_BANK_LIMIT;  //Sim/cockpit/autopilot/autopilot state
FlightSimFloat   sync_DG;     // sim/cockpit/gyros/dg_drift_vac_deg

FlightSimCommand cmd_HDG_HOLD;
FlightSimCommand cmd_AUTOTHROTTLE;
FlightSimCommand cmd_NAV;
FlightSimCommand cmd_VS;
FlightSimCommand cmd_VS_UP;
FlightSimCommand cmd_VS_DN;
FlightSimCommand cmd_ALT_HOLD;
FlightSimCommand cmd_ALT_ARM;
FlightSimCommand cmd_APPR;
FlightSimCommand cmd_VS_SYNC;
FlightSimCommand cmd_AIRSPEED_UP;
FlightSimCommand cmd_AIRSPEED_DN;
FlightSimCommand cmd_AIRSPEED_SYNC;
FlightSimCommand cmd_GLIDESLOPE;

// Rotaries

    long positionLeft  = 0;
    long positionRight = 0;
    long newLeft, newRight;

    Encoder knobLeft(31, 32);
    Encoder knobRight(14, 15); // VS Rotary
    Bounce btn_VS_SYNC    = Bounce(33, 5); //Autopilot AP Button
    Bounce btn_GPS        = Bounce(22, 5); //Autopilot AP Button
    Bounce btn_SNL        = Bounce(20, 5); //Autopilot AP Button
    Bounce btn_APPR       = Bounce(18, 5); //Autopilot AP Button
    Bounce btn_GS         = Bounce(16, 5); //Autopilot AP Button
    Bounce btn_ALT        = Bounce(21, 5); //Autopilot AP Button
    Bounce btn_VS         = Bounce(19, 5); //Autopilot AP Button
    Bounce btn_IAS_SYNC   = Bounce(30, 5); //Autopilot AP Button
    Bounce btn_FD         = Bounce(26, 5); //Autopilot AP Button
    Bounce btn_HDG        = Bounce(25, 5); //Autopilot AP Button
    Bounce btn_IAS        = Bounce(23, 5); //Autopilot AP Button
    Bounce btn_NAV        = Bounce(17, 5); //Autopilot AP Button
    Bounce btn_AP         = Bounce(24, 5); //Autopilot AP Button
    const int AVIONICS    = 12; // 74LS386 Chip Enable
    const int light_AP    = 0;
    const int light_FD    = 1; 
    const int light_HDG   = 2;
    const int light_IAS   = 3;
    const int light_NAV   = 4;
    const int light_GPS   = 6;
    const int light_VS    = 7;
    const int light_ALT   = 8;
    const int light_GS    = 9;
    const int light_APPR  = 10;
    const int light_SNL   = 5;

void setup()   /*----( SETUP: RUNS ONCE )----*/

    pinMode(AVIONICS, OUTPUT);  // Master Avionics Power

    pinMode(light_AP,   OUTPUT);  // light_AP
    pinMode(light_FD,   OUTPUT);  // light_FD
    pinMode(light_HDG,  OUTPUT);  // light_HDG
    pinMode(light_IAS,  OUTPUT);  // light_IAS
    pinMode(light_NAV,  OUTPUT);  // light_NAV
    pinMode(light_GPS, OUTPUT);  // light_GPSS
    pinMode(light_VS,   OUTPUT);  // light_VS
    pinMode(light_ALT,  OUTPUT);  // light_ALT
    pinMode(light_GS,   OUTPUT);  // light_GS
    pinMode(light_APPR, OUTPUT);  // light_APPR
    pinMode(light_SNL,  OUTPUT);  // light_SnL

  pinMode(16, INPUT_PULLUP);
  pinMode(17, INPUT_PULLUP);
  pinMode(18, INPUT_PULLUP);
  pinMode(19, INPUT_PULLUP);
  pinMode(24, INPUT_PULLUP);
  pinMode(25, INPUT_PULLUP);
  pinMode(26, INPUT_PULLUP);
  pinMode(20, INPUT_PULLUP);
  pinMode(21, INPUT_PULLUP);
  pinMode(22, INPUT_PULLUP);
  pinMode(23, INPUT_PULLUP);
  pinMode(30, INPUT_PULLUP);
  pinMode(33, INPUT_PULLUP);

// configure the X-Plane variables
   cmd_HDG_HOLD     = XPlaneRef("sim/autopilot/heading");
   cmd_AUTOTHROTTLE = XPlaneRef("sim/autopilot/autothrottle_toggle");
   cmd_NAV = XPlaneRef("sim/autopilot/NAV");
   cmd_VS = XPlaneRef("sim/autopilot/vertical_speed");
   cmd_APPR = XPlaneRef("sim/autopilot/approach");
   cmd_VS_SYNC = XPlaneRef("sim/autopilot/vertical_speed_sync");
   cmd_VS_UP = XPlaneRef("sim/autopilot/vertical_speed_up");
   cmd_VS_DN = XPlaneRef("sim/autopilot/vertical_speed_down");
   cmd_AIRSPEED_UP    = XPlaneRef("sim/autopilot/airspeed_up");
   cmd_AIRSPEED_DN    = XPlaneRef("sim/autopilot/airspeed_down");
   cmd_AIRSPEED_SYNC  = XPlaneRef("sim/autopilot/airspeed_sync");   
   cmd_GLIDESLOPE  = XPlaneRef("sim/autopilot/glideslope");   

   AVIONICS_MODE = XPlaneRef("sim/cockpit2/switches/avionics_power_on");
   AP_MODE = XPlaneRef("sim/cockpit/autopilot/autopilot_mode");
   AUTOPILOT_STATE = XPlaneRef("Sim/cockpit/autopilot/autopilot_state");
   AT_MODE = XPlaneRef("sim/cockpit2/autopilot/autothrottle_enabled");
   HDG_MODE = XPlaneRef("sim/cockpit2/autopilot/heading_status");
   IAS_MODE = XPlaneRef("sim/cockpit2/autopilot/speed_status");
   NAV_MODE = XPlaneRef("sim/cockpit2/autopilot/nav_status");
   VS_MODE = XPlaneRef("sim/cockpit2/autopilot/vvi_status");

// Tricky ALT Hold logic   
   ALT_MODE = XPlaneRef("sim/cockpit2/autopilot/altitude_hold_status");

   cmd_ALT_HOLD = XPlaneRef("sim/autopilot/altitude_hold");
   cmd_ALT_ARM  = XPlaneRef("sim/autopilot/altitude_arm");
   APPR_MODE = XPlaneRef("sim/cockpit2/autopilot/approach_status");
   GS_MODE = XPlaneRef("sim/cockpit2/autopilot/glideslope_status");
   sync_DG = XPlaneRef("sim/cockpit/gyros/dg_drift_vac_deg");


   AP_BANK_LIMIT = XPlaneRef("sim/cockpit2/autopilot/bank_angle_mode");


void loop()

AP_BANK_LIMIT = 4; // Limit bank angle when under Autopilot control (0-6)
sync_DG       = 0; // Slave the DG to Vacuum system #1 (for AP HDG Bug in Carenado aircraft)

if (AVIONICS_MODE == 0){digitalWrite(12, HIGH);} else {digitalWrite(12, LOW);}
if (AP_MODE == 0) {digitalWrite(light_AP, LOW);   digitalWrite(light_FD, LOW);}

if (AP_MODE == 1) {digitalWrite(light_AP, LOW);   digitalWrite(light_FD, HIGH);}
if (AP_MODE == 2) {digitalWrite(light_AP, HIGH);  digitalWrite(light_FD, HIGH);}

btn_AP.update();  if(btn_AP.fallingEdge())  {AP_MODE = AP_MODE ^2; }  //  { if(AP_MODE == 1){} else{AP_MODE = AP_MODE ^2; }}  // Toggle Bit 2

btn_FD.update();  if(btn_FD.fallingEdge())      { if(AP_MODE == 2){} else{AP_MODE = AP_MODE ^1; }}  // Toggle Bit 1

btn_HDG.update(); if(btn_HDG.fallingEdge())     { cmd_HDG_HOLD.once();}

btn_IAS.update(); if(btn_IAS.fallingEdge())     { cmd_AUTOTHROTTLE.once(); }

btn_NAV.update(); if(btn_NAV.fallingEdge())     { cmd_NAV.once();  }

btn_VS.update();  if(btn_VS.fallingEdge())      { cmd_VS.once(); }

// ALT HOLD Logic has to cycle through each mode (Off, Armed, Captured, then back to off)
btn_ALT.update(); if(btn_ALT.fallingEdge())     { if(ALT_MODE == 0){cmd_ALT_ARM.once();}    // ALT Hold ARM   
                                                  if(ALT_MODE == 1){cmd_ALT_HOLD.once();}   // ALT Hold Captured   
                                                  if(ALT_MODE == 2){cmd_ALT_HOLD.once();}   // ALT Hold OFF

btn_APPR.update();if(btn_APPR.fallingEdge())    { cmd_APPR.once(); }

btn_IAS_SYNC.update();if(btn_IAS_SYNC.fallingEdge()){ cmd_AIRSPEED_SYNC.once();}

btn_VS_SYNC.update();if(btn_VS_SYNC.fallingEdge()) { cmd_VS_SYNC.once(); }

btn_GS.update();if(btn_GS.fallingEdge()) { cmd_GLIDESLOPE.once(); }

// Flash the GS AP button if APPR engaged. Turns Solid green when Captured
if (GS_MODE == 1){ digitalWrite(light_GS, HIGH); delay(60);digitalWrite(light_GS, LOW);  delay(60);}
if (ALT_MODE == 1){ digitalWrite(light_ALT, HIGH); delay(60);digitalWrite(light_ALT, LOW);  delay(60);}

 newLeft  = knobLeft.read();
 newRight = knobRight.read();

if (newLeft-1 > positionLeft){ positionLeft = newLeft;   cmd_AIRSPEED_DN.once();  }
if (newLeft+1 < positionLeft){ positionLeft = newLeft;   cmd_AIRSPEED_UP.once();}

if (newRight-1 > positionRight ){ positionRight = newRight; cmd_VS_DN.once();}
if (newRight+1 < positionRight){ positionRight = newRight;  cmd_VS_UP.once();}


void updateAVIONICS(long value) {
  if (value == 0) {digitalWrite(AVIONICS, HIGH);} // OFF
  else{            digitalWrite(AVIONICS, LOW);}  // ON
void updateAP(long value) {
  if (value == 0) {digitalWrite(light_AP, LOW);   digitalWrite(light_FD, LOW);}
  if (value == 1) {digitalWrite(light_AP, LOW);   digitalWrite(light_FD, HIGH);}
  if (value == 2) {digitalWrite(light_AP, HIGH);  digitalWrite(light_FD, HIGH);}
void updateAPPR(long value)
  if (value == 0) { digitalWrite(light_APPR, LOW); }
 else{              digitalWrite(light_APPR, HIGH);}

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

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

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

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

void updateALT(long value)
  if (value == 0){ digitalWrite(light_ALT, LOW);}
  if (value == 1){ digitalWrite(light_ALT, HIGH); delay(100);digitalWrite(light_ALT, LOW);  delay(100);}
  if (value == 2){ digitalWrite(light_ALT, HIGH);}

void updateGS(long value)
  if (value == 0){ digitalWrite(light_GS, LOW);}
  if (value == 1){ digitalWrite(light_GS, HIGH); delay(100);digitalWrite(light_GS, LOW);  delay(100);}
  if (value == 2){ digitalWrite(light_GS, HIGH);}


void blinky(int _delay)
digitalWrite( light_AP,  HIGH);
digitalWrite( light_FD,  HIGH);
digitalWrite( light_HDG, HIGH);
digitalWrite( light_IAS, HIGH);
digitalWrite( light_NAV, HIGH);
digitalWrite( light_GPS, HIGH);
digitalWrite( light_VS,  HIGH);
digitalWrite( light_ALT, HIGH);
digitalWrite( light_GS,  HIGH);
digitalWrite( light_APPR,HIGH);
digitalWrite( light_SNL, HIGH);
digitalWrite( light_AP,  LOW);
digitalWrite( light_FD,  LOW);
digitalWrite( light_HDG, LOW);
digitalWrite( light_IAS, LOW);
digitalWrite( light_NAV, LOW);
digitalWrite( light_GPS, LOW);
digitalWrite( light_VS,  LOW); 
digitalWrite( light_ALT, LOW);
digitalWrite( light_GS,  LOW);
digitalWrite( light_APPR,LOW);
digitalWrite( light_SNL, LOW);
Ray Sotkiewicz


Just curious. Why use a Teensy? They have never appealed to me, and in fact I generally go out of my way to avoid them. I'm not really sure I have a good justification for my attitude either, other than they are single source.


Quote from: ame on January 18, 2022, 04:09:22 PMWhy use a Teensy?

They are the only microcontroller (Teensy 3.2 only) that you can plug directly into the sim computer without the need for any supporting external scripts.

The code I provided below works just by plugging the microcontroller into the sim computer. (Actually you do need the plugin but it's never been an issue.)
Ray Sotkiewicz


Do you mean this feature?


I thought it was no longer supported, but that does not seem to be the case.


Teensy is lightweight and super-simple, especially since I have a programming background. My only issue so far is I can't seem to get more than 7 or 8 of them recognized by the computer at the same time. But I've switched over to the 3.5 which is fast and has 58 pins so that gives me over 400 pins to work with which is plenty.

Thanks for the info, Ray. Based on that I think I'm doing it right. I suspect one of my networked computers is turning the AP off in LUA somewhere. I just gotta track it down once I get home. I'm in St. Barth for the week which I'm sure everyone here is familiar with  ;D

Some video for you all:


January 20, 2022, 08:52:57 PM #7 Last Edit: January 20, 2022, 08:54:59 PM by RayS
At one point I was running about  15 Teensy cards attached to the sim via 2 hubs.

To do that you have to ensure you are using high-quality hubs. A hub with a Transaction Translator >> Per Port << is imperative! (Usually referred to as a Multi-TT hub)

Also, you want to ensure you aren't saturating your USB bus with endless writes back to the sim.

if (value == 0) {digitalWrite(AVIONICS, HIGH);}

When "Value" = 0, it will write to the AVIONICS XP Command continuously. If you use this style often enough across multiple controllers, you'll end up flooding the USB bus with erratic results. (Ever hear a USB device disconnect mid-flight without warning?)

Instead you should think of using state-based code.

Basically, process the digitalWrite() only if "Value" changes.

This approach runs the risk of Teensy events not being seen by the sim. I won't get into the rat's nest of code required for that, but hopefully you get my point.

In a nutshell:
1. Detect if a variable has changed
2. If it has changed, write the new value to the sim. Otherwise remain silent.
3. Check to see if the new value made it to the sim.

Of course you could use the lazy programmer's way of ensuring you don't saturate the USB bus:

In your loop{}, add the following line:

delay(x); // In Milliseconds. I usually use 100. Don't tell anyone.


Ray Sotkiewicz


Quote from: RayS on January 20, 2022, 08:52:57 PM...
Of course you could use the lazy programmer's way of ensuring you don't saturate the USB bus:

In your loop{}, add the following line:

delay(x); // In Milliseconds. I usually use 100. Don't tell anyone.


LOL....I do the same thing Ray.
I put it there to get the thing working at the beginning, then just never went back to fix it.

Chief Pilot
Worldflight Team USA

Like the Website ?
Support Cockpitbuilders.com and Click Below to Donate