Ruby, IronRuby and FlightGear; Three big subjects in their own rights but here I am mixing them all together and perhaps getting into things a little to much over my head.

The idea of using these three programs is to get real time data from a flight simulator program and then process and output it through ruby. Also a future goal is to be able to send data  to control different systems while in flight through external components.

The following post contains information on FlightGears .xml protocols and configuring the simulator to output data through a socket. Also two scripts in Ruby and IronRuby which gets data from FlightGear and displays it.

Please also note that you will find that some information I give is similar to what is given at http://linkslink.wordpress.com/takeoff/ as I used the information as a guide when I was learning about the .xml Protocol files and has led me to some handy .Net libraries when using IronRuby.

Only last week IronRuby and FlightGear were unknown to me as I scowered through the immense achieves of the internet looking for any reference to Ruby being used to acquire data from Microsoft Flight Simulator X. But in the true spirit of Microsoft to even get access to the SDK you needed to have purchased the deluxe edition of FSX and perhaps I was aiming a little high with the Ruby side of things. Yet in my search I came across a very interesting project called IronRuby.

IronRuby allows ruby integration with the .Net libraries and you can get more information about it here: http://www.ironruby.net/ . Previous to using IronRuby I had been barely able to write a simple C# program but now things seem to make more sense. If anyone is interested I would recommend checking it out.

