Jump to content
The simFlight Network Forums

fast/slow rotary detection outside of Lua


Blake Buhlig

Recommended Posts

For my Bravo's two rotary controls, I've tried both a Rotaries.lua type of approach as well as a Lua event-driven approach, finding neither works well enough to my liking.  As suggested at https://forum.simflight.com/topic/92381-basic-question-to-start-a-lua-plugin/?do=findComment&comment=560588, it seems like the way to go for this sort of thing is rather some C++ code that runs faster than Lua to sense more rapid changes in the rotaries, and somehow feed that information back into FSUIPC.  One thought I had was to write a DLL using something like https://sfml-dev.org that implements a function that would block until a fast-vs.-slow rotation of a rotary switch was detected, then use luacom to interface to that function from Lua.  Or I suppose another way would be maybe a .EXE that polls the rotaries and writes appropriate information into an offset accessible by FSUIPC, but I've not yet discovered the details about how one might go about writing an FSUIPC-accessible offset.

Any suggestions? Thanks, -Blake

 

Link to comment
Share on other sites

1 hour ago, Blake Buhlig said:

For my Bravo's two rotary controls

One of the rotaries is the mode selector which has 5 different buttons/positions, so I guess you just need to control the 2-button inc/dec rotary, no?

1 hour ago, Blake Buhlig said:

I've tried both a Rotaries.lua type of approach as well as a Lua event-driven approach, finding neither works well enough to my liking.

You can usually achieve acceptable performance using both methods, especially if you assign to the offset increment/decrement controls and tune the inc/dec amount. However, being a two button rotary, its performance will be limited.

1 hour ago, Blake Buhlig said:

One thought I had was to write a DLL using something like https://sfml-dev.org that implements a function that would block until a fast-vs.-slow rotation of a rotary switch was detected, then use luacom to interface to that function from Lua. 

I don't know that library so can't really comment (although it seems more of a multi-media library than for device handling), but not sure how you would interface that to FSUIPC. The FSUIPC lua library is not available to external lua programs, i.e those not ran by FSUIPC. You would have to use the FSUIPC SDK to feed the input back to FSUIPC.

1 hour ago, Blake Buhlig said:

Or I suppose another way would be maybe a .EXE that polls the rotaries and writes appropriate information into an offset accessible by FSUIPC, but I've not yet discovered the details about how one might go about writing an FSUIPC-accessible offset.

You use the FSUIPC SDK (available for various languages) in an external program to write/read to/from FSUIPC offsets.

1 hour ago, Blake Buhlig said:

Any suggestions?

As indicated in that post you referenced (and was what the OP did), you could using another button (or key) as a type of latching switch, so when pressed/active the rotary would be performing fast in/dec, and when not the in/dec would be slow. You could even have different increments for different keys/buttons. You acieve this via compound button assignments (see the Advanced User guide).

John

Link to comment
Share on other sites

Thanks John. The two rotaries I had in mind are the inc/dec and the trim wheel. As far as performance, what I'm after on the inc/dec is to be able to grab it with my thumb and index finger then roll or cross them as quickly as I can to ideally result in a single "fast" virtual button. In doing this I'm rotating the knob so quickly that it makes a "zzzz" sound where my ear can't distinguish the individual clicks made by the rotary. About where I can distinguish those clicks is where I'd prefer each click to generate a "slow" virtual button. I couldn't get the Lua based code to distinguish between fast and slow in that sense, presumably Lua is just too slow for that

As far as SFML, I'm not experienced in development involving Windows USB devices and had run across a post suggesting using basic Windows APIs to do so is a lot more complicated than it needs to be. So I web searched for a free wrapper library with good docs and an apparently active support community, and SFML seems to fit the bill; web searching "SFML Joystick" quickly brings up the relevant API I'm interested in. That's the only thing I'm interested in so certainly possible it's overkill, and I'm open if you have simpler suggestions.

Seems my first step is to get some C++ program that can detect my conditions, then hook it up to the FSUIPC SDK as a second step.  It will be a while before I get there, but can you clarify that I want the zip file linked under www.fsuipc.com?  The description didn't mention FSUIPC7 so at first I overlooked it.

Thanks again. -Blake

