330
edits
m (→External links) |
(Add updated changes and some potential pitfalls) |
||
(15 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
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. | |||
== About Arduino == | |||
'''[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}}]. | |||
== 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) input | |||
const int stickyio = A1; //Define stick elevator (y) input | |||
float stickx = 0; //Start aileron (x) central | |||
float 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 === | |||
The following equipment was used for this example: | |||
* [[Changelog_3.2|FlightGear 3.2]] | |||
* [[FGRun]] | |||
* [[Cessna 172P|Cessna 172P Skyhawk]] (default aircraft) | |||
* [http://arduino.cc/en/Main/ArduinoBoardUno Arduino Uno] | |||
* Linux ([http://en.wikipedia.org/wiki/List_of_Ubuntu_releases#Ubuntu_10.04_LTS_.28Lucid_Lynx.29 Ubuntu 14.04]) | |||
* Simple on/off switch | |||
* Potentiometer | |||
=== Input protocol file === | |||
Input protocol file is used to specify how serial information is read by Flightgear. In Ubuntu protocol files are found in: | |||
<code>''/usr/share/games/flightgear/protocol''</code> directory. | |||
==== Protocol file structure ==== | |||
Create <code>''controltest.xml''</code> file in your protocol folder and paste code from below to it. | |||
<syntaxhighlight land="xml"> | |||
<?xml version="1.0"?> | |||
<PropertyList> | |||
<generic> | |||
<input> | |||
<line_separator>\n</line_separator> | |||
<var_separator>,</var_separator> | |||
<chunk> | |||
<name>Strobe</name> | |||
<node>/controls/lighting/strobe</node> | |||
<type>bool</type> | |||
</chunk> | |||
<chunk> | |||
<name>Throttle</name> | |||
<node>/controls/engines/engine/throttle</node> | |||
<type>float</type> | |||
</chunk> | |||
</input> | |||
</generic> | |||
</PropertyList> | |||
</syntaxhighlight> | |||
See [[Generic protocol]] for a description of the various XML tags. | |||
=== Wiring and coding === | |||
==== 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"> | |||
/* | |||
FGFS Input Test | |||
Reads a digital input on pin 7, prints the result to the serial port. | |||
Reads a potentiometer input on A0 and print result to serial port. | |||
This example code is in the public domain. | |||
*/ | |||
int potPin = 0; // potentiometer on A0 | |||
int switchPin = 7; // switch on pin 7 | |||
float potValue = 0; // float variable to store potentiometer value | |||
void setup() { | |||
Serial.begin(9600); // open serial connection | |||
pinMode(switchPin, INPUT); // pin 7 declared as input | |||
} | |||
void loop() { | |||
Serial.print(digitalRead(switchPin)); // read and print switch state | |||
Serial.print(","); // print , | |||
potValue = analogRead(potPin); // read potentiometer and store it to potValue | |||
potValue = potValue / 1024; // divide potValue with 1024 to make it between 0 and 1 | |||
PrintDouble(potValue, 2); // pass potValue to PrintDouble-function, read from below what magic happens | |||
Serial.print("\n"); // print new line | |||
delay(500); // delay only for making this guide easier to follow on serial monitor | |||
} | |||
void PrintDouble(double val, byte precision){ | |||
// prints val with number of decimal places determine by precision | |||
// precision is a number from 0 to 6 indicating the desired decimial places | |||
// example: lcdPrintDouble( 3.1415, 2); // prints 3.14 (two decimal places) | |||
// From http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1207226548 | |||
if(val < 0.0){ | |||
Serial.print('-'); | |||
val = -val; | |||
} | |||
Serial.print (int(val)); //prints the int part | |||
if( precision > 0) { | |||
Serial.print("."); // print the decimal point | |||
unsigned long frac; | |||
unsigned long mult = 1; | |||
byte padding = precision -1; | |||
while(precision--) | |||
mult *=10; | |||
if(val >= 0) | |||
frac = (val - int(val)) * mult; | |||
else | |||
frac = (int(val)- val ) * mult; | |||
unsigned long frac1 = frac; | |||
while( frac1 /= 10 ) | |||
padding--; | |||
while( padding--) | |||
Serial.print("0"); | |||
Serial.print(frac,DEC) ; | |||
} | |||
} | |||
</syntaxhighlight> | |||
==== Testing serial output ==== | |||
Use Arduino IDE's serial monitor and you should see something like this: | |||
[[File:Flightgear arduino serial monitor.png|frame|none|Arduino 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. | |||
{{Note|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.}} | |||
{{Note|The above note may not be relevant to newer versions of the Arduino IDE software.}} | |||
==== Starting FlightGear ==== | |||
===== 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 (FGRun) to launch FlightGear. See the image below for the correct settings. | |||
[[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 | |||
establish a connection to FlightGear.}} | |||
== Example 3: Outputting properties == | |||
<big>By {{usr|Rubdos}}</big> | |||
[[File:Arduinofgfs.jpg|thumb|270px|Arduino LCD panel displaying speed, heading and altitude.]] | [[File:Arduinofgfs.jpg|thumb|270px|Arduino LCD panel displaying speed, heading and altitude.]] | ||
This example uses the example using the [[Generic protocol]] and an [http://arduino.cc/en/Main/arduinoBoardMega2560 Arduino Mega 2560]. | |||
Below is the protocol XML file used to control the Arduino. | |||
<syntaxhighlight lang="xml"> | |||
<?xml version="1.0"?> | |||
<PropertyList> | |||
<generic> | |||
<output> | |||
<binary_mode>false</binary_mode> | |||
<line_separator>newline</line_separator> | |||
<var_separator>newline</var_separator> | |||
<preamble></preamble> | |||
<postamble></postamble> | |||
<chunk> | |||
<name>Altitude</name> | |||
<node>/position/altitude-ft</node> | |||
<type>integer</type> | |||
<format>altitude=%i</format> | |||
</chunk> | |||
<chunk> | |||
<name>RPM</name> | |||
<node>/engines/engine/rpm</node> | |||
<type>integer</type> | |||
<format>rpm=%i</format> | |||
</chunk> | |||
</output> | |||
<!-- <input> | |||
<line_separator>newline</line_separator> | |||
<var_separator>tab</var_separator> | |||
<chunk> | |||
</chunk> | |||
</input> --> | |||
</generic> | |||
</PropertyList> | |||
</syntaxhighlight> | |||
Below 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 forever | |||
long 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, 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. | |||
The | |||
Below is a demo uploaded to YouTube, with voiceover in which the display shows the RPM of [[Robin DR400]]'s single engine. | |||
{{#ev:youtube|lVtV9-CgqBo}} | |||
== Related content == | == Related content == | ||
Line 47: | Line 540: | ||
== External links == | == External links == | ||
* [http://arduino.cc/ Official website] | * [http://arduino.cc/ Official Arduino website] | ||
* [http://playground.arduino.cc/Main/FlightGear FlightGear Serial Communications with Arduino] (tutorial) | * [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) | * [http://forum.flightgear.org/viewtopic.php?f=18&t=11126 Arduino LCD and FlightGear] (FlightGear forum) | ||
* [https://sites.google.com/site/flightgeararduinoandlinux/ Flightgear, Arduino and Linux] (potentiometer and switch interfacing tutorial | * [https://sites.google.com/site/flightgeararduinoandlinux/ Flightgear, Arduino and Linux] (potentiometer and switch interfacing tutorial) | ||
[[Category:Cockpit building]] | [[Category:Cockpit building]] | ||
[[Category:Hardware]] | [[Category:Hardware]] |
edits