Flightgear Yoke and Panel🔗

Posted by Médéric Ribreux 🗓 In projects/ flightgear/

#dev #electronic #flightgear

Introduction

When I was a child (probably in 1990), I discovered the fantastic world of flight simulation with Flight Simulator 3. For a geek kid, it was really interesting because it mixed computers and another scientific and enthusiasts domain: how to fly an aircraft!

I even persuaded my parents to buy me a book about Flight Simulator, just to be able to learn how to use this software. I remembered to try to land to Chicago Meigs and to explore San Francisco. I even really enjoyed one long simulation during the night (from San Francisco to Los Angeles) with a Learjet. It was fantastic!

Years ago, I discovered Flightgear which is the free software reference in flight simulation. But whenever I tried to use it with my keyboard, it was really difficult to fly any craft with it. Flightgear offers far more controls and outputs than Flight Simulator 3 or 4. Managing them with a keyboard is nearly impossible.

I was really decided to buy a yoke some years ago but I forgot to do so because I started a new project. This year (2019), I decided to improve my electronic skills a bit and one of my project was to try to build a yoke for Flightgear, something really cheap, just a prototype.

Finaly I found that it could be interresting to add more controls to the yoke, thanks to VRInsight Flight Master Yokes. The idea of adding switches to a panel was really interesting.

With time and hard work, I managed to build this yoke and its panel. Here is a summary of what I have done. I tried to put the maximum of details.

Be careful that this production is far from being more than just a prototype. There are a lot of ways to improve it. Furthermore, I have never fled a true aircraft nor have used a flight simulation commercial yoke system.

So, do not think that this yoke is what you need to build to master Flightgear. But if you would like to reproduce it, you are free to do so.

Some pictures

Front Panel
Front Panel
Yoke and Panel box
Yoke and Panel box
Inside View
Inside View
Movement of rudder: middle
Movement of rudder: middle
Movement of rudder: full push
Movement of rudder: full push
Movement of rudder: full pull
Movement of rudder: full pull
Rudder mechanism
Rudder mechanism
Ailerons mechanism
Ailerons mechanism
Cabling to the arduino
Cabling to the arduino
Cabling on the left
Cabling on the left
Cabling on the right
Cabling on the right

What is emulated?

Front Panel controls description
Front Panel controls description

Here is the list of controls:

  1. Rudder and ailerons.
  2. Handbrake.
  3. Magnetos and starter.
  4. Pitot heat.
  5. Avionics.
  6. Master Alternator.
  7. Master Battery.
  8. Strobes.
  9. Nav lights.
  10. Beacon lights.
  11. Landing lights.
  12. Taxi lights.
  13. Gear Up/Down.
  14. Throttle.
  15. Mixture.
  16. Flaps.
  17. Primer.
  18. Fuel pump.
  19. Carburetor heater.
  20. Fuel tank selector.

Build it

Bill of materials

ComponentNumberManufacturerDatasheetPrice (Total)
Mechanics
MDF 810x405x9mm1ChinaDatasheet4.1€
MDF 1150x610x9mm1China-8.5€
Steel corner braces10?Datasheet3.9€
Angle bracket W40mmx60mmx60mm1Simpson Strong-TieDatasheet1.05€
Nail plate NP15/40/1201Simpson Strong-TieDatasheet1.05€
Table chrome leg L250mm, Ø30mm1?Datasheet4.61€
Plummer block bearing UCP206 Ø30mm1TRIDatasheet9.96€
Ball bearing drawer slide L=251mm2HandixDatasheet3.56€
Rack CMLN1-1501TRIDatasheet4.32€
Pinion 15 tooth EM10151TRIDatasheet1.2€
Electronics
Rocker Switch R5ABLKBLKFF02E-SwitchDatasheet2.54€
Rocker Switch R4ABLKREDIF02E-SwitchDatasheet1.7€
Rocker Switch R4FBLKBLKEFO1E-SwitchDatasheet1.0€
5 positions 30° Rotary Switch A10505RNZQ1C&KDatasheet4.44€
4 positions 30° Rotary Switch A10405RNZQ1C&KDatasheet4.21€
4 positions 90° Rotary Switch A12405MNZQ1C&KDatasheet4.17€
Knob 450-SL26122Eagle Plastic DevicesDatasheet2.46€
Knob MPKES70B1/43ApemDatasheet3.36€
Toggle Switches 2FA53-73/.1879CarlingDatasheet15.84€
Rotary Potentiometer PDB181-E420K-502B1BournsDatasheet0.935€
Rotary Encoder PEC11R-4030F-N00241BournsDatasheet1.14€
Linear Potentiometer PTB0143-2010BPB1032BournsDatasheet8.22€
Arduino Mega 25601Arduino LLCDatasheet31.57€
Connectors and cables
Terminal Tabs Connectors 94512-01018MolexDatasheet0.656€
Terminal Tabs Connectors 35718-101018MolexDatasheet1.64€
Crimp Male Terminal (x100) 70021 16-02-01071MolexDatasheet4.5€
Crimp Female Terminal (x100) 70058 16-02-00861MolexDatasheet5.2€
Crimp Housing 70066 50-57-900211MolexDatasheet3.069€
Crimp Housing 70066 50-57-90032MolexDatasheet0.74€
Crimp Housing 70066 50-57-90042MolexDatasheet0.74€
Crimp Housing 70067 50-57-90085MolexDatasheet2.305€
22 AWG Black cable8mAlphawireDatasheet2.0€
22 AWG Blue cable8mAlphawireDatasheet2.0€
22 AWG Red cable8mAlphawireDatasheet2.0€
22 AWG Yellow cable8mAlphawireDatasheet2.0€

