Board index FlightGear Development Nasal

Learning Nasal from scratch

Nasal is the scripting language of FlightGear.

Learning Nasal from scratch

Postby Imran Anees » Wed Dec 06, 2017 1:16 pm

Hi I've been wanting to learn nasal in Flightgear so I can develop complex aircraft and also ultimately learn Canvas so I can implement canvas gui. Reading in the wiki I learnt that you need to have a base on Javascript to understand nasal. So should I follow a web tutorial on Javascript or do I have to learn C++? The thing is I have no experience whatsoever at programming but I have experimented with XML and I don't completely understand everything explain on the Wiki articles.

Thanks,
Imran
FlightGear! Fly Free!
Imran Anees
 
Posts: 75
Joined: Mon Feb 22, 2016 11:14 am
Callsign: IM-RAN
IRC name: IM-RAN
Version: 2016.1
OS: Windows 10

Re: Learning Nasal from scratch

Postby legoboyvdlp » Wed Dec 06, 2017 2:08 pm

You don't really need to know either. I at no point learned Javascript or C++.

I'd advise, instead, to learn programming concepts, that is boolean / double values / strings, and object orientated programming. However, I basically started with setprop(); and getprop(); and started making my systems more complex as I learned: first I started using timers, then I learned about if / else loops, and just recently how to do object orientated programming.
User avatar
legoboyvdlp
 
Posts: 6020
Joined: Sat Jul 26, 2014 1:28 am
Callsign: YV-LEGO
Version: 2018.3.1
OS: Windows 10 HP

Re: Learning Nasal from scratch

Postby Imran Anees » Wed Dec 06, 2017 4:30 pm

Ok but where do I start? I can obtain information about the concepts but how do I put into use. I think the best way is to learn examples from developed aircrafts, but it is kinda hard for me to fully understand what it is and how I can use it
FlightGear! Fly Free!
Imran Anees
 
Posts: 75
Joined: Mon Feb 22, 2016 11:14 am
Callsign: IM-RAN
IRC name: IM-RAN
Version: 2016.1
OS: Windows 10

Re: Learning Nasal from scratch

Postby legoboyvdlp » Wed Dec 06, 2017 6:38 pm

Well, there are plenty of aircraft that need some systems :) I'd really advise you to get onto the FlightGear discord and ask in the aircraft development channel for some aircraft that need systems and for help with doing it :)
User avatar
legoboyvdlp
 
Posts: 6020
Joined: Sat Jul 26, 2014 1:28 am
Callsign: YV-LEGO
Version: 2018.3.1
OS: Windows 10 HP

Re: Learning Nasal from scratch

Postby Hooray » Thu Dec 07, 2017 5:25 pm

The best advice I can give you is ignoring aircraft and code embedded there - it takes too much time and distracts from the real thing.
Nasal is fairly simple actually, what is complicating getting how everything hangs together.
Thus, the best thing you can do is to work through some of the tutorials on the wiki using the built-in Nasal console and REPL

http://wiki.flightgear.org/Nasal_Console
Image

http://wiki.flightgear.org/Interactive_Nasal_Console
Image

I would start with these, in the following order:

http://wiki.flightgear.org/Nasal_Hello_World
http://wiki.flightgear.org/Nasal_Variables
http://wiki.flightgear.org/Nasal_Loops
http://wiki.flightgear.org/Nasal_Conditionals
http://wiki.flightgear.org/Using_Nasal_functions
http://wiki.flightgear.org/Nasal_Namespaces
http://wiki.flightgear.org/Howto:Unders ... nd_Methods


For starters, this has much more to do with actually making experiments (and mistakes) than actually understanding everything right now.

I would literally read each article and try to work through it, you will probably only understand 1% of it at first - i.e. using just copy & paste.

But repetition is key here - i.e. read it over again and try to tinker with different snippets of code, maybe putting things together from different tutorials, and see what it is doing.
You really cannot break anything here.

But really, do ignore aircraft stuff, and especially OOP/Canvas if you don't have any previous coding experience - or the whole journey will be frustratingly slow and error-prone.

