https://wiki.flightgear.org/w/api.php?action=feedcontributions&user=Gavino&feedformat=atom
FlightGear wiki - User contributions [en]
2024-03-28T16:53:18Z
User contributions
MediaWiki 1.39.6
https://wiki.flightgear.org/w/index.php?title=Howto:Use_Arduino_with_FlightGear&diff=92327
Howto:Use Arduino with FlightGear
2016-02-04T12:16:22Z
<p>Gavino: The baud rate was missing</p>
<hr />
<div>Thanks to 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.<br />
<br />
== About Arduino ==<br />
'''[http://www.arduino.cc/ Arduino]''' is an open-source electronics prototyping platform based on flexible, easy-to-use hardware and software. The hardware is a microcontroller designed around an 8-bit or 32-bit microcontroller, with several digital and analog {{Abbr|I/O|Input/Output}} ports. The software is the [http://arduino.cc/en/Main/Software Arduino {{Abbr|IDE|Integrated Development Environment}}].<br />
<br />
== Example 1: Controlling internal properties ==<br />
<big>By {{usr|Vaipe}}</big><br />
<br />
This example demonstrates the use of a switch and a potentiometer to control the [[Property Tree]].<br />
<br />
=== Equipment and software ===<br />
The following equipment was used for this example:<br />
* [[Changelog_3.2|FlightGear 3.2]]<br />
* [[FGRun]]<br />
* [[Cessna 172P|Cessna 172P Skyhawk]] (default aircraft) <br />
* [http://arduino.cc/en/Main/ArduinoBoardUno Arduino Uno]<br />
* Linux ([http://en.wikipedia.org/wiki/List_of_Ubuntu_releases#Ubuntu_10.04_LTS_.28Lucid_Lynx.29 Ubuntu 14.04])<br />
* Simple on/off switch<br />
* Potentiometer<br />
<br />
=== Input protocol file ===<br />
Input protocol file is used to specify how serial information is read by Flightgear. In Ubuntu protocol files are found in:<br />
<code>''/usr/share/games/flightgear/protocol''</code> directory.<br />
<br />
==== Protocol file structure ====<br />
Create <code>''controltest.xml''</code> file in your protocol folder and paste code from below to it.<br />
<syntaxhighlight land="xml"><br />
<?xml version="1.0"?><br />
<br />
<PropertyList><br />
<br />
<generic><br />
<input> <br />
<line_separator>\n</line_separator><br />
<var_separator>,</var_separator><br />
<br />
<chunk><br />
<name>Strobe</name><br />
<node>/controls/lighting/strobe</node><br />
<type>bool</type><br />
</chunk><br />
<br />
<chunk><br />
<name>Throttle</name><br />
<node>/controls/engines/engine/throttle</node><br />
<type>float</type><br />
</chunk><br />
<br />
</input><br />
</generic><br />
<br />
</PropertyList><br />
</syntaxhighlight><br />
See [[Generic protocol]] for a description of the various XML tags.<br />
<br />
=== Wiring and coding ===<br />
<br />
==== Wiring ====<br />
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.<br />
[[File:Arduino switch and potentiometer wiring.png|frame|none|Wiring schematic for connecting the potentiometer and switch to Arduino]]<br />
<br />
==== Code ====<br />
Copy this C code to Arduino IDE and send it to the Arduino Uno:<br />
<syntaxhighlight lang="c"><br />
/*<br />
FGFS Input Test<br />
Reads a digital input on pin 7, prints the result to the serial port.<br />
Reads a potentiometer input on A0 and print result to serial port.<br />
This example code is in the public domain.<br />
*/<br />
<br />
int potPin = 0; // potentiometer on A0<br />
int switchPin = 7; // switch on pin 7<br />
float potValue = 0; // float variable to store potentiometer value<br />
<br />
void setup() {<br />
Serial.begin(9600); // open serial connection<br />
pinMode(switchPin, INPUT); // pin 7 declared as input<br />
}<br />
<br />
<br />
void loop() {<br />
<br />
Serial.print(digitalRead(switchPin)); // read and print switch state<br />
Serial.print(","); // print ,<br />
potValue = analogRead(potPin); // read potentiometer and store it to potValue<br />
potValue = potValue / 1024; // divide potValue with 1024 to make it between 0 and 1<br />
PrintDouble(potValue, 2); // pass potValue to PrintDouble-function, read from below what magic happens<br />
Serial.print("\n"); // print new line<br />
delay(500); // delay only for making this guide easier to follow on serial monitor<br />
<br />
}<br />
<br />
<br />
void PrintDouble(double val, byte precision){<br />
// prints val with number of decimal places determine by precision<br />
// precision is a number from 0 to 6 indicating the desired decimial places<br />
// example: lcdPrintDouble( 3.1415, 2); // prints 3.14 (two decimal places)<br />
// From http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1207226548<br />
<br />
if(val < 0.0){<br />
Serial.print('-');<br />
val = -val;<br />
}<br />
<br />
Serial.print (int(val)); //prints the int part<br />
if( precision > 0) {<br />
Serial.print("."); // print the decimal point<br />
unsigned long frac;<br />
unsigned long mult = 1;<br />
byte padding = precision -1;<br />
while(precision--)<br />
mult *=10;<br />
<br />
if(val >= 0)<br />
frac = (val - int(val)) * mult;<br />
else<br />
frac = (int(val)- val ) * mult;<br />
unsigned long frac1 = frac;<br />
while( frac1 /= 10 )<br />
padding--;<br />
while( padding--)<br />
Serial.print("0");<br />
Serial.print(frac,DEC) ;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
==== Testing serial output ====<br />
Use Arduino IDE's serial monitor and you should see something like this:<br />
[[File:Flightgear arduino serial monitor.png|frame|none|Arduino IDE's serial monitor output]]<br />
<br />
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.<br />
<br />
{{Note|Remember to '''unplug Arduino's USB cable and plug it back'''.<br />
<br />
FlightGear will not be able to read serial without doing this!<br />
<br />
You have to do this every time after you use the Arduino IDE.}}<br />
<br />
==== Starting FlightGear ====<br />
<br />
===== Method 1: Command line =====<br />
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:<br />
<syntaxhighlight><br />
--generic=serial,in,30,/dev/ttyACM0,9600,controltest<br />
</syntaxhighlight><br />
<br />
===== Method 2: FGRun =====<br />
Alternatively, you can use FlightGear's graphical user interface (FGRun) to launch FlightGear. See the image below for the correct settings.<br />
[[File:Starting Flightgear with input options enabled.jpg|thumb|none|Starting Flightgear with FGRun, selecting input/output options]]<br />
<br />
If you don't know your correct port is , you can check it with a following command in terminal:<br />
<syntaxhighlight><br />
dmesg | tail<br />
</syntaxhighlight><br />
It should give you a message something like <code>ttyACM0: USB ACM device</code> or <code>ttyACM1: USB ACM device</code>. 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]<br />
<br />
== Example 2: Outputting properties ==<br />
<big>By {{usr|Rubdos}}</big><br />
[[File:Arduinofgfs.jpg|thumb|270px|Arduino LCD panel displaying speed, heading and altitude.]]<br />
This example uses the example using the [[Generic protocol]] and an [http://arduino.cc/en/Main/arduinoBoardMega2560 Arduino Mega 2560].<br />
Below is the protocol XML file used to control the Arduino.<br />
<syntaxhighlight lang="xml"><br />
<?xml version="1.0"?><br />
<br />
<PropertyList><br />
<br />
<generic><br />
<output><br />
<binary_mode>false</binary_mode><br />
<line_separator>newline</line_separator><br />
<var_separator>newline</var_separator><br />
<preamble></preamble><br />
<postamble></postamble><br />
<br />
<chunk><br />
<name>Altitude</name><br />
<node>/position/altitude-ft</node><br />
<type>integer</type><br />
<format>altitude=%i</format><br />
</chunk><br />
<br />
<chunk><br />
<name>RPM</name><br />
<node>/engines/engine/rpm</node><br />
<type>integer</type><br />
<format>rpm=%i</format><br />
</chunk><br />
<br />
</output><br />
<br />
<!-- <input><br />
<line_separator>newline</line_separator><br />
<var_separator>tab</var_separator><br />
<chunk><br />
</chunk><br />
</input> --><br />
<br />
</generic><br />
<br />
</PropertyList><br />
</syntaxhighlight><br />
<br />
Below is the C code used for the example, taken from https://gist.github.com/rubdos/5422870.<br />
<syntaxhighlight lang="c"><br />
//PIN 0 -> 7 has positive segment part<br />
<br />
// the setup routine runs once when you press reset:<br />
void setup() { <br />
// initialize the digital pin as an output.<br />
pinMode(2, OUTPUT);<br />
pinMode(3, OUTPUT);<br />
pinMode(4, OUTPUT); <br />
pinMode(5, OUTPUT); <br />
pinMode(6, OUTPUT); <br />
pinMode(7, OUTPUT); <br />
pinMode(8, OUTPUT); <br />
pinMode(9, OUTPUT); <br />
<br />
pinMode(49, OUTPUT); <br />
pinMode(50, OUTPUT);<br />
pinMode(51, OUTPUT);<br />
pinMode(52, OUTPUT);<br />
pinMode(53, OUTPUT);<br />
<br />
Serial.begin(9600);<br />
}<br />
<br />
void writeNumber(int nr)<br />
{<br />
if(nr == 0)<br />
{<br />
digitalWrite(2, LOW); // midden<br />
digitalWrite(3, HIGH); // lt<br />
digitalWrite(4, HIGH); // t<br />
digitalWrite(5, HIGH); // rt<br />
digitalWrite(6, HIGH); // lb<br />
digitalWrite(7, HIGH); // b<br />
digitalWrite(8, HIGH); // rb<br />
digitalWrite(9, LOW); // dot<br />
}<br />
else if(nr == 1)<br />
{<br />
digitalWrite(2, LOW); // midden<br />
digitalWrite(3, LOW); // lt<br />
digitalWrite(4, LOW); // t<br />
digitalWrite(5, HIGH); // rt<br />
digitalWrite(6, LOW); // lb<br />
digitalWrite(7, LOW); // b<br />
digitalWrite(8, HIGH); // rb<br />
digitalWrite(9, LOW); // dot<br />
}<br />
else if(nr == 2)<br />
{<br />
digitalWrite(2, HIGH); // midden<br />
digitalWrite(3, LOW); // lt<br />
digitalWrite(4, HIGH); // t<br />
digitalWrite(5, HIGH); // rt<br />
digitalWrite(6, HIGH); // lb<br />
digitalWrite(7, HIGH); // b<br />
digitalWrite(8, LOW); // rb<br />
digitalWrite(9, LOW); // dot<br />
}<br />
else if(nr == 3)<br />
{<br />
digitalWrite(2, HIGH); // midden<br />
digitalWrite(3, LOW); // lt<br />
digitalWrite(4, HIGH); // t<br />
digitalWrite(5, HIGH); // rt<br />
digitalWrite(6, LOW); // lb<br />
digitalWrite(7, HIGH); // b<br />
digitalWrite(8, HIGH); // rb<br />
digitalWrite(9, LOW); // dot<br />
}<br />
else if(nr == 4)<br />
{<br />
digitalWrite(2, HIGH); // midden<br />
digitalWrite(3, HIGH); // lt<br />
digitalWrite(4, LOW); // t<br />
digitalWrite(5, HIGH); // rt<br />
digitalWrite(6, LOW); // lb<br />
digitalWrite(7, LOW); // b<br />
digitalWrite(8, HIGH); // rb<br />
digitalWrite(9, LOW); // dot<br />
}<br />
else if(nr == 5)<br />
{<br />
digitalWrite(2, HIGH); // midden<br />
digitalWrite(3, HIGH); // lt<br />
digitalWrite(4, HIGH); // t<br />
digitalWrite(5, LOW); // rt<br />
digitalWrite(6, LOW); // lb<br />
digitalWrite(7, HIGH); // b<br />
digitalWrite(8, HIGH); // rb<br />
digitalWrite(9, LOW); // dot<br />
}<br />
else if(nr == 6)<br />
{<br />
digitalWrite(2, HIGH); // midden<br />
digitalWrite(3, HIGH); // lt<br />
digitalWrite(4, HIGH); // t<br />
digitalWrite(5, LOW); // rt<br />
digitalWrite(6, HIGH); // lb<br />
digitalWrite(7, HIGH); // b<br />
digitalWrite(8, HIGH); // rb<br />
digitalWrite(9, LOW); // dot<br />
}<br />
else if(nr == 7)<br />
{<br />
digitalWrite(2, LOW); // midden<br />
digitalWrite(3, LOW); // lt<br />
digitalWrite(4, HIGH); // t<br />
digitalWrite(5, HIGH); // rt<br />
digitalWrite(6, LOW); // lb<br />
digitalWrite(7, LOW); // b<br />
digitalWrite(8, HIGH); // rb<br />
digitalWrite(9, LOW); // dot<br />
}<br />
else if(nr == 8)<br />
{<br />
digitalWrite(2, HIGH); // midden<br />
digitalWrite(3, HIGH); // lt<br />
digitalWrite(4, HIGH); // t<br />
digitalWrite(5, HIGH); // rt<br />
digitalWrite(6, HIGH); // lb<br />
digitalWrite(7, HIGH); // b<br />
digitalWrite(8, HIGH); // rb<br />
digitalWrite(9, LOW); // dot<br />
}<br />
else if(nr == 9)<br />
{<br />
digitalWrite(2, HIGH); // midden<br />
digitalWrite(3, HIGH); // lt<br />
digitalWrite(4, HIGH); // t<br />
digitalWrite(5, HIGH); // rt<br />
digitalWrite(6, LOW); // lb<br />
digitalWrite(7, HIGH); // b<br />
digitalWrite(8, HIGH); // rb<br />
digitalWrite(9, LOW); // dot<br />
}<br />
else<br />
{<br />
digitalWrite(2, LOW); // midden<br />
digitalWrite(3, LOW); // lt<br />
digitalWrite(4, LOW); // t<br />
digitalWrite(5, LOW); // rt<br />
digitalWrite(6, LOW); // lb<br />
digitalWrite(7, LOW); // b<br />
digitalWrite(8, LOW); // rb<br />
digitalWrite(9, LOW); // dot<br />
}<br />
}<br />
<br />
// the loop routine runs over and over again forever<br />
long number = 0;<br />
int decimals[5] = {0, 0, 0, 0, 0};<br />
<br />
void loop() {<br />
for(int i = 49; i < 54; i++)<br />
{<br />
// Disable the incorrect segment displays<br />
if(i == 49)<br />
{<br />
digitalWrite(53, HIGH);<br />
}<br />
else<br />
{<br />
digitalWrite(i - 1, HIGH);<br />
}<br />
digitalWrite(i, LOW);<br />
<br />
// Enable the segments<br />
writeNumber(decimals[4 - (i - 49)]);<br />
delay(1);<br />
}<br />
if(Serial.available() > 14) // Wait until there are two bytes available. Then read them out.<br />
{<br />
String command;<br />
String var;<br />
char lastchar;<br />
<br />
while(lastchar != '=')<br />
{<br />
lastchar = Serial.read();<br />
if(lastchar != '=')<br />
{<br />
command += lastchar;<br />
}<br />
}<br />
while(lastchar != '\n')<br />
{<br />
lastchar = Serial.read();<br />
if(lastchar != '\n')<br />
{<br />
var += lastchar;<br />
}<br />
}<br />
<br />
if(command == "altitude" )<br />
{<br />
char buf[50];<br />
var.toCharArray(buf, 50);<br />
number = atol(buf);<br />
}<br />
<br />
/*if(number == 10000)<br />
{<br />
number = 0;<br />
}*/<br />
<br />
long currentnumber = number;<br />
<br />
int remainder = currentnumber % 10;<br />
currentnumber = (currentnumber - remainder) / 10;<br />
decimals[4] = remainder;<br />
<br />
remainder = currentnumber % 10;<br />
currentnumber = (currentnumber - remainder) / 10;<br />
decimals[3] = remainder;<br />
<br />
remainder = currentnumber % 10;<br />
currentnumber = (currentnumber - remainder) / 10;<br />
decimals[2] = remainder;<br />
<br />
remainder = currentnumber % 10;<br />
currentnumber = (currentnumber - remainder) / 10;<br />
decimals[1] = remainder;<br />
<br />
remainder = currentnumber % 10;<br />
currentnumber = (currentnumber - remainder) / 10;<br />
decimals[0] = remainder;<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
The hardware used was five seven-segment displays, multiplexed straight on the Arduino device. Ideally, you'd rather use some 74HC595 or other shift register chips to drive them, to unload the Arduino and have more current.<br />
<br />
Below is a demo uploaded to YouTube, with voiceover in which the display shows the RPM of [[Robin DR400]]'s single engine.<br />
{{#ev:youtube|lVtV9-CgqBo}}<br />
<br />
== Related content ==<br />
* [[Input device]]<br />
<br />
== External links ==<br />
* [http://arduino.cc/ Official Arduino website]<br />
* [http://playground.arduino.cc/Main/FlightGear FlightGear Serial Communications with Arduino] (tutorial)<br />
* [http://forum.flightgear.org/viewtopic.php?f=18&t=11126 Arduino LCD and FlightGear] (FlightGear forum)<br />
* [https://sites.google.com/site/flightgeararduinoandlinux/ Flightgear, Arduino and Linux] (potentiometer and switch interfacing tutorial)<br />
<br />
[[Category:Cockpit building]]<br />
[[Category:Hardware]]</div>
Gavino