Required tools (WIP)

ToolImageUsed for
Metallic Framing Square
Framing Square
Framing Square
Measurements
Ruler
ruler
ruler
Measurements
PenMeasurements
Hand saw
Hand saw
Hand saw
Wood cutting
Coping saw
Coping Saw
Coping Saw
Wood cutting
Drill
Drill
Drill
Drilling
Drill bits Ø6/8/10/12/32
Drill bits
Drill bits
Wood cutting/Drilling
Box Cutter
Box cutter
Box cutter
Wood Cutting and adjustments
File
File
File
Wood cutting and adjustments
Rasp
Rasp
Rasp
Wood cutting and adjustments
ScrewdriverBolt fixing
SocketsBolt fixing
Pliers crimp
PLiers crimp
PLiers crimp
Cabling

Building guide

The most "complicated" part of the yoke and panel is the panel. I tried to use FreeCAD (v0.18 from Debian) to build this technical drawing with dimensions:

Technical drawing of the front Panel
Technical drawing of the front Panel" caption="Technical Drawing with dimensions

If you are a FreeCAD user, you can download my work on this panel. I have also generated a PDF file for printing. If you use an A2 printer, you should have a 1:1 scale paper guide to help you drill holes in the panel.

Assembly guide

TODO

Calculations

Keyboard precision in Flightgear

Rack and pinion

Module 1 means 3.14mm per tooth.

Encoder precision

For a 24 pulses per rotation (ppr).

Rack Lenghtz for 1 turnz for pinionnumber of turnsPrecision
110mm35103.584 levels
100mm32103.277 levels
150mm48153.277 levels
125mm40152.6764 levels
110mm35152.3356 levels
100mm32152.1351 levels
150mm48163.072 levels
125mm40162.560 levels
100mm32162.048 levels
150mm48212.2854 levels
125mm40211.945 levels
100mm32211.5236 levels

Yoke course

Interfacing with Flightgear

Introduction

Flightgear has an interesting feature called generic protocol. With it, you can connect nearly everything in input or output for or from Flightgear.

The generic protocol is a way to build an interface with your hardware and Flightgear. It is sufficiently opened to be able to use the input of your choice. For example, you can connect a simple switch from a microcontroler and use it to operate a "virtual switch" in Flightgear.

Finding the property tree nodes

Flightgear uses heavily property tree for nearly everything inside the simulation engine. So, there is a huge number of nodes to explore. Fortunately, there is a property tree browser inside Flightgear.

You just have to press '/' to open it and explore the tree.

Designing a protocol file for flightgear

The protocol file is just an XML configuration file. Once designed, you just have to put it under $FG_ROOT/Protocol/ directory (which is in /usr/share/games/flightgear/Protocol in Debian).

You can use either ASCII protocol or binary protocol. ASCII uses strings to communicate. If you have lots of values, it can be tough to read a lot of things in ASCII mode, because it is far from being compact. But on the other side, ASCII mode is really easiest to implement and to debug. Let's start with it.

