zkv1000 / Nasal / afcs.nas /
Sébastien MARQUE commit initial
56c0030 7 years ago
1 contributor
247 lines | 8.872kb
var pitModes = {
    'PIT': 'pitch-hold',
    'ALT': 'altitude-hold',
    'VS': 'vertical-speed-hold',
    'FLC': 'flight-level-change',
    'GS': 'gs1-hold',
    'GP': '',
    'VPTH': 'vertical-path',
    'GA': 'go-around'
};
var pitMode = '';

var rollModes = {
    'ROL': 'wing-leveler',
    'HDG': 'dg-heading-hold',
    'GA': 'go-around',
    'GPS': '',
    'VOR': 'nav1-hold',
    'LOC': '',
    'VAPP': '',
};
var rollMode = '';

var AFCS = {
    nose_inc : 0,
    nose_node : '',
    nose_max : 0,
    nose_min : 0,
    AP  : func { 
              getprop('/instrumentation/zkv1000/status') or return;
              if (getPitchMode() == '') setPitchMode('PIT');
              setprop('/autopilot/locks/passive-mode', getprop('/autopilot/locks/passive-mode')? 0 : 1);
          },
    FD : func { 
             getprop('/instrumentation/zkv1000/status') or return;
             setPitchMode(getPitchMode() == '' ? 'PIT' : '');
         },
    ROL : func {
              setRollMode('ROL');
              settings.getNode('heading-bug-deg').unalias();
              afcs.getNode('roll-armed').setBoolValue(0);
              setprop('/autopilot/internal/target-roll-deg', 0);
          },
    HDG : func { 
              settings.getNode('heading-bug-deg').alias(afcs.getNode('heading-bug-deg')); 
          },
    NAV : func { 
              settings.getNode('heading-bug-deg').unalias();
              afcs.getNode('roll-armed').setBoolValue(0);
              checkRollAcquisition = checkNavAcquisition;
          },
    PIT : func { 
              AFCS.nose_inc = 0.5;
              AFCS.nose_node = '/autopilot/internal/target-pitch-deg';
              AFCS.nose_min = -15;
              AFCS.nose_max = 20;
              setprop(AFCS.nose_node, round(pitch));
          },
    VS  : func { 
              AFCS.nose_node = '/autopilot/settings/vertical-speed-fpm';
              AFCS.nose_inc = 100;
              AFCS.nose_min = -3000;
              AFCS.nose_max = 1500;
              setprop(AFCS.nose_node, round(vs, AFCS.nose_inc));
              setprop('/autopilot/settings/target-altitude-ft', getprop(afcs.getNode('selected-alt-ft').getPath()));
              checkPitchAcquisition = checkSelectedAltAcquisition;
          },
    ALT : func { 
              setprop('/autopilot/settings/target-altitude-ft', getprop(afcs.getNode('selected-alt-ft').getPath()));
              checkPitchAcquisition = checkSelectedAltAcquisition;
          },
    FLC : func { 
              AFCS.nose_node = '/autopilot/settings/target-speed-kt';
              AFCS.nose_inc = 1;
              AFCS.nose_min = 70;
              AFCS.nose_max = 165;
              computeAirspeedDiff = _computeAirspeedDiff;
              checkPitchAcquisition = checkSelectedAltAcquisition;
              setprop(AFCS.nose_node, round(ias, AFCS.nose_inc));
              setprop('/autopilot/settings/target-altitude-ft', getprop(afcs.getNode('selected-alt-ft').getPath()));
              FLCcomputation = _FLCcomputation;
          },
    NOSEUP : func { 
                 AFCS.nose_inc or return;
                 var s = getprop(AFCS.nose_node) + AFCS.nose_inc;
                 s <= AFCS.nose_max or return;
                 setprop(AFCS.nose_node, getprop(AFCS.nose_node) + AFCS.nose_inc);
             },
    NOSEDOWN : func { 
                   AFCS.nose_inc or return;
                   var s = getprop(AFCS.nose_node) - AFCS.nose_inc;
                   s >= AFCS.nose_min or return;
                   setprop(AFCS.nose_node, getprop(AFCS.nose_node) - AFCS.nose_inc);
               },
    VNV : func { 
              nyi('VNV');
          },
    APR : func {
              nyi('APR');
          },
    APDISC : void,
    CWS : void,
    GA : void
};

var checkNavAcquisition = func {
    var r = getprop('/instrumentation/zkv1000/cdi/radial');
    var h = getprop('/orientation/heading-deg');
    var d = getprop('/instrumentation/zkv1000/cdi/course-deflection');
    if (d < 0.5) {
        rollBlinking.switch(0);
        setprop('/instrumentation/zkv1000/afcs/roll-armed-mode', 0);
    }
    elsif (d > 1) {
        rollBlinking.switch(0);
        setprop('/instrumentation/zkv1000/afcs/roll-armed-mode', pitMode);
    }
    else {
        getprop('/instrumentation/zkv1000/afcs/roll-armed') or rollBlinking.switch(1);
        setprop('/instrumentation/zkv1000/afcs/roll-armed-mode', rollMode);
    }
}

