Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 14 of 14

Thread: Encoder Tester

  1. #1
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,120

    Encoder Tester

    Recently a lot of new encoder libraries and other encoder related information and questions were posted in the forum.

    To name a few:
    Encoders (once more)
    Encoder Library not as efficient as XOR method
    Rotary Encoder Debugging on SAMD11
    Hardware Quadrature Code for Teensy 3.x
    Encoder
    How to use encoders as pot
    ... and a lot more

    Due to the obviously growing interest in using encoders and writing encoder libraries I thought that publishing a small encoder simulator tool might be useful for systematic testing of the libraries. Here the link to the GitHub repo: https://github.com/luni64/EncSim. It can generate quadrature signals at count rates from 1Hz up to 1.4MHz. The phase of the generated signals can be adjusted from 90 (standard) down to 10. Optionally a random bouncing signal with adjustable parameters can be added. The simulator can be controlled from any serial terminal (TyCommander, PuTTy, arduino serial monitor...).

    In case somebody wants to try it without installing the library first, I attached the Hex files for T3.6 and T3.2 in the Repo and to this post. Just upload the FW, connect to a serial terminal and type help. Output signals are generated on pin 0 and pin 1.

    Click image for larger version. 

Name:	interface.PNG 
Views:	150 
Size:	61.1 KB 
ID:	10756


    and here an example of a generated signal with added simulated contact bouncing:

    Click image for larger version. 

Name:	50Hz_bounce5000_20_500.jpg 
Views:	152 
Size:	59.9 KB 
ID:	10757 Click image for larger version. 

Name:	50Hz_bounce5000_20_500_zoom.jpg 
Views:	139 
Size:	54.5 KB 
ID:	10758

    Detailed documentation can be found in the GitHub readme.
    Attached Files Attached Files
    Last edited by luni; 06-08-2017 at 07:03 PM.

  2. #2
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,120
    As per user request, I updated my quadrature generator library (EncSim) to be compatible to T4.x. I replaced the underlying timer library (TeensyDelay) by the TeensyTimerTool which supports all ARM Teensies.

    Precompiled hex files are available for various boards. https://github.com/luni64/EncSim/releases.

  3. #3
    Junior Member
    Join Date
    Aug 2020
    Posts
    6

    Adding 3rd output [Z / Trigger] possible?

    Great work with this tester luni!

    I'm just received a set of T4.1 boards and i'm new with the Teensy's.

    One of the first project with T4.1 is to make a simulator for rotary encoders witch supports at least 32768 (X4) pulses per rev. and with trigger (Z) also implemented.
    I'm found out that IMXRT1060RM "quadrature decoder/encoder" has a native support for home, trigger, so probably trigger can be added on this lib too? If so.. are you interested? thoughts? Ideas?

    Secondly is there idea about a performance yet?
    eg: with encoder type mentioned and with 25RPS we should get a 819200 transitions/s right?
    I'm not sure, but believe that teensy had now enough of juice to output this pulse rate and even higher without any trouble!?
    I had done past a simpler quadrature A,B,Z simulator with ESP32 where i toggling outputs with isr-timer and found out that output frequency with 32768ppr starts to come more unstable with higher frequency's.
    and was saturated somewhere around my target.

    ps, here's the encoders i try to simulate and they had a versions with max of 131072 ppr:
    https://www.baumer.com/dk/en/product...ncoder/c/33780

    -Tepa

  4. #4
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,120
    Glad you like it.

    One of the first project with T4.1 is to make a simulator for rotary encoders witch supports at least 32768 (X4) pulses per rev. and with trigger (Z) also implemented.
    By 'trigger' you mean a reference/zero pulse issued at a settable number of counts, right? I.e., the same as you usually get from rotary encoders once per revolution. That shouldn't be a big deal. I can have a look at that.

    Secondly is there idea about a performance yet?
    I didn't spend much time with optimization for the current version. As it is, it maxes out at a pulse rate of about 900kHz for a T4x.

    I'm not sure, but believe that teensy had now enough of juice to output this pulse rate and even higher without any trouble!?
    Unfortunately the interrupt system of the IMXRT is a bit on the slow side. So, don't expect much higher performance than a T3.6 in applications using timer interrupts. My gut feeling is that something like 2Mhz (counts per second) should be possible with some optimization. For higher frequencies the library concept would need to be changed completely.

    What is your targeted max pulse rate?

  5. #5
    Junior Member
    Join Date
    Aug 2020
    Posts
    6
    Thanks for quick reply


    Quote Originally Posted by luni View Post
    By 'trigger' you mean a reference/zero pulse issued at a settable number of counts, right? I.e., the same as you usually get from rotary encoders once per revolution. That shouldn't be a big deal. I can have a look at that.
    Yes correct!. i would be very pleasant for that!!

    I didn't spend much time with optimization for the current version. As it is, it maxes out at a pulse rate of about 900kHz for a T4x.

    Unfortunately the interrupt system of the IMXRT is a bit on the slow side. So, don't expect much higher performance than a T3.6 in applications using timer interrupts. My gut feeling is that something like 2Mhz (counts per second) should be possible with some optimization. For higher frequencies the library concept would need to be changed completely.

    What is your targeted max pulse rate?
    Currently i would be happy if can get clean out of for 300kHz so 900kHz sounds good to me!

    Ones implemented i can try to do stress test and share results here!

    br,
    Tepa

  6. #6
    Junior Member
    Join Date
    Aug 2020
    Posts
    6
    Here's a graph for showing alignment... Phase shift 90 and positive direction: zero (trigger) should should go high with B-rising and come back low with A-falling.
    Click image for larger version. 