<?xml version="1.0"?>

<PropertyList>

<generic>
<input>
	<line_separator>\n</line_separator>
	<var_separator>,</var_separator>
	<!-- Left panel upper group -->
	<chunk>
		<name>Avionics</name>
		<node>/controls/switches/master-avionics</node>
		<type>bool</type>
	</chunk>
	<chunk>
		<name>Master Alt</name>
		<node>/controls/switches/master-alt</node>
		<type>bool</type>
	</chunk>
	<chunk>
		<name>Master Bat</name>
		<node>/controls/switches/master-bat</node>
		<type>bool</type>
	</chunk>
	<chunk>
		<name>Instruments lightning</name>
		<node>/controls/lighting/instruments-norm</node>
		<type>float</type>
	</chunk>
	<!-- Left Panel middle group -->
	<chunk>
		<name>Magnetos</name>
		<node>/controls/switches/magnetos</node>
		<type>int</type>
	</chunk>
	<chunk>
		<name>Starter</name>
		<node>/controls/switches/starter</node>
		<type>bool</type>
	</chunk>
	<chunk>
		<name>Pitot Heat</name>
		<node>/controls/anti-ice/pitot-heat</node>
		<type>bool</type>
	</chunk>
	<!-- Left Panel lower group -->
	<chunk>
		<name>Parking Brakes</name>
		<node>/controls/gear/brake-parking</node>
		<type>bool</type>
	</chunk>
	<!-- Lights group -->
	<chunk>
		<name>Strobe</name>
		<node>/controls/lighting/strobe</node>
		<type>bool</type>
	</chunk>
	<chunk>
		<name>Landing</name>
		<node>/controls/lighting/landing-lights</node>
		<type>bool</type>
	</chunk>
	<chunk>
		<name>Taxi</name>
		<node>/controls/lighting/taxi-light</node>
		<type>bool</type>
	</chunk>
	<chunk>
		<name>Beacon</name>
		<node>/controls/lighting/beacon</node>
		<type>bool</type>
	</chunk>
	<chunk>
		<name>Nav</name>
		<node>/controls/lighting/nav-lights</node>
		<type>bool</type>
	</chunk>
	<!-- Right panel upper group -->
	<chunk>
		<name>Primer</name>
		<node>/controls/engines/engine/primer-lever</node>
		<type>bool</type>
	</chunk>
	<!-- There is no fuel pump control in Cessna 172p for the moment -->
	<chunk>
		<name>Fuel Pump</name>
		<node>controls/engines/engine[0]/fuel-pump</node>
		<type>bool</type>
	</chunk>
	<chunk>
		<name>Carb Heat</name>
		<node>/controls/engines/current-engine/carb-heat</node>
		<type>bool</type>
	</chunk>
	<chunk>
		<name>Fuel Selector Left</name>
		<node>/consumables/fuel/tank[0]/selected</node>
		<type>bool</type>
	</chunk>
	<chunk>
		<name>Fuel Selector Right</name>
		<node>/consumables/fuel/tank[1]/selected</node>
		<type>bool</type>
	</chunk>
	<!-- Right Panel lower group -->
	<chunk>
		<name>Flaps</name>
		<node>/controls/flight/flaps</node>
		<type>float</type>
	</chunk>
	<chunk>
		<name>Gear Down</name>
		<node>/controls/gear/gear-down</node>
		<type>bool</type>
	</chunk>
	<chunk>
		<name>Throttle</name>
		<node>/controls/engines/engine/throttle</node>
		<type>float</type>
	</chunk>
	<chunk>
		<name>Mixture</name>
		<node>/controls/engines/engine/mixture</node>
		<type>float</type>
	</chunk>
</input>
</generic>

</PropertyList>

Arduino code

Now that we have defined a protocol for communication, we need the Arduino to send correct values towards the computer. We need to build some code that will:

Here is what I have produced in C++ for Arduino. You have three files:

Here is the content of yoke_and_panel.h:

