14 Dec 2020 09:47 - 14 Dec 2020 10:53#49210by ScottBouch
Hi guys,
Can someone please cast their eye over this attached Nasal script and tell me where I'm going wrong?
It does not generate the root /hydraulics branch in the property tree, and has a parse error at the actual script part. All I have done is copy methods form other scripts, I mush have introduced a mistake, but can't spot it.
The actual functional script is very early days (please almost ignore it), I really just need help in getting the basics working of generating the branch of the property tree and some properties, and I can go from there.
This is for the FGUK Lightning currently on GitLab, I've been debugging a little over the last few months (so there are some recent updates), and thought it was about time to model the hydraulic systems.
I'm just trying to set two local variables "engine1_rpm" and "engine 2_rpm" to contain the same data as the global rpm's. This is because I'll be using the rpm's a few times in my code.
var main_loop = func {
var engine1_rpm.setValue(props.globals.getValue("/engines/engine/rpm"));
var engine2_rpm.setValue(props.globals.getValue("/engines/engine[1]/rpm"));
}
# It is assumed the aircraft last flew / ran a few hours ago, and retains minimum services pressure to operate canopy and wheelbrakes only.
var hydraulics_loop = func { # Main Loop
var engine1_rpm = getprop("/engines/engine/rpm");
var engine2_rpm = getprop("/engines/engine[1]/rpm");
# Generate a pressure following engine %rpm
var serv_pump1_press_psi_raw = engine1_rpm * (3000/100);
# Clamp to low limit of 1700psi
if (serv_pump1_press_psi_raw > 1700) {
serv_pump1_press_psi_raw = 1700 ;
}
# then do something, like ... .
setprop("/hydraulics/services/serv_pump1_press_psi", serv_pump1_press_psi_raw);
setprop("/hydraulics/services/serv_pump2_press_psi", serv_pump1_press_psi_raw);
settimer(hydraulics_loop, update_period);
}
setlistener("/sim/signals/fdm-initialized", func { # ====================== initialization
# Settings & Defaults
var update_period = 0.25; # Loop Frequency
# Services pumps:
setprop("/hydraulics/services/serv_pump1_press_psi", 0);
setprop("/hydraulics/services/serv_pump2_press_psi", 0);
# Controls pumps:
setprop("/hydraulics/controls/cont_pump1_press_psi", 0);
setprop("/hydraulics/controls/cont_pump2_press_psi", 0);
# Controls pumps pressure switches:
setprop("/hydraulics/controls/cont_pump1_low_pressure_switch", 0);
setprop("/hydraulics/controls/cont_pump2_low_pressure_switch", 0); # switches only exist on the controls side
# Services pressure, common to both pumps:
setprop("/hydraulics/services/serv_press_psi", 0);
# Wheelbrake pressure (downstream of NRV):
setprop("/hydraulics/services/wheelbrake_press_psi", 1700);
hydraulics_loop();
})
14 Dec 2020 15:00 - 14 Dec 2020 16:17#49214by ScottBouch
Thank you so much for that help, I'd not use getprop before.
so, it worked in that I could generate the properties and set values, thank you.
I have corrected a few other errors, but I have one question now, I need to declare a variable, and have done so as just: var serv_pumps_hss_press_psi;
But it's throwing another parse error at this line, I have not set it to equal anything, this may be the issue, but I want to IF statement to set it's value..
var main_loop = func {
# Engine speeds:
var engine1_rpm = getprop("/engines/engine/rpm");
var engine2_rpm = getprop("/engines/engine[1]/rpm");
# Services:
# Generate a pressure following engine %rpm
var serv_pump1_press_raw_psi = engine1_rpm * (3000/100);
var serv_pump2_press_raw_psi = engine2_rpm * (3000/100);
var serv_pumps_hss_press_psi;
# Rail pressure = highest pump pressure
if (serv_pump1_press_raw_psi >= serv_pump2_press_raw_psi) {
serv_pumps_hss_press_psi = serv_pump1_press_raw_psi ;
}
if (serv_pump2_press_raw_psi > serv_pump1_press_raw_psi) {
serv_rail_hss_press_psi = serv_pump2_press_raw_psi ;
}
setprop("/hydraulics/services/serv_pump1_press_psi", serv_pump1_press_raw_psi);
setprop("/hydraulics/services/serv_pump2_press_psi", serv_pump2_press_raw_psi);
setprop("/hydraulics/services/wheelbrake_press_psi", serv_rail_hss_press_psi);
}
One question though - this var is now being assigned a value of 0, and then whatever sensible value the IF statement changes it to as the programme progresses...
As both of these assignments are within the main loop, why does the value not get set to zero, then the IF value each time the loop is run? ie: how does Nasal know to ignore the initial "var serv_pumps_hss_press_psi = 0 ;" after the first iteration?
Usually one would place a definition like that outside the loop
so it would have no effect when the loop starts executing. I
don't do much Nasal but that's what I'd do in other types of
scripting.
In my defence, I was answering the question of whether a var needed to be assigned a value on declaration. The etc kind of meant "deal with all eventualities"
Maybe something like this:
var serv_pumps_hss_press_psi = serv_pump2_press_raw_psi ;
if (serv_pump1_press_raw_psi >= serv_pump2_press_raw_psi){
serv_pumps_hss_press_psi = serv_pump1_press_raw_psi
}
etc
Yes, it could be declared outside of any functions in the body of hydraulics.nas just once and could then be changed by any function. If that is what you want. If you want other functions to have access to it that would certainly be preferable. Also, if you want it to "hold" its value until you want to change it for some reason.
But if you are only using it in this loop then there might be some advantage in confining it to this function - so you won't inadvertently change it in another call as the code gets bigger. A classic example of where you could get in a real mess with if it is available to all functions is the
for (var i = 0; i < 2; i += 1)
type construct.
Also, self contained things are more portable. I'm not saying either way is better/preferable. They are just options - your choice.
I think that "as the programme progresses..." is maybe a bit misleading. hydraulics_loop is a little programme that executes, in this case, every 250ms. When it's done it's done. Any vars declared and manipulated within it die at the closing } to be born again 250ms later.
Just a suggestion: maybe don't call things "main_loop" as you could end up with so many of them you can't tell which is which.
I like your explanations on how to think about how a program treats variables. I wish I'd studied C or similar in the past just to get more familiar with general programming, which is why I'm doing these project, to learn... as such most of what I'm doing so far is just copying ideas form other scripts, and a relying on a little teaching a friend once gave to me. This help you gave today certainly is useful to building my confidence with programming, thank you.
I had previously been taught it's good practice to keep as many variables within the function as possible, and only to make them"global" if needed for sharing between functions, so had been sticking with what I was taught.
With the hydraulics I had not split it up into separate functions as it's not that complex a system, and also there's no need to call separate parts under different circumstances, so I just stuck it all into one main function in it's own hydraulics .nas file. However, calling the loops more specific names could be helpful as you have suggested, I may do that.
I can't see this script being copied to another aircraft simply because no two aircraft are the same, so wasn't thinking about portability.
I now have a functioning Nasal script and have completed 50% of the hydraulic systems, the rest should be easier now I've got this far, ie: I can copy / paste a lot of what's now done and working. It's now comitted to the FGUK GitLab Lightning.
I have a Lightning wheelbrake pressure indicator on my desk that is working correctly now, driven by this script, via my Arduino, good to get another original indicator working!
A function is just a combination of things that
can be done with one call. Or that's how I see
it anyway. And a function can include a loop
for repetitive things.
So the function can still have local variables
which are not in the loop.