maartentamboer / X-Touch-Mini-FS2020

Control FS2020 with a Behringer X-Touch Mini
https://dev-tty.nl/X-Touch-Mini-FS2020/
MIT License
59 stars 19 forks source link

rotary encoder problem with Thrustmaster TCA Throttle buttons #32

Closed rdmans closed 3 years ago

rdmans commented 3 years ago

Hi,

I'm still encountering a problem, which may and may not be associated with this script.

I'm using the Thrustmaster TCA Throttle and Stick. I know exactly when the problem occurs but have no idea why.

As soon as I push/adjust certain buttons (Engine Master 1 & 2, Crank/Mode Norm/IGN switch) on the Thrustmaster throttle, when I fiddle with the rotary encoders on the Behringer, they change the in-game value by 10x for HDG and SPD, and by 1000x feet for ALT.

If I turn everything to the default position on the throttle (Engine master switches off, IGN switch at norm position), then the rotary dials on the Behringer work perfectly fine (by 1s for HDG and SPD, 100s for ALT). But because when I'm in the air the Engine Switches are always in the ON position, I really can't use Behringer's rotary dials to control the AP accurately because the increments are not fine enough. (and I don't really want to sacrifice the functionality of master switches on the throttle, since I bought the stick and throttle for extra realism)

I don't encounter this problem if I disconnect my throttle, or simply delete the bindings of those buttons. Then I can change HDG and SPD by 1 increments, and 100 feet for ALT. And thrust lever works perfectly fine. But those engine/norm switches are one of the few buttons on the throttle, and for the added realism I want to keep it working if possible.

Any ideas why this happens and how to fix it?

maartentamboer commented 3 years ago

https://github.com/maartentamboer/X-Touch-Mini-FS2020/issues/26 This issue is very similar though it is on a HoneyComb Alpha

it appears that this may be a problem in FS2020. Because my software just sends a simconnect event whenever you rotate a knob.

SQLSammy commented 3 years ago

Has someone found a MSFS solution for this problem? I have unplugged the TCA Throttle and have 1° for HDG, 100ft for ALT, ... with i have 10° and 1000ft.

I am sure this is not a problem with this tool, its one of the tons of bugs in MSFS

rdmans commented 3 years ago

Has someone found a MSFS solution for this problem? I have unplugged the TCA Throttle and have 1° for HDG, 100ft for ALT, ... with i have 10° and 1000ft.

I am sure this is not a problem with this tool, its one of the tons of bugs in MSFS

For now, my (sort of) solution is simply unbind the "mode crank/norm/ign" switch, as well as the two engine master switches on my throttle in MSFS control settings. Then I can use the X-Touch as well as the rest of my TCA throttle buttons/lever without any issues. If you can live with that, that's the only solution I have now. I hope that will be fixed by MSFS team in the future.

vicentezc commented 3 years ago

Hello,

I have been reading some forums, and I may have a solution for this bug, however my solution is incomplete, so it would require something else (the tricky part).

