Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dial backlash (needs testing) #31

Closed
wants to merge 2 commits into from
Closed

Fix dial backlash (needs testing) #31

wants to merge 2 commits into from

Conversation

goodhoko
Copy link
Member

@goodhoko goodhoko commented Dec 14, 2023

We had a long debug session today with @bschwind and we found out the cause. This PR tries to solve it but it's a blind shot - I did not test this yet and the timeout duration is guesstimated.

Cause

Our rotary encoder reports 4 increments per one physical detent and so in the firmware we accumulate the increments and only report a tick when the accumulated value reaches 4.

Unfortunately the HW is little noisy and sometimes the detents' position drifts in relation to the increments. This causes our accumulator to be non-zero even though the dial is resting on a detent. When this happens rotating the dial in one direction has no effect even if the rotation causes 4 increments.

Example (variable names match the code linked above):

  • start with last_count = 0
  • dial is rotated one tick to the right, quei.count reports 4, in turn we report a tick and set last_count = 4
  • because *noise*, one more increment comes in and quei.count reports 5 as the dial settles on the detent position
  • the button is rotated left, which makes quei.count to report 1 (the expected number since we expect 4 increments per detent) but we do not report anything because last_count - count is 3 (4 - 1)
  • rotating right again, quei.count reports 5, which again doesn't trigger a tick because last_count - count is -1
  • i.e. unless the count leaves the (0, 8) range we report no ticks but the two adjacent detents are located at 1 and 5.

Solution

There's no way for us to know where exactly the detents are located in relation to count. The only other dimension we can work with is time.

We can take advantage of the fact that users usually (and detented dials in general) stop for a brief while on the detents. In other words whenever there's no rotation for a while, the dial is probably sitting on a detent and we should reset our accumulator.

This has two caveats:

  1. When the dial stops in between dials we assume it's a detent. However, this should seldom happen and when it does it will be corrected the next time the dials slips to a detented position.
  2. If the user rotates the button sufficiently slow between detents the rotation will not be registered as the accumulator will be reset before it has chance to accumulate 4 increments. This depends on how we tune the timeout duration. I believe it can be set to value such that reasonably slow ticks are safely registered.

This needs throughout testing.

Fixes https://github.com/tonarino/portal/issues/2666

@goodhoko goodhoko requested review from strohel and bschwind December 14, 2023 13:42
@goodhoko goodhoko marked this pull request as draft December 14, 2023 14:01
@goodhoko
Copy link
Member Author

Actually, I'll mark this as a draft until it's tested to work.

@goodhoko goodhoko mentioned this pull request Dec 14, 2023
@goodhoko
Copy link
Member Author

Afterall, it seems we'll be able to fix the backlash with by merely changing the decoder configuration. No flaky timers needed!

@goodhoko goodhoko closed this Dec 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant