Nasal Help

14 Dec 2020 09:47 - 14 Dec 2020 10:53 #49210 by 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.

Many thanks, Scott.
Attachments:

Please Log in or Create an account to join the conversation.

14 Dec 2020 10:59 #49211 by ScottBouch
SCRAP that.. I commented out all ofmy half scripting, and the basics now work!

Turned out that a parse error further down the script caused the initial basics to break.

I now have the hydraulics systems and properties in the property tree! Hooray!

Now to figure out how to correctly script it...

Please Log in or Create an account to join the conversation.

14 Dec 2020 11:04 #49212 by ScottBouch
Ok, why does this throw a parse error?

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"));
}

Please Log in or Create an account to join the conversation.

14 Dec 2020 13:06 #49213 by Warty
Maybe try something like this?
# 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();
	
})

Mac 10.14.1 Mojave, FG 2020.4.0

Please Log in or Create an account to join the conversation.

14 Dec 2020 15:00 - 14 Dec 2020 16:17 #49214 by 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);
}

(HSS = High Signal Select).

Thank you, Scott.

Please Log in or Create an account to join the conversation.

14 Dec 2020 16:22 #49215 by Warty
Yes, assign a value when you declare it - even if it is only . . .

var serv_pumps_hss_press_psi = 0 ;
if(....){ serv_pumps_hss_press_psi = 10; }

etc

Mac 10.14.1 Mojave, FG 2020.4.0

Please Log in or Create an account to join the conversation.

15 Dec 2020 14:38 #49216 by ScottBouch
Excellent advice, thank you again.

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?

Cheers, Scott.

Please Log in or Create an account to join the conversation.

15 Dec 2020 15:12 #49218 by timi
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.

Please Log in or Create an account to join the conversation.

15 Dec 2020 16:52 #49219 by Warty
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" B)
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.

Mac 10.14.1 Mojave, FG 2020.4.0

Please Log in or Create an account to join the conversation.

15 Dec 2020 17:45 #49220 by eagle12
For me these are hieroglyphs. I didn't know that you are archaeologists.
How are you Nefertiti ?

Please Log in or Create an account to join the conversation.

15 Dec 2020 17:58 #49221 by ScottBouch
Thank you for these tips...

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!

Thanks again, Scott.

Please Log in or Create an account to join the conversation.

15 Dec 2020 18:18 #49222 by timi
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.

Please Log in or Create an account to join the conversation.

16 Dec 2020 20:24 #49226 by sanni
@Warty:

I don't know the internals of Nasal, but
/engines/engine[]
is an array.

That means that
/engines/engine
and
/engines/engine[1]
are the same variable!!?!

Please Log in or Create an account to join the conversation.

16 Dec 2020 20:45 - 16 Dec 2020 21:35 #49227 by Warty
Nasal is a bit different :)
/engines/engine
is a shortcut for
/engines/engine[0]
.. the first engine (very often the only engine).
In my own stuff, I try to use the second "[0]" version

Mac 10.14.1 Mojave, FG 2020.4.0
The following user(s) said Thank You: sanni

Please Log in or Create an account to join the conversation.

24 Jun 2021 14:29 - 24 Jun 2021 18:12 #50590 by ScottBouch
Hi all, just need a little Nasal help please.

Here are some snippets from a script I'm working on for modelling the Lightning T5 DC electrical system. Whole file not submitted as it's quite lengthy.

PK is the emergency battery busbar, permanently connected to the emergency battery.
PE is the main battery busbar, permanently connected to the main battery.
PL is the main distribution busbar, connected to PE via the "battery isolator relay".
.
#########################
# Base Busbar Properties

	var base = props.globals.getNode("/systems/electrical/",1);

	var dcDist = base.getNode("dc-distribution",1);

	var pkBus = dcDist.getNode("pk-bus",1);
		# Emergency battery

	var peBus  = dcDist.getNode("pe-bus",1);
		# Main battery to PL via battery isolation relay

#########################
## Bus Voltage Properties

	var peV = peBus.getNode("pe-voltage",1);
	peV.setValue(0);

	var plV = plBus.getNode("pl-voltage",1);
	plV.setValue(0);

	var pkV = pkBus.getNode("pk-voltage",1);
	pkV.setValue(0);

#########################
## Main Contactor / Breaker / Relay Properties

	var relays =  dcDist.getNode("relays",1);
		# Group for relays / breakers / contactors

	var relayBatteryIsolator = relays.getNode("main-battery",1);
		# Main battery isolation relay, between PE and PL
	relayBatteryIsolator.setBoolValue(0);

#########################
## Power Supply Properties

	var powerSupplies =  dcDist.getNode("power-supplies",1);
		# Group for power supplies

	var emergBattV = powerSupplies.getNode("emerg-battery-voltage",1);
		# Emergency battery voltage
	emergBattV.setValue(24);

	var mainBattV = powerSupplies.getNode("main-battery-voltage",1);
		# Main battery voltage
	mainBattV.setValue(24);

#########################
# Functions

var busVoltages = func {

	pkV.setValue(powerSupplies.getValue("emerg-battery-voltage",1));
		# Sets Busbar PK Voltage to emergency battery voltage (no relay)

	peV.setValue(powerSupplies.getValue("main-battery-voltage",1));
		# Set busbar PE Voltage to main battery voltage

	if (relays.getBoolValue("main-battery",1)) {
				# If battery isolator is energised..
		plV.setValue(peBus.getValue("pe-voltage",1));
				# ..set busbar PE Voltage to busbar PL Voltage
	}

}

A "main_loop" calls the "busVoltages" function ok every 250mS.

In the FGFS property tree I'm getting PK and PE set to 24V by the "busVoltages" function, and when I adjust the battery Voltages on the fly, they also change, so all good.

The problem is when I make the main battery relay Bool true, the voltage at PL stays at zero, like the "if" statement isn't working.

Any ideas what I'm doing wrong with the 'if' statement?? (remember I'm still quite fresh to Nasal!)

Cheers, Scott.

Please Log in or Create an account to join the conversation.

24 Jun 2021 21:50 #50591 by enrogue
I suspect it's the relays.getBoolValue("main-battery",1) that is failing - check what this is returning

Please Log in or Create an account to join the conversation.

25 Jun 2021 07:12 - 25 Jun 2021 08:07 #50592 by ScottBouch

enrogue wrote: I suspect it's the relays.getBoolValue("main-battery",1) that is failing - check what this is returning


Thanks, I think you may be on to something.

I commented out the "if" statement, and instead created a new property for testing:

Properties:
var relayTest = relays.getNode("relay-test",1);
	relayTest.setBoolValue(0);

Looped function:
relayTest.setBoolValue(relays.getBoolValue("main-battery",1));

Test results:

1) In the FGFS property tree I can set "main-battery" to true, but "relay-test" remains false.

2) In the FGFS property tree I tried to set "relay-test" true, but something else must be writing a false to it, so it immediately pings back to false. This is the case when "main-battery" is true OR false.

3) When I comment out the test line in the function, in the FGFS property tree I can set "relay-test" true or false with no problem.

Any ideas on this now with the extra information?

Please Log in or Create an account to join the conversation.

25 Jun 2021 08:26 #50593 by enrogue
Actually I think it may be the usage of getBoolValue()

Are you trying to use it to read a sub-property? like {relays}/main-battery

Because in the reference it appears to only reference a prop directly:

var node = props.Node.new();
node.setDoubleValue(1.23);
print(node.getBoolValue() ? "true" : "false"); # prints "true"
node.setDoubleValue(-1.23);
print(node.getBoolValue() ? "true" : "false"); # prints "true"
node.setDoubleValue(0.0);
print(node.getBoolValue() ? "true" : "false"); # prints "false"

In wiki.flightgear.org/Nasal_library/props#getBoolValue.28.29 it doesn't ever appear to take an argument, so the node must have to refer to the property path itself

Also I can't see any use of an argument in FGDATA for getBoolValue()
The following user(s) said Thank You: ScottBouch

Please Log in or Create an account to join the conversation.

25 Jun 2021 09:05 #50594 by enrogue
try

if(relays.getNode("main-battery", 1).getBoolValue())

for the if statement instead?

Please Log in or Create an account to join the conversation.

25 Jun 2021 09:46 #50595 by ScottBouch
Thank you, I can see you train of thought on this.

However, I just tried it as below, but Nasal threw a parse error, you may be on the right track, and it may be just a slight adjustment to get it working.

if(relays.getNode("main-battery", 1).getBoolValue())
plV.setValue(peBus.getValue("pe-voltage",1));
}

Please Log in or Create an account to join the conversation.

Time to create page: 0.368 seconds
Powered by Kunena Forum

Latest Forum Posts

PM Notifications

You are not logged in.

PM Mailbox

You are not logged in.