The JavaScript advice ... well, I added that - and I keep mentioning that still, while you don't need it - it's simple to learn and the syntax is applicable to FlightGear scripting.
But that's about it honestly. So you really don't need it. But there are obviously more learning resources for JavaScript than for Nasal/FG scripting.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11263
Joined: Tue Mar 25, 2008 8:40 am

Re: Learning Nasal from scratch

Postby Imran Anees » Fri Dec 08, 2017 12:35 am

Allright thanks for pointning out that. I have learned Java during my schooling and I understand the concepts of OOP. I will start with those wiki articles for now. But I really want to learn Canvas... anyway I'll finish those wiki tutorials first.

Thanks,
Imran
FlightGear! Fly Free!
Imran Anees
 
Posts: 75
Joined: Mon Feb 22, 2016 11:14 am
Callsign: IM-RAN
IRC name: IM-RAN
Version: 2016.1
OS: Windows 10

Re: Learning Nasal from scratch

Postby Hooray » Fri Dec 08, 2017 1:28 pm

Ok, someone with a little Java background knowledge will not have much of a problem picking up basic FlightGear scripting/Nasal concepts.

Nasal really is a simple language, much simpler than Java/JavaScript - it does not even do OOP the way it is done in Java.

If you want to do Canvas stuff, you will sooner or later encounter OOP though.
The main thing to keep in mind here is that most things go through the property tree.
So, do make sure to understand the property tree itself (unrelated to Nasal scripting), as well as the setprop/getprop extension functions and the higher level props.nas module which provides an OO wrapper around the whole thing.

For that, you will definitely want to tinker a bit with a few Nasal/OOP tutorials - again, the wiki is your friend here.
The key thing to keep in mind: Nasal has no constructors or destructors, there also is no "class" keyword.

Instead, we have hash maps - i.e. dictionaries that have key/value pairs, using a comma-separated list of key/value pairs (untested pseudo code below):

Code: Select all

var someHash = {
 x: 100,
 y: 200,
 z: 300,
};




This is a hash that has 3 members: x,y,z - they can be accessed via:

Code: Select all
someHash.x
someHash.y
someHash.z



You can assign arbitrary values to these keys, including strings, but also functions:

Code: Select all

var someHash = {
 x: func() {return 100;},
 y: func() {return 200;},
 z: func() {return 300;},
};


Next, inheritance is accomplished by using a single Nasal specific keyword only, called parents.
This can be a hash-specific vector containing a list of other hashes for the member/field (method) lookup, i.e. serving as a template:


Code: Select all

var someHash = {
 x: func() {return 100;},
 y: func() {return 200;},
 z: func() {return 300;},
};

var someNewHash = { parents:[someHash] };



At this point, someNewHash is inherited from someHash.

Most commonly, this is done using a pseudo constructor that we name "new", i.e. a key/value pair where new is the key, and a func is the value, usually this also gets a matching pseudo-destructor, that is commonly named "del":

Code: Select all

var someOtherHash = {
new: func() {
 return {parents:[someHash]};
},


del: func() {
},

};




With your sort of background, everything should fall into place once you do a little more reading, and some experiments with different tutorials and code snippets - and again, leave anything alone that is aircraft specific, there is too much complex stuff happening that is unrelated to Nasal the language.

For starters, all you will need to know can be learned via the wiki, the forum and a few tutorials - if in doubt, just ask your questions here, and people will usually be quick to post an answer.

I would also definitely suggest using just the Nasal Console and REPL for starters - it will all make much more sense, I would only look at creating separate files, once you understand the language and extensions mechanisms well enough - otherwise there are literally dozens of potential pitfalls where things can go wrong, despite using correct code

My suggestion would be do little "assignments" first before digging into the more complicated stuff, i.e. things like:

  • make flightgear print "Hello World" to the console
  • make flightgear print "Hello World" 5 times using a loop (try different kinds of loops)
  • try putting 5 names into a vector (array) or hash and make FlightGear print that to the console using a loop
  • set a value in the property tree from a Nasal string
  • get(prop) a value from the property tree and read it back into a Nasal string
  • write a function that accepts a vector and writes all its elements to the console
  • do it again, this time with a hash
  • make it accept a list of properties, and write the values in the tree to the console


