Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

ESP32: Add Quadrature Encoder and Pulse Counter classes.#8766

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
IhorNehrutsa wants to merge1 commit intomicropython:master
base:master
Choose a base branch
Loading
fromIhorNehrutsa:ESP32_PCNT_Encoder_Counter

Conversation

IhorNehrutsa
Copy link
Contributor

@IhorNehrutsaIhorNehrutsa commentedJun 16, 2022
edited
Loading

Applied to industrial encoders. Has a 32-bit wide counter!!! Has a 32-bit wide matching value !!! (64 bit wide is possible).
image

Count pulses on Pin(17) with direction on Pin(16) an irq handler on zero value.

from machine import Counter, Pindef irq_handler(self):    print('irq_handler()', self.id(), self.status(), self.value())cnt = Counter(0, src=Pin(17, mode=Pin.IN), direction=Pin(16, mode=Pin.IN))cnt.irq(irq_handler, Counter.IRQ_ZERO)  # set irq handlerprint(cnt.value())  # get current counter value

Please note that this pull request
ESP32: Add Quadrature Encoder and Pulse Counter classes.#8766
and
docs\machine: Add Counter and Encoder classes.#8072
and
mimxrt: Add Quadrature Encoder and Pulse Counter classes.#7911
are mutually agreed upon.

Note: MicroPython-lib PRAdd Stepper Motor PWM-Counter driver. requires this PR.

cederom, tomklapka, pidou46, and acciochris reacted with thumbs up emoji
@harbaum
Copy link

Please consider#7582 as a replacement for this one. The other one is more flexible as it exposes the PCNT API and implements the machine.Counter and machine.Encoder in Pyrhon which is IMHO a much nicer approach as it allows to use PCNT for further counter types like on that uses two dedicated pins to count up and down.

@harbaum
Copy link

harbaum commentedAug 14, 2022
edited
Loading

I would still like to understand why this PR is preferable over e.g.#7582

This one is IMHO significantly more limited than#7582 as it hides the underlying PCNT API of the ESP32.#7582 exposes this and implements Encoder and Counter as one of many possibilities on top of that.

Furthermore this PR IMHO does not handle setting the counter correctly as it implements a separate offset to the non-settable hardware counter which in turn won't work with the IRQs (counter passes zero, counter reaches a certain value) as the offset happens on the software side and is not taken into account by the hardware side.

If I am wrong with my assumptions, then please correct me.

@msamblanet
Copy link

Hello - new here and just built the branch and tested it with a 100 PPR CNC rotary wheel and initial test works great!

I do wonder if it might make sense for the encoder at least to have a default non-zero filter_ns value. I needed it due to bounce on my encoder and suspect a lot of users will be confused by behavior caused by not setting filter_ns for rotary encoders. Those who have use-cases where no filter is needed will likely be more advanced users who will know to override the default.

For reference, this was tested on an Unexpected Maker ProS3. If there are any specific tests the team needs that I can help with, let me know - otherwise I'll report in if I see any issues during my development.

@IhorNehrutsa
Copy link
ContributorAuthor

@msamblanet Can you check the maximum rotation speed of the encoder shaft when measuring the exact pulse count without pulse losses?

@msamblanet
Copy link

msamblanet commentedAug 18, 2022
edited
Loading

@IhorNehrutsa - I don’t have a mechanical drive other than my hand. I was stress testing it by spinning around 6 full rotations per second (600 steps or 2400 counts per second) with no loss (way faster than my real world use case). I was using a 10000ns filter (arbitrary choice but a filter was needed with my setup). Given the frequency of the esp32 pcnt unit (25mhz I think) I’m not too worried here :)

I think once during my testing I lost a couple pulses but I am testing in a breadboard with a couple iffy connections. As it was a single occurrence, I’m ignoring it unless it happens repeatable.

Edit - corrected pulses to counts in rate

@msamblanet
Copy link

