Board index FlightGear Development Nasal

Total beginner... creating a new property in tree

Nasal is the scripting language of FlightGear.

Total beginner... creating a new property in tree

Postby ScottBouch » Thu May 23, 2019 11:44 pm

Hi all,

Welcome to my first ever Nasal script. And I'm very much a novice programmer, so please bear with me.

System: (Linux Manjaro 4.19.36-1-MANJARO, X86_64, XFCE, FGFS 2018.3.2)

Goal:

To add a new property to the property tree of the FGUK Lightning T5. The value of this new property is to be a string of 9 bools.

These bools are to represent the undercarriage position in terms of the cockpit indicator lamps that are illuminated per undercaruage leg:

Green (locked down)
Amber (unlocked / in transit)
Red (locked up)

I am trying to read the 0.00 to 1.00 value of each leg using these properties:

Port: props.globals.getValue(gear/gear[1]/position-norm
Nose: props.globals.getValue(gear/gear[0]/position-norm
Stbd: props.globals.getValue(gear/gear[2]/position-norm

Then I am doing less than / greater than compares within IF functions to set my bools, which are then hopefully assembled into a string in a new property:

gear/indicators/as-string

This new string property is to be sent out over serial protocol to my Arduino board to operate a physical undercarriage indicator. I want it as a single string with no delimiters between the bools as I wish to chuff it straight out of the Arduino over I2C to an I/O expander IC dedicated to this indicator unit. (Had I set up individual properties for each bool, I'd end up with delimited data going to the Arduino which I'd then have to re-assemble as a string.)

Work so far:

This has all very much been a monkey-see, monkey do approach to coding, as I couldn't really understand the nasal instructions / guidance. As an alternative approach, I delved into existing nasal files and had a go at interpreting the code from them, and forming my own take on it.

I have edited /home/scott/fguk/Aircraft/EE-Lightning/ lightningT5-yasim-set.xml to include a reference for the nasal script, I assume this to be correct as my .nas file appears in the log file (with errors):

Code: Select all
        <uc-hardware-indicators>
                <file>Aircraft/EE-Lightning/Nasal/uc-hw-ind.nas</file>
        </uc-hardware-indicators>
        </nasal>


/home/scott/fguk/Aircraft/EE-Lightning/Nasal/uc-hw-ind.nas file contents - I must emphasise this was based on my best guess of what might work based on no nasal experience :| You should be able to see what I am trying to achieve in the code though:

Code: Select all
print("loading Undercarriage Hardware Indicator script...");

bool port-red;
bool port-amber;
bool port-green;

bool nose-red;
bool nose-amber;
bool nose-green;

bool stbd-red;
bool stbd-amber;
bool stbd-green;


##Build string of bools, one for each indicator lamp:
initNode(path = gear/indicators/as-string, value = "port-red""port-amber""port-green""nose-red""nose-amber""nosegreen""stbd-red""stbd-amber""stbd-green", STRING);



##Port [1] undercarriage indicator lamps:

if ( props.globals.getValue(gear/gear[1]/position-norm < 0.2 ) {
        port-red.setBoolValue(1);
        }
        else {
        port-red.setBoolValue(0);
        }

if ( props.globals.getValue(gear/gear[1]/position-norm > 0.2 ) {
        if ( props.globals.getValue(gear/gear[1]/position-norm < 0.8 ) {
                port-amber.setBoolValue(1);
                }
                else {
                port-amber.setBoolValue(0);
                }
        }

if ( props.globals.getValue(gear/gear[1]/position-norm > 0.8 ) {
        port-green.setBoolValue(1);
        }
        else {
        port-green.setBoolValue(0);
        }


##Nose [0] undercarriage indicator lamps:

if ( props.globals.getValue(gear/gear[0]/position-norm < 0.2 ) {
        nose-red.setBoolValue(1);
        }
        else {
        nose-red.setBoolValue(0);
        }

if ( props.globals.getValue(gear/gear[0]/position-norm > 0.2 ) {
        if ( props.globals.getValue(gear/gear[0]/position-norm < 0.8 ) {
                nose-amber.setBoolValue(1);
                }
                else {
                nose-amber.setBoolValue(0);
                }
        }

if ( props.globals.getValue(gear/gear[0]/position-norm > 0.8 ) {
        nose-green.setBoolValue(1);
        }
        else {
        nose-green.setBoolValue(0);
        }


##Stbd [0] undercarriage indicator lamps:

if ( props.globals.getValue(gear/gear[2]/position-norm < 0.2 ) {
        stbd-red.setBoolValue(1);
        }
        else {
        stbd-red.setBoolValue(0);
        }

if ( props.globals.getValue(gear/gear[2]/position-norm > 0.2 ) {
        if ( props.globals.getValue(gear/gear[2]/position-norm < 0.8 ) {
                stbd-amber.setBoolValue(1);
                }
                else {
                stbd-amber.setBoolValue(0);
                }
        }

if ( props.globals.getValue(gear/gear[2]/position-norm > 0.8 ) {
        stbd-green.setBoolValue(1);
        }
        else {
        stbd-green.setBoolValue(0);
        }


Log File error:

Code: Select all
nasal:5:/var/tmp/pamac-build-scott/flightgear/src/flightgear-2018.3.2/src/Scripting/NasalSys.cxx:1315:Nasal parse error: parse error in /home/scott/fguk/Aircraft/EE-Lightning/Nasal/uc-hw-ind.nas, line 25


Ok, so a parse error in the first request for data from the property tree in this line: "if ( props.globals.getValue(gear/gear[1]/position-norm < 0.2 ) {" since all the other requests follow the same format I'll correct them all too if someone can tell me what's wrong.

I ran fgfs, checked the property browser, and found my new string property is not there under gear/ so I guess if I can fix this parse error in the log, it'll be followed by another error of creating the new property.

Please, any help is greatly appreciated, I hope this explains what I'm trying to achieve, and how I've gone about it in enough detail.

Many thanks, Scott.
User avatar
ScottBouch
 
Posts: 183
Joined: Wed Jun 22, 2016 4:14 pm
Location: Midlands, UK
OS: Linux Mint

Re: Total beginner... creating a new property in tree

Postby Thorsten » Fri May 24, 2019 6:01 am

Code: Select all
if ( props.globals.getValue(gear/gear[1]/position-norm < 0.2 )


Missing closing bracket after position-norm
Thorsten
 
Posts: 12490
Joined: Mon Nov 02, 2009 9:33 am

Re: Total beginner... creating a new property in tree

Postby legoboyvdlp » Fri May 24, 2019 8:39 am

Things like this also won't work:
Code: Select all
bool port-red;


You'll have to initialize it using initNode, e.g.
Code: Select all
var portRed = initNode("/gear/annunciator/port-red", 0, "BOOL");
print(portRed.getBoolValue());


However, there is a way to avoid using the property tree for this, see below.

Next, string contacenation is also done using the tilde (~), and you need to have an updating function using a timer, or else it will only run once. I would suggest a maketimer for this.

Finally, this won't work:
Code: Select all
initNode(path = gear/indicators/as-string, value = "port-red""port-amber""port-green""nose-red""nose-amber""nosegreen""stbd-red""stbd-amber""stbd-green", STRING);
, as it will a) only initialize it not update it runtime and b) is incorrect syntax.

You would want to initialize it to "" and in your updating function at the very beginning have a string variable to which you contacenate the values - e.g. as such:

Code: Select all
var update = func() {
var string = ""
if (condition) {
portRed = False;
} else {
portRed = True;
}
string = string ~ portRed;
# more code...
}


I am not quite sure that will work as I've never tried concatenating bools like that. But it should, if not try replacing it with an integer and 1 / 0. Nasal doesn't really need to know it's a boil, your Arduino code might however so you can translate it at that point if needed?

No warranty on any of the code snippets as they are untested and you'll need to edit them to match what you want to do ;)

You should find the wiki nasal errors a lot of help, especially the "Nasal Library" article :)
User avatar
legoboyvdlp
 
Posts: 7981
Joined: Sat Jul 26, 2014 2:28 am
Location: Northern Ireland
Callsign: G-LEGO
Version: next
OS: Windows 10 HP

Re: Total beginner... creating a new property in tree

Postby ScottBouch » Fri May 24, 2019 10:01 am

Thanks Thorsten, the brackets cleared that issue.

Wow, thank you for the guidance legoboyvdlp! You hit the nail on the head, as after getting past the bracket issue, this was indeed the next thing that caused a problem.

I've corrected the brackets, and the property tree initNodes so far, and have some progress in that there's a different error in the log file, sill with the initNodes.

Code: Select all
nasal:5:/var/tmp/pamac-build-scott/flightgear/src/flightgear-2018.3.2/src/Scripting/NasalSys.cxx:1315:Nasal parse error: bad lvalue in /home/scott/fguk/Aircraft/EE-Lightning/Nasal/uc-hw-ind.nas, line 4


(I've not yet tried editing the part for building the string up. On that front, the Arduino will happily receive characters of 1 or 0 , regardless of the type specified in fgfs. My main objective here is to remove work from the Arduino, doing most within the boundary of FGFS.)

Current uc-hw-ind.nas file:
Code: Select all
print("loading Undercarriage Hardware Indicator script...");


var port-red = initNode("gear/gear[1]/locked-up", 0, "BOOL");
   print (port-red.getBoolValue());

var port-amber = initNode("gear/gear[1]/unlocked", 0, "BOOL");
   print (port-amber.getBoolValue());

var port-green = initNode("gear/gear[1]/locked-down", 0, "BOOL");
   print (port-green.getBoolValue());



var nose-red = initNode("gear/gear[0]/locked-up", 0, "BOOL");
   print (nose-red.getBoolValue());

var nose-amber = initNode("gear/gear[0]/unlocked", 0, "BOOL");
   print (nose-amber.getBoolValue());

var nose-green = initNode("gear/gear[0]/locked-down", 0, "BOOL");
   print (nose-green.getBoolValue());



var stbd-red = initNode("gear/gear[1]/locked-up", 0, "BOOL");
   print (stbd-red.getBoolValue());

var stbd-amber = initNode("gear/gear[1]/unlocked", 0, "BOOL");
   print (stbd-amber.getBoolValue());

var stbd-green = initNode("gear/gear[1]/locked-down", 0, "BOOL");
   print (stbd-green.getBoolValue());




##Build string of bools, one for each indicator lamp:
initNode(path = gear/indicators/as-string, value = "port-red""port-amber""port-green""nose-red""nose-amber""nosegreen""stbd-red""stbd-amber""stbd-green", STRING);



##Port [1] undercarriage indicator lamps:

if ( props.globals.getValue(gear/gear[1]/position-norm < 0.2 )) {
   port-red.setBoolValue(1);
   }
   else {
   port-red.setBoolValue(0);
   }

if ( props.globals.getValue(gear/gear[1]/position-norm > 0.2 )) {
   if ( props.globals.getValue(gear/gear[1]/position-norm < 0.8 )) {
      port-amber.setBoolValue(1);
      }
      else {
      port-amber.setBoolValue(0);
      }
   }

if ( props.globals.getValue(gear/gear[1]/position-norm > 0.8 )) {
   port-green.setBoolValue(1);
   }
   else {
   port-green.setBoolValue(0);
   }



##Nose [0] undercarriage indicator lamps:

if ( props.globals.getValue(gear/gear[0]/position-norm < 0.2 )) {
   nose-red.setBoolValue(1);
   }
   else {
   nose-red.setBoolValue(0);
   }

if ( props.globals.getValue(gear/gear[0]/position-norm > 0.2 )) {
   if ( props.globals.getValue(gear/gear[0]/position-norm < 0.8 )) {
      nose-amber.setBoolValue(1);
      }
      else {
      nose-amber.setBoolValue(0);
      }
   }

if ( props.globals.getValue(gear/gear[0]/position-norm > 0.8 )) {
   nose-green.setBoolValue(1);
   }
   else {
   nose-green.setBoolValue(0);
   }



##Stbd [0] undercarriage indicator lamps:

if ( props.globals.getValue(gear/gear[2]/position-norm < 0.2 )) {
   stbd-red.setBoolValue(1);
   }
   else {
   stbd-red.setBoolValue(0);
   }

if ( props.globals.getValue(gear/gear[2]/position-norm > 0.2 )) {
   if ( props.globals.getValue(gear/gear[2]/position-norm < 0.8 )) {
      stbd-amber.setBoolValue(1);
      }
      else {
      stbd-amber.setBoolValue(0);
      }
   }

if ( props.globals.getValue(gear/gear[2]/position-norm > 0.8 )) {
   stbd-green.setBoolValue(1);
   }
   else {
   stbd-green.setBoolValue(0);
   }


Sorry I need such hand-holding, like I said it's all a bit new to me, but I'm trying to teach myself from scratch..
User avatar
ScottBouch
 
Posts: 183
Joined: Wed Jun 22, 2016 4:14 pm
Location: Midlands, UK
OS: Linux Mint

Re: Total beginner... creating a new property in tree

Postby AndersG » Fri May 24, 2019 2:13 pm

Note that your variable names, such as "port-red" and "port-amber", aren't ok in Nasal. The minus sign makes it parse as "port - red" for the two unknown variables "port" and "red", which is also not at all expected after the "var" keyword.

You could exchange "-" with "_" to get ok variable names.
Callsign: SE-AG
Aircraft (uhm...): Submarine Scout, Zeppelin NT, ZF Navy free balloon, Nordstern, Hindenburg, Short Empire flying-boat, ZNP-K, North Sea class, MTB T21 class, U.S.S. Monitor, MFI-9B, Type UB I submarine, Gokstad ship, Renault FT.
AndersG
 
Posts: 2527
Joined: Wed Nov 29, 2006 10:20 am
Location: Göteborg, Sweden
Callsign: SE-AG
OS: Debian GNU Linux

Re: Total beginner... creating a new property in tree

Postby legoboyvdlp » Fri May 24, 2019 3:56 pm

You'll want to also use props.globals.initNode rather than just initNode. initNode is in the props.globals. namespace.
User avatar
legoboyvdlp
 
Posts: 7981
Joined: Sat Jul 26, 2014 2:28 am
Location: Northern Ireland
Callsign: G-LEGO
Version: next
OS: Windows 10 HP

Re: Total beginner... creating a new property in tree

Postby ScottBouch » Sat May 25, 2019 8:26 am

Thank you for the tip on variable names, that makes a lot of sense! Will edit accordingly.

Cheers, Scott
User avatar
ScottBouch
 
Posts: 183
Joined: Wed Jun 22, 2016 4:14 pm
Location: Midlands, UK
OS: Linux Mint

Re: Total beginner... creating a new property in tree

Postby Richard » Mon May 27, 2019 8:16 am

ScottBouch wrote in Thu May 23, 2019 11:44 pm:Welcome to my first ever Nasal script. And I'm very much a novice programmer, so please bear with me.


there are quite a lot of mistakes in the script; firstly nasal is largely untyped so instead of "bool variable_name" you have to do "var variable_name = 0", Nasal kinda supports bools but it's better to use ints. Next all property names need to be quoted; and check the documentation for the methods that you're calling (e.g. the initNode).

You don't really need properties for the intermediate values for each lamp; just use the Nasal variables (much more efficient). Next this is an ideal candidate for using listeners - which allows you to set a callback when a property is changed.

The following is a working script that does what you want. Hopefully you'll be able to follow it. Sorry for just rewriting your code rather than going through line by line and explaining what needs to be done.
Code: Select all
var port_red = 0;
var port_amber = 0;
var port_green = 0;

var nose_red = 0;
var nose_amber = 0;
var nose_green = 0;

var stbd_red = 0;
var stbd_amber = 0;
var stbd_green = 0;
var output_property = props.globals.getNode("landing-gear-lamps-composite",1);

##Build string of bools, one for each indicator lamp:
getv = func(red,amber,green){
    var rv="";
    rv ~= red ? "1" : "0";
    rv ~= amber ? "1" : "0";
    rv ~= green ? "1" : "0";
    return rv;
}

update_property = func{
    var ts = "";
    ts ~= getv(port_red, port_amber, port_green);
    ts ~= getv(nose_red, nose_amber, nose_green);
    ts ~= getv(stbd_red, stbd_amber, stbd_green);
    output_property.setValue(ts);
};

setlistener("gear/gear[0]/position-norm", func(v){
    nose_red = v.getValue() < 0.2;
    nose_amber = v.getValue() > 0.2 and v.getValue() < 0.8;
    nose_green = v.getValue() > 0.8;
    update_property();
},1,0);

setlistener("gear/gear[1]/position-norm", func(v){
    port_red = v.getValue() < 0.2;
    port_amber = v.getValue() > 0.2 and v.getValue() < 0.8;
    port_green = v.getValue() > 0.8;
    update_property();
},1,0);

setlistener("gear/gear[2]/position-norm", func(v){
    stbd_red = v.getValue() < 0.2;
    stbd_amber = v.getValue() > 0.2 and v.getValue() < 0.8;
    stbd_green = v.getValue() > 0.8;
    update_property();
},1,0);

Richard
 
Posts: 810
Joined: Sun Nov 02, 2014 11:17 pm
Version: Git
OS: Win10


Return to Nasal

Who is online

Users browsing this forum: No registered users and 2 guests