This is really basic stuff, and while it may sound complicated, most people around here who have a little Nasal coding can complete all of these in under 10 minutes - but it will go a long way to help provide the foundation for some of the more sophisticated concepts, especially anything involving OOP and Canvas stuff.

Anyway, good luck
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11263
Joined: Tue Mar 25, 2008 8:40 am

Re: Learning Nasal from scratch

Postby Imran Anees » Fri Dec 08, 2017 2:40 pm

Ok. Thanks a lot. I'll try the stuff you have listed out and whenever I feel stuck I'll come to forums. Currently, I have some exams to clear with good grades, so I might take some time to start on this.

Thanks,
Imran
FlightGear! Fly Free!
Imran Anees
 
Posts: 75
Joined: Mon Feb 22, 2016 11:14 am
Callsign: IM-RAN
IRC name: IM-RAN
Version: 2016.1
OS: Windows 10

Re: Learning Nasal from scratch

Postby Hooray » Sat Dec 09, 2017 5:16 pm

Also, there is basically two different ways to put something into a hash that may confuse people new to doing OOP in Nasal, as well two different types of keys to be used:

Code: Select all
var myHash = {

'number': 100,

};

next, consider:

Code: Select all
var myHash = {
number: 100,
};



and now:

Code: Select all
var myHash = {};

myHash['number'] = 100;


vs.


Code: Select all
var myHash = {};

myHash.number = 100;
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11263
Joined: Tue Mar 25, 2008 8:40 am

Re: Learning Nasal from scratch

Postby legoboyvdlp » Sat Dec 09, 2017 6:47 pm

As an example, today I created this basic code which simulates power consumption of LCDs:

First, I declared some variables at the beginning of the file
Code: Select all
var power_consumption = nil;
var screen_power_consumption = nil;
var screens = nil;


Then came this:
Code: Select all
var screen = {
    name: "",
    type: "", # LCD or CRT, will be used later when we have CRTs
    max_watts: 0,
    dim_watts: 0,
    dim_prop: "",
    power_consumption: func() {
        if (getprop(me.dim_prop) != 0) {
            screen_power_consumption = (getprop(me.dim_watts) + (10 * getprop(me.dim_prop)));
        } else {
            screen_power_consumption = 0;
        }
        return screen_power_consumption;
    },
    new: func(name,type,max_watts,dim_watts,dim_prop) {
        var s = {parents:[screen]};
       
        s.name = name;
        s.type = type;
        max_watts = max_watts;
        dim_watts = dim_watts;
        dim_prop = dim_prop;
       
        return s;
    }
};


Then, inside some code that is executed once the FDM is initialized:

Code: Select all
screens = [screen.new("DU1","LCD",60,50,"controls/lighting/DU/du1"),
                screen.new("DU2","LCD",60,50,"controls/lighting/DU/du2"),
                screen.new("DU3","LCD",60,50,"controls/lighting/DU/du3"),
                screen.new("DU4","LCD",60,50,"controls/lighting/DU/du4"),
                screen.new("DU5","LCD",60,50,"controls/lighting/DU/du5"),
                screen.new("DU6","LCD",60,50,"controls/lighting/DU/du6")];


Finally, inside some code that is executed every so often, I put an update function:

Code: Select all
foreach(var screena; screens) {
     power_consumption = screena.power_consumption();
     setprop("/systems/electrical/DU/" ~ screena.name ~ "/watts",power_consumption);
}


