I like flight simulators, but I’m not very good at them. What I need is a panic button that puts me at a safe altitude for recovery. Fortunately the flight simulator I’m playing right now, FlightGear, has a way to get and set internal properties over a socket interface. There are some super big problems I ran into that aren’t well documented (or documented at all) in FlightGear’s wiki pages on the subject, and I go over those at the end.

Here is how I used my Arduino Uno to create a panic button that immediately sets my altitude to 9000 feet (there’s a video of it in action at the bottom of this post).

For a quick crash course in FlightGear’s property tree, start FlightGear with the “–httpd=5480” option and point a web browser (on the same machine) to http://localhost:5480. You can click through all the properties, and also set them right in the browser. Navigate to /position/altitude-ft and enter in 9000 (and click “submit”). This is pretty much what we’re going to do with the button, but instead of using the httpd interface we’ll be doing it over a network socket.

First thing is to create an XML file defining what properties we want exposed for manipulation. There’s a “generic” protocol that FlightGear uses for this. You can see an example near the bottom of http://wiki.flightgear.org/Property_Tree/Sockets. Here’s what mine looks like for the panic button:

<?xml version="1.0"?> <PropertyList> <generic> <input> <line_separator>newline</line_separator> <var_separator>tab</var_separator> <chunk> <node>/position/altitude-ft</node> <name>altitude</name> <type>int</type> <format>%i</format> </chunk> </input> </generic> </PropertyList>

Call it “setaltitude.xml” and put it in the FlightGear\Data\Protocol directory.

Here’s the Arduino code for handling the button press. It’s not all that interesting – it just detects the button press and sends a serial message. The delay is to prevent button bounce from generating a ton of serial messages.

const int buttonPin = 2; int buttonState = 0; void setup() { pinMode(buttonPin, INPUT); Serial.begin(9600); } void loop() { buttonState = digitalRead(buttonPin); if (buttonState == LOW) { Serial.print("Pressed

"); delay(500); } }

Here is a small Python program that acts as the middle-man between the Arduino and FlightGear. It intercepts the serial message and then sends the desired altitude to FlightGear over a socket.

from serial import Serial from socket import * ser = Serial('/dev/cu.usbmodemfd121', 9600) s = socket(AF_INET, SOCK_STREAM) s.connect(('192.168.1.5', 5500)) while(1): if (ser.inWaiting() > 0): serialRead = ser.readline() print "Read: " + serialRead s.sendall('9000

')

Before I go over tying it all together I want to lay out two problems I had.

1) The XML file lets you define the properties you want to set, and the type of data (integer, float, string) that it is. I thought that this meant you needed to deliver the data in that way, too. I spent a lot of time getting erratic behavior from FlightGear because I was packing the altitude as binary data before sending it across. Regardless of the data type described in the XML file you need to send the data as a simple string terminated by the line_ separator defined.

2) I had assumed that FlightGear always acted like the server when the socket interface was enabled. This is incorrect (and again… not documented as far as I can tell). If you’ve set FlightGear’s socket interface as input you need to write the program delivering the data as the client. If you’ve set FlightGear’s socket interface as the output, you need to write your data receiving program as the server. Since I’m setting the socket interface as an input I have written my Python program as the client and it MUST be run after starting FlightGear, or you’ll get an error. I have no idea what the behavior is if you set the socket to be bi-directional.

To tie it all together, start FlightGear with the socket interface enabled and set to use the XML file as a generic description of what we want to send to FlightGear. Then start the Python program. It will sit and wait for a serial command from the Arduino and then send FlightGear the altitude. I set the rate at 5 Hz since I’m not really sending a lot of data rapidly.

This is what my settings (in Windows) looks like for FlightGear.

Here’s the button in action.

I’ve already gone the next step and interfaced a potentiometer for controlling the rudder. I’ll go over that in a future post, but I want to mention it now because I ran into bit of a problem. It was my intention to add this rudder control to the button program, but I discovered that if you have two property inputs defined in the XML file (in this case the altitude and the rudder position) you MUST send two values over the socket every time you update one or both values. The implication here is that every time I send rudder values I have to send an altitude. This is obviously impractical since I don’t want to alter the altitude all the time. I had hoped there was a value I could pass (such as an empty string) that would indicate “don’t update this value”, but no such luck. The only solution I can think of is to not mix control surface manipulation with flight model manipulation. The other solution would be to implement a bi-directional protocol and be constantly reading the altitude so that I know what the current altitude is and can send it along with the rudder values. This might cause very bad behavior if I can’t get and send the altitude value faster than the flight model changes it.

I like FlightGear, but the nearly nonexistent documentation is preventing me from loving it. It’s open source and the source is very well organized and clean, which is the only reason I figured out the solutions/workarounds to the problems I described above. Visually it’s behind the times, but that’s forgivable. It takes 58 seconds to start on both of my machines which have wildly different specs. I know it’s got a lot of terrain and stuff to parse through, but still.