Heretic
Resource contributor
- Messages
- 6,830
- Country
I know that there are at least half a dozen threads on this subject out there, but the solutions offered are either frontends for FSX autopilot code or the code is fairly hard to get into or is pretty spaghetti-ish.
My last - and only foray - into PID controllers was for half a semester almost seven years ago and the subject is so complex that fully catching up for a flight simulator project is nigh impossible, so forgive me if my terminology and explanations are sketchy.
The code below works rather well for a medium sized passenger aircraft, but might require adaption for any other winged contraptions.
Calculating the airspeed difference is pretty self-explanatory.
During development I've found that running the controller in a timer decreased its effectiveness, so to keep the code running at MSFS' 18Hz limit and still stop execution when the sim is paused, I've introduced the timer-related block as a cheap method for determining the sim's pause status.
The variables for the sim's pause status which are provided by XMLTools or the XML Sound gauge tend to stop working after half a dozen aircraft reloads so I have to stick to a more basic approach.
As far as I know, the proportional element of a controller is used to counteract large deviations from the target value, but is prone to induce unwanted oscillations. Since I've found that it did more harm than good when left unchecked, I've introduced a narrow boundary in which it may influence pitch trim. This is also the reason why the proportional gain on elevator trim is rather low.
Again, as far as my one hour refresher course provided, the integrative term is used to determine a trend to help "steer" the current value toward the target value. The trend is created by reading the current acceleration, convertinng, multiplying and then adding it to the current speed to obtain a future value for the current airspeed. Since this works rather well for dampening controller response, I've made it the most important element of the controller as can be seen by the amount of trim commands issued.
The derivative term basically trolls the other two terms by counteracting their commands to minimize acceleration. Yet, it helps to dampen the control response of the other two terms and thus enable the controller to attaint he target spead more quickly. Therefor I've made this the second most important term in the chain as evidenced by the control response.
When enabling this controller with a huge differential between your target and actual speed, you will see one or two pretty hefty oscillations, but this is quite normal. After that, the oscillations should successively become smaller before settling on a pitch value that will maintain the target speed.
Should the plane not stop oscillating, you will have to play with the boundary conditions, "look ahead" time or the gains (number of control inputs, i.e. "trim up/down").
I hope that my explanation wasn't too wrong and that someone finds this useful.
My last - and only foray - into PID controllers was for half a semester almost seven years ago and the subject is so complex that fully catching up for a flight simulator project is nigh impossible, so forgive me if my terminology and explanations are sketchy.
The code below works rather well for a medium sized passenger aircraft, but might require adaption for any other winged contraptions.
Code:
(A:AIRSPEED INDICATED, knots) (L:AP_SPD_Hold_Target, number) - (>L:AP Speed Diff, number)
(P:Absolute time,seconds) (L:AP Timer 1, number) ==
if{ 1 (>G:Var8) }
els{ 0 (>G:Var8) }
(P:Absolute time,seconds) (>L:AP Timer 1, number)
(G:Var8) 1 <
if{
<!-- Proportional: Trim when outside of airspeed tolerance. Kp = 1, Boundaries: 0.1 to 20 knots (absolute) -->
-20 -0.1 (L:AP Speed Diff, number) rng
if{ (>K:ELEV_TRIM_DN) }
0.1 20 (L:AP Speed Diff, number) rng
if{ (>K:ELEV_TRIM_UP) }
<!-- Integrative: Convert ft/s2 into nm/s2, then project 72 / 18 = 4 seconds into the future. Ki = 4, Boundaries: Projected speed lower/higher than target speed to infinity. -->
(A:ACCELERATION BODY Z, feet per second squared) 0.592484 * 72 * (A:AIRSPEED INDICATED, knots) + (L:AP_SPD_Hold_Target, number) <
if{ (>K:ELEV_TRIM_DN) (>K:ELEV_TRIM_DN) (>K:ELEV_TRIM_DN) (>K:ELEV_TRIM_DN) }
(A:ACCELERATION BODY Z, feet per second squared) 0.592484 * 72 * (A:AIRSPEED INDICATED, knots) + (L:AP_SPD_Hold_Target, number) >
if{ (>K:ELEV_TRIM_UP) (>K:ELEV_TRIM_UP) (>K:ELEV_TRIM_UP) (>K:ELEV_TRIM_UP) }
<!-- Derivative: Trim when acceleration is outside of limits. Kd = 2, Boundaries: "Not 0" to inf -->
(A:ACCELERATION BODY Z, feet per second squared) 0 <
if{ (>K:ELEV_TRIM_DN) (>K:ELEV_TRIM_DN) }
(A:ACCELERATION BODY Z, feet per second squared) 0 >
if{ (>K:ELEV_TRIM_UP) (>K:ELEV_TRIM_UP) }
}
Calculating the airspeed difference is pretty self-explanatory.
During development I've found that running the controller in a timer decreased its effectiveness, so to keep the code running at MSFS' 18Hz limit and still stop execution when the sim is paused, I've introduced the timer-related block as a cheap method for determining the sim's pause status.
The variables for the sim's pause status which are provided by XMLTools or the XML Sound gauge tend to stop working after half a dozen aircraft reloads so I have to stick to a more basic approach.
As far as I know, the proportional element of a controller is used to counteract large deviations from the target value, but is prone to induce unwanted oscillations. Since I've found that it did more harm than good when left unchecked, I've introduced a narrow boundary in which it may influence pitch trim. This is also the reason why the proportional gain on elevator trim is rather low.
Again, as far as my one hour refresher course provided, the integrative term is used to determine a trend to help "steer" the current value toward the target value. The trend is created by reading the current acceleration, convertinng, multiplying and then adding it to the current speed to obtain a future value for the current airspeed. Since this works rather well for dampening controller response, I've made it the most important element of the controller as can be seen by the amount of trim commands issued.
The derivative term basically trolls the other two terms by counteracting their commands to minimize acceleration. Yet, it helps to dampen the control response of the other two terms and thus enable the controller to attaint he target spead more quickly. Therefor I've made this the second most important term in the chain as evidenced by the control response.
When enabling this controller with a huge differential between your target and actual speed, you will see one or two pretty hefty oscillations, but this is quite normal. After that, the oscillations should successively become smaller before settling on a pitch value that will maintain the target speed.
Should the plane not stop oscillating, you will have to play with the boundary conditions, "look ahead" time or the gains (number of control inputs, i.e. "trim up/down").
I hope that my explanation wasn't too wrong and that someone finds this useful.