Outerra forum

Anteworld - Outerra Game => Modding: Importer, Tools & Utilities => JavaScript development => Topic started by: Uriah on April 23, 2015, 12:48:34 pm

Title: GPS Navigations Systems for HSI, HUD, and MFDs
Post by: Uriah on April 23, 2015, 12:48:34 pm
I've developed a basic navigation system, and implemented it on the MiG-29. Currently you can only display the navigation system on the console, by pressing the 'P' key, but I will eventually build a GUI to replace this, as well as integrate the system with the cockpit instruments of the MiG-29, including the HSI.

Compass Mode allows you to simply set the HSI Bearing Needle to a fixed direction.

Currently, in GPS mode, any user can enter a single Waypoint (latitude/longitude), or select Home mode by editing the variables at the top of the script, (Alt+E). If you select home mode, than the navigation system will set the waypoint to the initial location where the aircraft is spawned. I like to save a location at the threshold of a runway so I can easily load that location, spawn the aircraft and take-off. In Home mode, it is much easier to navigate back to the runway.

I also plan to write a string array function, so any user can easily enter a waypoint course, of an unlimited number of waypoints. There will be three added parameters for each waypoint besides lat/long, these are altitude, speed and approach bearing. When your GPS coordinates come within a specified radius of each waypoint, the navigation system will switch to the next waypoint, and display the bearing, distance, attitude, speed and approach to the next waypoint.

You can download the MiG-29 script here and replace it in: ./Anteworld/packages/outerra/mig29/mig29.js

Best regards,


These variables need to be added at the top of the script, allowing any user to select navigation and gps modes, and enter a GPS waypoint to navigate to.

Code: [Select]
nav_mode = 0; //GPS = 0, Compass = 1

gps_mode = 0; //Home = 0, Waypoint = 1

//GPS Waypoint Navigation
var lat_gps_wp_deg = 48.1439; //Latitude Waypoint Degrees, N = 0 to +90, S = 0 to -90
var long_gps_wp_deg = 17.1097; //Longitude Waypoint Degrees, E = 0 to +180, W = 0 to -180

var lat_wp_deg; //Latitude Waypoint Degrees
var long_wp_deg; //Longitude Waypoint Degrees

var lat_deg; //Latitude Degrees
var long_deg; //Longitude Degrees

var lat_orig_deg; //Latitude Origin Degrees
var long_orig_deg; //Longitude Origin Degrees

//Compass Navigation
var compass_nav_deg = 180; // 0 = North, 45 = NE, 90 = East, 135 = SE, 180 = South,
                           // 125 = SW, 170 = West, 215 = NW

Next the Home waypoint code needs to be added somewhere in the initialize section below where you cache the jsb interface, like:

Code: [Select]
function initialize(reload){

  geom = this.get_geomob(0); // get first geometry isntance
  jsb = this.jsb();      // get JSBSim interface
  snd = this.sound();         // get SoundMan interface

  lat_orig_deg = jsb["position/vrp-gc-latitude_deg"]; //Latitude Origin Degrees
  long_orig_deg = jsb["position/vrp-longitude_deg"];  //Longitude Origin Degrees

Next a few functions need to be added in-between the initialize section and the update section.

Code: [Select]
function rad2deg(angle_rad){return angle_rad*180/PI;}
function km2mile(kilometer){return kilometer*0.621371;}

Next the core of the navigation system is added to the update section, including the equation to calculate Bearing (forward azimuth) and distance to waypoint. I will eventually add this in as a function so it is more efficient, but I have to re-code some other interface first before I refactor the nav system to integrate the multiple waypoint system.

Code: [Select]
//Waypoint Navigation System

  //GPS Sensor
  lat_deg = jsb["position/vrp-gc-latitude_deg"]; //Latitude Origin Degrees
  long_deg = jsb["position/vrp-longitude_deg"]; //Longitude Origin Degrees

  var φ1 = deg2rad(lat_deg); //Latitude Origin Radians
  var λ1 = deg2rad(long_deg); //Longitude Origin Radians

  var φ2 = deg2rad(lat_wp_deg); //Latitude Waypoint Radians
  var λ2 = deg2rad(long_wp_deg); //Longitude Waypoint Radians

  //Distance to Waypoint

  var R = 6371000; // metres
  var Δφ = (φ2-φ1);
  var Δλ = (λ2-λ1);

  var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
          Math.cos(φ1) * Math.cos(φ2) *
          Math.sin(Δλ/2) * Math.sin(Δλ/2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

  var waypoint_distance = R * c;

  //HSI Bearing to GPS Waypoint (Forward Azimuth)
  var y = Math.sin(λ2-λ1) * Math.cos(φ2);
  var x = Math.cos(φ1)*Math.sin(φ2) - Math.sin(φ1)*Math.cos(φ2)*Math.cos(λ2-λ1);
  var fwd_azimuth = Math.atan2(y, x);

  var compass_nav_rad = deg2rad(compass_nav_deg);

  //Waypoint Mode
  if (gps_mode==0){lat_wp_deg = lat_orig_deg;}
  else if (gps_mode==1){lat_wp_deg = lat_gps_wp_deg;}
  else {lat_wp_deg = lat_orig_deg;}
  if (gps_mode==0){long_wp_deg = long_orig_deg;}
  else if (gps_mode==1){long_wp_deg = long_gps_wp_deg;}
  else {long_wp_deg = long_orig_deg;}

  //HSI Navigation Mode
  var hsi_bearing;
  if (nav_mode==1){hsi_bearing=compass_nav_rad;}
  else if (nav_mode==0){hsi_bearing=fwd_azimuth;}
  else {hsi_bearing=fwd_azimuth;}

Next, log the navigation system data to the console at the end of the update section.

Code: [Select]
  this.log_inf("Fuel Tanks (%): " + (Math.round(jsb['propulsion/tank[0]/pct-full']*100)/100)+" - "
  + (Math.round(jsb['propulsion/tank[1]/pct-full']*100)/100)+" - "
  + (Math.round(jsb['propulsion/tank[2]/pct-full']*100)/100)+" - "
  + (Math.round(jsb['propulsion/tank[3]/pct-full']*100)/100)

this.log_inf("Fuel (lbs): " + (Math.round(jsb['propulsion/tank[0]/contents-lbs']*100)/100)+" - "
  + (Math.round(jsb['propulsion/tank[1]/contents-lbs']*100)/100)+" - "
  + (Math.round(jsb['propulsion/tank[2]/contents-lbs']*100)/100)+" - "
  + (Math.round(jsb['propulsion/tank[3]/contents-lbs']*100)/100)

  this.log_inf("Mach: " + (Math.round(jsb['velocities/mach']*100)/100));

  this.log_inf("Heading (deg): " + (Math.round(rad2deg(jsb['attitude/psi-rad'])*100)/100));
  this.log_inf("HSI Bearing (deg): " + rad2deg(hsi_bearing));

  this.log_inf("Distance Home (miles): " + (Math.round(km2mile(waypoint_distance/1000)*1000)/1000));
  else if(gps_mode===1){
  this.log_inf("Distance to Waypoint (miles): " + (Math.round(km2mile(waypoint_distance/1000)*1000)/1000));
  else{this.log_inf("Distance Home (miles): " + (Math.round(km2mile(waypoint_distance/1000)*1000)/1000));}

  this.log_inf("Latitude: " + lat_deg + ", Longitude: " + long_deg);
  this.log_inf("Lat Orig: " + lat_orig_deg + ", Long Orig: " + long_orig_deg);

I've also included the code I used to animate a 3-axis attitude indicator (aka navball) and the HSI. Note: For the HSI, there are two animated BONE joints, the Compass Card and the Bearing Needle. For the HSI to work correctly, the compass card needs to be initially facing 0 degrees due North, and will be rotated to the correct heading. The Bearing Needle takes the forward azimuth angle from the navigation system mode selected, and adds that to the heading, so that the bearing needle is aligned to the compass card. The navball also needs to be initially aligned to 0 degrees due north, and 0 degrees pitch/roll.

Code: [Select]
  var roll = jsb['attitude/phi-rad'];
  var pitch = jsb['attitude/theta-rad'];
  var heading = jsb['attitude/heading-true-rad'];

  //HSI Bearing to Waypoint 
  this.geom.rotate_joint_orig(hsi_heading_line_1, heading-hsi_bearing, {x:1,y:0,z:0});

  //HSI Compass
  this.geom.rotate_joint_orig(hsi_compass_1, heading, {x:1,y:0,z:0});

  this.geom.rotate_joint_orig(navball_1, heading, {x:0,y:0,z:-1});
  this.geom.rotate_joint_orig(navball_roll_1, roll, {x:0,y:-1,z:0});
  this.geom.rotate_joint_orig(navball_pitch_1, pitch, {x:1,y:0,z:0});

Title: Re: GPS Navigations Systems for HSI, HUD, and MFDs
Post by: Acetone on April 24, 2015, 12:45:06 pm
Works flawlessly :)
It's really interesting to see that you were able to add various basic nav functions, even without an internal engine framework.
Title: Re: GPS Navigations Systems for HSI, HUD, and MFDs
Post by: Uriah on April 25, 2015, 12:07:13 am
Instead of implementing this in the script, I'm actually porting it over to the FDM because that is more optimal. I'll build a version for scripts, to be used with vehicles/Bullet, but for aircraft all you'll need to do to add the navigation system nav_system.xml to the FDM/aircraft/mig29/Systems/ folder and add an include for the system in the FDM. To set initial Home position, all you'll need to add to the script is two lines in the initialize section like so:

Code: [Select]
function initialize(reload){

geom = this.get_geomob(0);
jsb = this.jsb();
snd = this.sound();


This sets the JSB property in the nav_system.xml to the initial lat/lon coordinates, and now you simply call the downrange-distance and forward-azimuth jsb properties in the script, like so:

Code: [Select]

This greatly simplifies and optimizes the implementation of this system for new developers. Each part of the system will be a different FDM system file, so they could pull the systems necessary for a helicopter or spacecraft and simply include the system xml files without having to add more than a few lines to the script. The reason scripts are not optimal is because javascript is translated to C++ before it is executed, which has a serious performance impact in long/complicated scripts such as the MiG-29 or Levi's F-117A. XML is the best long-term solution.

I'll upload a new version of the UH-60 helicopter in a few mintues with the cockpit instruments and nav system as seen in the screenshots above. It has a working HSI, with Bearing Needle which points to forward azimuth for waypoint/home.

Title: Re: GPS Navigations Systems for HSI, HUD, and MFDs
Post by: Uriah on April 25, 2015, 02:04:16 am
My apologies, I stand corrected on my previous statement:

The reason scripts are not optimal is because javascript is translated to C++ before it is executed, which has a serious performance impact in long/complicated scripts such as the MiG-29 or Levi's F-117A. XML is the best long-term solution.

It turns out XML actually has worse performance than JavaScript, as it is also translated to C++ and is less computationally efficient than JS.

I will therefore keep these systems in JS, however instead of how it is implemented currently, the JS systems will be modules separate from the main aircraft script and added via include(s) for each system module in the main script. Using this method all of variables and methods from the system module script can be accessed from anywhere in the aircraft script as necessary. That is the most optimal solution for now, besides a direct C++ implementation, or DLL plugin.

Best regards,
Title: Re: GPS Navigations Systems for HSI, HUD, and MFDs
Post by: Uriah on April 25, 2015, 02:29:08 am
Here is the update I promised for the UH-60 Black Hawk. (Still using AH-64 FDM)


You will need to edit your eng.cfg file ( ./Anteworld_Data/eng.cfg ) and set min_obj_size = .01, or similar small value. If you don't do this, you won't be able to see critical components of the HSI indicator, including the arrow on the Bearing Needle, and forward azimuth line above the Compass Card.

The navigation system is currently set to Home Point mode, therefore the home point is where you spawn the aircraft, and it updated every time you reload the script. Therefore, if you want to keep the home point as the location of the runway touchdown point so you can navigate back to the runway, you can spawn the aircraft at that position, and it will automatically set that as the home point, or alternatively you can taxi to the touchdown point (runway touchdown threshold markings are the white lines white lines) and hit Alt+R to re-load the script. Now the home point is updated to the touchdown point, which is useful for landing. Hence fourth, you can reload the script at any point in the flight to set that as the home point to return to. Remember to configure your light preferences in the variables near the top of script before take off, as changing them in flight and reloading the script will re-set the home point.

When I have some time I'll add the parameters for speed and altitude for the home point/waypoints. That way you'll know what altitude (ASL) and speed are indicated for the approach.

Also, you can use Hover Mode ('H' key) if you don't have a joystick to properly control the helicopter.

Best regards,