Changes

Howto:Use Arduino with FlightGear

9,195 bytes added, 16:24, 17 June 2019
Add updated changes and some potential pitfalls
Thanks to [[FlightGear|FlightGear's]] [[generic protocol]], [[:Category:Hardware|hardware ]] can easily interface with [[FlightGear]]. This hardware can be used to improve the immersion and/or realism of the simulation. Arduino is no exception.
== About Arduino ==
'''[http://www.arduino.cc/ Arduino]''' is an open-source electronics prototyping platform based on flexible, easy-to-use [[:Category:Hardware|hardware]] (consisting of and software. The hardware is a board microcontroller designed around an 8-bit or a 32-bit microcontroller) , with several digital and analog {{Abbr|I/O|Input/Output}} ports. The software is the [http://arduino.cc/en/mainMain/software Software Arduino {{Abbr|IDE|Integrated Development Environment}}]).
== Controlling Flightgear Example 1: 2-axis joystic ==<big>By ScottBouch</big> This example demonstrates use of two potentiometers (2-axis joystic) with a simple calibration in arduino code. Example is done with Linux Mint. To see more detailed version of this quide go to [http://www.scottbouch.com/flightgear-sim-arduino-serial-hardware-2-axis-potentiometer-joystick.html 2-Axis Potentiometer Joystick:Integration With Flightgear Flight Sim]. === Wiring ===Connect 5V to other terminal of potentiometers and 0V to other terminal. Connect potentiometers wiper terminals to Arduino boards A0 and A1. === Arduino code ===<syntaxhighlight lang="c">/*Flightgear hardware integration 01: Stick X and Y only so far. Scott Bouchard UK www.scottbouch.com 14-06-2017*/ const int stickxio = A0; //Define stick aileron (x) inputconst int stickyio = A1; //Define stick elevator (y) input float stickx = 0; //Start aileron (x) centralfloat sticky = 0; //Start elevator (y) central void setup() { Serial.begin(9600); //Open up serial communication to PC} void loop() { stickx = (analogRead(stickxio)/512.0)-0.99; //Calibration span and offset sticky = (analogRead(stickyio)/512.0)-0.99; //Calibration span and offset  Serial.print(stickx); //Send aileron position Serial.print(","); //Variable (var) separator Serial.print(sticky); //Send elevator position Serial.print("\n"); //Line separator }</syntaxhighlight> === Calibration ===Use Arduino serial monitor to see that serial data acquired from Arduino board is between -1.00...1.00 when potentiometers are rotated. Potentiometers middle position should send 0.00. If potentiometers are not giving good readings, modify Arduino code "Calibration span and offset" row to fix it. === Flightgear protocol code ===Create a file called hardware.xml to /usr/share/games/flightgear/Protocol directory and paste following lines to it: <syntaxhighlight lang="xml"><?xml version="1.0"?> <PropertyList>  <generic>  <input> <line_separator>\n</line_separator> <var_separator>,</var_separator>  <chunk> <name>aileron</name> <type>float</type> <node>/controls/flight/aileron</node> </chunk>  <chunk> <name>elevator</name> <type>float</type> <node>/controls/flight/elevator</node> </chunk>  </input>  </generic> </PropertyList></syntaxhighlight> === Make Flightgear to read serial data ===Find port where Arduino is connected. Look from Arduino IDE Tools... Serial Port... Should be something like ttyACM. (Note: Scott Bouch tutorial uses FGRUN which is not used anymore) Start Flightgear and paste following code to Settings... Additional settings... when starting Flightgear. Change serial port to correct port name. <syntaxhighlight>--generic=serial,in,30,/dev/ttyACM0,9600,hardware.xml</syntaxhighlight> == Example 2: Controlling internal properties ==<big>By {{usr|Vaipe}}</big> This example demonstrates the use of a switch and a potentiometer to control the [[Property Tree]].
=== Equipment and software ===
This example uses the The following components and softwareequipment was used for this example:* [[Changelog_3.2|FlightGear 3.2]] or higher* [[FlightGear Launch ControlFGRun]]* [[Cessna 172P|Cessna 172P Skyhawk]] (or FGRundefault aircraft) * [http://arduino.cc/en/Main/ArduinoBoardUno Arduino UNOUno]* Linux ([http://en.wikipedia.org/wiki/List_of_Ubuntu_releases#Ubuntu_10.04_LTS_.28Lucid_Lynx.29 Ubuntu 14.04])* OnSimple on/off switch
* Potentiometer
* [[Cessna 172P|Cessna 172P Skyhawk]] (default aircraft)
=== Input protocol file ===
==== Wiring ====
A potentiometer is connected to Arduinos ground and +5 volts. The potentiometer's middle connector is connected to A0 analoq input. Switch is connected to ground with 10 kOhms pull-down resistor and +5 and digital pin 7. The diagram below illustrates the setup.
[[File:Arduino switch and potentiometer wiring.png|frame|none|Wiring schematic for connecting the potentiometer and switch to Arduino]]
==== Code ====
Copy this C code to Arduino IDE and send it to the Arduino Uno:
<syntaxhighlight lang="c">
/*
==== Testing serial output ====
Use Arduino IDEs IDE's serial monitor and you should see something like this:[[File:Flightgear arduino serial monitor.png|frame|none|Arduino IDEs IDE's serial monitor output]]
The first number is switch data, so it's either 0 (switch off) or 1 (switch on). After the "," mark is our throttle data. First it's 0.00, which meaning idle throttle and then potentiometer is gradually turned until it reaches 0.99.
{{tipNote|Remember to '''unplug Arduino's USB cable and plug it back'''.
FlightGear will not be able to read serial without doing this!
You have to do this every time after you use the Arduino IDE.}}
==== Start FlightGear ====Flightgear needs to be started with a correct command line option for it to {{Note|The above note may not be able relevant to read serial connectionnewer versions of the Arduino IDE software. This example uses following option:}}
--generic=serial,in,30,/dev/ttyACM0,controltest=== Starting FlightGear ====
If you like===== Method 1: Command line =====FlightGear needs to be started with a correct command line option for it to be able to read serial connection. This example uses following option:<syntaxhighlight>--generic=serial,in,30,/dev/ttyACM0,9600,controltest</syntaxhighlight> ===== Method 2: FGRun =====Alternatively, you can use FlightGear's graphical user interface, [[FlightGear Launch Control]] (aka FGRun), to launch FlightgearFlightGear. Select See the image below for the correct settings from Advanced Option tab. [[File:Starting Flightgear with input options enabled.jpg|thumb|none|Starting Flightgear with FGRun, selecting input/output options]] If you don't know your correct port is , you can check it with a following command in terminal:<syntaxhighlight>dmesg | tail</syntaxhighlight>It should give you a message something like <code>ttyACM0: USB ACM device</code> or <code>ttyACM1: USB ACM device</code>.  {{Note|This command gives you the last event in the stack, so you need to make sure you plug in or unplug your Arduino to the serial port immediately prior to running the command.}} That is your port. Finally, save setting by clicking "OK" and click "Run" to start FlightGear. For a more detailed guide, see [https://sites.google.com/site/flightgeararduinoandlinux/home Flightgear, Arduino and Linux] {{Note|In some installations you need set permission for $user to the groups tty and dialout or the Arduino will fail to
If you don't know your correct port, you can check it with establish a following command in terminal: dmesg | tail. It should give you a message something like: "ttyACM0: USB ACM device" or "ttyACM1: USB ACM device". That's your port. Finally save setting by clicking 'OK' and click 'Run' connection to start flightgear. For a more detailed guide, see [https://sites.googleFlightGear.com/site/flightgeararduinoandlinux/home Flightgear, Arduino and Linux]}}
== Example 3: Outputting properties ==
<big>By {{usr|Rubdos}}</big>
[[File:Arduinofgfs.jpg|thumb|270px|Arduino LCD panel displaying speed, heading and altitude.]]
== Example =={{usr|Rubdos}} (Ruben De Smet) has built an This example uses the example using the [[generic Generic protocol]] and an [http://arduino.cc/en/Main/arduinoBoardMega2560 Arduino Mega 2560].The code Below is the protocol XML file used to control the Arduino with generic protocol was:.
<syntaxhighlight lang="xml">
<?xml version="1.0"?>
</PropertyList>
</syntaxhighlight>
It is a simple plaintext protocol, which can easily be parsed by an Arduino. The code used on the Arduino is available on github as a gist: [https://gist.github.com/rubdos/5422870]
As hardwareBelow is the C code used for the example, taken from https://gist.github.com/rubdos/5422870.<syntaxhighlight lang="c">//PIN 0 -> 7 has positive segment part // the setup routine runs once when you press reset:void setup() { // initialize the digital pin as an output. pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); pinMode(6, OUTPUT); pinMode(7, OUTPUT); pinMode(8, OUTPUT); pinMode(9, OUTPUT);   pinMode(49, OUTPUT); pinMode(50, OUTPUT); pinMode(51, OUTPUT); pinMode(52, OUTPUT); pinMode(53, OUTPUT); Serial.begin(9600);} void writeNumber(int nr){ if(nr == 0) { digitalWrite(2, LOW); // midden digitalWrite(3, HIGH); // lt digitalWrite(4, HIGH); // t digitalWrite(5, HIGH); // rt digitalWrite(6, HIGH); // lb digitalWrite(7, HIGH); // b digitalWrite(8, HIGH); // rb digitalWrite(9, LOW); // dot } else if(nr == 1) { digitalWrite(2, LOW); // midden digitalWrite(3, LOW); // lt digitalWrite(4, LOW); // t digitalWrite(5, HIGH); // rt digitalWrite(6, LOW); // lb digitalWrite(7, LOW); // b digitalWrite(8, HIGH); // rb digitalWrite(9, LOW); // dot } else if(nr == 2) { digitalWrite(2, HIGH); // midden digitalWrite(3, LOW); // lt digitalWrite(4, HIGH); // t digitalWrite(5, HIGH); // rt digitalWrite(6, HIGH); // lb digitalWrite(7, HIGH); // b digitalWrite(8, LOW); // rb digitalWrite(9, LOW); // dot } else if(nr == 3) { digitalWrite(2, HIGH); // midden digitalWrite(3, LOW); // lt digitalWrite(4, HIGH); // t digitalWrite(5, HIGH); // rt digitalWrite(6, LOW); // lb digitalWrite(7, HIGH); // b digitalWrite(8, HIGH); // rb digitalWrite(9, LOW); // dot } else if(nr == 4) { digitalWrite(2, HIGH); // midden digitalWrite(3, HIGH); // lt digitalWrite(4, LOW); // t digitalWrite(5, HIGH); // rt digitalWrite(6, LOW); // lb digitalWrite(7, LOW); // b digitalWrite(8, HIGH); // rb digitalWrite(9, LOW); // dot } else if(nr == 5) { digitalWrite(2, HIGH); // midden digitalWrite(3, HIGH); // lt digitalWrite(4, HIGH); // t digitalWrite(5, LOW); // rt digitalWrite(6, LOW); // lb digitalWrite(7, HIGH); // b digitalWrite(8, HIGH); // rb digitalWrite(9, LOW); // dot } else if(nr == 6) { digitalWrite(2, HIGH); // midden digitalWrite(3, HIGH); // lt digitalWrite(4, HIGH); // t digitalWrite(5, LOW); // rt digitalWrite(6, HIGH); // lb digitalWrite(7, HIGH); // b digitalWrite(8, HIGH); // rb digitalWrite(9, LOW); // dot } else if(nr == 7) { digitalWrite(2, LOW); // midden digitalWrite(3, LOW); // lt digitalWrite(4, HIGH); // t digitalWrite(5, HIGH); // rt digitalWrite(6, LOW); // lb digitalWrite(7, LOW); // b digitalWrite(8, HIGH); // rb digitalWrite(9, LOW); // dot } else if(nr == 8) { digitalWrite(2, HIGH); // midden digitalWrite(3, HIGH); // lt digitalWrite(4, HIGH); // t digitalWrite(5, HIGH); // rt digitalWrite(6, HIGH); // lb digitalWrite(7, HIGH); // b digitalWrite(8, HIGH); // rb digitalWrite(9, LOW); // dot } else if(nr == 9) { digitalWrite(2, HIGH); // midden digitalWrite(3, HIGH); // lt digitalWrite(4, HIGH); // t digitalWrite(5, HIGH); // rt digitalWrite(6, LOW); // lb digitalWrite(7, HIGH); // b digitalWrite(8, HIGH); // rb digitalWrite(9, LOW); // dot } else { digitalWrite(2, LOW); // midden digitalWrite(3, LOW); // lt digitalWrite(4, LOW); // t digitalWrite(5, LOW); // rt digitalWrite(6, LOW); // lb digitalWrite(7, LOW); // b digitalWrite(8, LOW); // rb digitalWrite(9, LOW); // dot }} // the loop routine runs over and over again foreverlong number = 0;int decimals[5] = {0, 0, 0, 0, 0}; void loop() { for(int i = 49; i < 54; i++) { // Disable the incorrect segment displays if(i == 49) { digitalWrite(53, HIGH); } else { digitalWrite(i - 1, HIGH); } digitalWrite(i, LOW); // Enable the segments writeNumber(decimals[4 - (i - 49)]); delay(1); } if(Serial.available() > 14) // Wait until there are two bytes available. Then read them out. { String command; String var; char lastchar;  while(lastchar != '=') { lastchar = Serial.read(); if(lastchar != '=') { command += lastchar; } } while(lastchar != '\n') { lastchar = Serial.read(); if(lastchar != '\n') { var += lastchar; } } if(command == "altitude" ) { char buf[50]; var.toCharArray(buf, 50); number = atol(buf); } /*if(number == 10000) { number = 0; }*/ long currentnumber = number; int remainder = currentnumber % 10; currentnumber = (currentnumber - remainder) / 10; decimals[4] = remainder; remainder = currentnumber % 10; currentnumber = (currentnumber - remainder) / 10; decimals[3] = remainder; remainder = currentnumber % 10; currentnumber = (currentnumber - remainder) / 10; decimals[2] = remainder; remainder = currentnumber % 10; currentnumber = (currentnumber - remainder) / 10; decimals[1] = remainder; remainder = currentnumber % 10; currentnumber = (currentnumber - remainder) / 10; decimals[0] = remainder; }}</syntaxhighlight> The hardware used was five seven -segment displays were used, multiplexed straight on the Arduino device. In production Ideally, you'd rather use some 74HC595 or other shift register chips to drive them, to unload the Arduino and have more current.A demo Below is a demo uploaded to youtubeYouTube, with voiceover in which the display shows the RPM of the first engine of (the single engine) [[Robin DR400]]: [https://www's single engine.{{#ev:youtube.com/watch?v=|lVtV9-CgqBo]}}
== Related content ==
== External links ==
* [http://arduino.cc/ Official Arduino website]
* [http://playground.arduino.cc/Main/FlightGear FlightGear Serial Communications with Arduino] (tutorial)
* [http://forum.flightgear.org/viewtopic.php?f=18&t=11126 Arduino LCD and FlightGear] (FlightGear forum)
255
edits