Because of the increment bug in the MSFS, which happens with any peripheral with a constant "pressed down" state (see this post for the explanation: https://forums.flightsimulator.com/t/heading-increment-bug-10-degree-instead-of-1-explained/290173), the only way to solve this is to set the Speed/Heading/Altitude to the value that we want, instead of using the _INC and _DEC events.

So for example, these should be equivalent without the bug:

"{{ data.trigger_event('AP_SPD_VAR_INC', 1) }}", and "{{ data.trigger_event('AP_SPD_VAR_SET', data.get_simvar_value('AUTOPILOT_AIRSPEED_HOLD_VAR')+1) }}",

However, because of the bug, the first one increases the speed by increments of 10, and the second by increments of 1.

These are the variables I am using for the Autopilot:

So by setting the value instead of increasing the value, we are able to have the expected increments.

Now the problem with this approach is that if I turn the encoders too quickly, I may have rotated the encoder by 10 "steps", but it seems that all these steps are not "recorded", so the value doesn't increase at the same pace. Moreover, if you turn quickly, ideally there should be an acceleration, which of course is not there.

So the question is: does anyone have an idea to solve this?

In the logs, I can see the following when turning an encoder: on_cc_data: 5: 65 on_cc_data: 5: 67 on_cc_data: 5: 67 on_cc_data: 5: 67 on_cc_data: 5: 68 on_cc_data: 5: 68 on_cc_data: 5: 69 on_cc_data: 5: 69 on_cc_data: 5: 69 on_cc_data: 5: 69 on_cc_data: 5: 69 on_cc_data: 5: 70 on_cc_data: 5: 70 on_cc_data: 5: 70 on_cc_data: 5: 70 on_cc_data: 5: 70 on_cc_data: 5: 69 on_cc_data: 5: 69 on_cc_data: 5: 69 on_cc_data: 5: 69 on_cc_data: 5: 69 on_cc_data: 5: 69 on_cc_data: 5: 67 on_cc_data: 5: 67

So the quicker an encoder is turned, the higher the value. Is it possible to access that value in the config files? If it is possible, then we could simply do something like this:

"{{ data.trigger_event('AP_SPD_VAR_SET', data.get_simvar_value('AUTOPILOT_AIRSPEED_HOLD_VAR')+(on_cc_data - 64)) }}",

maartentamboer commented 3 years ago

The code should call the event for each encoder pulse. https://github.com/maartentamboer/X-Touch-Mini-FS2020/blob/main/rotaryencoder.py#L94-L99 So if you receive 70 it should perform the event 6 times.

The thing is that the get_simvar_value may get cached by the simulator and therefore still havent updated the next time that it is called

vicentezc commented 3 years ago

I tried a dirty workaround, by adding the encoder value in global_storage each time there is an event, so I can access it in my config script. It works fine as long as I don't turn the encoder too quickly, when I do this the value in the sim can sometimes decrease (even if I am turning the encoder to increase it) or viceversa.

But good point, as you say, this may be related to how the get_simvar_value is cached by the simulator. At the next event, instead of taking the updated value, it may be taking an old simvar value which didn't take into account the previous update.

As a workaround, I will try to define a global var to store the updated values, so that each event uses the local var instead of the simvar. If this works, I will be posting what I did here. in case anyone has ideas to improve the algorithm.

Cheers!

vicentezc commented 3 years ago

OK, I am quite happy with the results of this script (for the A320 SPD, similar for other AP knobs):

  "event_up": {
    "type": "condition",
    "event": [ "{% if data.get_global_variable('SPD_MODE') == 'SELECTED' %}",
                 "{% if data.get_global_variable('SPD_CACHE') == None %}",
                   "{{ data.set_global_variable('SPD_CACHE', data.get_simvar_value('AUTOPILOT_AIRSPEED_HOLD_VAR')) }}",
                 "{% endif %}",
                 "{% if data.get_global_variable('ENC_VAL') <= 65 %}",
                   "{{ data.set_global_variable('SPD_LOCAL', data.get_global_variable('SPD_CACHE') + 1) }}",
                 "{% else %}",
                   "{{ data.set_global_variable('SPD_LOCAL', data.get_global_variable('SPD_CACHE') + ((data.get_global_variable('ENC_VAL') - 64) / 3) | round(0, 'floor')) }}",
                 "{% endif %}",
                 "{% if data.get_global_variable('SPD_LOCAL') > 990 %}",
                   "{{ data.set_global_variable('SPD_LOCAL', 990) }}",
                 "{% endif %}",
                 "{{ data.set_global_variable('SPD_CACHE', data.get_global_variable('SPD_LOCAL')) }}",
                 "{{ data.trigger_event('AP_SPD_VAR_SET', data.get_global_variable('SPD_CACHE')) }}",
               "{% endif %}" ]
  },
  "event_down": {
    "type": "condition",
    "event": [ "{% if data.get_global_variable('SPD_MODE') == 'SELECTED' %}",
                 "{% if data.get_global_variable('SPD_CACHE') == None %}",
                   "{{ data.set_global_variable('SPD_CACHE', data.get_simvar_value('AUTOPILOT_AIRSPEED_HOLD_VAR')) }}",
                 "{% endif %}",
                 "{% if data.get_global_variable('ENC_VAL') >= 63 %}",
                   "{{ data.set_global_variable('SPD_LOCAL', data.get_global_variable('SPD_CACHE') - 1) }}",
                 "{% else %}",
                   "{{ data.set_global_variable('SPD_LOCAL', data.get_global_variable('SPD_CACHE') + ((data.get_global_variable('ENC_VAL') - 64) / 3) | round(0, 'ceil')) }}",
                 "{% endif %}",
                 "{% if data.get_global_variable('SPD_LOCAL') < 0 %}",
                   "{{ data.set_global_variable('SPD_LOCAL', 0) }}",
                 "{% endif %}",
                 "{{ data.set_global_variable('SPD_CACHE', data.get_global_variable('SPD_LOCAL')) }}",
                 "{{ data.trigger_event('AP_SPD_VAR_SET', data.get_global_variable('SPD_CACHE')) }}",
               "{% endif %}" ]
  },

Some comments:

So thanks a lot for your comment about the simvars being cached, it really helped to understand that a local value needs to be used to update the simvar properly.

SQLSammy commented 3 years ago

SimVars, the hint about SimVars caching and using global vars in one topic, look like a good sample for the documentation

vicentezc commented 3 years ago

I have an update: actually there is a simpler way, there's no need to get access to the encoder value apparently:

So acceleration is already taken into account. The above can be simplified like this:

  "event_up": {
    "type": "condition",
    "event": [ "{% if data.get_global_variable('SPD_MODE') == 'SELECTED' %}",
                 "{% if data.get_global_variable('SPD_CACHE') == None %}",
                   "{{ data.set_global_variable('SPD_CACHE', data.get_simvar_value('AUTOPILOT_AIRSPEED_HOLD_VAR')) }}",
                 "{% endif %}",
                 "{{ data.set_global_variable('SPD_CACHE', data.get_global_variable('SPD_CACHE') + 1) }}",
                 "{% if data.get_global_variable('SPD_CACHE') > 990 %}",
                   "{{ data.set_global_variable('SPD_CACHE', 990) }}",
                 "{% endif %}",
                 "{{ data.trigger_event('AP_SPD_VAR_SET', data.get_global_variable('SPD_CACHE')) }}",
               "{% endif %}" ]
  },
  "event_down": {
    "type": "condition",
    "event": [ "{% if data.get_global_variable('SPD_MODE') == 'SELECTED' %}",
                 "{% if data.get_global_variable('SPD_CACHE') == None %}",
                   "{{ data.set_global_variable('SPD_CACHE', data.get_simvar_value('AUTOPILOT_AIRSPEED_HOLD_VAR')) }}",
                 "{% endif %}",
                 "{{ data.set_global_variable('SPD_CACHE', data.get_global_variable('SPD_CACHE') - 1) }}",
                 "{% if data.get_global_variable('SPD_CACHE') < 0 %}",
                   "{{ data.set_global_variable('SPD_CACHE', 0) }}",
                 "{% endif %}",
                 "{{ data.trigger_event('AP_SPD_VAR_SET', data.get_global_variable('SPD_CACHE')) }}",
               "{% endif %}" ]

So the key to update Speed/Heading/Alt is just to use a cached global var. I am now running it nicely without modifications to main.py

maartentamboer commented 3 years ago

WU4 has fixed the increment bug https://forums.flightsimulator.com/t/heading-increment-bug-10-degree-instead-of-1-explained/290173/609