Link to comment
Share on other sites

8 minutes ago, Blake Buhlig said:

The two rotaries I had in mind are the inc/dec and the trim wheel.

Ah, the trim wheel uses buttons! Sorry, I had assumed that was an axis...

8 minutes ago, Blake Buhlig said:

About where I can distinguish those clicks is where I'd prefer each click to generate a "slow" virtual button. I couldn't get the Lua based code to distinguish between fast and slow in that sense, presumably Lua is just too slow for that

Have you tried adjusting the PollInterval (to read the button states faster) or the ButtonRepeat ini parameters (to control the repeat rate)? You can usually achieve acceptable results adjusting these together with the timings in your lua. See the Advanced User guide for details on these ini parameters.

13 minutes ago, Blake Buhlig said:

Seems my first step is to get some C++ program that can detect my conditions, then hook it up to the FSUIPC SDK as a second step.  It will be a while before I get there, but can you clarify that I want the zip file linked under www.fsuipc.com?

Yes, its the same SDK for the various FSUIPC versions. Note that this is also installed (if selected) in an SDK folder under your FSUIPC7 installation folder.

But I would persist with lua for the time being and try those ini parameters if not done already, before looking at the SDK.

 

Link to comment
Share on other sites

Thanks, I did tweak those parameters but to no effect. I then went down the C++ path and found even that way that I could get neither the inc/dec nor the trim wheel to detect an interval between button presses shorter than 95ms which is about what I was seeing with lua.

For the inc/dec I know each audible click corresponds to one button press so when spinning it as fast as I was doing, I was expecting an interval between button presses maybe in the 10-30ms range. So it would seem a more fundamental limitation with the device itself keeps detectable events from being triggered that quickly.

Link to comment
Share on other sites

3 hours ago, Blake Buhlig said:

For the inc/dec I know each audible click corresponds to one button press

That's not true for a rotary encoder. Each click is a change -- i.e a press or a release, alternately. So you need to assign the same thing to both press and release.

Pete

 

Link to comment
Share on other sites

11 hours ago, Pete Dowson said:

Each click is a change -- i.e a press or a release, alternately.

That's what I was expecting to be true but it's not what I'm observing with my C++ program that polls the Bravo button states in a loop with only a 1 microsecond delay each time through the loop.   For the Bravo inc/dec, each click is a press and a release.  Regardless of how fast the rotary is turned, the release comes around 60-70ms after the button press.  When rotating it fast, the next button press comes 20-30ms after the button release.

For the trim wheel, I can't discern any tactile or audible feedback about when the presses happen.  But the behavior is generally the same in that while rotating the wheel at different speeds will cause the button presses to come at different frequencies, once the button press comes a button release always happens 60-70ms later, with the next button press coming no sooner than 20-30ms after that.

Link to comment
Share on other sites

16 hours ago, Blake Buhlig said:

So it would seem a more fundamental limitation with the device itself keeps detectable events from being triggered that quickly.

