Example Analog Input Potentiometer - MobiFlight/MobiFlight-Connector GitHub Wiki
A potentiometer is a manually adjustable variable resistor with 3 terminals. Two of the terminals are connected to the opposite ends of a resistive element, and the third terminal connects to a sliding contact, called a wiper, moving over the resistive element. MobiFlight 8.3.0 introduced support for analog input (potentiometers). This allows us to use potentiometers to send axis type inputs to the simulator like flaps, elevator, rudder, aileron, trims, throttle, sound volume controls, lighting brightness controls, etc.
The analog to digital converter (ADC) in an Arduino board is a 10-bit converter, meaning it has a resolution of 0 to 1023 units corresponding to voltages of 0 and 5v respectively. The Arduino board is simply reading the voltage given by a potentiometer and converting it proportionally to an integer value.
In general, potentiometers only require one Arduino analog pin, making their use for knobs more economical than say digital encoders that require two digital pins. Of course, there is some application overlap possible between these two devices, but not every knob can or should be implemented with potentiometers. They also require a 5v and a Ground connection.
On this example, the picture is for a Uno board, but any supported board will work.
Create the device config in Mobiflight Modules.
Pin Setting: Define the analog pin you connected the potentiometer, as per the wiring diagram above.
Sensitivity: This sets the minimum threshold for a change in the potentiometer reading to be considered as a new reading. Set this initially to about 5. You may need to adjust later, if you find your potentiometer is too sensitive.
Upload your new config to the board and exit Mobiflight Modules by pressing OK.
Activate Mobiflight logging mode in Extras Menu, Settings. A new log window will open in the lower part of the Mobiflight main window. Without pressing Run, move the potentiometer knob. All the potentiometer movements should be registered indicating your potentiometer is ready for configuration with any simulator events. If you can't see the movements, then you probably need to check your wiring and make sure the pin used in the Arduino is an analog capable pin.
Add new input on MobiFlight and edit it. In this example we will store the value to a new MF variables, named "MyPoti" as a number.
The value of the potentiometer is between 0 and 1023, and you need to use the "@" placeholder to get the potentiometer value.
Choose "Mobiflight Variable", and set the name "MyPoti" has a number.
Now you can press "RUN", and turn the potentiometer, Mobiflight will show the value of the output config you created in the output list, output value column. The output value store in "MyPoti" should change from 0 to 1023. If you are not using the full rotation range of your potentiometer, the actual operating range may be a subset of the full range. Often times, potentiometers may not go to zero turned down to minimum but stay at around 13-20 as the minimum. You will need to know what the actual operating range is later on, when configuring the input config in Mobiflight, so please take note of the actual operating range as seen in the Mobiflight log entries.
Congratulations, Mobiflight can read your potentiometer and display its value as an output.
Now that we have a working potentiometer that we can read, let's use it to control a panel light dimmer in the MSFS2020 simulator. Light potentiometers in MSFS normally take values in the range 0 to 100. Go back to the input config and change its Action to MSFS2020 instead of a Mobiflight Variable. You can select a preset from the drop down menus.
Taking the FBW A320 as example (because it is simple):
The sim variable that stores the pedestal panel knob light potentiometer value is (A:LIGHT POTENTIOMETER:76, percent)
. Please note that the normal potentiometer value from your board in the range 0 to 1023 is divided by 10.23 to result in the desired range of 0 to 100. This result is sent to the simulator and then stored in the A: variable mentioned.
We should now create an output for this variable.
Since the A: variable has a range of 0 to 100, but the range to control brightness with PWM has a range 0 to 255, we add a Transform modifier in the Modify tab and multiply the value times 2.55. This will result in the output config having a value in the desired range of 0 to 255 (the PWN function range).
In the Display tab we now select the LED for this output and activate the PWM Mode by checking on the appropriate click box.
That's it. The led should now dim as you move the potentiometer in sync with the simulator.
Analog input can also be used to connect multiple buttons or multiple position rotary switches very efficiently, as only one analog pin is required. This can be a good alternative if you are running out of Arduino pins and just need a few buttons more. The technique is creating a cascading series of resistors, such that each button or rotary position has an additional resistor in series, thus resulting in a different analog value being received by Mobiflight with each different button being pressed. Mobiflight does not directly support this as button presses, but a workaround is not too difficult to do.
A similar approach can be used with a multiple position rotary switch. Here is an example for a five position rotary using the cascading resistors technique.
The analog input config in Mobiflight can then be used to separate the values into different actions as required. One way of doing this could be to create an input config for the analog input saved to a Mobiflight variable. Then using the Mobiflight variable value as criteria for triggering two or more output driven input via the Display tab input action. Another way can be to create one RPN script that can take the analog value input and through a cascade of if statements, decide which discrete action should be taken.
You should, of course, know what the analog port value is for each button or rotary switch position, by checking the Mobiflight log mode.
Example using output configs
This is for the first case, using Mobiflight output configs to separate the value from the potentiometer into separate output driven input events.
-
Read and store the analog input pin from the resistor ladder into a MF variable. Call it say "Analog Buttons"
-
Create an output for this MF variable.
-
Create one output for each button press.
-
In each output for button press, specify the MF variable output as config reference with placeholder #.
-
Use a Transform to check the value of "Analog Buttons" is in the target range. Make sure there is no overlap in the ranges.
if(#>50 and #<59, 1, 0)
-
Use the Display tab of the output config, Input Action, On Press, to trigger an input event if the Transform is true (value=1).
-
Repeat steps 3 to 6 for as many buttons as you have in the resistor ladder.
Code example using RPN (only for MSFS2020)
For the second way mentioned, where only one input config is required, here is an example of an existing preset for a potentiometer with discrete events separated in individual ranges, using RPN for MSFS2020 (this is for the PMDG 737 flaps lever) here.
@ 20 - 10.03 / near 0 max 100 min s0
l0 5 < if{ 714101 (>K:ROTOR_BRAKE) quit }
l0 15 < if{ 714201 (>K:ROTOR_BRAKE) quit }
l0 35 < if{ 714301 (>K:ROTOR_BRAKE) quit }
l0 50 < if{ 714401 (>K:ROTOR_BRAKE) quit }
l0 64 < if{ 714501 (>K:ROTOR_BRAKE) quit }
l0 75 < if{ 714601 (>K:ROTOR_BRAKE) quit }
l0 85 < if{ 714701 (>K:ROTOR_BRAKE) quit }
l0 98 < if{ 714801 (>K:ROTOR_BRAKE) quit }
714901 (>K:ROTOR_BRAKE)
This example is intended for a potentiometer connected to a lever, but it would work just as well using a resistor ladder with 9 individual buttons for each position. Note that the analog pin value is read with @ and converted to a scale 0 to 100. This conversion is done just as a convenience for easier visualization of where in the range an event is located. The direct potentiometer values can be used, just as well. This value is then used in a cascading if statements that check for the first range value that is true and execute a specific event instruction for that range.
Also note that only the upper bound of each range is checked. There is no need to check for lower bound of each range because the previous if statement already did that.