Skip to content

Commit 1341eac

Browse files
committed
DRIVERS.md Improve Encoder description.
1 parent c85001f commit 1341eac

File tree

1 file changed

+34
-25
lines changed

1 file changed

+34
-25
lines changed

v3/docs/DRIVERS.md

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -340,35 +340,37 @@ this for applications requiring rapid response.
340340

341341
# 6. Quadrature encoders
342342

343-
This is a work in progress. Changes may occur.
344-
345343
The `Encoder` class is an asynchronous driver for control knobs based on
346344
quadrature encoder switches such as
347345
[this Adafruit product](https://www.adafruit.com/product/377). The driver is
348346
not intended for applications such as CNC machines where
349347
[a solution such as this one](https://github.com/peterhinch/micropython-samples#47-rotary-incremental-encoder)
350348
is required. Drivers for NC machines must never miss an edge. Contact bounce or
351349
vibration induced jitter can cause transitions to occur at a high rate; these
352-
must be tracked.
350+
must be tracked. Consequently callbacks occur in an interrupt context with the
351+
associated concurrency issues.
353352

354-
This driver runs the user supplied callback in an `asyncio` context, so it runs
355-
only when other tasks have yielded to the scheduler. This ensures that the
356-
callback can run safely, even if it triggers complex application behaviour.
353+
This driver runs the user supplied callback in an `asyncio` context, so that
354+
the callback runs only when other tasks have yielded to the scheduler. This
355+
ensures that the callback runs with the same rules as apply to any `uasyncio`
356+
task. This offers safety, even if the task triggers complex application
357+
behaviour.
357358

358359
The `Encoder` can be instantiated in such a way that its effective resolution
359360
can be reduced. A virtual encoder with lower resolution can be useful in some
360361
applications.
361362

362363
The driver allows limits to be assigned to the virtual encoder's value so that
363364
a dial running from (say) 0 to 100 may be implemented. If limits are used,
364-
encoder values no longer represent absolute angles, as the user might continue
365-
to rotate the dial when it is "stuck" at an endstop.
365+
encoder values no longer approximate absolute angles: the user might continue
366+
to rotate the dial when its value is "stuck" at an endstop.
366367

367368
The callback only runs if a change in position of the virtual encoder has
368369
occurred. In consequence of the callback running in an `asyncio` context, by
369370
the time it is scheduled, the encoder's position may have changed by more than
370371
one increment. The callback receives two args, the absolute value of the
371-
virtual encoder and the signed change since the previous callback run.
372+
virtual encoder at the time it was triggered and the signed change in this
373+
value since the previous time the callback ran.
372374

373375
## 6.1 Encoder class
374376

@@ -385,34 +387,41 @@ Constructor arguments:
385387
down, to produce a virtual encoder with lower resolution. This was found usefl
386388
in some applications with the Adafruit encoder.
387389
7. `callback=lambda a, b : None` Optional callback function. The callback
388-
receives two args, `v` being the encoder's current value and `delta` being
389-
the signed difference between the current value and the previous one. Further
390-
args may be appended by the following.
390+
receives two integer args, `v` being the virtual encoder's current value and
391+
`delta` being the signed difference between the current value and the previous
392+
one. Further args may be appended by the following.
391393
8. `args=()` An optional tuple of positionl args for the callback.
392394

393395
Synchronous method:
394-
* `value` No args. Returns an integer being the `Encoder` current value.
396+
* `value` No args. Returns an integer being the virtual encoder's current
397+
value.
395398

396399
Class variable:
397400
* `delay=100` After motion is detected the driver waits for `delay` ms before
398401
reading the current position. This was found useful with the Adafruit encoder
399402
which has mechanical detents, which span multiple increments or decrements. A
400-
delay gives time for motion to stop enabling just one call to the callback.
403+
delay gives time for motion to stop in the event of a single click movement.
404+
If this occurs the delay ensures just one call to the callback. With no delay
405+
a single click typically gives rise to two callbacks, the second of which can
406+
come as a surprise in visual applications.
401407

402-
#### Note
408+
#### Note on accuracy
403409

404410
The driver works by maintaining an internal value `._v` which uses hardware
405411
interrupts to track the absolute position of the physical encoder. In theory
406-
this should be precise, but on ESP32 with the Adafruit encoder it is not:
407-
returning the dial to a given detent shows a small "drift" in position.
408-
409-
Currently under investigation: it may be a consequence of ESP32's use of soft
410-
IRQ's.
411-
412-
This is probably of little practical consequence as encoder knobs are usually
413-
used in systems where there is user feedback. In a practical application
414-
([micro-gui](https://github.com/peterhinch/micropython-micro-gui)) I can see no
415-
evidence of the missed pulses.
412+
this should be precise with jitter caused by contact bounce being tracked. With
413+
the Adafruit encoder it is imprecise: returning the dial to a given detent
414+
after repeated movements shows a gradual "drift" in position. This occurs on
415+
hosts with hard or soft IRQ's. I attempted to investigate this with various
416+
hardware and software techniques and suspect there may be mechanical issues in
417+
the device. Possibly pulses may occasionally missed with direction-dependent
418+
probability. Unlike optical encoders these low cost controls make no claim to
419+
absolute accuracy.
420+
421+
This is of little practical consequence as encoder knobs are usually used in
422+
systems where there is user feedback. In a practical application
423+
([micro-gui](https://github.com/peterhinch/micropython-micro-gui)) there is no
424+
obvious evidence of the missed pulses.
416425

417426
###### [Contents](./DRIVERS.md#1-contents)
418427

0 commit comments

Comments
 (0)