Howto:Implement a Fly-By-Wire System for Airliners

From FlightGear wiki
Revision as of 09:15, 7 February 2012 by Hooray (talk | contribs) (add categories: NASAL and HOWTO)
Jump to navigation Jump to search
This article is a stub. You can help the wiki by expanding it.

Objective: Implement a Nasal based fly-by-wire system for Airliners with fly-by-wire and set configuration properties to get desired results.

Background

The Fly-By-Wire system was developed for the Boeing 787-8, but can be used for other aircraft too. As Boeing wanted to give pilots the upper hand, the fly-by-wire systems CAN be disabled and overridden by pilot inputs. If you would like to use this fly-by-wire script for an Airbus Aircraft, you might want to make a few changes to give the fly-by-wire more power.

The whole idea here is to get the pilot's control inputs through a nasal script, and creating custom output properties which are then read by the FDM. To implement this system, you'll need to work with the following files:

  • -set.xml
  • fbw.nas
  • FDM xml file

Note that as the new 787 uses JSBSim, this tutorial will focus on implementing the FBW to an aircraft running with JSBSim.

Functions

The Boeing 787-8 Fly-By-Wire system executes the following functions which help stabilize the aircraft:

  • Accordingly adjusts thrust and elevators to maintain lift during turns
  • Helps during turns with rudder movement
  • Doesn't allow the plane to turn beyond the specified bank limit (customizable)
  • Applies thrust and slightly moves the elevators down when closing in on stall speed
  • Reduces thrust when exceeding 250 knots under 10000 ft MSL and when reaching Vne above 10000 ft MSL


The Fly-By-Wire Configs can be set/edit from the property tree. In the Boeing 787-8 (new one coming up soon), you can edit the following FBW Configurations from the FBW CONFIG menu in the CDU:

  • Fly-By-Wire Status (ACTIVE / DISABLED)
  • Rudder Control (ALLOWED / DENIED)
  • YAW DAMPER (ACTIVE / DISABLED)
  • BANK LIMIT (CYCLE BETWEEN 15, 20, 25, 30, 35, 40)

Implementation

/Nasal/fbw.nas

Open your aircraft's nasal directory and create a file called 'fbw.nas'. Copy and paste the following code in that file and save it.

#########################################
## FLY BY WIRE SYSTEM FOR BOEING 787-8 ##
#########################################
## Designed by Omega Pilot and Redneck ##
#########################################

# Fly By Wire Functions

## Dampen Surface positions
## Set Bank and Pitch Limits
## Help in turns with rudder
## Apply power while turning
## Maintain vertical speed during turns

# CONSTANTS

var RAD2DEG = 57.2957795;
var DEG2RAD = 0.0174532925;