I just tried to rebase this PR so I could test it combined with another PR which is based on a new MP base. This PR fails to build when rebased at 2 points in machine_encoder.c. Full error output below. The branch without a rebase builds fine for me.

In file included from /project/micropython/py/mpstate.h:33,                 from /project/micropython/py/runtime.h:29,                 from /project/micropython/ports/esp32/machine_encoder.c:50:/project/micropython/ports/esp32/machine_encoder.c: In function 'mp_machine_Counter_init_helper':/project/micropython/py/misc.h:54:50: error: size of unnamed array is negative #define MP_STATIC_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)]))                                                  ^/project/micropython/py/misc.h:58:40: note: in expansion of macro 'MP_STATIC_ASSERT' #define MP_STATIC_ASSERT_NOT_MSC(cond) MP_STATIC_ASSERT(cond)                                        ^~~~~~~~~~~~~~~~/project/micropython/py/obj.h:764:5: note: in expansion of macro 'MP_STATIC_ASSERT_NOT_MSC'     MP_STATIC_ASSERT_NOT_MSC((t) != &mp_type_int), assert((t) != &mp_type_int),           \     ^~~~~~~~~~~~~~~~~~~~~~~~/project/micropython/py/obj.h:769:31: note: in expansion of macro 'mp_type_assert_not_bool_int_str_nonetype' #define mp_obj_is_type(o, t) (mp_type_assert_not_bool_int_str_nonetype(t) && mp_obj_is_exact_type(o, t))                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/project/micropython/ports/esp32/machine_encoder.c:483:20: note: in expansion of macro 'mp_obj_is_type'         } else if (mp_obj_is_type(args[ARG_scale].u_obj, &mp_type_int)) {                    ^~~~~~~~~~~~~~/project/micropython/ports/esp32/machine_encoder.c: In function 'mp_machine_Encoder_init_helper':/project/micropython/py/misc.h:54:50: error: size of unnamed array is negative #define MP_STATIC_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)]))                                                  ^/project/micropython/py/misc.h:58:40: note: in expansion of macro 'MP_STATIC_ASSERT' #define MP_STATIC_ASSERT_NOT_MSC(cond) MP_STATIC_ASSERT(cond)                                        ^~~~~~~~~~~~~~~~/project/micropython/py/obj.h:764:5: note: in expansion of macro 'MP_STATIC_ASSERT_NOT_MSC'     MP_STATIC_ASSERT_NOT_MSC((t) != &mp_type_int), assert((t) != &mp_type_int),           \     ^~~~~~~~~~~~~~~~~~~~~~~~/project/micropython/py/obj.h:769:31: note: in expansion of macro 'mp_type_assert_not_bool_int_str_nonetype' #define mp_obj_is_type(o, t) (mp_type_assert_not_bool_int_str_nonetype(t) && mp_obj_is_exact_type(o, t))                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/project/micropython/ports/esp32/machine_encoder.c:716:20: note: in expansion of macro 'mp_obj_is_type'         } else if (mp_obj_is_type(args[ARG_scale].u_obj, &mp_type_int)) {                    ^~~~~~~~~~~~~~[1412/1425] Building C object esp-idf/main/CMakeFiles/__idf_main.dir/__/modsocket.c.objninja: build stopped: subcommand failed.
IhorNehrutsa reacted with eyes emoji

@IhorNehrutsa
Copy link
ContributorAuthor

IhorNehrutsa commentedNov 6, 2022
edited
Loading

@msamblanet,@AmirHmZz
PR is rebased and fixed

@IhorNehrutsa
Copy link
ContributorAuthor

Tested with industrial 6250ppr encoder.
lir-137a.pdf
image

