Howto:Methods to replace the NASAL code with JSBSim code

From FlightGear wiki
Jump to navigation Jump to search

Often may be convenient not mix NASAL functions with JSBSim functions, both for having a code easier to maintain, but also for greater efficiency in terms of execution. JSBSim is a data driven language ( Data-driven programming is similar to event-driven programming, in which both are structured as pattern matching and processing, and are usually implemented by a loop, though they are typically applied to different domains from: Wikipedia Data-driven programming). Having noticed that in Flightgear NASAL is often used instead of JSBSim because often do not know the potential of JSBSim implemented in Flightgear, I think it is useful to put notes on the various methods that can facilitate this work.

Performance of JSBSim (or data-driven languages) in a real-time (RT) context

For many programmers accustomed to the procedural language classes with event-driven extensions, they think that the "data driven" approach can be more expensive because for each step-time all the variables are read and the related transformation processes are performed. At 120 Hz (recalculation rate typical of JSBSim in Flightgear) it can actually seem a very expensive process, but without using the particular optimization parameters (anyway present in JSBSim), the machine cycles necessary to perform a complete recalculation of all the variables presently present an aircraft of Flightgear are few because it is not necessary, in these languages, to perform an interpreter and to activate methods of management of interruptions, timers etc ... But everything remains confined within a vector of variables that is read and transformed according to the implemented algortms. Operatively, it is observed that the CPU load, due to the JSBSim applications, is still quite low because the main-loop mechanism is efficient (a mechanism typically used for real-time programming).

CPU load reduction by execrate option

A classic criticism that is made of an extensive use of JSBSim in terms of a useful replacement of NASAL code is that JSBSim executes its modules at a frequency of 120 Hz, whereas NASAL executes its modules according to the frame-rate, which on average it is 20-30 Hz. This difference may seem very high and therefore make extensive use of JSBSim too heavy.
In fact, as explained above, JSBSim is very light in execution and its percentage of CPU occupancy is very low (on average only some percentage value ...). But it is possible to reduce the CPU load even more on the individual groups of modules (called Channel) by use a declarative option called execrate. The method used by execrate to do this is to execute a module only after a certain number of cycles, the number of wait cycle less one is defined as parameter in the execrate declaration.

Let's take an example that should clarify the concept:

    <channel name="jato electric" execrate="8">
        <switch name="systems/jato/electric-active">
            <default value="0"/>
            <test logic="AND" value="1">
                systems/electric/bus[1]/V GT 18
                systems/electric/bus[1]/JATO-ignition/fuse == 1
            </test>
        </switch>
    </channel>

The declaration: <channel name="jato electric" execrate="8"> defines that every eight cycles the modules inside the channel will be executed.
In this way it is possible to considerably reduce the CPU load, but we must remember that:

The modules executed with active execrate are evaluated with a lower frequency of the modules without execrate and this fact could create collateral problems.

A typical case is when an output variable present in the module that do not belong to the same channel. In this case is it possible generate problems of incorrect synchronization that can lead to mysterious malfunctions. A typical case is when the output variable writes on a variable that is also updated by the Flightgear properties tree (variables starting with "/", for example the variable: /controls/engines/engine/throttle) in this case it is probable that the variable can randomly updated by Flightgear and not by JSBSim, this generating a substantial uncertainty in its value that could lead to unpredictable behavior. However, this is a typical problem of concurrent processes that must be managed with appropriate measures.

Using the variables defined in the Flightgear properties tree, by JSBSim

The implementation of JSBSim for Flightgear contains an easy way to assign or read values to the variables in the Flightgear properties tree:

All variables starting with / are with absolute references, referring to the Flightgear properties tree where JSBSim is a subset. For example, the variable: /controls/engines/engine[1]/throttle define the throttle value for engine 1. If the variables not start with the character / is a variable with relative references, for example : fcs/throttle-cmd-norm[1] which is the equivalent in JSBSim of the variable normally used by Flightgear (and NASAL) /controls/engines/engine[1]/throttle. Vice versa, in XML scripts it is possible to refer to a JSBSim variable simply by inserting the suffix: fdm/jsbsim/...

Summarise:

In NASAL or in Flihtgear XML is equivalent:

/controls/engines/engine[1]/throttle -> fdm/jsbsim/fcs/throttle-cmd-norm[1]

In JSBSim is equivalent:

fcs/throttle-cmd-norm[1] -> /controls/engines/engine[1]/throttle

A complete example of changing the throttle value from JSBSim

The problem is due to the fact that there is a binding between the Flightgear application and the JSBSim implementation. This means that the variable fcs/throttle-cmd-norm[n] (where n is the engine number) is continuously updated by Flightgear and therefore can not be changed directly. Unfortunately, the implementation of JSBSim for Flightgear does not currently have the ability to silence the fcs/throttle-cmd-norm[n] variable synchronization function with the corresponding Flightgear variable /controls/engines/engine[n]/throttle So it's better to play cunning and edit the Flightgear assign /controls/engines/engine[n]/throttle directly by assigning the value that we would like to assume fcs/throttle-cmd-norm[n] at this point everything works perfectly.

For example, to activate a solid fuel rocket engine it is sufficient to set (even for a moment) the variable: /controls/engines/engine[n]/throttle to 1 via a switch method or a function fcs_function this is the code I used:

        <switch name="throttle cmd norm[1]">
            <default value="0"/>
            <test logic = "AND" value = "1">
                systems/jato/ignition-on == 1
                systems/jato/rocket_number_1 == 1
            </test>
            <output>/controls/engines/engine[1]/throttle</output>
        </switch>

This switch function reminds us of two important things to know: If in JSBSim for Flightgear a variable starts with the character / it means that it is a variable that refers to the properties tree of Flightgear, this means that the variable /controls/engines/engine[1]/throttle can be so assigned or read directly by JSBSim. The Switch function that I put in the example can not be defined with the name or tied properties (which in the example has become only a generic reference), but the assignment must be done only through the <output> ... </output> method. If instead a reference to a variable does not start with the / character, then that variable has a reference relative to the JSBSim properties tree only (a sort of local variable).