var fbw = {
	init : func { 
        me.UPDATE_INTERVAL = 0.001; 
        me.loopid = 0; 
		me.throttle = 0;
		me.throttlefix = 0;
		me.vsinit = 0;
		me.throttleinit = 0;
		me.targetthrottle = 0;
		me.turnthrottlefix = 0;
		me.targetaileron = 0;
		me.targetelevator = 0;
		me.targetrudder = 0;
		me.adjustelevators = 0;

		me.disconnectannounce = 0;

## Initialize with FBW Activated

setprop("/controls/fbw/active", 1);
setprop("/controls/fbw/rudder", 1);
setprop("/controls/fbw/yaw-damper", 1);
setprop("/controls/fbw/bank-limit", 35);

## Initialize Control Surfaces

setprop("/fdm/jsbsim/fcs/aileron-fbw-output", 0);
setprop("/fdm/jsbsim/fcs/rudder-fbw-output", 0);
setprop("/fdm/jsbsim/fcs/elevator-fbw-output", 0);

        me.reset(); 
}, 
	update : func {

var fcs = "/fdm/jsbsim/fcs/";

## Fix Damp Rate according to Framerate

if (getprop("/sim/frame-rate") != nil) var fpsfix = 25 / getprop("/sim/frame-rate");
else fpsfix = 1;

## Bank Limit Setting

var banklimit = getprop("/controls/fbw/bank-limit");

## Position and Orientation

var altitudeagl = getprop("/position/altitude-agl-ft");

var altitudemsl = getprop("/position/altitude-ft");

var pitch = getprop("/orientation/pitch-deg");
var roll = getprop("/orientation/roll-deg");

var airspeedkt = getprop("/velocities/airspeed-kt");

var vsfps = getprop("/velocities/vertical-speed-fps");

## Flight Control System Properties

var aileronin = getprop(fcs~"aileron-cmd-norm");
var elevatorin =  getprop(fcs~"elevator-cmd-norm");
var rudderin = getprop(fcs~"rudder-cmd-norm");

## FBW Output (actual surface positions)

var aileronout = getprop(fcs~"aileron-fbw-output");
var elevatorout =  getprop(fcs~"elevator-fbw-output");
var rudderout = getprop(fcs~"rudder-fbw-output");

## Engine Throttle Positions

throttle0 = getprop("controls/engines/engine[0]/throttle");
throttle1 = getprop("controls/engines/engine[1]/throttle");

## This is where the FBW actually does it's job ;)

### The Fly-by--wire only works when it is active. In the Boeing 787, pilots have the option to disable fly-by-wire and use power-by-wire* in case of emergencies. The Fly By Wire Configuration includes: On/Off, Bank Limit and Rudder Control. The FBW Configs can be set in the FBW CONFIG Page in the CDU(s)

## Turn on Fly By Wire only if we have power

if (getprop("/systems/electrical/outputs/efis") != nil) {
if ((getprop("/systems/electrical/outputs/efis") < 9) and (altitudeagl >= 200)) {
setprop("/controls/fbw/active", 0);
if (me.disconnectannounce == 0) {
screen.log.write("Fly By Wire Disconnected!", 1, 0, 0);
me.disconnectannounce = 1;
} } }

if (getprop("/controls/fbw/active")) {

me.disconnectannounce = 0;

## AILERON CONTROLS

### Set Aileron Direction and Roll Direction

if (roll < 0) var rolldir = -1;
if (roll > 0) var rolldir = 1;
if (roll == 0) var rolldir = 0;

if (aileronin < 0) var ailerondir = -1;
if (aileronin > 0) var ailerondir = 1;
if (aileronin == 0) var ailerondir = 0;

if (((roll <= banklimit) and (roll >= -banklimit)) or (rolldir != ailerondir)) {

if (aileronin > aileronout) aileronout += 0.05 * fpsfix;

if (aileronin < aileronout) aileronout -= 0.05 * fpsfix;

} else {

### Don't let the plane bank past the bank limit

if (roll < -banklimit) me.targetaileron = -(roll + banklimit) * 0.025;
if (roll > banklimit) me.targetaileron = -(roll - banklimit) * 0.025;

if (aileronout < me.targetaileron) aileronout += 0.025 * fpsfix;
if (aileronout > me.targetaileron) aileronout -= 0.025 * fpsfix;

}

## ELEVATOR CONTROLS

if (elevatorin > elevatorout) elevatorout += 0.05 * fpsfix;

if (elevatorin < elevatorout) elevatorout -= 0.05 * fpsfix;

if ((elevatorin - elevatorout < 0.05) and (elevatorin - elevatorout > 0)) elevatorout += 0.01; 
if ((elevatorout - elevatorin < 0.05) and (elevatorin - elevatorout < 0)) elevatorout -= 0.01; 

### Use elevator to stabilize VS on turns

if ((roll <= -5) or (roll >= 5)) {

if (me.adjustelevators == 0) {
me.adjustelevators = 1;
me.vsinit = vsfps;
}

if (vsfps < me.vsinit) elevatorout -= 0.02;
if (vsfps > me.vsinit) elevatorout += 0.02;

} else {
if (me.adjustelevators == 1) {

if (vsfps < me.vsinit) elevatorout -= 0.02;
elsif (vsfps > me.vsinit) elevatorout += 0.02;
else me.adjustelevators = 0;

}
}

## THROTTLE CONTROLS

### Disconnect Throttle fix if manually overridden

if (throttle0 != me.throttle) {
me.throttlefix = 0;
me.turnthrottlefix = 0;
}


### Adjust throttle while turning

if ((roll <= -5) or (roll >= 5)) {

if (me.turnthrottlefix == 0) {
me.throttleinit = throttle0;
me.turnthrottlefix = 1;
}

me.targetthrottle = me.throttleinit + (me.throttleinit * math.sin(math.abs(roll * DEG2RAD)))/2;

if (me.targetthrottle > throttle0) {
throttle0 += 0.001 * fpsfix;
throttle1 += 0.001 * fpsfix;
} elsif (me.targetthrottle < throttle0) {
throttle0 -= 0.001 * fpsfix;
throttle1 -= 0.001 * fpsfix;
} 

}

if ((roll > -5) and (roll <= 5) and (me.turnthrottlefix == 1)) {

if (throttle0 <= me.throttleinit - 0.05) {
throttle0 += 0.001 * fpsfix;
throttle1 += 0.001 * fpsfix;
} elsif (throttle0 > me.throttleinit + 0.05) {
throttle0 -= 0.001 * fpsfix;
throttle1 -= 0.001 * fpsfix;
} else me.turnthrottlefix = 0;
}

### Reduce throttle if aircraft is faster than 250 KIAS under 10000 ft

if ((airspeedkt >= 250) and (altitudemsl <= 10000) and (throttle0 != 0) and (throttle1 != 0)) {
throttle0 -= 0.001 * fpsfix;
throttle1 -= 0.001 * fpsfix;
me.throttlefix = 1;
}

if ((me.throttlefix == 1) and (airspeedkt < 245) and (altitudemsl <= 10000) and (throttle0 != 1) and (throttle1 != 1)) {
throttle0 += 0.001 * fpsfix;
throttle1 += 0.001 * fpsfix;
}

### Adjust Throttle to stay under Vne

if ((airspeedkt >= 350) and (altitudemsl > 10000) and (throttle0 != 0) and (throttle1 != 0)) {
throttle0 -= 0.001 * fpsfix;
throttle1 -= 0.001 * fpsfix;
me.throttlefix = 1;
}

if ((me.throttlefix == 1) and (airspeedkt < 340) and (altitudemsl > 10000) and (throttle0 != 1) and (throttle1 != 1)) {
throttle0 += 0.001 * fpsfix;
throttle1 += 0.001 * fpsfix;
}

### Adjust Throttle to keep from stalling

if ((airspeedkt < 125) and (altitudeagl > 250) and (throttle0 != 1) and (throttle1 != 1)) {
throttle0 += 0.001 * fpsfix;
throttle1 += 0.001 * fpsfix;

### Also help by pushing forward on the stick

elevatorout += 0.02;

}

## RUDDER CONTROLS

if (getprop("/controls/fbw/rudder")) {

if ((roll < -5) or (roll > 5)) {
me.targetrudder = aileronout / 2;

if (me.targetrudder < rudderout) rudderout -= 0.015;
if (me.targetrudder > rudderout) rudderout += 0.015;

} }

## YAW DAMPER

if (getprop("/controls/fbw/yaw-damper")) {

if (rudderin > rudderout) rudderout += 0.05 * fpsfix;

if (rudderin < rudderout) rudderout -= 0.05 * fpsfix;

} else {

rudderout = rudderin;

}

# Transmit output signals to surfaces

setprop(fcs~"aileron-fbw-output", aileronout);
setprop(fcs~"elevator-fbw-output", elevatorout);
setprop(fcs~"rudder-fbw-output", rudderout);

setprop("controls/engines/engine[0]/throttle", throttle0);
setprop("controls/engines/engine[1]/throttle", throttle1);

me.throttle = throttle0; # This is to find out if the pilot moved the throttle

} else {

# Transmit input signals directly to surfaces

setprop(fcs~"aileron-fbw-output", aileronin);
setprop(fcs~"elevator-fbw-output", elevatorin);
setprop(fcs~"rudder-fbw-output", rudderin);

}

},
    reset : func {
        me.loopid += 1;
        me._loop_(me.loopid);
    },
    _loop_ : func(id) {
        id == me.loopid or return;
        me.update();
        settimer(func { me._loop_(id); }, me.UPDATE_INTERVAL);
    }

};

fbw.init();
print("Fly-By-Wire ......... Initialized");

# *Power-by-wire : corresponds to power steering in cars