/* Pin definition */
/* Digital pins */
#define AVIONICS 41
#define MASTER_ALT 50
#define MASTER_BAT 39
#define MAGNETO_OFF 45
#define MAGNETO_RIGHT 49
#define MAGNETO_LEFT 47
#define MAGNETO_BOTH 51
#define STARTER 53
#define PITOT 43
#define PARKING_BRAKES 52
#define STROBE 48
#define NAV 36
#define BEACON 46
#define LANDING 34
#define TAXI 44
#define PRIMER 32
#define FUEL_PUMP 42
#define CARB_HEAT 22
#define FUEL_LEFT 35
#define FUEL_RIGHT 24
#define FUEL_BOTH 33
#define FUEL_OFF 30
#define FLAPS_0 28
#define FLAPS_10 26
#define FLAPS_20 38
#define FLAPS_30 37
#define GEAR_UP 40

/* Analog pins */
#define AILERONS A0
#define THROTTLE A2
#define MIXTURE A1
#define ENCPINA 2
#define ENCPINB 3

/* Global variables */
extern boolean avionics;
extern boolean masterAlt;
extern boolean masterBat;
extern boolean gearUp;
extern boolean pitotHeat;
extern boolean parkingBrakes;
extern boolean strobeLight;
extern boolean navLight;
extern boolean taxiLight;
extern boolean beaconLight;
extern boolean landingLight;
extern boolean fuelPump;
extern boolean carbHeat;
extern boolean fuelLeft;
extern boolean fuelRight;
extern boolean primerLeverState;
extern boolean starterState;

extern float flaps;
extern float throttle;
extern float mixture;
extern float instrumentBrightness;
extern float ailerons;

extern unsigned int magnetos;
extern unsigned int primer;
extern unsigned long starterEndTimer;

/* Encoder variables */
extern volatile byte aFlag;
extern volatile byte bFlag;
extern volatile byte elevatorPos;
extern volatile byte oldElevatorPos;
extern volatile byte elevatorRaw;

/* Functions declarations */
void setup();
void EncPinA();
void EncPinB();
void fuelTanksValue();
void magnetosValue();
void flapsValue();
void primerValue();
void loop();

Here is the content of the main code:

/*
 * This file is part of flightgear_yoke_and_panel
 *
 * This code is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Alfred is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with flightgear_yoke_and_panel.
 * If not, see <https://www.gnu.org/licenses/>.
 *
 * Copyright (C) 2018 Médéric Ribreux <mederic.ribreux@medspx.fr>
 *---------------------------------------------------------------------
 * yoke_and_panel.cpp: Main Arduino source code for yoke and panel.
 */

#include <Arduino.h>
#include "yoke_and_panel.h"

/* Global variables */
boolean avionics = false;
boolean masterAlt = false;
boolean masterBat = false;
boolean gearUp = false;
boolean pitotHeat = false;
boolean parkingBrakes = false;
boolean strobeLight = false;
boolean navLight = false;
boolean taxiLight = false;
boolean beaconLight = false;
boolean landingLight = false;
boolean fuelPump = false;
boolean carbHeat = false;
boolean fuelLeft = false;
boolean fuelRight = false;
boolean primerLeverState = false;
boolean starterState = false;

float flaps = 0.0;
float throttle = 0.0;
float mixture = 0.0;
float ailerons = 0.0;
float elevator = 0.0;
/* float instrumentBrightness = 0.0; */
unsigned int magnetos = 0;
unsigned int primer =0;
unsigned long starterEndTimer = 0;

static int pinA = 2; // Encoder first pin
static int pinB = 3; // Encoder second pin
volatile byte aFlag = 0;
volatile byte bFlag = 0;
volatile byte elevatorPos = 30;
volatile byte elevatorRaw = 0; // Elevator raw value

