• 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.

FSX Detecting that Elevator Trim is Changing

Messages
159
Country
us-colorado
I'm trying to devise a way to detect that the elevator trim is changing (moving) either due to input from the pilot or from the Autopilot.
One possible way to do this might be to compare appropriately time spaced values of the elevator trim position variable. Is there a better way?
Thx,
Al
 
One possible way to do this might be to compare appropriately time spaced values of the elevator trim position variable.
That sounds like a pretty good way to me. Just measure each gauge update, and compare the value to the one you read on the last cycle. FSX does not have rate variables for the control surfaces, so unfortunately I do not believe that there is a better way...
 
Hi Al

I just use an Elevator Trim readout .
Code is ,
Code:
<String>%((A:ELEVATOR TRIM POSITION, degrees) 10 * near 10 / )%!5.1f!</String>

It clearly indicates both (A) current state , and (B) if a change is taking place .

I also use the following code , which could easily be adapted for elevator trim , however it only gives the direction above or below
a default zero value
Code:
     <!--VSI indicator-->
        <Element>
      <Visible>(L:VSItoggle mode,enum) 0 ==</Visible>
<!--**************** Climb Arrow ****************-->
      <Element>
        <Visible>(A:Vertical speed, feet per minute) 100 &gt;</Visible>
          <Position X="255" Y="41"/>
          <Image Name="VS_up.bmp" Bright="Yes"/>
       </Element>
<!--**************** Level Arrow ****************-->
      <Element>
        <Visible>(A:Vertical speed, feet per minute) 100 &lt; (A:Vertical speed, feet per minute) -100 &gt; &amp;&amp;</Visible>
          <Position X="253" Y="44"/>
          <Image Name="VS_level.bmp" Bright="Yes"/>
      </Element>
<!--**************** Descend Arrow ****************-->
      <Element>
        <Visible>(A:Vertical speed, feet per minute) -100 &lt;</Visible>
          <Position X="255" Y="41"/>
          <Image Name="VS_down.bmp" Bright="Yes"/>
       </Element>
    </Element>

Cheers
Karol
 
Last edited:
Hi Al

I just use an Elevator Trim readout .
Code is ,
Code:
<String>%((A:ELEVATOR TRIM POSITION, degrees) 10 * near 10 / )%!5.1f!</String>

It clearly indicates both (A) current state , and (B) if a change is taking place .

Karol

Thanks for the replies.
My goal here is to play a trim motor sound when the trim is moving, so I don't need to worry about trim direction.
Karol -- I don't understand how your trim readout code above indicates a change is taking place unless you read successive trim values and compare them.
Perhaps that is what you meant.
Thx,
Al
 
This hypothesis is the result of way too much coffee and waiting for an arrival at the house... Not tested whatsoever.
Al - Just seen that you posted a more elaborate request, not going to change this code.. But it could be used.
If (L:Trim_Commanded, bool) = 1 and (L:Trim_Disp_On_Off, bool) = 1 then play sound. The "Trim Display" <Element> would no longer be needed.


XML:
<Gauge Name="Elev_Trim_Detector" Version="0.1a">

    <!-- Image required for string display and a MUST for "keys" detection below,  200x27 -->
    <Image Name="something.bmp" ImageSizes="200,27" Luminous="No"/>

    <Update Frequency="18"> <!-- Adjust frequency as needed for detection level  -->
    <!-- Activate if changed -->
    (A:ELEVATOR TRIM POSITION, degrees) (L:Old_Trim_Pos, number) != if{
    <!-- Get direction -->
    (A:ELEVATOR TRIM POSITION, degrees) (L:Old_Trim_Pos, number) &gt; (>L:Trim_Up_Down, bool)
    <!-- Turn on display -->
    1 (>L:Trim_Disp_On_Off, bool)
    <!-- Update previous trim register -->
    (A:ELEVATOR TRIM POSITION, degrees) (>L:Old_Trim_Pos, number)
      }
    <!-- Turn off display -->
    els{ 0 (>L:Trim_Disp_On_Off, bool) }
    </Update>

    <Element Name="Trim Display">
        <Visible>(L:Trim_Disp_On_Off, bool)</Visible>
        <Element>
            <Position X="0" Y="0"/>
            <FormattedText X="200" Y="27" Font="Arial Bold" FontSize="27" VerticalAdjust="Center" Adjust="Center" Color="Red" Bright="No">
                <String>%Trim is moving %('DOWN' 'UP' (L:Trim_Up_Down, bool)  ?)%!s!% via %('Trim' 'Autopilot' (L:Trim_Commanded, bool)  ?)%.</String>
            </FormattedText>
        </Element>
    </Element>

    <Element Name="Reset Non-Autopilot Trigger">
        <Select><Value>0 (>L:Trim_Commanded, bool)</Value></Select>
    </Element>

    <!-- DETECT USER COMMANDED TRIM CHANGE -->
    <!-- THE WINDOW THAT HOLDS THIS GAUGE MUST BE OPEN TO WORK -->
    <!-- USING XMLTOOLS WOULD BE A MUCH BETTER SOLUTION -->
    <Keys>
        <On Event="ELEV_TRIM_DN">1 (>L:Trim_Commanded, bool)</On>
        <On Event="ELEV_TRIM_UP">1 (>L:Trim_Commanded, bool)</On>
        <!-- NOTE, THE FOLLWING 1 OR 2 "MAY" BE OVERKILL AND "MAY" BE USED BY THE AUTOPILOT. TESTING REQ'D -->
        <On Event="ELEVATOR_TRIM_SET">1 (>L:Trim_Commanded, bool)</On>
        <On Event="AXIS_ELEV_TRIM_SET">1 (>L:Trim_Commanded, bool)</On>
    </Keys>