Note that there is a bad getprop argument somewhere on this line: screen_power_consumption = (getprop(me.dim_watts) + (10 * getprop(me.dim_prop))); (which I would love if somone could find, as I can't! Maybe I need to do var dim_watts; and var dim_prop; at the top?)but this shows what you can do with OOP.
User avatar
legoboyvdlp
 
Posts: 6020
Joined: Sat Jul 26, 2014 1:28 am
Callsign: YV-LEGO
Version: 2018.3.1
OS: Windows 10 HP

Re: Learning Nasal from scratch

Postby Hooray » Sat Dec 09, 2017 7:00 pm

I don't what you are referring to regardingthe "bad getprop argument" - but if that is to say that the getprop() call returns nil/not a number, then you really only need to default the argument to a sane value.
To see where the problem is, and what it is - simply put those expressions in separate lines, and the error message will become much clearer, i.e. whenever you are seeing a getprop() not returning what you expect, just move it outside the long expression into a single statement/expression, without any other stuff in that line.
You can then easily use debug.dump() to see what is going on, as well as debug.bt() to get a backtrace.
For starters, it should probably suffice to simply dump the property path to the console and the return value.

If in doubt, pass a default argument to the getprop() (as per the wiki docs) or use something like:
Code: Select all

var value = getprop("/bullshit/value") or 0.00;




PS: Maybe, this would have been better posted in another topic (or even a tutorial for the wiki/newsletter) ?
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11263
Joined: Tue Mar 25, 2008 8:40 am

Re: Learning Nasal from scratch

Postby legoboyvdlp » Sat Dec 09, 2017 7:14 pm

FWIW I was just posting this as an example of what can be done with OOP, but a tutorial in the wiki would be an excellent idea, once I have time I'll get it up.

And here it is:

http://wiki.flightgear.org/Howto:Basic_OOP_Programming

Please feel free to edit it, expand, or whatever :)
User avatar
legoboyvdlp
 
Posts: 6020
Joined: Sat Jul 26, 2014 1:28 am
Callsign: YV-LEGO
Version: 2018.3.1
OS: Windows 10 HP

Re: Learning Nasal from scratch

Postby Hooray » Sun Dec 10, 2017 1:11 pm

To actually be useful as a tutorial, it would make sense to comment/annotate the corresponding source code - either by explaining what you are doing, and why - or at the very least by adding comments to the main building blocks of your code.

That being said, the way you are instantiating new screen objects is unnecessarily convoluted/complicated - you could just as well move all instance specific stuff into a list (vector of hashes and then use that in the foreach loop to instantiate each object.

Besides, for people to actually use such code, it would make sense for it to be self-contained, in the form that it can be put into a Nasal file and would "just work" - or even better, pasted into the Nasal console to illustrate what it is doing
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11263
Joined: Tue Mar 25, 2008 8:40 am

Re: Learning Nasal from scratch

Postby legoboyvdlp » Sun Dec 10, 2017 1:57 pm

I've made it as standalone as possible, if I haven't missed anything. Have you any more suggestions?
User avatar
legoboyvdlp
 
Posts: 6020
Joined: Sat Jul 26, 2014 1:28 am
Callsign: YV-LEGO
Version: 2018.3.1
OS: Windows 10 HP

Re: Learning Nasal from scratch

Postby Hooray » Sun Dec 10, 2017 5:49 pm

Like I said, at the very least, I would add more comments to the code to annotate the whole thing - otherwise, people new to Nasal/coding in general, may have a really hard time understanding what you are doing there. Personally, I would recommend using at least 1-2 lines of comments for every 5 lines of code in something that is intended to be a tutorial. Alternatively, split up your code accordingly and introduce the whole function/loop using a short paragraph.

I would also used named arguments in your function calls, especially those taking multiple arguments, for example consider:

Code: Select all
# name,type,max_watts,dim_watts,dim_prop
screen.new(name: "DU6", type:"LCD", max_watts:60, dim_watts50, dim_prop"controls/lighting/DU/du6");


PS: the id returned by setlistener should be stored in a vector, that is later on freed using removelistener - otherwise, you may be leaking listeners, which may mean that performance is degrading, because more and more listeners may trigger the same callback/s. (same goes for the timer object). Also note that ELEC is not actually a "class" here, because you don't use it as such (e.g. no new constructor, and no parents vector to set up new instances of the hash object)
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11263
Joined: Tue Mar 25, 2008 8:40 am

Next

Return to Nasal

Who is online

Users browsing this forum: No registered users and 2 guests