Howto:Implement a Fly-By-Wire System for Airliners: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
(Undo revision 40194 by Omega1174 (talk))
No edit summary
Line 243: Line 243:
throttle1 -= 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
</syntaxhighlight>
=== -set.xml ===
Call the Nasal file in your aircraft's -set.xml file by adding the following code inside <nasal></nasal>
<syntaxhighlight lang="xml">
<fbw>
<file>Aircraft/787-8/Nasal/fbw.nas</file>
</fbw>
</syntaxhighlight>
Replace '787-8' with your aircraft folder name.
=== JSBSim FDM ===
Replace 'aileron-cmd-norm' with 'aileron-fbw-output', replace 'elevator-cmd-norm' with 'elevator-fbw-output' and finally, replace 'rudder-cmd-norm' with 'rudder-fbw-output'.
For example,
<syntaxhighlight lang="xml">
  <summer name="Pitch Trim Sum">
      <input>fcs/elevator-cmd-norm</input>
      <input>fcs/pitch-trim-cmd-norm</input>
      <clipto>
        <min> -1 </min>
        <max>  1 </max>
      </clipto>
  </summer>
</syntaxhighlight>
was changed to
<syntaxhighlight lang="xml">
  <summer name="Pitch Trim Sum">
      <input>fcs/elevator-fbw-output</input>
      <input>fcs/pitch-trim-cmd-norm</input>
      <clipto>
        <min> -1 </min>
        <max>  1 </max>
      </clipto>
  </summer>
</syntaxhighlight>
== Configuration ==
Add the following switches anywhere (preferably the CDU) to be able to configure the CDU in FlightGear:
* /controls/fbw/active (controls whether the fly-by-wire system is active or not)
* /controls/fbw/yaw-damper (controls the yaw damper)
* /controls/fbw/rudder (controls whether the fly-by-wire controls rudder or not)
* /controls/fbw/bank-limit (controls the aircraft's bank limit)
If you don't want any of the configurations to be edited in Flightgear, but configured generally, add the following under </sim> to your -set.xml for the appropriate properties you want to configure:
<syntaxhighlight lang="xml">
<controls>
<fbw>
<yaw-damper type="int">1</yawdamper>
<rudder type="int">1</rudder>
<bank-limit type="int">30</bank-limit> <!-- 30 degrees bank permitted -->
</fbw>
</controls>
</syntaxhighlight>
[[Category:Howto]]
[[Category:Nasal]]

Revision as of 10:26, 7 February 2012

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.

B787-8 Fly-By-Wire

Another feature in the Boeing 787-8's Fly By Wire is the automatic control of the trailing edge camber which affects lift and drag. The fly-by-wire automatically adjusts that to get maximum efficiency. Redneck and I am working on that but it's not included in the below nasal code as I don't think any other aircraft has that. And ofcourse, it's not yet completed. The rest of the Fly-By-Wire is stable at the moment and has been tested on the new Boeing 787-8.

Note for Airbus Aircraft Developers

About Airbus Fly By Wire : [1]

I've just seen that the airbus Fly By Wire works slightly different. I'll create a new fly-by-wire / modify this one to have it function that way. In Airbus Aircraft, moving the control stick controls angular acceleration, and not angular velocity. That is, when you move the stick to the left, the plane starts turning left, when you bring the stick back to the center, the fly-by-wire asks the plane to maintain that bank angle. It's the same case for pitch, and this is not available in Boeing's Fly-By-Wire.

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
  • Dampens the controls to prevent sudden movements


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 FLIGHTGEAR  ##
#########################################
## Designed by Omega Pilot and Redneck ##
#########################################

# 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

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

## 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;
  } # end of disconnect announce
 } # end of efis/agl check
}

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

-set.xml

Call the Nasal file in your aircraft's -set.xml file by adding the following code inside <nasal></nasal>

	<fbw>
		<file>Aircraft/787-8/Nasal/fbw.nas</file>
	</fbw>

Replace '787-8' with your aircraft folder name.

JSBSim FDM

Replace 'aileron-cmd-norm' with 'aileron-fbw-output', replace 'elevator-cmd-norm' with 'elevator-fbw-output' and finally, replace 'rudder-cmd-norm' with 'rudder-fbw-output'.

For example,

   <summer name="Pitch Trim Sum">
      <input>fcs/elevator-cmd-norm</input>
      <input>fcs/pitch-trim-cmd-norm</input>
      <clipto>
        <min> -1 </min>
        <max>  1 </max>
      </clipto>
   </summer>

was changed to

   <summer name="Pitch Trim Sum">
      <input>fcs/elevator-fbw-output</input>
      <input>fcs/pitch-trim-cmd-norm</input>
      <clipto>
        <min> -1 </min>
        <max>  1 </max>
      </clipto>
   </summer>

Configuration

Add the following switches anywhere (preferably the CDU) to be able to configure the CDU in FlightGear:

  • /controls/fbw/active (controls whether the fly-by-wire system is active or not)
  • /controls/fbw/yaw-damper (controls the yaw damper)
  • /controls/fbw/rudder (controls whether the fly-by-wire controls rudder or not)
  • /controls/fbw/bank-limit (controls the aircraft's bank limit)

If you don't want any of the configurations to be edited in Flightgear, but configured generally, add the following under </sim> to your -set.xml for the appropriate properties you want to configure:

	<controls>
		<fbw>
			<yaw-damper type="int">1</yawdamper>
			<rudder type="int">1</rudder>
			<bank-limit type="int">30</bank-limit> <!-- 30 degrees bank permitted -->
		</fbw>
	</controls>