# encoders_test.pyfrom time import sleepfrom machine import Pinfrom machine import Encoder# Define an Encoder pinsENCODER_A = 16ENCODER_B = 17ENCODER_R = 18  # one impulse per revolutionPPR = 6250  # pulses per revolution of the encoder shaftX124 = 4PPR *= X124def callback(enc):    print("\nEncoder value:", enc.value())try:    a = Pin(ENCODER_A, mode=Pin.IN)    b = Pin(ENCODER_B, mode=Pin.IN)      r = Pin(ENCODER_R, mode=Pin.IN)      print('A', a, a.value())    print('B', b, b.value())    print('Z', r, r.value())    enc = Encoder(0, a, b, x124=X124)    enc.irq(handler=callback, trigger=Encoder.IRQ_MATCH1, value=50_000)    enc.irq(handler=callback, trigger=Encoder.IRQ_ZERO)    enc.irq(handler=callback, trigger=Encoder.IRQ_MATCH2, value=-50_000)    print(enc)    _a = None    _b = None    _r = None    _value = None    while True:        __a = a.value()        __b = b.value()        __r = r.value()        __value = enc.value()        if (_a != __a) or (_b != __b) or (_r != __r) or (_value != __value):            _a = __a            _b = __b            _r = __r            _value = __value            print("a={}, b={}, r={}, value={:10}".format(_a, _b, _r, _value), end='        \r')        sleep(0.1)finally:    try:        # use enc.deinit(), otherwise enc.callback() will work after exiting the program        enc.deinit()    except:        pass

%Run -c $EDITOR_CONTENT

A Pin(16) 0B Pin(17) 1Z Pin(18) 1Encoder(0, phase_a=Pin(16), phase_b=Pin(17), x124=4, match1=50000, match2=-50000)a=0, b=1, r=1, value=         0        Encoder value: 0a=1, b=0, r=1, value=     49687        Encoder value: 50001a=1, b=0, r=1, value=     50634        Encoder value: 49999a=1, b=1, r=1, value=       526        Encoder value: -1a=0, b=1, r=1, value=    -42349        Encoder value: -50007a=0, b=0, r=1, value=    -50095        Encoder value: -50000

@IhorNehrutsa
Copy link
ContributorAuthor

Add_src inverse pulse input.

.. class:: Counter(id, src=None, \*, direction=Counter.UP, _src=None, edge=Counter.RISING, filter_ns=0)    The Counter starts to count immediately. Filtering is disabled.      - *id*. Values of *id* depend on a particular port and its hardware.        Values 0, 1, etc. are commonly used to select hardware block #0, #1, etc.      - *src* is the pulse input :ref:`machine.Pin <machine.Pin>` to be monitored.        *src* is required in the constructor.      - *direction* specifies the direction to count. Values for this include the constants        - Counter.UP - (default value) and        - Counter.DOWN to control the direction by software or        - :ref:`machine.Pin <machine.Pin>` object to control the direction externally. If ``Pin.value()``:           - 0 - count down,           - 1 - count up.      - *_src* is the inverse pulse input :ref:`machine.Pin <machine.Pin>` to be monitored.        If the *_src* keyword is present then the *direction* keyword does not matter.        *src* and *_src* count in opposite directions, one in the UP direction        and the other in the DOWN direction, i.e. as an incremental/decremental counter.      - *edge* specifies which edges of the input signal will be counted by Counter:        - Counter.RISING : raise edges,        - Counter.FALLING : fall edges,        - Counter.RISING | Counter.FALLING : both edges.      - *filter_ns* specifies a ns-value for the minimal time a signal has to be stable        at the input to be recognized. The largest value is 12787ns (1023 * 1000000000 / APB_CLK_FREQ).        The default is 0 – no filter.

