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 wass 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, 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 it.

Some pictures

Front panel and Yoke
Front Panel
Side view of the box
Yoke and Panel box
Inside mechanism and cabling
Inside view

Rudder in middle position
Movement of rudder: middle
Rudder in full pushed position
Movement of rudder: full push
Rudder in fully pulled position
Movement of rudder: full pull
Rudder mechanism
Rudder mechanism
Ailerons mechanism
Ailerons mechanism

Cabling to the arduino Cabling on the left Cabling on the right

What is emulated?

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

Component Number Manufacturer Datasheet Price (Total)
Mechanics
MDF 810x405x9mm 1 China Datasheet 4.1€
MDF 1150x610x9mm 1 China - 8.5€
Steel corner braces 10 ? Datasheet 3.9€
Angle bracket W40mmx60mmx60mm 1 Simpson Strong-Tie Datasheet 1.05€
Nail plate NP15/40/120 1 Simpson Strong-Tie Datasheet 1.05€
Table chrome leg L250mm, Ø30mm 1 ? Datasheet 4.61€
Plummer block bearing UCP206 Ø30mm 1 TRI Datasheet 9.96€
Ball bearing drawer slide L=251mm 2 Handix Datasheet 3.56€
Rack CMLN1-150 1 TRI Datasheet 4.32€
Pinion 15 tooth EM1015 1 TRI Datasheet 1.2€
Electronics
Rocker Switch R5ABLKBLKFF0 2 E-Switch Datasheet 2.54€
Rocker Switch R4ABLKREDIF0 2 E-Switch Datasheet 1.7€
Rocker Switch R4FBLKBLKEFO 1 E-Switch Datasheet 1.0€
5 positions 30° Rotary Switch A10505RNZQ 1 C&K Datasheet 4.44€
4 positions 30° Rotary Switch A10405RNZQ 1 C&K Datasheet 4.21€
4 positions 90° Rotary Switch A12405MNZQ 1 C&K Datasheet 4.17€
Knob 450-SL2612 2 Eagle Plastic Devices Datasheet 2.46€
Knob MPKES70B1/4 3 Apem Datasheet 3.36€
Toggle Switches 2FA53-73/.187 9 Carling Datasheet 15.84€
Rotary Potentiometer PDB181-E420K-502B 1 Bourns Datasheet 0.935€
Rotary Encoder PEC11R-4030F-N0024 1 Bourns Datasheet 1.14€
Linear Potentiometer PTB0143-2010BPB103 2 Bourns Datasheet 8.22€
Arduino Mega 2560 1 Arduino LLC Datasheet 31.57€
Connectors and cables
Terminal Tabs Connectors 94512-0101 8 Molex Datasheet 0.656€
Terminal Tabs Connectors 35718-1010 18 Molex Datasheet 1.64€
Crimp Male Terminal (x100) 70021 16-02-0107 1 Molex Datasheet 4.5€
Crimp Female Terminal (x100) 70058 16-02-0086 1 Molex Datasheet 5.2€
Crimp Housing 70066 50-57-9002 11 Molex Datasheet 3.069€
Crimp Housing 70066 50-57-9003 2 Molex Datasheet 0.74€
Crimp Housing 70066 50-57-9004 2 Molex Datasheet 0.74€
Crimp Housing 70067 50-57-9008 5 Molex Datasheet 2.305€
22 AWG Black cable 8m Alphawire Datasheet 2.0€
22 AWG Blue cable 8m Alphawire Datasheet 2.0€
22 AWG Red cable 8m Alphawire Datasheet 2.0€
22 AWG Yellow cable 8m Alphawire Datasheet 2.0€

Required tools

(WIP)

Tool Image Used for
Metallic Framing Square Measurements
Ruler Measurements
Pen Measurements
Hand saw Wood cutting
Coping saw Wood cutting
Drill Drilling
Drill bits Ø6/8/10/12/32 Wood cutting/Drilling
Box Cutter Wood Cutting and adjustments
File Wood cutting and adjustments
Rasp Wood cutting and adjustments
Screwdriver Bolt fixing
Sockets Bolt fixing
Pliers crimp Cabling

Building guide

TODO

Assembly guide

TODO

Calculations

Keyboard precision in Flightgear

  • Throttle: 30 discrete values with keyboard (PgUp).
  • Mixture: 20 discrete values with mouse.
  • Elevator: 20 + 20 = 40 discrete positions with keyboard (Up/Down keys).
  • Ailerons: 20 + 20 = 40 discrete positions with keyboard (Left/Right keys).

Rack and pinion

  • z: teeth number.
  • mod: module.

Module 1 means 3.14mm per tooth.

  • 150mm long rack => 48 teeth for a whole turn.
  • 125mm long rack => 40 teeth for a whole turn.
  • 110mm long rack => 35 teeth for a whole turn.
  • 100mm long rack => 32 teeth for a whole turn.

Encoder precision

For a 24 pulses per rotation (ppr).

Rack Lenght z for 1 turn z for pinion number of turns Precision
110mm 35 10 3.5 84 levels
100mm 32 10 3.2 77 levels
150mm 48 15 3.2 77 levels
125mm 40 15 2.67 64 levels
110mm 35 15 2.33 56 levels
100mm 32 15 2.13 51 levels
150mm 48 16 3.0 72 levels
125mm 40 16 2.5 60 levels
100mm 32 16 2.0 48 levels
150mm 48 21 2.28 54 levels
125mm 40 21 1.9 45 levels
100mm 32 21 1.52 36 levels

Yoke course

  • 30mm clearance full pushed.
  • 10mm of panel thickness.
  • 30mm clearance for panel switches.
  • 10mm of bearing support board.
  • 190mm of course from inner bearing.
  • MAX course: 110mm
  • Aimed course: 100mm.

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

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:

  • read all the values from the physical switches and components.
  • transform them to adjusted values for Flightgear.
  • transfert by serial line the values, conforming to our generic protocol specifications.

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

  • The header file yoke_and_panel.h.
  • The real code file: yoke_and_panel.cpp.
  • The Makefile: Makefile.

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:

  • tell to Flightgear to open the serial port: serial.
  • use to listen something: in.
  • the device will be read at the frequency of 30Hz (30 times per second) in Flightgear.
  • the system device is /dev/ttyACM0 which is our Arduino serial port.
  • Speed for serial is 9600 bauds.
  • We use the fg_yoke_and_panel.xml for generic protocol.

References

Generic parts

Electronics

Fligtgear interfacing