/* Initial setup */
void setup() {
  /* Pins assignment */
  /* Digital Pins */
  pinMode(AVIONICS, INPUT_PULLUP);
  pinMode(MASTER_ALT, INPUT_PULLUP);
  pinMode(MASTER_BAT, INPUT_PULLUP);
  pinMode(MAGNETO_OFF, INPUT_PULLUP);
  pinMode(MAGNETO_RIGHT, INPUT_PULLUP);
  pinMode(MAGNETO_LEFT, INPUT_PULLUP);
  pinMode(MAGNETO_BOTH, INPUT_PULLUP);
  pinMode(PARKING_BRAKES, INPUT_PULLUP);
  pinMode(STARTER, INPUT_PULLUP);
  pinMode(PITOT, INPUT_PULLUP);
  pinMode(STROBE, INPUT_PULLUP);
  pinMode(NAV, INPUT_PULLUP);
  pinMode(TAXI, INPUT_PULLUP);
  pinMode(BEACON, INPUT_PULLUP);
  pinMode(LANDING, INPUT_PULLUP);
  pinMode(PRIMER, INPUT_PULLUP);
  pinMode(LANDING, INPUT_PULLUP);
  pinMode(FUEL_PUMP, INPUT_PULLUP);
  pinMode(CARB_HEAT, INPUT_PULLUP);
  pinMode(FUEL_LEFT, INPUT_PULLUP);
  pinMode(FUEL_RIGHT, INPUT_PULLUP);
  pinMode(FUEL_BOTH, INPUT_PULLUP);
  pinMode(FUEL_OFF, INPUT_PULLUP);
  pinMode(FLAPS_0, INPUT_PULLUP);
  pinMode(FLAPS_10, INPUT_PULLUP);
  pinMode(FLAPS_20, INPUT_PULLUP);
  pinMode(FLAPS_30, INPUT_PULLUP);
  pinMode(GEAR_UP, INPUT_PULLUP);
  /* pinMode(INSTR_BRIGHT, INPUT); */

  /* Analog Pins */
  pinMode(AILERONS, INPUT);
  /* pinMode(RUDDER, INPUT); */
  pinMode(THROTTLE, INPUT);
  pinMode(MIXTURE, INPUT);

  /* Encoder */
  pinMode(pinA, INPUT_PULLUP);
  pinMode(pinB, INPUT_PULLUP);
  /*attachInterrupt(digitalPinToInterrupt(pinA), EncPinA, RISING);
	attachInterrupt(digitalPinToInterrupt(pinB), EncPinB, RISING);*/
  attachInterrupt(0, EncPinA, RISING);
  attachInterrupt(1, EncPinB, RISING);

  /* Open serial line to computer */
  Serial.begin(115200);
	}

	/* Interruption function for encoder */
	void EncPinA(){
  noInterrupts();
  elevatorRaw = PINE & 0x30;
  if(elevatorRaw == 0b00110000 && aFlag) {
	elevatorPos --;
	bFlag = 0; //reset flags for the next turn
	aFlag = 0; //reset flags for the next turn
  }
  else if (elevatorRaw == 0b00010000) {
	bFlag = 1; //signal that we're expecting pinB to signal the transition to detent from free rotation
  }
  interrupts();
	}

	/* Interruption function for encoder */
	void EncPinB(){
  noInterrupts();
  //elevatorPos = 20;
  elevatorRaw = PINE & 0x30;
  if (elevatorRaw == 0b00110000 && bFlag) {
	elevatorPos ++;
	bFlag = 0; //reset flags for the next turn
	aFlag = 0; //reset flags for the next turn
  }
  else if (elevatorRaw == 0b00100000) {
	aFlag = 1; //signal that we're expecting pinA to signal the transition to detent from free rotation
  }
  interrupts();
	}

	/* Fuel tank logic */
	void fuelTanksValue() {
  if (!digitalRead(FUEL_LEFT)) {
	fuelRight = 0;
	fuelLeft = true;
  } else if (!digitalRead(FUEL_RIGHT)) {
	fuelRight = true;
	fuelLeft = 0;
  } else if (!digitalRead(FUEL_BOTH)) {
	fuelRight = true;
	fuelLeft = true;
  } else if (!digitalRead(FUEL_OFF)) {
	fuelRight = 0;
	fuelLeft = 0;
  }
	}

	/* Magneto logic */
	void magnetosValue() {
  if (!digitalRead(MAGNETO_OFF)) {
	magnetos = 0;
  } else if (!digitalRead(MAGNETO_LEFT)) {
	magnetos = 1;
  } else if (!digitalRead(MAGNETO_RIGHT)) {
	magnetos = 2;
  } else if (!digitalRead(MAGNETO_BOTH)) {
	magnetos = 3;
  }
	}

	/* Flaps logic */
	void flapsValue() {
  if (!digitalRead(FLAPS_0)) {
	flaps = 0.0;
  } else if (!digitalRead(FLAPS_10)) {
	flaps = 0.33;
  } else if (!digitalRead(FLAPS_20)) {
	flaps = 0.66;
  } else if (!digitalRead(FLAPS_30)) {
	flaps = 1.0;
  }
	}

	/* Primer logic */
	void primerValue() {
  /* You push primer button */
  if (!digitalRead(PRIMER)) {
	/* Set lever state to true if required*/
	if (primerLeverState == false) {
	  primerLeverState = true;
	}

  }
  /* You release primer button */
  else {
	if (primerLeverState == true) {
	  primer = primer + 1;
	  primerLeverState = false;
	}
  }
  /* delay primer value for 5 seconds after starter stop.*/
  if (starterEndTimer > 0) {
	unsigned long currentMillis = millis();
	if (currentMillis - starterEndTimer > 5000) {
	  primer = 0;
	  starterEndTimer = 0;
	}
  }
	}

	/* Starter and primer value reset */
	void starterValue() {
  /* Starter is set starterState */
  if (!digitalRead(STARTER)) {
	if (starterState == false) {
	  starterState = true;
	  starterEndTimer = 0;
	}
  }
  else {
	/* Starter is stopped */
	if (starterState == true) {
	  starterState = false;
	  starterEndTimer = millis();
	}
  }
	}

	/* Main loop */
	void loop() {
  /* we read everything */
  avionics = !digitalRead(AVIONICS);
  masterAlt = !digitalRead(MASTER_ALT);
  masterBat = !digitalRead(MASTER_BAT);
  pitotHeat = !digitalRead(PITOT);
  parkingBrakes = !digitalRead(PARKING_BRAKES);
  strobeLight = !digitalRead(STROBE);
  navLight = !digitalRead(NAV);
  taxiLight = !digitalRead(TAXI);
  beaconLight = !digitalRead(BEACON);
  landingLight = !digitalRead(LANDING);
  fuelPump = !digitalRead(FUEL_PUMP);
  carbHeat = !digitalRead(CARB_HEAT);
  flapsValue();
  magnetosValue();
  fuelTanksValue();
  primerValue();
  starterValue();
  /* instrumentBrightness = (analogRead(INSTR_BRIGHT)/512.0); */
  throttle = analogRead(THROTTLE)/1024.0;
  mixture = analogRead(MIXTURE)/1024.0;
  /* ailerons smoothing */
  ailerons = 0.99 - (analogRead(AILERONS)/512.0);
  /* An example of smoothing for centering ailerons
  if (abs(ailerons) < 0.02) {
	ailerons = 0.0;
  }*/
  /* elevator smoothing */
  elevator = (30 - elevatorPos) / 60.0;
  if (abs(elevator) < 0.02) {
	  elevator = 0.0;
  }

  /* We send everything towards serial */
  Serial.print(avionics);
  Serial.print(",");
  Serial.print(masterAlt);
  Serial.print(",");
  Serial.print(masterBat);
  Serial.print(",");
  /*Serial.print(instrumentBrightness);
	Serial.print(",");*/
  Serial.print(magnetos);
  Serial.print(",");
  Serial.print(starterState);
  Serial.print(",");
  Serial.print(pitotHeat);
  Serial.print(",");
  Serial.print(parkingBrakes);
  Serial.print(",");
  Serial.print(strobeLight);
  Serial.print(",");
  Serial.print(landingLight);
  Serial.print(",");
  Serial.print(taxiLight);
  Serial.print(",");
  Serial.print(beaconLight);
  Serial.print(",");
  Serial.print(navLight);
  Serial.print(",");
  Serial.print(primerLeverState);
  Serial.print(",");
  Serial.print(primer);
  Serial.print(",");
  Serial.print(fuelPump);
  Serial.print(",");
  Serial.print(carbHeat);
  Serial.print(",");
  Serial.print(fuelLeft);
  Serial.print(",");
  Serial.print(fuelRight);
  Serial.print(",");
  Serial.print(flaps);
  Serial.print(",");
  Serial.print(gearUp);
  Serial.print(",");
  Serial.print(throttle);
  Serial.print(",");
  Serial.print(mixture);
  Serial.print(",");
  Serial.print(ailerons);
  Serial.print(",");
  Serial.print(elevator);
  Serial.print("\n");
  //delay(3050);
}

Connect Flightgear to the Arduino

You just have to launch Flightgear with the following option:

--generic=serial,in,60,/dev/ttyACM0,9600,fg_yoke_and_panel.xml

With this option we:

References

Generic parts

Electronics

Fligtgear interfacing