This would be my guess. I have also been through much experimentation with rotary encoders and Lua and FSUIPC (https://forum.simflight.com/profile/109385-matthew-twomey/content/ is one thread). I don't know about the specific use of Lua in FSUIPC, but generally speaking - it's incredibly fast, so it makes sense to me that you saw similar results in C.

Link to comment
Share on other sites

12 hours ago, Blake Buhlig said:

That's what I was expecting to be true but it's not what I'm observing with my C++ program that polls the Bravo button

It isn't a normal encoder then. I use encoders, connected via Leo Bodnar USB boards, and they all click on the change -- press/release alternately.

But if there is a press and a release for every click, your are actually getting twice the click speed, so it should really have been no problem -- seems it's the 60-70 mSecs the switch takes to release which is the limitation.  As you say, a switch design weakness.

If you don't mind a slight irregularity in trying to set things, maybe do the action twice on the press and once on the release in order to get a more regular interval.

Pete

 

 

 

Link to comment
Share on other sites

For me regular reliable behavior moving the switches slowly is as important as moving them fast so I'll probably need to continue ignoring the release event, and differentiate fast vs slow operation with some sort of compound button assignment.  Maybe someday I'll open it up and try to find a DIY mod for processing those switches.

Link to comment
Share on other sites

6 minutes ago, Blake Buhlig said:

For me regular reliable behavior moving the switches slowly is as important as moving them fast so I'll probably need to continue ignoring the release event, and differentiate fast vs slow operation

But this is what the Rotaries.lua does for you, activating different virtual flags for fast and slow movement (in each direction). So you can assign to the  fast virtual button on press and release, and the slow virtual button on press only.

Link to comment
Share on other sites

9 hours ago, John Dowson said:

But this is what the Rotaries.lua does for you, activating different virtual flags for fast and slow movement (in each direction). So you can assign to the  fast virtual button on press and release, and the slow virtual button on press only.

Maybe, sort of. I was really trying to get a rapid spin of the rotary in a given direction to generate a single "fast" virtual button click, and since a single rapid spin of the rotary will generate some number of button clicks happening less than the "FastTimeLimit", I guess it's a matter of detecting a minimum number of those happening, then generating the "fast" event, then ignoring any follow-on clicks until none are received for the duration of some timer.  Similarly I want slower turning to generate a slow virtual button for each click, so when I get a button press I'd need to wait for FastTimeLimit to pass before sending the slow virtual button. 

Before the C++ tangent, I had spent quite a while with a Rotaries.lua like approach and couldn't get it to work well, but maybe I only need to incorporate mods to ignore the button release.  In terms of the Rotaries.lua code, it seems "Diff = logic.Xor(Buttons, PrevButtons)" would need to become "Diff = logic.And(Buttons, logic.Not(PrevButtons))" so that it ignores button releases, and then the "FastTimeLimit" would need to be doubled, e.g. default 80 would become 160.  95ms between button presses was the minimum interval I saw, so maybe it could be reduced to something like 120ms to minimize the slow button expiration timer yet still have a range where fast clicks would be reliably detected.  I guess I'd just have to try.

Since I'd already have the expiration timeouts to deal with, for even the initial button detection I wonder if it would be cleaner to use event.button instead of polling. 

Link to comment
Share on other sites

@Blake Buhlig Just took a look at this. Seems each 'click' on the bravo rotary is a press and release, but even the timings between these near simultaneous events seems to be a minimum of 60-80ms, so I don't think its possible to get more than 8-10 presses per second (even when PollInterval is set to 1, which is what I used for testing). Of course, you can use releases as well. Attached is a short lua script that will log fast/slow for the Bravo trim wheel and adjustment rotary, which gives logs the following:

Quote

    69094 LUA.2: Slow rotary up detected (on button press)
    69172 LUA.2: Slow rotary up detected (on button release)
    69313 LUA.2: Slow rotary up detected (on button press)
    69391 LUA.2: Slow rotary up detected (on button release)
    69547 LUA.2: Slow rotary up detected (on button press)
    69625 LUA.2: Slow rotary up detected (on button release)
    69766 LUA.2: Slow rotary up detected (on button press)
    69844 LUA.2: Slow rotary up detected (on button release)
    69969 LUA.2: Slow rotary up detected (on button press)
    70032 LUA.2: Slow rotary up detected (on button release)
    70125 LUA.2: Fast rotary up detected (on button press)
    70188 LUA.2: Fast rotary up detected (on button release)
    70235 LUA.2: Fast rotary up detected (on button press)
    70297 LUA.2: Fast rotary up detected (on button release)
    71547 LUA.2: Slow rotary down detected (on button press)
    71610 LUA.2: Slow rotary down detected (on button release)
    71735 LUA.2: Slow rotary down detected (on button press)
    71813 LUA.2: Slow rotary down detected (on button release)
    72016 LUA.2: Slow rotary down detected (on button press)
    72094 LUA.2: Slow rotary down detected (on button release)
    72266 LUA.2: Slow rotary down detected (on button press)
    72344 LUA.2: Slow rotary down detected (on button release)
    73141 LUA.2: Slow rotary up detected (on button press)
    73219 LUA.2: Slow rotary up detected (on button release)
    73235 LUA.2: Fast rotary up detected (on button press)
    73297 LUA.2: Fast rotary up detected (on button release)
    73329 LUA.2: Fast rotary up detected (on button press)
    73407 LUA.2: Fast rotary up detected (on button release)
    73438 LUA.2: Fast rotary up detected (on button press)
    73500 LUA.2: Fast rotary up detected (on button release)
    73532 LUA.2: Fast rotary up detected (on button press)
    73610 LUA.2: Fast rotary up detected (on button release)
    74141 LUA.2: Slow rotary up detected (on button press)
    74204 LUA.2: Slow rotary up detected (on button release)
    74250 LUA.2: Fast rotary up detected (on button press)
    74313 LUA.2: Fast rotary up detected (on button release)
    74344 LUA.2: Fast rotary up detected (on button press)
    74407 LUA.2: Fast rotary up detected (on button release)
    74454 LUA.2: Fast rotary up detected (on button press)
    74516 LUA.2: Fast rotary up detected (on button release)
    75563 LUA.2: Slow rotary up detected (on button press)
    75625 LUA.2: Slow rotary up detected (on button release)
    75641 LUA.2: Fast rotary up detected (on button press)
    75735 LUA.2: Fast rotary up detected (on button release)
    75766 LUA.2: Fast rotary up detected (on button press)
    75829 LUA.2: Fast rotary up detected (on button release)
    75844 LUA.2: Fast rotary up detected (on button press)
    75922 LUA.2: Fast rotary up detected (on button release)
    75954 LUA.2: Fast rotary up detected (on button press)
    76032 LUA.2: Fast rotary up detected (on button release)
    77094 LUA.2: Slow rotary up detected (on button press)
    77141 LUA.2: Slow rotary up detected (on button release)
    77172 LUA.2: Fast rotary up detected (on button press)
    77250 LUA.2: Fast rotary up detected (on button release)
    77282 LUA.2: Fast rotary up detected (on button press)
    77344 LUA.2: Fast rotary up detected (on button release)
    77375 LUA.2: Fast rotary up detected (on button press)
    77454 LUA.2: Fast rotary up detected (on button release)
    78469 LUA.2: Slow rotary down detected (on button press)
    78532 LUA.2: Slow rotary down detected (on button release)
    78563 LUA.2: Fast rotary down detected (on button press)
    78625 LUA.2: Fast rotary down detected (on button release)
    78657 LUA.2: Fast rotary down detected (on button press)
    78735 LUA.2: Fast rotary down detected (on button release)
    78750 LUA.2: Fast rotary up detected (on button press)
    78766 LUA.2: Fast rotary down detected (on button press)
    78813 LUA.2: Fast rotary up detected (on button release)
    78829 LUA.2: Fast rotary down detected (on button release)
    78844 LUA.2: Fast rotary up detected (on button press)
    78907 LUA.2: Fast rotary up detected (on button release)
    79375 LUA.2: Slow rotary down detected (on button press)
    79454 LUA.2: Slow rotary down detected (on button release)
    79485 LUA.2: Fast rotary down detected (on button press)
    79547 LUA.2: Fast rotary down detected (on button release)
    79579 LUA.2: Fast rotary down detected (on button press)
    79657 LUA.2: Fast rotary down detected (on button release)
    79688 LUA.2: Fast rotary down detected (on button press)
    79750 LUA.2: Fast rotary down detected (on button release)
    79782 LUA.2: Fast rotary down detected (on button press)
    79860 LUA.2: Fast rotary down detected (on button release)
    82485 LUA.2: Slow trim wheel down detected (on button press)
    82563 LUA.2: Slow trim wheel down detected (on button release)
    82610 LUA.2: Fast trim wheel down detected (on button press)
    82672 LUA.2: Fast trim wheel down detected (on button release)
    82704 LUA.2: Fast trim wheel down detected (on button press)
    82766 LUA.2: Fast trim wheel down detected (on button release)
    82860 LUA.2: Fast trim wheel down detected (on button press)
    82922 LUA.2: Fast trim wheel down detected (on button release)
    83000 LUA.2: Fast trim wheel down detected (on button press)
    83079 LUA.2: Fast trim wheel down detected (on button release)
    83297 LUA.2: Slow trim wheel down detected (on button press)
    83360 LUA.2: Slow trim wheel down detected (on button release)
    83594 LUA.2: Slow trim wheel down detected (on button press)
    83657 LUA.2: Slow trim wheel down detected (on button release)
    84063 LUA.2: Slow trim wheel down detected (on button press)
    84125 LUA.2: Slow trim wheel down detected (on button release)
    84829 LUA.2: Slow trim wheel down detected (on button press)
    84907 LUA.2: Slow trim wheel down detected (on button release)
    85110 LUA.2: Slow trim wheel down detected (on button press)
    85188 LUA.2: Slow trim wheel down detected (on button release)
    86188 LUA.2: Slow trim wheel up detected (on button press)
    86266 LUA.2: Slow trim wheel up detected (on button release)
    86704 LUA.2: Slow trim wheel up detected (on button press)
    86766 LUA.2: Slow trim wheel up detected (on button release)
    87235 LUA.2: Slow trim wheel up detected (on button press)
    87297 LUA.2: Slow trim wheel up detected (on button release)
    87688 LUA.2: Slow trim wheel up detected (on button press)
    87766 LUA.2: Slow trim wheel up detected (on button release)
    89204 LUA.2: Slow trim wheel up detected (on button press)
    89266 LUA.2: Slow trim wheel up detected (on button release)
    90329 LUA.2: Slow trim wheel down detected (on button press)
    90407 LUA.2: Slow trim wheel down detected (on button release)
    90422 LUA.2: Fast trim wheel down detected (on button press)
    90500 LUA.2: Fast trim wheel down detected (on button release)
    90532 LUA.2: Fast trim wheel down detected (on button press)
    90610 LUA.2: Fast trim wheel down detected (on button release)
    90625 LUA.2: Fast trim wheel down detected (on button press)
    90704 LUA.2: Fast trim wheel down detected (on button release)
    90735 LUA.2: Fast trim wheel down detected (on button press)
    90797 LUA.2: Fast trim wheel down detected (on button release)
    90829 LUA.2: Fast trim wheel down detected (on button press)
    90907 LUA.2: Fast trim wheel down detected (on button release)
    90938 LUA.2: Fast trim wheel down detected (on button press)
    91000 LUA.2: Fast trim wheel down detected (on button release)
    91032 LUA.2: Fast trim wheel down detected (on button press)
    91110 LUA.2: Fast trim wheel down detected (on button release)
    91969 LUA.2: Slow trim wheel down detected (on button press)
    92032 LUA.2: Slow trim wheel down detected (on button release)
    92063 LUA.2: Fast trim wheel down detected (on button press)
    92125 LUA.2: Fast trim wheel down detected (on button release)
    92157 LUA.2: Fast trim wheel down detected (on button press)
    92235 LUA.2: Fast trim wheel down detected (on button release)
    92266 LUA.2: Fast trim wheel down detected (on button press)
    92329 LUA.2: Fast trim wheel down detected (on button release)
    92454 LUA.2: Slow trim wheel down detected (on button press)
    92516 LUA.2: Slow trim wheel down detected (on button release)
    92547 LUA.2: Fast trim wheel down detected (on button press)
    92625 LUA.2: Fast trim wheel down detected (on button release)
    92657 LUA.2: Fast trim wheel down detected (on button press)
    92704 LUA.2: Fast trim wheel down detected (on button release)
    92735 LUA.2: Fast trim wheel down detected (on button press)
    92813 LUA.2: Fast trim wheel down detected (on button release)
    92844 LUA.2: Fast trim wheel down detected (on button press)
    92907 LUA.2: Fast trim wheel down detected (on button release)
    92938 LUA.2: Fast trim wheel down detected (on button press)
   ...

Here's the script if interested: RotariesEvent.lua

It also requires socket.lua:   

socket.lua

 I'll take a look at using the com library at some point, but I don't think it will be any faster...

John

Later: one other thing you can try is to increase the increment/decrement (delta) value on successive 'fast' clicks, so the delta increases the more fast clicks received, and reset the (fast) delta on the next slow button press

Link to comment
Share on other sites

Thanks, yes, you are describing what I see. That long fixed delay before rotary button release is really frustrating. I saw no difference with C++ polling the button state every microsecond, so I'm convinced that delay is a result of the device's hardware or firmware. I'm still playing around with lua code that does what I suggested in my last message, and includes things along the lines of what you suggest. While so far it does make it somewhat more usable, it's not yet enough for me.

The rotaries are one of the main reasons I bought the Bravo, and given my electronics background I've considered opening it up to learn more about why it behaves that way, see if any reasonable mods are possible, etc. Though I'd be taking a risk if I broke it given how hard these are to find. I don't know. I'm at least glad I managed not to overpay a scalper for it.

Link to comment
Share on other sites

Ok, but if using lua, just use lua (i.e. send your controls from lua) rather than lua to flag virtual buttons. And for "fast" press/releases, it is better to send the desired control on both, as well as increasing the delta. You can also temporarily increase the FastTimeLimit (as well as the delta) as you receive fast presses, to prevent the odd 'slow' press being registered.

Anyway, it would be interesting to see what you eventually come up with, if you could share it. It may be useful for others. I'll also be looking into this further, to configure my Bravo at some point. Still got to figure out how to mount it on my flight rig though, as its pretty bulky compared to my old saitek one.

3 hours ago, Blake Buhlig said:

The rotaries are one of the main reasons I bought the Bravo, and given my electronics background I've considered opening it up to learn more about why it behaves that way, see if any reasonable mods are possible, etc. Though I'd be taking a risk if I broke it given how hard these are to find. I don't know. I'm at least glad I managed not to overpay a scalper for it.

Would be interesting to know how you get along with that, but sounds like quite a major undertaking.... I've also heard that they are in short supply, with no more available until October at the earliest.

Good luck! Please post again to let me know how you get on, and the solution you end up with.

 

Link to comment
Share on other sites

I filed a support request with Honeycomb. Who knows, maybe they'll say the 60ms-70ms delay is from a conservative debounce algorithm implemented in their firmware, and could be tweaked with a firmware upgrade. 

11 hours ago, John Dowson said:

just use lua (i.e. send your controls from lua) rather than lua to flag virtual buttons.

Why do you suggest that?

Especially for the inc/dec, I'm sending different controls depending on the position of the Alt/VS/Hdg/Crs/IAS selector, that I expect will need to vary depending on selected aircraft.  All manageable with virtual buttons and different profiles, not so much if I have to do it all in lua.

11 hours ago, John Dowson said:

And for "fast" press/releases, it is better to send the desired control on both, as well as increasing the delta.

I don't understand this either? Logically the button release on these rotaries gives no meaningfully new information. By that I mean, when a button press happens I'd just as well send a control/virtual keypress, then start a 60ms timer to send it again -- all the while completely ignoring the button release. And then why would I want the 60ms delay at all, versus just sending two control/virtual keypresses on the button press, or a single control/virtual keypress that has twice the normal impact?  

But yes, I'll share updates and my code as I can.

Edited by Blake Buhlig
Clarified my 2nd question
Link to comment
Share on other sites

13 hours ago, Blake Buhlig said:

Why do you suggest that?

Especially for the inc/dec, I'm sending different controls depending on the position of the Alt/VS/Hdg/Crs/IAS selector, that I expect will need to vary depending on selected aircraft.  All manageable with virtual buttons and different profiles, not so much if I have to do it all in lua.

Just to avoid the overhead of flagging the virtual button that triggers an assignment that then sends the control, by sending the control directly. However, makes more sense to use virtual buttons if your assignments are different for different profiles, as you say.

13 hours ago, Blake Buhlig said:

I don't understand this either? Logically the button release on these rotaries gives no meaningfully new information.

The 'fast' rotary should send the controls at a faster rate. If you are only sending controls in the press event you are only getting around 8-10 'presses' per second, and are so only sending 8-10 controls. If you also send on release, you double this to 16-20 controls per second. It is common practice to assign this way for 'fast' rotaries.

Another common practice, especially for trim wheel assignments, is to duplicate your assignments (by editing the ini, copying the assignment line and increasing the index number), which is basically the same as 'just sending two control/virtual keypresses on the button press', as you say. Of course, you can also do this for the releases, if you also have them assigned.

Some people use one method, others a mixture of both, whatever feels right for them. 

 

Link to comment
Share on other sites

  • 2 weeks later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use. Guidelines Privacy Policy We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.