</Gauge>
 
As used in a 727:

Code:
(A:ELEVATOR TRIM POSITION, radians) rddg (L:727 Elev Trim Temp, number) - abs 0.25 &gt;
if{ 1 (&gt;L:727_Elec_Trim1,number)
(A:ELEVATOR TRIM POSITION, radians) rddg (&gt;L:727 Elev Trim Temp, number) }

The 0.25 is a treshhold to avoid annoying me to death by playing the sound at the slightest trim change.
 
As used in a 727:

Code:
(A:ELEVATOR TRIM POSITION, radians) rddg (L:727 Elev Trim Temp, number) - abs 0.25 &gt;
if{ 1 (&gt;L:727_Elec_Trim1,number)
(A:ELEVATOR TRIM POSITION, radians) rddg (&gt;L:727 Elev Trim Temp, number) }

The 0.25 is a treshhold to avoid annoying me to death by playing the sound at the slightest trim change.


Hi!! thanks your code. But would you re-write and complete example?.... my sound name is "LVar20=DSD_trimwheel_SD". I don´t understand "rddg".

Thanks.
 
"rddg" is the conversion radians to degrees.
I suppose one could put the conversion right in the trim read.
XML:
(A:ELEVATOR TRIM POSITION, degrees) (L:Elev Trim Temp, number) - abs 0.25 &gt; if{
    1 (>L:DSD_trimwheel_SD, number) (A:ELEVATOR TRIM POSITION, degrees) (>L:Elev Trim Temp, number)
}
 
"rddg" is the conversion radians to degrees.
I suppose one could put the conversion right in the trim read.
XML:
(A:ELEVATOR TRIM POSITION, degrees) (L:Elev Trim Temp, number) - abs 0.25 &gt; if{
    1 (>L:DSD_trimwheel_SD, number) (A:ELEVATOR TRIM POSITION, degrees) (>L:Elev Trim Temp, number)
}
Hi! I have another question about this code. Is it necesary to add frequency at the beginning or not.... Thanks.
 
Not required if you want the detection at full speed (18Hz).
<Update> blah blah blah... </Update>
helo spokes2112 i have this code and nothing hapens when the trim wheels and stab trim moves.

Code:
<Gauge Name="Flaps Announcements" Version="1.0">
<Update Frequency="18">
    <Element>
        <Select>
            <Value>

                (A:ELEVATOR TRIM POSITION, degrees) (L:Elev Trim Temp, number) - abs 0.25 &gt; if{
    1 (>L:B737_Callout_trimwheel, number) (A:ELEVATOR TRIM POSITION, degrees) (>L:Elev Trim Temp, number)
}

            </Value>
        </Select>
    </Element>
    </Update>
</Gauge>

I use trimwheel.wav file and downson sound xml. Have you Any idea my friend?

Thanks
 
