Skip to content

Commit 5cc34b3

Browse files
committed
Encoder: Improve driver, document.
1 parent f8d1257 commit 5cc34b3

File tree

3 files changed

+41
-15
lines changed

3 files changed

+41
-15
lines changed

v3/docs/DRIVERS.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -866,7 +866,7 @@ behaviour.
866866

867867
The `Encoder` can be instantiated in such a way that its effective resolution
868868
can be reduced. A virtual encoder with lower resolution can be useful in some
869-
applications.
869+
applications. In particular it can track the "clicks" of a mechanical detent.
870870

871871
The driver allows limits to be assigned to the virtual encoder's value so that
872872
a dial running from (say) 0 to 100 may be implemented. If limits are used,
@@ -908,10 +908,10 @@ Constructor arguments:
908908
receives two integer args, `v` being the virtual encoder's current value and
909909
`delta` being the signed difference between the current value and the previous
910910
one. Further args may be appended by the following.
911-
9. `args=()` An optional tuple of positionl args for the callback.
911+
9. `args=()` An optional tuple of positional args for the callback.
912912
10. `delay=100` After motion is detected the driver waits for `delay` ms before
913-
reading the current position. A delay can be used to limit the rate at which
914-
the callback is invoked. This is a minimal approach. See
913+
reading the current position. A delay limits the rate at which the callback is
914+
invoked and improves debouncing. This is a minimal approach. See
915915
[this script](https://github.com/peterhinch/micropython-async/blob/master/v3/primitives/tests/encoder_stop.py)
916916
for a way to create a callback which runs only when the encoder stops moving.
917917

v3/docs/TUTORIAL.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,13 +1163,14 @@ async def foo(tsf): # Periodically set the ThreadSafeFlag
11631163
await asyncio.sleep(1)
11641164
tsf.set()
11651165

1166-
def ready(tsf, poller):
1167-
poller.register(tsf, POLLIN)
1166+
def ready(tsf, poller):
1167+
r = (tsf, POLLIN)
1168+
poller.register(*r)
11681169

1169-
def is_rdy():
1170-
return len([t for t in poller.ipoll(0) if t[0] is tsf]) > 0
1170+
def is_rdy():
1171+
return r in poller.ipoll(0)
11711172

1172-
return is_rdy
1173+
return is_rdy
11731174

11741175
async def test():
11751176
tsf = asyncio.ThreadSafeFlag()

v3/primitives/encoder.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# encoder.py Asynchronous driver for incremental quadrature encoder.
22

3-
# Copyright (c) 2021-2022 Peter Hinch
3+
# Copyright (c) 2021-2023 Peter Hinch
44
# Released under the MIT License (MIT) - see LICENSE file
55

6-
# For an explanation of the design please see
6+
# For an explanation of the design please see
77
# [ENCODERS.md](https://github.com/peterhinch/micropython-samples/blob/master/encoders/ENCODERS.md)
88

99
# Thanks are due to the following collaborators:
@@ -19,11 +19,33 @@
1919

2020
import uasyncio as asyncio
2121
from machine import Pin
22+
from select import poll, POLLIN
2223

23-
class Encoder:
2424

25-
def __init__(self, pin_x, pin_y, v=0, div=1, vmin=None, vmax=None,
26-
mod=None, callback=lambda a, b : None, args=(), delay=100):
25+
def ready(tsf, poller):
26+
r = (tsf, POLLIN)
27+
poller.register(*r)
28+
29+
def is_rdy():
30+
return r in poller.ipoll(0)
31+
32+
return is_rdy
33+
34+
35+
class Encoder:
36+
def __init__(
37+
self,
38+
pin_x,
39+
pin_y,
40+
v=0,
41+
div=1,
42+
vmin=None,
43+
vmax=None,
44+
mod=None,
45+
callback=lambda a, b: None,
46+
args=(),
47+
delay=100,
48+
):
2749
self._pin_x = pin_x
2850
self._pin_y = pin_y
2951
self._x = pin_x()
@@ -34,8 +56,9 @@ def __init__(self, pin_x, pin_y, v=0, div=1, vmin=None, vmax=None,
3456
self._trig = asyncio.Event()
3557

3658
if ((vmin is not None) and v < vmin) or ((vmax is not None) and v > vmax):
37-
raise ValueError('Incompatible args: must have vmin <= v <= vmax')
59+
raise ValueError("Incompatible args: must have vmin <= v <= vmax")
3860
self._tsf = asyncio.ThreadSafeFlag()
61+
self._tsf_ready = ready(self._tsf, poll()) # Create a ready function
3962
trig = Pin.IRQ_RISING | Pin.IRQ_FALLING
4063
try:
4164
xirq = pin_x.irq(trigger=trig, handler=self._x_cb, hard=True)
@@ -67,6 +90,8 @@ async def _run(self, vmin, vmax, div, mod, cb, args):
6790
plcv = pcv # Previous value after limits applied
6891
delay = self.delay
6992
while True:
93+
if delay > 0 and self._tsf_ready(): # Ensure ThreadSafeFlag is clear
94+
await self._tsf.wait()
7095
await self._tsf.wait()
7196
await asyncio.sleep_ms(delay) # Wait for motion to stop.
7297
hv = self._v # Sample hardware (atomic read).

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy