Howto:Terrain sampling in Nasal

From FlightGear wiki
Jump to navigation Jump to search


This tutorial will document all the steps involved in creating a new Nasal module that constantly updates itself to sample the surrounding terrain.

This tutorial is based on Howto: Create a new Nasal module and Howto: Create a new system in Nasal, so you should fully understand those tutorials first.

A system that constantly updates itself at a fixed rate could for example be used to simulate a new instrument in FlightGear.

Please keep in mind that Nasal functions that are invoked this way are obviously limited by the frame rate of the simulator (e.g. if your frame rate is 50 fps, you cannot run a Nasal function at higher rates). Update rates of a couple hertz are fine however.

Keep in mind though, that the time spent in each Nasal function will obviously also have an effect (on the frame rate, too).

Steps:

  1. Create a new plain text file under $FG_ROOT/Nasal/<module>.nas, replacing <module> with the name of your new module (for example, use "test").
  2. Paste the code below into this file using a text editor (such as Notepad on Windows)
# test.nas (save in $FG_ROOT/Nasal)
var sampler = func(){
    print("Running sampler");
}

var timer = maketimer(3, sampler); # register a timer, invoke the "sampler" function again after 3 seconds

setlistener("/sim/signals/nasal-dir-initialized", func {
    timer.start();
});

This piece of code defines a new function named "sampler" that just prints a message to the console. Next, a timer is registered to invoke the sampler function again after 3 seconds have passed.

The setlistener() call at the end of the snippet waits for the Nasal system to be initialized before the "mycode" function gets called for the first time.

Now, add some code to get the current position:

# test.nas (save in $FG_ROOT/Nasal)

var lat = 0;
var lon = 0;

var sampler = func {
    print("Running sampler");
    lat = getprop("/position/latitude-deg");
    lon = getprop("/position/longitude-deg");
}

var timer = maketimer(3, sampler); # register a timer, invoke the "sampler" function again after 3 seconds

setlistener("/sim/signals/nasal-dir-initialized", func {
    timer.start();
});

Now, we have the current latitude and longitude stored in the variables lat and lon, next, we are going to add a call to Nasal's geodinfo() call for this position. It is a FlightGear-specific extension function that queries the built-in terrain cache and returns meta information for the position passed.

# test.nas (save in $FG_ROOT/Nasal)

var lat = 0;
var lon = 0;
var result = nil;
var elevation_m = 0;

var sampler = func(){
    print("Running sampler");
    lat = getprop("/position/latitude-deg");
    lon = getprop("/position/longitude-deg");
    result = geodinfo(lat, lon);
    elevation_m = result[0];
    print("Elevation is: ", elevation_m, " m");
}

var timer = maketimer(3, sampler); # register a timer, invoke the "sampler" function again after 3 seconds

setlistener("/sim/signals/nasal-dir-initialized", func {
    timer.start();
});

As you can see, the result of the geodinfo() call is stored in the result variable. According to the docs, geodinfo() returns a vector as a result. The first element of the vector contains the altitude in meters, while the second element contains a hash with additional ground cover information (if available, otherwise nil).