Wednesday, April 6, 2011

Flightgear: control aircraft externally

In the previous article the Flightgear program's some features were discussed. Today's topic will be about controlling aircraft through sockets from another program. There is a command line option "--generic" , which can be used for modifying items of property tree(see previous article, about http://localhost:1234).
Run the program with the following options.
The first generic argument means: Use sockets, for sending data out, 10 times a second, to the 127.0.0.1 machine(this is localhost's ip address), using the port 49001, use UDP protocol, the actual data which sent out are described in file "outputprotocol".
The second generic argument means: Use sockets again, for getting data from out, 10 times a second, skip the ip address, using the port 49000, use UDP protocol again, the coming data described in the file "inputprotocol".
If the program hangs, this means you are using the Flightgear version 2.0.0, which has a known bug and you need to downgrade to the version 1.9.1. Now if the hanging is over, then the program must give an error(see console's screen), because "outputprotocol" and "inputprotocol" files doesn't exists.
The following is "inputprotocol.xml" file's content, which describes 3 values, that the program will wait for input(aileron, elevator and throttle).
The following is "outputtprotocol.xml" file's content,which describes the same 3 values from input and plus one more (the speed of aircraft).
Now copy those files to the "C:\Program Files (x86)\FlightGear\data\Protocol" directory and run the program again. It will again give error(Error reading data), because no one send data to the input.
Now lets write a program in C#, which will send the input data to and receive output data from Flightgear. Add the controls to the main form as pictured in the screenshot:
We will use timer to send data in every 100ms(10 times in a second as described in the argument). This is sending part code: We will use threads to asynchronously get data from Flightgear. This is it:That's all.

13 comments:

  1. Way to go! I've been looking all over for someone who has done something like this on C#. I've been sending data to FlightGear through MATLAB Simulink, where I've created an FDM for my simulator. I use FlightGear for the scenery. Now I'm rewriting the FDM on C# which is a new language for me.

    I'm having trouble sending position data to FlightGear through UDP. I can't seem find much on how the struct is sent. Could you shed some light on this, please? You've already shown me quite a bit. Any help would be greatly appreciated! Thanks!

    ReplyDelete
  2. Run the Flightgear with the option --httpd=1234 and you can see the position properties in http://localhost:1234/position/
    I think you want the "altitude-agl-ft" option: position above ground. But I'm afraid to disappoint you, there is a bug in Flightgear http://code.google.com/p/flightgear-bugs/issues/detail?id=220
    But you can give a try, maybe your version of Flightgear doesn't have it.

    ReplyDelete
  3. Thanks a lot! :) I checked it through --httpd=1234 and it all works fine with my version of FlightGear.

    As for the C# program, I don't want to update "altitude-agl-ft". I want to update the six position and orientation values which are "latitude-deg", "longitude-deg", "altitude-ft", "heading-deg", "pitch-deg",and "roll-deg".

    I get the following message in the command prompt when I run FlightGear: "Error reading data".

    Any suggestions?

    I'm including my run command and C# program. Could not copy/paste the input protocol xml content here. Any way I could send you that? Thanks for all the help! :)

    Here's how I'm calling FlightGear using the command prompt:

    ------------------------------------------------

    "C:\Program Files (x86)\FlightGear\bin\Win32\fgfs" ^
    "--fg-root=C:\Program Files (x86)\FlightGear\data" ^
    "--aircraft=ufo" ^
    "--generic=socket,in,10,127.0.0.1,49000,udp,inputProtocolMaverick"

    ------------------------------------------------


    Here's my C# test program which sends the position data over UDP:


    -----------------------------------------------
    double latitude_deg = 37.65740554d;
    double longitude_deg = -122.4288669d;
    double altitude_ft = 338.9325791d;
    float heading_deg = 96.17898864f;
    float pitch_deg = 1.851260767e-133f;
    float roll_deg = 1.011915142e-298f;

    private UdpClient sending_UdpClient = new UdpClient();
    private void timer1_Tick(object sender, EventArgs e)
    {

    String str = latitude_deg.ToString() + "'" + longitude_deg.ToString() + "'"
    + altitude_ft.ToString() + "'" + heading_deg.ToString() + "'"
    + pitch_deg.ToString() + "'" + roll_deg.ToString() + "\n";

    Byte[] sendBytes = Encoding.ASCII.GetBytes(str);

    sending_UdpClient.Send(sendBytes, sendBytes.Length, "127.0.0.1", 49000);
    }
    ------------------------------------------------

    ReplyDelete
  4. Hey I got my error! I was using " ' " as a separator instead of " , " in sending the udp data packet. No wonder FlightGear got confused lol.

    ReplyDelete
  5. New question:

    When I change the "pitch-deg or "roll-deg" options, the attitude/orientation always returns to a wings level and nose level position. How can I make it STAY in my desired orientation?

    ReplyDelete
  6. I don't understand your question, could you explain with an example.
    What you mean by saying "the attitude/orientation always returns to a wings level and nose level position".

    Maybe this will help:
    There are some options with read-only values, actually you can change the values, but Flightgear doesn't react to it, and changes back them.

    I couldn't find any documentation about how to check which values are read-only, and which aren't. Do you know anything about this?

    ReplyDelete
  7. Thanks for the help. I found the solution! Let me explain the problem again first.

    Suppose I change the pitch attitude (pitch-deg) to 15 degrees. The nose should pitch up, right? Well, it goes up, but it doesn't stay there. It goes back to 0 (nose level). Even if I try to send it to 90, it goes to 90 and then comes back.

    Same for roll-deg. I change it to say, a 30 degree roll. It goes to a 30-deg roll, then comes back in like 0.5 seconds.

    Try doing it yourself. Seems you have been having some problems like this too? Now for the solution.

    It has something to do with the flight model. Some values are inside the flight model equations used by FlightGear. So if you change them, it will change them back. It is constantly calculating them. Values like pitch, roll, angle of attack, speed, etc. Others, like latitude, longitude, time of day, altitude, etc, are not part of flight dynamics. So once they are changed, they stay that way.

    If you want FlightGear to stop interfering, you should stop running the flight model. You can do this by using the "--fdm=external" option. When you use this option, it will tell FlightGear not to run the flight model, but instead wait for values from another, external flight model. In our case, it can simply be a C# program. FlightGear doesn't care as long as it's getting values. So you call FlightGear as follows:

    "C:\Program Files (x86)\FlightGear\bin\Win32\fgfs" ^
    "--fg-root=C:\Program Files (x86)\FlightGear\data" ^
    "--aircraft=ufo" ^ "--generic=socket,in,10,127.0.0.1,49000,udp,inputProtocolMaverick" ^
    "--fdm=external"

    Here's the documentation link:

    http://wiki.flightgear.org/index.php?title=Property_Tree/Sockets

    As far as I know, read-only values can only be checked by trial and error. Or if you check the FlightGear source code and check the dynamics equations. But if you use the "fdm=external" option, there are no read-only values remaining. You can change any value you wish. Does this answer your question?

    ReplyDelete
  8. Yea, the "fdm=external" option disables calculations and properties' values can be changed manually from the external program.

    Thanks, :)

    ReplyDelete
  9. Hi!

    You're welcome for the previous post.

    I've managed well with porting my simulator code to C#, and sending data to FlightGear. But there's a slight problem. I'm not sure how to define the format for 'double' values. Your example mentions the format for 'float' only. Can you please provide the format? Nothing online seems to help!

    ReplyDelete
  10. I cannot send FGNetCtrls data somehow to fgfs. I would be really thankful if you could help. I use the following command to run fgfs and it starts in the state where the engine is running.

    fgfs --native-fdm='socket,out,70,192.168.40.27,22222,udp' --native-ctrls='socket,in,70,,22223,udp' --aircraft=c172p --telnet=22224

    Then I send FGNetCtrls data to port number 22223 and nothing reaches there. I have even run wireshark on the remote host to verify whether or not data reaches the remote host. And it does.

    ReplyDelete
  11. This comment has been removed by the author.

    ReplyDelete
  12. This comment has been removed by the author.

    ReplyDelete
  13. Hello gyus please could anyone help me
    All the inputs are working good besides Throthle even I am changing the value the aircraft is not moving at all ...

    ReplyDelete