Try taking the <Element> out of the <Update>. <Element> cannot be a child of <Update>.
-or-
Just use the <Element> set.
These 2 will do the exact same thing, it is a matter of preference.
XML:
<Gauge Name="Flaps Announcements" Version="1.0">
    <Update Frequency="18">

        (A:ELEVATOR TRIM POSITION, degrees) (L:Elev Trim Temp, number) - abs 0.25 &gt; if{
            1 (>L:B737_Callout_trimwheel, number) (A:ELEVATOR TRIM POSITION, degrees) (>L:Elev Trim Temp, number)
        }

    </Update>
</Gauge>
-or-
XML:
<Gauge Name="Flaps Announcements" Version="1.0">
    <Element>
        <Select>
            <Value>

                (A:ELEVATOR TRIM POSITION, degrees) (L:Elev Trim Temp, number) - abs 0.25 &gt; if{
    1 (>L:B737_Callout_trimwheel, number) (A:ELEVATOR TRIM POSITION, degrees) (>L:Elev Trim Temp, number)
}

            </Value>
        </Select>
    </Element>
</Gauge>
 
Try taking the <Element> out of the <Update>. <Element> cannot be a child of <Update>.
-or-
Just use the <Element> set.
These 2 will do the exact same thing, it is a matter of preference.
XML:
<Gauge Name="Flaps Announcements" Version="1.0">
    <Update Frequency="18">

        (A:ELEVATOR TRIM POSITION, degrees) (L:Elev Trim Temp, number) - abs 0.25 &gt; if{
            1 (>L:B737_Callout_trimwheel, number) (A:ELEVATOR TRIM POSITION, degrees) (>L:Elev Trim Temp, number)
        }

    </Update>
</Gauge>
-or-
XML:
<Gauge Name="Flaps Announcements" Version="1.0">
    <Element>
        <Select>
            <Value>

                (A:ELEVATOR TRIM POSITION, degrees) (L:Elev Trim Temp, number) - abs 0.25 &gt; if{
    1 (>L:B737_Callout_trimwheel, number) (A:ELEVATOR TRIM POSITION, degrees) (>L:Elev Trim Temp, number)
}

            </Value>
        </Select>
    </Element>
</Gauge>
thanks for your code! It is OK ! perfect
 
All these contributions did help me a great deal in creating a stabilizer warning gauge for a MD-11 aircraft.
So, thank you very much all!
As I am still a XML coder with very few experience I have a question:
The stabilizer warning sound must be triggered when the autopilot is on and
the stabilizer moves more than 2º in 30 seconds.
What value for the 'Update Frequency=' must I set?
BTW here is my current code:


XML:
<Gauge Name="StabilizerMonitor" Version="1.0">
 <Update Frequency="18">
    (A:AUTOPILOT MASTER, bool) if{
        (A:ELEVATOR TRIM POSITION, degrees) (L:ElevTrimPosPrev, number) - abs 2.01 &gt; if{
            1 (>L:SND_STABILIZER, bool) (A:ELEVATOR TRIM POSITION, degrees) (>L:ElevTrimPosPrev, number)
        }
    }

    (A:AUTOPILOT MASTER, bool) 0 == if{
    0 (>L:SND_STABILIZER, bool) (A:ELEVATOR TRIM POSITION, degrees) (>L:ElevTrimPosPrev, number)   
    }           

  </Update>
</Gauge>

Thanks for replying in advance.
 
You could leave the update as is and just deal with the comparing value.
At 18hz there are 540 ticks in 30 seconds. Then, 2.01 / 540 = 0.003722.
Just change the 2.01 to 0.003722, that should do it for a 18hz update rate,

Just a side note, it could also be re-written like this (neither tested) :

XML:
<Gauge Name="StabilizerMonitor" Version="1.0">
        <Update Frequency="18">
                (A:AUTOPILOT MASTER, bool)
                (A:ELEVATOR TRIM POSITION, degrees) (L:ElevTrimPosPrev, number) - abs 0.003722 &gt; and
                if{
                        1 (>L:SND_STABILIZER, bool)
                }    els{
                        0 (>L:SND_STABILIZER, bool)
                }
                (A:ELEVATOR TRIM POSITION, degrees) (>L:ElevTrimPosPrev, number)  
        </Update>
</Gauge>
 
Last edited:
Hi sokes2112,

Thank you for your quick responding.
Unfortunately the code does not work for me because
with the 0.003722 &gt value the sound is triggered too soon AND the sound has no chance to play
completely because of 0 (&gt;L:SND_STABILIZER, bool) if the difference has not been reached.
This due to the fact, I guess and see in a debug window, that now constantly the variable
L:ElevTrimPosPrev is set to the value of A:ELEVATOR TRIM POSITION, even regardless of the state of the master AutoPilot.
So for now I switch back to the older code.
However I think that that code could be improved by making it check the elevator difference within 30 seconds....
I saw some code of Rob Barendregt and tried to adapt it like:

XML:
<Update Frequency="6"/>
   <Element>
      <Select>
         <Value>
            (G:Var1) 0 ==
            if{
               (P:Local Time,seconds) (&gt;G:Var2)
               1 (&gt;G:Var1)
               // initialize variable containing current elevator state
            }
         </Value>
      </Select>
   </Element>
   <Element>
      <Select>
         <Value>
           (G:Var1) 1 ==
            if{
               (P:Local Time,seconds) (G:Var2) 30 &gt;  // wait 30 seconds ?
               if{ 2 (&gt;G:Var1) }
            }
         </Value>
      </Select>
   </Element>
   <Element>
      <Select>
         <Value>
            (G:Var1) 2 ==
            if{
                // compare code for elevator state
                // and trigger sound when difference is more than 2 degrees when AP on
                // reset variable containing elevator state
            }
         </Value>
      </Select>
   </Element>
</Gauge>

I tried something like that but then I could not let it work, maybe I must try again (and again).
Again sokes2112, thanks for replying!
I wish there was a good and extensive XML language tutorial with examples and reference...
 
Last edited:
Kind of thought that my code was probably wrong, too fast of sampling.
Here is another idea. It toggles between 2 modes ; Update old trim & compare trims. This occurs every other second.
Not tested :(
XML:
<Gauge Name="StabilizerMonitor" Version="1.0">
    <Update Frequency="1">
        <!-- ONLY ACTIVE IF AP IS ON, IF OFF, MAKE SURE SOUND IS OFF -->
        (A:AUTOPILOT MASTER, bool) if{
            <!-- TOGGLE G:VAR1 BETWEEN UPDATE AND COMPARE MODES -->
            (G:Var1) ! (>G:Var1)
            <!-- G:VAR1 IS IN UPDATE MODE, GET OLD TRIM VALUE -->
            (G:Var1) 0 == if{
                (A:ELEVATOR TRIM POSITION, degrees) (>L:ElevTrimPosPrev, number)
            } els{
                <!-- G:VAR1 IS IN COMPARE MODE -->
                <!-- 2.01* / 30 TICKS FOR A 30 SECOND SAMPLE @ WITH FREQUENCY AT 1 = 0.067 -->
                (A:ELEVATOR TRIM POSITION, degrees) (L:ElevTrimPosPrev, number) - abs 0.067 &gt; if{
                    1 (>L:SND_STABILIZER, bool) <!-- PLAY SOUND IF COMPARE IS TRUE -->
                } els {
                    0 (>L:SND_STABILIZER, bool) <!-- TURN OFF SOUND IF COMPARE IS FALSE -->
                } 
            }
        } els{
            0 (>L:SND_STABILIZER, bool) <!-- MAKE SURE SOUND IS OFF IF AP IS OFF -->
            (A:ELEVATOR TRIM POSITION, degrees) (>L:ElevTrimPosPrev, number) <!-- KEEP OLD TRIM UPDATED IF AP IS OFF, SO IT IS READY WHEN AP GETS TURNED ON -->
        }
    </Update>
</Gauge>
 
Last edited:
Thank you for participating spokes2112.
I surely will test your new code, but only the day after tomorrow as
I will be off from my PC in the between time.
I will inform you later on.
 
Hi spokes2112

Back again and did test you latest code.
Unfortunately it isn't working as expected.
So I did put back the old code for now.
However to make the code more exact I did conjure
a pseudo code. Maybe you can look at it.
Anyways, here it is:

Code:
ElevTrimPosPrev      NUMBER
StartTime            TIME

if (AutoPilot == O) {
    SND_STABILIZER = 0; StartTime = CurrentTime;
    ElevTrimPosPrev = CurrentTrimPos;
    exit; // Is existing in XML ???
}

If (CurrentTime - StartTime) <  31 secs {
    if (abs (CurrentTrimPos - ElevTrimPosPrev)) > 2.01 degrees {
         SND_STABILIZER = 1;     
    }
}
else {
    StartTime = CurrentTime
    ElevTrimPosPrev = CurrentTrimPos
    SND_STABILIZER = 0
}
 
Back
Top