In the end I gave up on Microsoft Flight Simulator when I found FlightGear (http://www.flightgear.org/) which is quite a nice open source flight simulator project and I look forward to being able to do some work on the source code of my own as I have a few ideas I would like to try out in it. Anyway I digress.

Getting Data from FlightGear

FlightGear provides a relatively easy way to access information about the aircraft and other environmental variables in realtime through a number of different methods of communication. These are either through a TCP or UDP network socket connection, serial connection or by writing a file to the hard drive which can be updated at a specified amount of times per second.

For my purposes the socket connection method is the most practical so this is what I will be covering here. Before I go into setting up this output method an important thing to understand is what format the data will be outputted in and exactly what data is going to be outputted. FlightGear uses .xml files to control how data is sent or recieved through a socket connection and what data it is. These files are kept in \data\Protocol file which is in the FlightGear directory, also a document I recommend you read is kept in the \docs file which is called README.protocol, it goes over how a general .xml protocol file is setup but I am going to cover it briefly here.

.xml Protocol Files

The basic structure of the .xml Protocol files are as follows:

<?xml version=”1.0″?>
<PropertyList>
<generic>
<output>
<line_separator>newline</line_separator>
<var_separator>|</var_separator>
<chunk>
<name>speed</name>
<type>integer</type>
<format>%d</format>
<node>/velocities/airspeed-k</node>
</chunk>
… Have as many output chunks as you desire …
</output>
</generic>
</PropertyList>

The <output> tag it can be replaced with <input> but I am not going to be covering that at this time so the first important things to look as is the <line_separator> and <var_separator> tags. These, as their names suggest determine how the chunks of data are to be separated. In this case after all the chunks of data have been sent it then starts on a newline when it goes to send the data again, but as each chunk of data is sent it puts a | between them so we can determine where a chunk begins and a chunk ends. <chunk> tags define what data to print by giving, <type>, <format> and <node>.

The <name> tag doesn’t get sent and is simply there for us old humans so we know whats what. Also there are other tags that can be put within a chunk and you can find more information on them in the README.protocol file.

<type> defines what type of data the chunk is, types that can be used are things such as: integer, string, boolean and float. <format> pretty much speaks for itself, and is similar to the job of <type> yet has more functions.

<node> defines the location of the chunk of data and the easiest way I know of so far of finding this information is by doing the following setup in Advanced Options in flight gear, starting up the game and then minimizing out of the game, opening a web browser and going to 127.0.0.1:5501 or localhost:5501.

For the Ruby and IronRuby examples I give here I use following .xml Protocol file:

<?xml version=”1.0″?><PropertyList><generic>

<output>
<line_separator>newline</line_separator>
<var_separator>|</var_separator>

<chunk>
<name>speed</name>
<format>%d</format>
<node>/velocities/airspeed-kt</node>
</chunk>

<chunk>
<name>heading</name>
<format>%02d</format>
<node>/orientation/heading-deg</node>
<factor>57.29578</factor>  <!– radians to degrees –>
</chunk>

<chunk>
<name>altitiude</name>
<format>%02d</format>
<node>/position/altitiude-ft</node>
</chunk>

<chunk>
<name>rate of climb</name>
<format>%02d</format>
<node>/velocities/vertical-speed-fps</node>
</chunk>

<chunk>
<name>pitch angle</name>
<format>%05.1f</format>
<type>float</type>
<node>/orientation/pitch-deg</node>
</chunk>

<chunk>
<name>bank angle</name>
<format>%05.1f</format>
<type>float</type>
<node>/orientation/roll-deg</node>
</chunk>

<chunk>
<name>engine</name>
<format>%02d</format>
<node>/engines/engine[0]/rpm</node>
</chunk>
</output>

</generic>

</PropertyList>

Configuring the Output of FlightGear

FlightGear then needs to be configured so that we can get an output from it using our .xml protocol. This is quite easy to do as you can either do it through a command line or through the FlightGear Wizard GUI which I show here.

Notice that the Generic field allows you to select the .xml Protocol file.

Getting FlightGear to talk to Ruby

Now this is pretty straight forward as Flightgear sends its data in an ASCII coding, though you can change that to binary if you wish through the .xml Protocol files. In Ruby all we practicly have to do is setup a TCP server and listen for FlightGear on a specific socket. When it connects we then split the data up into an array and this allows us to show only the data we want.

This Ruby program simply prints the recieved data, so it isn’t very special but basicly a foundation for better things to come… assuming they will come.

require ’socket’include Socket::Constants

socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.pack_sockaddr_in(5500, ‘127.0.0.1′)
socket.bind(sockaddr)
socket.listen(5)

puts “Server Started. Waiting for connection from client…”

while (FgClient  = socket.accept)
puts “Client Connected, getting data…”
loop do
rawData = FgClient[0].readline
data = rawData.split(’|')
puts “Speed = #{data[0]}”
puts “Heading = #{data[1]}”
puts “Altitude = #{data[2]}”
puts “Rate of Climb = #{data[3]}”
puts “Pitch Angle = #{data[4]}”
puts “Bank Angle = #{data[5]}”
end
end

Getting FlightGear to talk to IronRuby

And here is practically the same thing in IronRuby though I haven’t put the received data through any formatting so that you can see how the data is sent from FlightGear.

require ‘mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=x86′
require ‘System, Version=2.0.50727.42, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL’
#call on the different classes required within the .Net framework
tcpListener = System::Net::Sockets::TcpListener
networkStream = System::Net::Sockets::NetworkStream
streamReader = System::IO::StreamReader
ipAddress = ‘127.0.0.1′
port = 5500
#Parse IPAddress
localAddr = System::Net::IPAddress::Parse(ipAddress)
puts “FgACS >> Starting FlightGear Aircraft Control Server…”
#Start TCP Server
FgServer = tcpListener.new(localAddr, port)
FgServer.Start()#ToDo: need to check to see if server already started before starting new one.
puts “FgACS >> Server online. IP Address: #{ipAddress}, Port: #{port}”
puts “FgACS >> Waiting for FlightGear Client to connect…”
FgSocket = FgServer.AcceptSocket()
puts “FgACS >> FlightGear Client Connected Successfully”
FgStream = networkStream.new(FgSocket)
readStream = streamReader.new(FgStream)
while FgStream.CanRead do
$receivedData = readStream.ReadLine()
puts “#{$receivedData}”
end

In Conclusion

There is a multitude of more information I could add to this post but as I see it that information is very easy to get your hands on and doesn’t really need repeating here so use your head an you will be able to fill in any of the blanks I have made. There is still so much more I have to learn in this area and as I see it this is just the very tip of the iceberg.

Perhaps ruby is not the way forward if you are looking from a consumers perspective but I found that it makes building up a prototype of an idea or trying something to see if it will work so much more quicker and easier.

I hope some of you find this post of some interest!

Enjoy!

Leave a Reply