@IhorNehrutsaIhorNehrutsaforce-pushed theESP32_PCNT_Encoder_Counter branch from002923f tocec1abfCompareMarch 10, 2023 08:14
@IhorNehrutsaIhorNehrutsaforce-pushed theESP32_PCNT_Encoder_Counter branch 3 times, most recently from47db009 to5ef41faCompareAugust 1, 2023 08:30
@IhorNehrutsaIhorNehrutsaforce-pushed theESP32_PCNT_Encoder_Counter branch from5ef41fa toa6d25caCompareAugust 18, 2023 16:57
@IhorNehrutsaIhorNehrutsaforce-pushed theESP32_PCNT_Encoder_Counter branch 3 times, most recently from462994a to7b82d99CompareAugust 25, 2023 05:00
@IhorNehrutsaIhorNehrutsaforce-pushed theESP32_PCNT_Encoder_Counter branch from7b82d99 to4d752d2CompareOctober 6, 2023 06:14
@IhorNehrutsaIhorNehrutsaforce-pushed theESP32_PCNT_Encoder_Counter branch from4d752d2 toab46ae5CompareNovember 8, 2023 14:34
@IhorNehrutsaIhorNehrutsaforce-pushed theESP32_PCNT_Encoder_Counter branch 2 times, most recently froma58be0b to3b44fa5CompareNovember 10, 2023 08:34
@IhorNehrutsaIhorNehrutsaforce-pushed theESP32_PCNT_Encoder_Counter branch 2 times, most recently fromd0a3849 to4bd7b04CompareJanuary 30, 2024 09:08
@github-actionsGitHub Actions
Copy link

github-actionsbot commentedJan 30, 2024
edited
Loading

Code size report:

@IhorNehrutsaIhorNehrutsaforce-pushed theESP32_PCNT_Encoder_Counter branch from5bbba6d to4da4454CompareJanuary 30, 2024 09:30
@codecovCodecov
Copy link

codecovbot commentedJan 30, 2024
edited
Loading

Codecov Report

All modified and coverable lines are covered by tests ✅

Comparison is base(d5b9681) 98.36% compared to head(c5bfb0d) 98.36%.
Report is 10 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@##           master    #8766   +/-   ##=======================================  Coverage   98.36%   98.36%           =======================================  Files         159      159             Lines       21088    21093    +5     =======================================+ Hits        20743    20748    +5  Misses        345      345

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report?Share it here.

@IhorNehrutsaIhorNehrutsaforce-pushed theESP32_PCNT_Encoder_Counter branch 3 times, most recently frombcd081d toc5bfb0dCompareJanuary 31, 2024 08:37
@projectgus
Copy link
Contributor

This is an automated heads-up that we've just merged a Pull Request
that removes the STATIC macro from MicroPython's C API.

See#13763

A search suggests this PR might apply the STATIC macro to some C code. If it
does, then next time you rebase the PR (or merge from master) then you should
please replace all theSTATIC keywords withstatic.

Although this is an automated message, feel free to @-reply to me directly if
you have any questions about this.

@IhorNehrutsaIhorNehrutsaforce-pushed theESP32_PCNT_Encoder_Counter branch 7 times, most recently from34aed01 todb9df03CompareNovember 7, 2024 10:13
@IhorNehrutsaIhorNehrutsaforce-pushed theESP32_PCNT_Encoder_Counter branch fromdb9df03 to1a9e3c2CompareJanuary 20, 2025 12:23
@IhorNehrutsaIhorNehrutsaforce-pushed theESP32_PCNT_Encoder_Counter branch 6 times, most recently fromaf8c71e tob650e6fCompareFebruary 1, 2025 18:12
Co-Authored-By: robert-hh <robert@hammelrath.com>Co-Authored-By: Jonathan Hogg <me@jonathanhogg.com>Signed-off-by: IhorNehrutsa <Ihor.Nehrutsa@gmail.com>
@IhorNehrutsaIhorNehrutsaforce-pushed theESP32_PCNT_Encoder_Counter branch from670a7a0 to98a04f1CompareMarch 13, 2025 08:21
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers
No reviews
Assignees
No one assigned
Labels
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

5 participants
@IhorNehrutsa@harbaum@msamblanet@projectgus@dpgeorge

[8]ページ先頭

©2009-2025 Movatter.jp