Name:	quadrature.png 
Views:	14 
Size:	33.2 KB 
ID:	21417

  7. #7
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,120
    The start of the Z pulse obviously depends on the period ('ppr') you select. E.g., if you set the period to an odd number, the starting edge for the Z pulse will change each time, if you use a period which can be divided by 4, the pulse will always start at the falling edge of B. Real life encoders necessarily have a period which can be divided by 4. So, just make sure you set the period correctly then it will work as expected.

    Here a first test result. I set the pulse rate to 800'000 pps. To display the zero pulses without zooming I used a small zero pulse period of 12.

    Click image for larger version. 

Name:	Anmerkung 2020-08-19 113624.jpg 
Views:	20 
Size:	63.2 KB 
ID:	21418

    Code:
    #include "EncSim.h"
    
    EncSim encSim(0, 1, 2);             // A=0, B=1, Z=2
    
    void setup()
    {
        pinMode(LED_BUILTIN, OUTPUT);
    
        encSim.begin();
        encSim                          // setup parameters
            .setFrequency(800'000)      // 800 kpps
            .setPeriod(12)              // Zero pulse every 12 counts
            .setPhase(90)               // normal 90 phase
            .setTotalBounceDuration(0); // no bouncing
    
        encSim.moveRelAsync(5000);      // run for some time
    }
    
    void loop()
    {
        digitalToggleFast(LED_BUILTIN); // heart beat
        delay(250);
    }

  8. #8
    Junior Member
    Join Date
    Aug 2020
    Posts
    6
    This is looking great thanks a lot luni!

  9. #9
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,120
    I updated the GitHub repository with the index pulse generation feature: (v2.1.0.0) https://github.com/luni64/EncSim/releases Let me know if it works for you.

  10. #10
    Junior Member
    Join Date
    Aug 2020
    Posts
    6
    Quote Originally Posted by luni View Post
    I updated the GitHub repository with the index pulse generation feature: (v2.1.0.0) https://github.com/luni64/EncSim/releases Let me know if it works for you.
    Quite close!!

    Pulse sequence is correct Z works as it should. tested with .setPeriod(32768) witch is my current most high count encoder.

    Frequency is a bit tricky for me. I see you had used 800k so probably i had something wrong next i try explain what happened while playing.
    from 100k to 500k frequency was rising linearly.. using .setFrequency(500'000) i got [A&B pulse freq 117,1kHz] [Z pulse freq 14,3Hz] witch corresponds in shaft speed 859rpm.
    .setFrequency(500'001) and any bigger number.. and i have output of [A&B freq 185,1kHz] [Z freq 22,6Hz] = 1356rpm.

    I hope to get clean frequency with: [A&B freq 273kHz] [Z freq 33,33Hz] = 2000rpm.
    Also i noted that by keep something inside loop effecting output frequency and especially variation of frequency ( this was expected )
    Code:
    #include "Arduino.h"
    #include "EncSim.h"
    
    EncSim encSim(0, 1, 2);             // A=0, B=1, Z=2
    
    void setup()
    {
        pinMode(LED_BUILTIN,OUTPUT);   
        
        encSim.begin();
        encSim                          // setup parameters
            .setFrequency(500'000)      // 500000 Counts per second / equals [A&B freq == 117,2kHz] [Z freq 14,3Hz = 859rpm]
            //.setFrequency(500'001)    // 500001 Counts per second / equals [A&B freq == 185,1kHz] [Z freq 22,6Hz = 1356rpm] 
            .setPeriod(32768)           // Index pulse every 32768 counts [X4 mode] 
            .setPhase(90)               // 90 phase signal
            .setTotalBounceDuration(0); // no bouncing
    
        encSim.moveRelAsync(INT32_MAX); // run for some time INT32_MAX = 2147483647
    }
    
    void loop()
    {
        //digitalToggleFast(LED_BUILTIN); // heart beat   
        //delay(1000);
        
    }
    Arduino Settings:
    Click image for larger version. 

Name:	TeensySettings.png 
Views:	10 
Size:	18.7 KB 
ID:	21440

  11. #11
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,120
    Interesting, I'll have a look but will need some time

  12. #12
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,120

    EncSim v2.2.0.0

    I could reproduce you issues and fixed them

    Explanation:
    To be able to generate non 90 quadrature signals I used chained one shot timers. However, triggering those timers takes some time so that the resulting frequency of the quadrature signal is less than required. The effect gets larger for smaller signal periods since then the additional delay gets dominant.

    Fix:
    • I changed the lib to use a periodic timer instead. To generate the non 90 signals I set the next period of the timer in the ISR which doesn't introduce the retrigger errors.
    • I also switched the main timer from software to hardware (PIT) to get a more stable output frequency. The bounce timers are still software but they are not critical at all.


    Here an updated test sketch using your parameters.

    Code:
    #include "EncSim.h"
    
    EncSim encSim(0, 1, 2);           // A=0, B=1, Z=2
    
    constexpr float rpm  = 150;       // revolutions per minute
    constexpr float ppr  = 32768;     // encoder pulses per revolution
    constexpr float rps  = rpm / 60;  // revolutions per second
    constexpr float freq = rps * ppr; // count frequency
    
    void setup()
    {
        pinMode(LED_BUILTIN, OUTPUT);
        while (!Serial && millis() < 1500) {}
    
        Serial.printf("rpm:\t%8.2f 1/min\n", rpm);
        Serial.printf("pps:\t%8.2f kHz\n", freq / 1000.0f);
        Serial.printf("phase freq:\t%8.2f kHz\n", freq / 4000.0f);
        Serial.printf("z-freq :\t%8.2f Hz\n", rps);
    
        encSim
            .begin()
            .setFrequency(freq)         // calculated above
            .setPeriod(ppr)             // defined above
            .setPhase(90)               // 90 phase signal
            .setTotalBounceDuration(0); // no bouncing
    
        encSim.moveRelAsync(INT32_MAX); // run for some time INT32_MAX = 2147483647
    }
    
    void loop()
    {
        digitalToggleFast(LED_BUILTIN); // heart beat
        delay(250);
    }
    Here the output of the sketch
    Code:
    rpm:          800.00 1/min
    pps:          436.91 kHz
    phase freq:   109.23 kHz
    z-freq :      13.33 Hz
    And here the measurement result. Expected frequencies fit nicely to the measurement now. Works up to a count frequency of >1MHz on a T4. -> Your 2000rpm should work as well.

    Click image for larger version. 

Name:	Anmerkung 2020-08-23 183057.jpg 
Views:	22 
Size:	46.4 KB 
ID:	21448

    Click image for larger version. 

Name:	Anmerkung 2020-08-23 193319.jpg 
Views:	21 
Size:	34.8 KB 
ID:	21449

    Updated library is on GitHub (v2.2.1.0) https://github.com/luni64/EncSim
    Last edited by luni; 08-23-2020 at 05:50 PM.

  13. #13
    Junior Member
    Join Date
    Aug 2020
    Posts
    6
    Tested and confirmed now it works nice and clean even with toggling led at loop.. Nice work thanks a lot!

    Indeed it goes up to round 2500rpm now and i think i can use it "as is" for a long time from now.

    For future i'm interested how or is it possible to improve still further some show?
    If i had take it correctly now hw pit timer fires interrupts to toggling gpio right?
    how about if using pit against DMA for switching pin or some other technique?

    Here's my measurement with top frequency setting 2500rpm i've got avg @2441 rpm and peak to peak was only 12rpm Not Bad
    Click image for larger version. 

Name:	enc.jpg 
Views:	13 
Size:	81.7 KB 
ID:	21456

    Thanks Tepa,

  14. #14
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,120
    As per user request I exchanged the IntervalTimer by IntervalTimerEx and encapsulated it in the simulator class. It is now possible to generate up to four independent simulator objects. (v2.3.0) https://github.com/luni64/EncSim/releases

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •