Board index FlightGear Development Nasal

Nasal Randomness

Nasal is the scripting language of FlightGear.

Re: Nasal Randomness

Postby PINTO » Wed Apr 27, 2016 5:58 am

setlistener() isn't the greatest for this application, but whatever floats your boat. It's your plane.

And it's nonsensical that it'd fail at exactly 100 kts, or between 99 and 105, or whatever. But, hey, maybe I'm not seeing the application, so there's that. I did set the Blackbird to unstart between mach 3.53 and 3.55 (in hindsight, 3.55 is probably low, 3.60 might be better), so maybe there's something I'm totally missing with this.

Anywho, I'm out of this thread. Good luck.
Actively developing the MiG-21bis (github repo) (forum thread) (dev discord) (fg wiki)

http://opredflag.com is an active flightgear dogfighting community (using a system that isn’t bombable)
User avatar
PINTO
 
Posts: 966
Joined: Wed Oct 21, 2015 7:28 pm
Callsign: pinto
Version: stable
OS: Win10

Re: Nasal Randomness

Postby Thorsten » Wed Apr 27, 2016 6:14 am

I still think using setListener(); is better.


What is the sampling accuracy needed?

Tying a listener to an FDM property samples it 120 times per second (or more if someone clocks up FDM rate), using a loop at framerate samples typically 30-60 times per second (or less if your framerate is less), running a loop at a second samples every second. That's the major conceptual difference.

Is it important that failure X occurs between frame 14 and frame 15 of the current second, or is it enough that it occurred some time during the second?

For gear/ground interactions, a sampling rate of 120 Hz at 230 kt touchdown speed means 90 cm sampling intervals between subsequent gear states - sampling at 0.1 seconds increases that to 11 m. So you need as much accuracy as you can get. For an engine failure?
Thorsten
 
Posts: 12490
Joined: Mon Nov 02, 2009 9:33 am

Re: Nasal Randomness

Postby legoboyvdlp » Wed Apr 27, 2016 3:53 pm

Problem...

This is the error
Code: Select all
Nasal runtime error: undefined symbol: engineLFail100
  at /sim/bindings/gui/binding, line 2


This is the .xml dialog
Code: Select all
<?xml version="1.0" encoding="UTF-8"?>

<PropertyList>

   <name>Failures</name>
   <layout>vbox</layout>

   <text>
      <label>Failures Control</label>
   </text>

   <hrule />
      
   <text>
      <label>Engine Failure (100 knots)</label>
   </text>

   <checkbox>
      <label>Left Engine</label>
      <property>/controls/switches/Lengine100fail</property>
      <binding>
         <command>nasal</command>
         <script>
         engineLFail100();
         print("LEFT ENGINE FAILURE... ARMED");         </script>
      </binding>
      <live>true</live>
   </checkbox>
   
      <checkbox>
      <label>Right Engine</label>
      <property>/controls/switches/Rengine100fail</property>
      <binding>
         <command>nasal</command>
         <script>
         engineRFail100();
         print("RIGHT ENGINE FAILURE... ARMED");         </script>
      </binding>
      <live>true</live>
   </checkbox>
      
   <hrule />
   
   <group>
   <layout>hbox</layout>

      <button>
         <legend>Close</legend>
         <default>true</default>
         <key>Esc</key>
      <padding>5</padding>
         <binding>
            <command>dialog-apply</command>
         </binding>
         <binding>
            <command>dialog-close</command>
         </binding>
      </button>
      
   </group>

</PropertyList>


And this is the nasal code
Code: Select all
var engineLFail100 = func {                                             # Start of function, checkbox should call this.
   var L100armed = getprop("/controls/switches/Lengine100fail");
   var speed = 0;                                                                                        # Don't want to recreate the value each time, so this is the initial set of "speed"
   setlistener("/instrumentation/airspeed-indicator/indicated-speed-kt", func {   # Sets a listener for the airspeed, so when it changes, this gets run
      speed = getprop("/instrumentation/airspeed-indicator/indicated-speed-kt");         # Updates the value of "speed"
   });
   if (speed >= 95 and speed <= 105 and L100armed){                                    # Checks if "speed" is equal to 100 or not.
      setprop("engines/engine[0]/state", 4);                              # Sets the LEFT engine (0) state to 4 (shutdown)
      setprop("/controls/engines/engine[0]/cutoff",1);                     # Sets the fuel switch to cutoff.
      setprop("/controls/switches/Lengine100fail",0);     
   } else if (L100armed) {                                             # If "speed" is not 100, but "L100armed" is true
      engineLFail100();                                             # Rerun the if statement from beginning to check again
   } else {                                                      # If "speed" is not 100, and "L100armed" is false
      return 0;                                                   # Exit, since the statements are not met.
   }
}






var engineRFail100 = func {                                             # Start of function, checkbox should call this.
   var R100armed = getprop("/controls/switches/Lengine100fail");
   var speed = 0;                                                                                        # Don't want to recreate the value each time, so this is the initial set of "speed"
   setlistener("/instrumentation/airspeed-indicator/indicated-speed-kt", func {   # Sets a listener for the airspeed, so when it changes, this gets run
      speed = getprop("/instrumentation/airspeed-indicator/indicated-speed-kt");         # Updates the value of "speed"
   });
   if (speed >= 95 and speed <= 105 and R100armed){                                    # Checks if "speed" is equal to 100 or not.
      setprop("engines/engine[1]/state", 4);                              # Sets the LEFT engine (0) state to 4 (shutdown)
      setprop("/controls/engines/engine[1]/cutoff",1);                     # Sets the fuel switch to cutoff.
      setprop("/controls/switches/Rengine100fail",0);     
   } else if (R100armed) {                                             # If "speed" is not 100, but "L100armed" is true
      engineRFail100();                                             # Rerun the if statement from beginning to check again
   } else {                                                      # If "speed" is not 100, and "L100armed" is false
      return 0;                                                   # Exit, since the statements are not met.
   }
}



Joshua -- I'm stumped, I guess I'll have to squeal for help again.
It just fails with that console error...
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: Nasal Randomness

Postby Richard » Wed Apr 27, 2016 4:46 pm

legoboyvdlp wrote in Wed Apr 27, 2016 3:53 pm:Problem...

Nasal runtime error: undefined symbol: engineLFail100


You probably need to do something like module.engineLFail100 - where module is whatever section you loaded the nasal module into in the -set.xml

secondly the listener on speed is not really a good idea. Speed will change pretty much every frame so this isn't going to be efficient. you should just do the following at the top of the function.

Code: Select all
   var speed = getprop("/instrumentation/airspeed-indicator/indicated-speed-kt");


This isn't going to do what you expect either; it doesn't reschedule the function next frame, it will run it again immediately and possibly keep running it until you run out of stack space.
Code: Select all
      engineLFail100();                                             # Rerun the if statement from beginning to check again


Most aircraft have a nasal update loop that runs at the frame rate. You can find this by looking for a timer set to zero. This is where you should insert the call to check for the malfunction.
Richard
 
Posts: 810
Joined: Sun Nov 02, 2014 11:17 pm
Version: Git
OS: Win10

Re: Nasal Randomness

Postby legoboyvdlp » Wed Apr 27, 2016 5:01 pm

Thank you Richard -- it seems my error was typing engineLFail100(); in the .xml file instead of MD88.engineLFail100();
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: Nasal Randomness

Postby Octal450 » Wed Apr 27, 2016 7:40 pm

Well my code causes a stack overflow, the value changes too much for setlistener. I guess use a timer?

Regards,
Skillset: JSBsim Flight Dynamics, Systems, Canvas, Autoflight/Control, Instrumentation, Animations
Aircraft: A320-family, MD-11, MD-80, Contribs in a few others

Octal450's GitHub|Launcher Catalog
|Airbus Dev Discord|Octal450 Hangar Dev Discord
User avatar
Octal450
 
Posts: 5583
Joined: Tue Oct 06, 2015 1:51 pm
Location: Huntsville, AL
Callsign: WTF411
Version: next
OS: Windows 11

Re: Nasal Randomness

Postby legoboyvdlp » Wed Apr 27, 2016 7:48 pm

Yes
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: Nasal Randomness

Postby legoboyvdlp » Wed Apr 27, 2016 7:53 pm

it0uchpods!

Will this work?

Code: Select all
var engineLFail100 = func {                                             # Start of function, checkbox should call this.
   var L100armed = getprop("/controls/switches/Lengine100fail");
   
   var timer = maketimer(1, func(){
        var speed = getprop("/instrumentation/airspeed-indicator/indicated-speed-kt");
   });
   timer.start();
   
   if (speed >= 95 and speed <= 105 and L100armed){                                    # Checks if "speed" is equal to 100 or not.
      setprop("engines/engine[0]/state", 4);                              # Sets the LEFT engine (0) state to 4 (shutdown)
      setprop("/controls/engines/engine[0]/cutoff",1);                     # Sets the fuel switch to cutoff.
      setprop("/controls/switches/Lengine100fail",0);     
   } else if (L100armed) {                                             # If "speed" is not 100, but "L100armed" is true
      engineLFail100();                                             # Rerun the if statement from beginning to check again
   } else {                                                      # If "speed" is not 100, and "L100armed" is false
      return 0;                                                   # Exit, since the statements are not met.
     timer.stop();                                   # turn off timer
   }
}
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: Nasal Randomness

Postby legoboyvdlp » Wed Apr 27, 2016 8:00 pm

Does not work -- undefined symbol 'speed' on line 9.
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: Nasal Randomness

Postby sanhozay » Wed Apr 27, 2016 8:24 pm

The variable "speed" is defined inside the function passed to maketimer and is not visible outside that function.
sanhozay
 
Posts: 1207
Joined: Thu Dec 26, 2013 12:57 pm
Location: EGNM
Callsign: G-SHOZ
Version: Git
OS: Ubuntu 16.04

Re: Nasal Randomness

Postby legoboyvdlp » Wed Apr 27, 2016 8:53 pm

I think I thought of a method, probably not the best way..

Simply setprop the speed to a new property and getprop in the other function.

Thanks, sanhozay, Richard, Hooray, Horsten, and it0uchpods for all your help
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: Nasal Randomness

Postby Richard » Wed Apr 27, 2016 9:07 pm

legoboyvdlp wrote in Wed Apr 27, 2016 7:53 pm:Will this work?


Nope; as I previously said you'll get a stack overflow because you are calling the method from within the method.

Something more like what's below. You need to have all of the logic inside the timer, and control how often the timer is executed. One of the powerful features of Nasal is that you can pass values in from the xml - so this could be adapted to fail an engine by number. I've not done that, and this code isn't tested I just typed it in.

Code: Select all
var preset_malfunction_timer = maketimer(1, func
{
    var speed = getprop("/instrumentation/airspeed-indicator/indicated-speed-kt");
    var L100armed = getprop("/controls/switches/Lengine100fail");
   
    if (!L100armed ) # if not armed then only check every second
        preset_malfunction_timer.restart(1);
 
   if (speed >= 95 and speed <= 105){                                    # Checks if "speed" is equal to 100 or not.
        setprop("engines/engine[0]/state", 4);                              # Sets the LEFT engine (0) state to 4 (shutdown)
        setprop("/controls/engines/engine[0]/cutoff",1);                     # Sets the fuel switch to cutoff.
        setprop("/controls/switches/Lengine100fail",0);     
        preset_malfunction_timer.stop();
    }
    preset_malfunction_timer.restart(0);
    setprop("/controls/switches/Lengine100fail",0);
} );

 var enginePresetFailure = func {                                             # Start of function, checkbox should call this.
     setprop("/controls/switches/Lengine100fail",1);
     preset_malfunction_timer.restart(1);
 };
Richard
 
Posts: 810
Joined: Sun Nov 02, 2014 11:17 pm
Version: Git
OS: Win10

Previous

Return to Nasal

Who is online

Users browsing this forum: No registered users and 7 guests