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:
sim/autopilot/servos_on
sim/autopilot/servos2_on
sim/autopilot/servos3_on
sim/autopilot/servos_toggle
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? :-\
Thanks!
Brian
Cannot help you with your question but just want to compliment you on your sim. Really nice work.
Steve
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;
// BOUNCE()
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 )----*/
{
Serial.begin(9600);
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");
AT_MODE.onChange(updateIAS);
HDG_MODE = XPlaneRef("sim/cockpit2/autopilot/heading_status");
HDG_MODE.onChange(updateHDG);
IAS_MODE = XPlaneRef("sim/cockpit2/autopilot/speed_status");
IAS_MODE.onChange(updateIAS);
NAV_MODE = XPlaneRef("sim/cockpit2/autopilot/nav_status");
NAV_MODE.onChange(updateNAV);
VS_MODE = XPlaneRef("sim/cockpit2/autopilot/vvi_status");
VS_MODE.onChange(updateVS);
// Tricky ALT Hold logic
ALT_MODE = XPlaneRef("sim/cockpit2/autopilot/altitude_hold_status");
ALT_MODE.onChange(updateALT);
cmd_ALT_HOLD = XPlaneRef("sim/autopilot/altitude_hold");
cmd_ALT_ARM = XPlaneRef("sim/autopilot/altitude_arm");
APPR_MODE = XPlaneRef("sim/cockpit2/autopilot/approach_status");
APPR_MODE.onChange(updateAPPR);
GS_MODE = XPlaneRef("sim/cockpit2/autopilot/glideslope_status");
GS_MODE.onChange(updateGS);
sync_DG = XPlaneRef("sim/cockpit/gyros/dg_drift_vac_deg");
AP_BANK_LIMIT = XPlaneRef("sim/cockpit2/autopilot/bank_angle_mode");
}
void loop()
{FlightSim.update();
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);
delay(_delay+1);
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);
delay(_delay);
}
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.)
Do you mean this feature?
https://www.pjrc.com/teensy/td_flightsim.html
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:
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.
Example:
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.
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.