• Which the release of FS2020 we see an explosition of activity on the forun and of course we are very happy to see this. But having all questions about FS2020 in one forum becomes a bit messy. So therefore we would like to ask you all to use the following guidelines when posting your questions:

    • Tag FS2020 specific questions with the MSFS2020 tag.
    • Questions about making 3D assets can be posted in the 3D asset design forum. Either post them in the subforum of the modelling tool you use or in the general forum if they are general.
    • Questions about aircraft design can be posted in the Aircraft design forum
    • Questions about airport design can be posted in the FS2020 airport design forum. Once airport development tools have been updated for FS2020 you can post tool speciifc questions in the subforums of those tools as well of course.
    • Questions about terrain design can be posted in the FS2020 terrain design forum.
    • Questions about SimConnect can be posted in the SimConnect forum.

    Any other question that is not specific to an aspect of development or tool can be posted in the General chat forum.

    By following these guidelines we make sure that the forums remain easy to read for everybody and also that the right people can find your post to answer it.

Trim Increment/Decrement Speed

Messages
61
Country
us-california
Now for the next question...

As part of the Flight Control System in this aircraft, I've been working on some coding that will enable the aircraft to correlate stick position to the amount of G pulled by the aircraft, regardless of speed. So, if you pull back on your stick 20%, for example, the aircraft's elevator trim will work alongside the aircraft's elevator and will continuously adjust itself so that the aircraft will achieve and maintain 2.4 G. As the speed increases, the elevator trim will automatically decrease, and the opposite as speed decreases. Here is the code, that I've developed:

Code:
// --- G FORCE / STICK CONNECT
<!-- Algorithm to calculate commanded G based on stick position.  Neutral stick commands 1 G, full aft stick commands 7.5 G (F/A-18's Max commanded G) -->

<!-- Calculation starts if stick is pulled from neutral by more than 3%-->
[B](A:ELEVATOR POSITION, Percent) 3 &gt;[/B]
(A:GEAR CENTER POSITION,Percent) 30 &lt; and
(A:AIRSPEED TRUE,knots) 50 &gt; and
(A:SIM ON GROUND, bool) ! and
(A:AUTOPILOT MASTER, bool) ! and
       if{ [COLOR="red"][B](A:ELEVATOR POSITION, Percent) 0.065 * 1 + (&gt;L:G_CUTOFF_INDEX,number)[/B][/COLOR] }

<!-- Calculation starts if stick is pushed from neutral by more than 3%-->
[B](A:ELEVATOR POSITION, Percent) -3 &lt;[/B]
(A:GEAR CENTER POSITION,Percent) 30 &lt; and
(A:AIRSPEED TRUE,knots) 50 &gt; and
(A:SIM ON GROUND, bool) ! and
(A:AUTOPILOT MASTER, bool) ! and
        if{ [COLOR="red"][B](A:ELEVATOR POSITION, Percent) 0.065 * 1 + (&gt;L:G_CUTOFF_INDEX,number)[/B][/COLOR] }


<!-- Compares the commanded G to actual aircraft G by diving the two together. -->

<!-- Compares commanded G to actual aircraft G when stick is pulled -->
[B](A:ELEVATOR POSITION, Percent) 3 &gt;[/B]
(A:GEAR CENTER POSITION,Percent) 30 &lt; and
(A:AIRSPEED TRUE,knots) 50 &gt; and
(A:SIM ON GROUND, bool) ! and
(A:AUTOPILOT MASTER, bool) ! and
        if{ [COLOR="red"][B](L:G_CUTOFF_INDEX,number) (A:G FORCE,G Force) / (&gt;L:G_CUTOFF,number)[/B][/COLOR] }

<!-- Compares commanded G to actual aircraft G when stick is pushed -->
[B](A:ELEVATOR POSITION, Percent) -3 &lt;[/B]
(A:GEAR CENTER POSITION,Percent) 30 &lt; and
(A:AIRSPEED TRUE,knots) 50 &gt; and
(A:SIM ON GROUND, bool) ! and
(A:AUTOPILOT MASTER, bool) ! and
        if{ [COLOR="red"][B](L:G_CUTOFF_INDEX,number) (A:G FORCE,G Force) / (&gt;L:G_CUTOFF,number)[/B][/COLOR] }

<!-- Commands elevator down trim if current G is more than commanded G while stick is pulled -->
[B](L:G_CUTOFF,number) 1 &lt;[/B]
[B](A:ELEVATOR POSITION, Percent) 3 &gt; and[/B]
(A:GEAR CENTER POSITION,Percent) 30 &lt; and
(A:AIRSPEED TRUE,knots) 50 &gt; and
(A:SIM ON GROUND, bool) ! and
(A:AUTOPILOT MASTER, bool) ! and
        if{ [COLOR="red"][B](&gt;K:ELEV_TRIM_DN)[/B][/COLOR] } 

<!-- Commands elevator down trim if current G is more than commanded G while stick is pushed-->
[B](L:G_CUTOFF,number) 1 &lt;[/B]
[B](A:ELEVATOR POSITION, Percent) -3 &lt; and[/B]
(A:GEAR CENTER POSITION,Percent) 30 &lt; and
(A:AIRSPEED TRUE,knots) 50 &gt; and
(A:SIM ON GROUND, bool) ! and
(A:AUTOPILOT MASTER, bool) ! and
        if{ [B][COLOR="red"](&gt;K:ELEV_TRIM_DN)[/COLOR][/B] }

<!-- Commands elevator up trim if current G is less than commanded G while stick is pulled-->
[B](L:G_CUTOFF,number) 1 &gt;[/B]
[B](A:ELEVATOR POSITION, Percent) 3 &gt; and[/B]
(A:GEAR CENTER POSITION,Percent) 30 &lt; and
(A:AIRSPEED TRUE,knots) 50 &gt; and
(A:SIM ON GROUND, bool) ! and
(A:AUTOPILOT MASTER, bool) ! and
        if{ [COLOR="red"][B](&gt;K:ELEV_TRIM_UP)[/B][/COLOR] }

<!-- Commands elevator up trim if current G is less than commanded G while stick is pushed-->
[B](L:G_CUTOFF,number) 1 &gt;[/B]
[B](A:ELEVATOR POSITION, Percent) -3 &lt; and[/B]
(A:GEAR CENTER POSITION,Percent) 30 &lt; and
(A:AIRSPEED TRUE,knots) 50 &gt; and
(A:SIM ON GROUND, bool) ! and
(A:AUTOPILOT MASTER, bool) ! and
        if{ [COLOR="Red"][B](&gt;K:ELEV_TRIM_UP)[/B][/COLOR] }

Although initial implementation and testing has proven successful, it does take a few seconds for the trim to increment/decrement to where it initially needs to be, or for it to release the trim once the G is released. Does anyone know how to change the speed at which the simulator increments or decrements the elevator trim once commanded? As usual, thanks everyone for your help!
 
Thanks for the response, I have worked with Roy's PID in the past (and still am with the Powered Approach Mode). One thing I have learned is that it tends to be static, in that you have to know the exact value for the final result in order for it to work as advertised. A system like the one mentioned above is very dynamic in that the final result is constantly changing. I have thought and even implemented a somewhat of a closed-loop system where the FCS algorithm takes into account the position of the stick and the speed of the aircraft to calculate a direct value to be fed into the elevator trim system, but it seems as though these inputs occur a little too quick, leaving the aircraft a little too sensitive. I would like for the system to dynamically increment and decrement the trim as needed, but just with a quicker onset or offset than what I currently have.

I already have the refresh rate for the gauge up to 18, which I believe is the highest it can go. The only other thing I can think of is to increase the elevator trim effectiveness to a little more "bang or the buck" but I fear that will lead to unwanted oscillations...
 
Code:
 <Element>
    <Select> 
      <Value> 
           (A:AUTOPILOT MASTER,percent) 50 &gt; 
           (L:apabfang, keyframe) 50 &gt; and
           (A:RADIO HEIGHT, meters) (A:DECISION HEIGHT, meters) - 1000 &lt; and
           (A:DECISION HEIGHT, meters) 100 &gt; and

         if{
           (A:VERTICAL SPEED, meters/second) -10 &lt;
           (A:ELEVATOR POSITION, percent) 65 &lt; and
            if{ (&gt;K:ELEV_UP) (&gt;K:ELEV_UP) (&gt;K:ELEV_UP) (&gt;K:ELEV_UP) }
           
        els{ 
           (A:ELEVATOR POSITION, percent) 10 &gt;
           (A:VERTICAL SPEED, meters/second) 0 &lt; and
           (A:G FORCE, G Force) 1 &gt; and 
            if{ 
               [COLOR="Red"] (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) 
                (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) 
                (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) 
                (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) 
                (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) 
                (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) 
                (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) 
                (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN) (&gt;K:ELEV_DOWN)[/COLOR] 
                
              } els{ (&gt;L:apabfang, bool) (&gt;K:SPOILERS_OFF) (&gt;K:CENTER_AILER_RUDDER) (&gt;K:THROTTLE_60) } 
           }
           }
      </Value>
    </Select>
  </Element>


 <Element>
    <Select> 
      <Value> 
           (A:AUTOPILOT MASTER,percent) 50 &gt; 
           (L:apabfang, keyframe) 50 &gt; and
           (A:RADIO HEIGHT, meters) (A:DECISION HEIGHT, meters) - 1200 &lt; and
           (A:DECISION HEIGHT, meters) 100 &gt; and

         if{
           (A:PLANE BANK DEGREES, degrees) 350 &lt; 
           (A:PLANE BANK DEGREES, degrees) 179.999 &gt; and
           (A:AILERON POSITION, percent) -65 &gt; and
           

            if{ [COLOR="Red"](&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) 
                (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT)
                (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) 
                (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) [/COLOR]
              }
           
        els{ 
           (A:PLANE BANK DEGREES, degrees) 10 &gt; 
           (A:PLANE BANK DEGREES, degrees) 180.001 &lt; and
           (A:AILERON POSITION, percent) 65 &lt; and

           if{ [COLOR="Red"](&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) 
               (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) 
               (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) 
               (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) [/COLOR]
              }
           }
           }
      </Value>
    </Select>
  </Element>

 <Element>
    <Select> 
      <Value> 
           (A:AUTOPILOT MASTER,percent) 50 &gt; 
           (L:apabfang, keyframe) 50 &gt; and
           (A:RADIO HEIGHT, meters) (A:DECISION HEIGHT, meters) - 1200 &lt; and
           (A:DECISION HEIGHT, meters) 100 &gt; and
         if{
           (A:PLANE BANK DEGREES, degrees) 10 &lt; 
           (A:PLANE BANK DEGREES, degrees) 0.01 &gt; and
           (A:AILERON POSITION, percent) -10 &gt; and

           if{ 
                [COLOR="Red"](&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT)
                (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT)
                (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) 
                (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT)
                (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT)
                (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) (&gt;K:AILERONS_LEFT) [/COLOR]
              }
           }
             
      </Value>
    </Select>
  </Element>

 <Element>
    <Select> 
      <Value> 
           (A:AUTOPILOT MASTER,percent) 50 &gt; 
           (L:apabfang, keyframe) 50 &gt; and
           (A:RADIO HEIGHT, meters) (A:DECISION HEIGHT, meters) - 1200 &lt; and
           (A:DECISION HEIGHT, meters) 100 &gt; and
         if{
           (A:PLANE BANK DEGREES, degrees) 350 &gt; 
           (A:PLANE BANK DEGREES, degrees) 359.99 &lt; and
           (A:AILERON POSITION, percent) 10 &lt; and

           if{ 
                [COLOR="Red"](&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) 
                (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) 
                (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) 
                (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) 
                (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) 
                (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) (&gt;K:AILERONS_RIGHT) [/COLOR]
              }
           }
             
      </Value>
    </Select>
  </Element>
 
Last edited:
This is the relevant section from the Bendix / King KAS-297B Altitude Alerter on the Mooney Bravo. You set the required vertical speed and engage. The output drives the elevator trim. You could try adapting this.

Code:
<!-- Engage VS -->
<!-- output  =  loop gain * ( error + (integral(error) / INT) + derivative(error) * DIF ) -->
<!-- Set Initial Values -->
<Element>
  <Select>
    <Value>(L:KVal_Init,Bool) ! if{ 0.05 (&gt;L:ElevatorKp,Number) 50 (&gt;L:ElevatorKi,Number) 10 (&gt;L:ElevatorKd,Number) 0.1 (&gt;L:ElevatorKt,Number) 1 (&gt;L:KVal_Init,Bool) }</Value>
  </Select>
</Element>

<!-- Proportional
       error = setpoint - value
       output = error -->
<Element>
  <Select>
    <Value>(A:AUTOPILOT VERTICAL HOLD VAR,Feet per minute) (A:VERTICAL SPEED,Feet per minute) - (&gt;L:ElevatorSetErr,Number)</Value>
  </Select>
</Element>

<Element>
  <Select>
    <Value>(L:ElevatorSetErr,Number) (&gt;L:ElevatorPIDOut,Number)</Value>
  </Select>
</Element>

<!-- Integral
       output = output + (Integral * dT / INT)
       Integral = Integral + error -->
<Element>
  <Select>
    <Value>(L:ElevatorPIDOut,Number) (L:ElevatorIntegral,Number) (L:ElevatorKt,Number) (L:ElevatorKi,Number) / * + (&gt;L:ElevatorPIDOut,Number)</Value>
  </Select>
</Element>

<Element>
  <Select>
    <Value>(L:ElevatorIntegral,Number) (L:ElevatorSetErr,Number) + (&gt;L:ElevatorIntegral,Number)</Value>
  </Select>
</Element>

<!-- Stop Integrator Windup if Sim Paused -->
<Element>
  <Select>
    <Value>(L:SimRate,Number) 0 == if{ 0 (&gt;L:ElevatorIntegral,Number) 0 (&gt;L:ElevatorPIDOut,Number) }</Value>
  </Select>
</Element>

<!-- Derivative
       Change = error - Derivative
       output = output + (Change * DIF / dT)
       Derivative = error -->
<Element>
  <Select>
    <Value>(L:ElevatorSetErr,Number) (L:ElevatorDerivative,Number) - (&gt;L:ElevatorChange,Number)</Value>
  </Select>
</Element>

<Element>
  <Select>
    <Value>(L:ElevatorPIDOut,Number) (L:ElevatorChange,Number) (L:ElevatorKd,Number) (L:ElevatorKt,Number) / * + (&gt;L:ElevatorPIDOut,Number)</Value>
  </Select>
</Element>

<Element>
  <Select>
    <Value>(L:ElevatorSetErr,Number) (&gt;L:ElevatorDerivative,Number)</Value>
  </Select>
</Element>

<!-- Add loop gain
       output = output * loop gain -->
<Element>
  <Select>
    <Value>(L:ElevatorPIDOut,Number) (L:ElevatorKp,Number) * (&gt;L:ElevatorPIDOut,Number)</Value>
  </Select>
</Element>

<!-- Output limiting -->
<Element>
  <Select>
    <Value>(L:ElevatorPIDOut,Number) 1024 min -1024 max (&gt;L:ElevatorPIDOut,Number)</Value>
  </Select>
</Element>

<!-- Drive output -->
<Element>
  <Select>
    <Value>(L:VSEngaged,Bool) 0 != if{ (A:ELEVATOR TRIM PCT,Percent) 163.84 * (L:ElevatorPIDOut,Number) + (&gt;K:ELEVATOR_TRIM_SET) }</Value>
  </Select>
</Element>

<!-- Zero output & reset latch if disengaged -->
<Element>
  <Select>
    <Value>(L:VSEngaged,Bool) 0 == if{ 0 (&gt;L:ElevatorPIDOut,Number) 0 (&gt;L:ElevatorIntegral,Number) 0 (&gt;L:VSLatch,Bool) }</Value>
  </Select>
</Element>

<!-- Disengage if Elevator output > 80% -->
<Element>
  <Select>
    <Value>(A:ELEVATOR TRIM PCT,Percent) abs 80 &gt; if{ 0 (&gt;L:VSEngaged,Bool) 1 (&gt;L:TrimAlert,Number) }</Value>
  </Select>
</Element>

<!-- Selecting AP also implicitly sets altitude hold, we need to explicitly switch it off -->
<Element>
  <Select>
    <Value>(A:AUTOPILOT MASTER,Bool) (L:VSEngaged,Bool) (L:VSLatch,Bool) ! &amp;&amp; &amp;&amp; if{ 0 (&gt;K:AP_PANEL_ALTITUDE_HOLD) 0 (&gt;K:AP_ALT_HOLD_OFF) 1 (&gt;L:VSLatch,Boo) }</Value>
  </Select>
</Element>
 
Thanks all. I will give these a go. Still trying to get a complete grasp of the whole PID thing though. Thanks again
 
The output is the elevator trim, just as you need. The input for my gauge is desired v/s and actual v/s. You just need to change this to G.
 
The PID constants will need to be tuned to match specific aircraft and floght conditions..
 
The PID constants will need to be tuned to match specific aircraft and floght conditions..

True, true, but that's half the fun (spelt 'frustration'). If you need it, I have a dynamic tuning tool that I use to save reloading the aircraft after every change.
 
True, true, but that's half the fun (spelt 'frustration'). If you need it, I have a dynamic tuning tool that I use to save reloading the aircraft after every change.

Woah, really? Sounds neat! How does it work? :p
 
OK Gentlemen,

Still trying to get my head around the whole PID thing. Can you help me with the basics please. How do the following variables affect the operation of the PID and how it effects the elevator trim? Thanks.

-Integral
-Derivative
-Loop Gain
 
Back
Top