Rotary encoder with asyncio?

Discussion about programs, libraries and tools that work with MicroPython. Mostly these are provided by a third party.
Target audience: All users and developers of MicroPython.
ilium007
Posts: 37
Joined: Tue Feb 16, 2021 10:29 am

Rotary encoder with asyncio?

Post by ilium007 » Sat Feb 27, 2021 10:56 am

Is there a rotary encoder library that makes use of micropython-async (https://github.com/peterhinch/micropython-async) instead of interrupts?

I have been playing with uencoder (https://gitlab.com/WiLED-Project/uencoder) but would like to see how this could be implemented using asyncio.

I am assuming I would need to create two asyncio tasks to replace the pin interrupts

Code: Select all

if use_interrupts:
            mode = Pin.IRQ_RISING | Pin.IRQ_FALLING
            self.pin_A_irq = self.pin_A.irq(trigger=mode, handler=self.process)
            self.pin_B_irq = self.pin_B.irq(trigger=mode, handler=self.process)
        # TODO: Implement a polling-only method, with asyncio

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

This is a case for interrupts or hardware

Post by pythoncoder » Sat Feb 27, 2021 2:25 pm

Much as I frequently advocate uasyncio rather than interrupts, this is an exception. Please look at this link.

Encoders present a challenge because they can produce a stream of pulses which don't signify motion. This happens if the machine stops with the encoder at a physical transition between on and off: any vibration can result in a string of pulses as the optical device jitters around an edge. The algorithm for dealing with this is simple, but does need to be capable of a fast response.

The solution is to have an interrupt driven process which maintains a position value: the latter may then be read by your uasyncio code as required.

The Pyboard can do even better as it can be configured to decode one or two encoders in hardware. This enables it to handle very fast rotation rates.
Peter Hinch
Index to my micropython libraries.

ilium007
Posts: 37
Joined: Tue Feb 16, 2021 10:29 am

Re: This is a case for interrupts or hardware

Post by ilium007 » Sun Mar 27, 2022 11:15 am

pythoncoder wrote:
Sat Feb 27, 2021 2:25 pm
The Pyboard can do even better as it can be configured to decode one or two encoders in hardware. This enables it to handle very fast rotation rates.
Sorry to dig this up again but have only just got back into this project after building a house and all the mess that is Covid.

Do you have some more info on using the STM32F405 hardware quadrature decoding? I'm using an Adafruit STM32F405 board because I couldn't easily get hold of a Pyboard to test with.

*Edit* found the info here:
https://github.com/dhylands/upy-example ... encoder.py

rkompass
Posts: 66
Joined: Fri Sep 17, 2021 8:25 pm

Re: Rotary encoder with asyncio?

Post by rkompass » Sun Mar 27, 2022 6:50 pm

Have a look at https://github.com/dhylands/upy-examples encoder2.py and encoder3.py.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Rotary encoder with asyncio?

Post by pythoncoder » Mon Mar 28, 2022 9:15 am

@illum07 Since posting the above I wrote this class for interfacing an encoder to uasyncio.

The driver uses interrupts to handle the transitions, but performs callbacks in a uasyncio context. Simple interrupt driven drivers have the drawback that callbacks occur in an IRQ context and are subject to all the limitations that involves. In this driver the callbacks have no such limitations. Also the driver enables the encoder's sensitivity to be controlled, so that callbacks occur only when the position has changed by N edges.
Peter Hinch
Index to my micropython libraries.

ilium007
Posts: 37
Joined: Tue Feb 16, 2021 10:29 am

Re: Rotary encoder with asyncio?

Post by ilium007 » Mon Mar 28, 2022 10:28 am

Thanks, I'll take a look.

ilium007
Posts: 37
Joined: Tue Feb 16, 2021 10:29 am

Re: Rotary encoder with asyncio?

Post by ilium007 » Mon Mar 28, 2022 11:09 am

I have had an initial look at the Encoder class but can't make it read anything through its value() method. I have set up an Encoder object and passed in the two machine.Pin's from the rotary encoder. I have tested that the encoder is producing quadrature grey code with an oscilloscope.

Code: Select all

>>> from machine import Pin
>>> from encoder import Encoder
>>>
>>> pina = Pin("A4", Pin.IN, Pin.PULL_UP)
>>> pinb = Pin("A5", Pin.IN, Pin.PULL_UP)
>>> encoder1 = Encoder(pina, pinb)
>>> encoder1.value()
0
>>> encoder1.value()
0
>>>
I get no value change when turning the encoder

ilium007
Posts: 37
Joined: Tue Feb 16, 2021 10:29 am

Re: Rotary encoder with asyncio?

Post by ilium007 » Mon Mar 28, 2022 11:16 am

Where in encoder.py does the class do the actual grey code decoding?

pidou46
Posts: 101
Joined: Sat May 28, 2016 7:01 pm

Re: Rotary encoder with asyncio?

Post by pidou46 » Mon Mar 28, 2022 2:03 pm

They have been multiple attempts to include PCNT esp32's hardware counter in firmware, but it stalled.

As a workaround, I have jump on a AS5600 magnetic encoder.
The main advantages I found is :
- it's super easy to setup mechanically
- setup is been done using i2c bus
- reading can done via i2c, 0-1vcc
- absolute measurement
- fast response time
- quit precise, given the resolution. I haven't made any measurement of the real precision.
- low cost https://fr.aliexpress.com/item/10050035 ... 5e5bQzdDeb

drawback: it is limited to one turn

I hope hardware pulse counter of esp32 will be supported one day, but until now I quite happy with this workaround.
nodemcu V2 (amica)
micropython firmware Daily build 05/31/2016

ilium007
Posts: 37
Joined: Tue Feb 16, 2021 10:29 am

Re: Rotary encoder with asyncio?

Post by ilium007 » Mon Mar 28, 2022 8:24 pm

I’m using the Adafruit STM32F405 board to prototype with.

Post Reply