var checkSelectedAltAcquisition = func {
    var s = getprop('/autopilot/settings/target-altitude-ft');
    var diff = abs(alt - s);
    var climb = (alt - s > 0);
    if (diff < 50) {
        pitchBlinking.switch(0);
        setPitchMode('ALT');
    }
    elsif (diff > 400) {
        setprop('/instrumentation/zkv1000/vertical-speed-fpm', (climb and !getPitchMode('VS'))? 1000 : -500);
        if (!getPitchMode('FLC')) setPitchMode('VS', 0);
        pitchBlinking.switch(0);
    }
    else {
        setprop('/instrumentation/zkv1000/vertical-speed-fpm', climb? 100 : -100);
        setPitchMode('VS');
        getprop('/instrumentation/zkv1000/afcs/pitch-armed') or pitchBlinking.switch(1);
    }
}

# Note: use SetPitchMode('') to exit the Flight Director mode
var setPitchMode = func (m, s=1) {
    checkPitchAcquisition = void;
    FLCcomputation = void;
    computeAirspeedDiff = void;
    AFCS.nose_inc = 0;
    if (pitMode == m and s) pitMode = 'PIT';
    else pitMode = m;
    setprop('/autopilot/locks/pitch', pitMode != '' ? pitModes[pitMode] : pitMode);
    setprop('/instrumentation/zkv1000/afcs/pit-active-mode', pitMode);
    setprop('/instrumentation/zkv1000/afcs/pit-armed-mode', pitMode);
    setprop('/instrumentation/zkv1000/afcs/pit-armed-mode-text', pitMode);
    setprop('/instrumentation/zkv1000/afcs/pit-active-mode-text', pitMode);
    setprop('/instrumentation/zkv1000/afcs/pit-active-mode-blink', 0);
    if (pitMode != '') {
        computeAltitudeDiff = _computeAltitudeDiff;
        setprop('/instrumentation/zkv1000/afcs/alt-bug-visible', 1);
        if (getRollMode() == '') setRollMode('ROL');
    }
    else {
        setprop('/instrumentation/zkv1000/afcs/alt-bug-visible', 0);
        rollBlinking.switch(0);
        computeAltitudeDiff = void;
        computeAirspeedDiff = void;
        setRollMode('', 0);
    }
    init_main_loop();
}

var setRollMode = func (m, s=1) {
    checkRollAcquisition = void;
    if (rollMode == m and s) rollMode = 'ROL';
    else rollMode = m;
    setprop('/autopilot/locks/roll', (rollMode != '')? rollModes[rollMode] : rollMode);
    setprop('/instrumentation/zkv1000/afcs/roll-active-mode', rollMode);
    setprop('/instrumentation/zkv1000/afcs/roll-armed-mode', rollMode);
    setprop('/instrumentation/zkv1000/afcs/roll-armed-mode-text', rollMode);
    setprop('/instrumentation/zkv1000/afcs/roll-active-mode-text', rollMode);
    setprop('/instrumentation/zkv1000/afcs/roll-active-mode-blink', 0);
    if (rollMode != '') {
        setprop('/instrumentation/zkv1000/afcs/fd-bars-visible', 1);
        if (getPitchMode() == '') setPitchMode('PIT');
    }
    else {
        setprop('/instrumentation/zkv1000/afcs/fd-bars-visible', 0);
        settings.getNode('heading-bug-deg').unalias();
        rollBlinking.switch(0);
    }
    init_main_loop();
}

var getPitchMode = func (mode = nil) {
    var m = getprop('/autopilot/locks/pitch');
    if (mode)
        return (m == mode);
    else
        return m;
}

var getRollMode = func (mode = nil) { 
    var m = getprop('/autopilot/locks/roll'); 
    if (mode)
        return (m == mode);
    else
        return m;
}


var _FLCcomputation = func {
    var t1 = getprop('/autopilot/internal/flc-airspeed-pitch-deg');
    var t2 = getprop('/autopilot/internal/flc-altitude-pitch-deg');
    setprop('/autopilot/internal/target-pitch-deg', (t1 + t2) / 2);
}

var _computeAltitudeDiff = func {
    var sel = getprop('/instrumentation/zkv1000/afcs/selected-alt-ft');
    setprop('/instrumentation/zkv1000/afcs/selected-alt-ft-diff', sel - alt);
}

var _computeAirspeedDiff = func {
    var sel = getprop('/autopilot/settings/target-speed-kt');
    setprop('/instrumentation/zkv1000/afcs/selected-ias-kt-diff', sel - ias);
}

var settings = props.globals.getNode('/autopilot/settings');

var pitchBlinking = nil;
var rollBlinking = nil;

var init_AFCS = func {
     pitchBlinking = aircraft.light.new(afcs.getNode('pit-active-mode-blink').getPath(), 
        [0.5, 0.5], 
        afcs.getNode('pitch-armed').getPath());
     pitchBlinking.switch(0);

     rollBlinking = aircraft.light.new(afcs.getNode('roll-active-mode-blink').getPath(), 
        [0.5, 0.5], 
        afcs.getNode('roll-armed').getPath());
     rollBlinking.switch(0);
     if (getprop('/sim/systems/autopilot/path') == 'Aircraft/Generic/generic-autopilot.xml') {
         setprop('/sim/systems/autopilot/path', 'Aircraft/Instruments-3d/zkv1000/Systems/autopilot.xml');
     }
}