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

Thread: Cheap quadrature encoder jumps values greatly when turned quickly

  1. #1

    Cheap quadrature encoder jumps values greatly when turned quickly

    Using only one knob from the "TwoKnobs Encoder Test" from the PJRC encoder library to read a cheap quadrature encoder that I picked up. Got help on this forum a few months ago to constrain the value to the 0 - 127 midi standard. Of all of the interrupt-based encoder sketches that I was able to find online, this one came the closest to what I'm trying to do, which is simply count up and down by one-per-click.

    The one problem with this code is that when I turn it a certain speed (not very fast at all), the value will most often lurch forward or backward by as much as 40-60. This behavior is inconsistent because sometimes it counts normally, though that is rare. Is there something about this code that I need to change in order to prevent this behavior? I'm not looking for laser accurate readings e.g. I don't mind if it doesn't read every click if I twist it quickly, what's most important for me is that the count remains sequential instead of jumping uncontrollably.

    If there's a better solution for a cheap rotary encoder that increments/decrements once per click, and is relatively understandable for someone who doesn't specialize in coding, I'm all ears. Thanks!

    Code:
    #include <Encoder.h>
    
    Encoder knobLeft(40, 39);
    
    void setup() {
      Serial.begin(9600);
      Serial.println("TwoKnobs Encoder Test:");
    }
    
    int positionLeft  = 0;
    
    void loop() {
    
      byte newLeft;
      byte finalVal;
    
      newLeft = knobLeft.read() / 2;
      finalVal = newLeft >> 1;
      if (newLeft != positionLeft) {
        positionLeft = newLeft;
        Serial.print("Left = ");
        Serial.print(finalVal);
        Serial.println();
      }
    }

  2. #2
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    7,955
    That was 2 weeks ago
    And you still use byte and the bitshift.

    There are better encoder libraries, luni wrote a good one (use the forum search).
    But the best way is not to use cheap encoders.

  3. #3
    Forgive me, time is not real at the moment. If it means anything, I did change the 'byte' part in the larger controller code, but referred back to this one since the code was mostly the same. Thanks for the tip!

  4. #4
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    7,955
    No, its not important here.

  5. #5
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,369
    luni wrote a good one (use the forum search).
    Thanks for the shoutout. Here the link to the library: https://github.com/luni64/EncoderTool. Actually I'd be quite interested if it works with your problematic encoder (which is quite expensive by the way).

    I translated your code fromn #1, so that it works with the EncoderTool. Looking at it, it seems that you have an encoder with two counts per detent (unfortunately the datasheet doesn't have much information).
    I therefore set the count mode to CountMode::half. You can set it to CountMode::quarter if you have a 'nomal' 4 counts per detent encoder.
    The code assumes that your encoders have a common GND and activates the internal pullups (can be switched to common VCC with pulldowns if needed).

    Code:
    #include "Arduino.h"
    #include "EncoderTool.h"
    using namespace EncoderTool;
    
    Encoder knobLeft;
    
    void setup()
    {
        while (!Serial && millis() < 1000) {}
        Serial.println("TwoKnobs Encoder Test:");
    
        knobLeft.begin(39, 40, CountMode::half);  // set to CountMode::quarter if your encoder has 4 counts per detent
        knobLeft.setLimits(0, 127, false);        // limits counts to 0..127, set third param to true if you want cyclic boundaries
    }
    
    void loop()
    {
        if (knobLeft.valueChanged())
        {
            Serial.print("Left = ");
            Serial.print(knobLeft.getValue());
            Serial.println();
        }
    }

  6. #6
    Thanks for going through the trouble to do that, Luni! I've installed the library, but the code is not compiling, and is giving me this error:

    Code:
    In file included from /Users/coryoleson/Documents/Arduino/libraries/EncoderTool-master/src/EncoderBase.h:2:0,
                     from /Users/coryoleson/Documents/Arduino/libraries/EncoderTool-master/src/Multiplexed/EncPlexBase.h:4,
                     from /Users/coryoleson/Documents/Arduino/libraries/EncoderTool-master/src/Multiplexed/EncPlex74165.h:5,
                     from /Users/coryoleson/Documents/Arduino/libraries/EncoderTool-master/src/EncoderTool.h:3,
                     from /Users/coryoleson/Documents/Arduino/Study/Luni_Encoder_Tool/Luni_Encoder_Tool.ino:2:
    /Users/coryoleson/Documents/Arduino/libraries/EncoderTool-master/src/EncoderButton.h:19:14: error: 'bool EncoderTool::EncoderButton::readCurrentState()' marked 'override', but does not override
             bool readCurrentState() override { return curState; }
                  ^
    Error compiling for board Teensy 4.1.
    As the error states, I'm using a Teensy 4.1. I tried changing the count mode to quarter, and changed to true for cyclic boundaries, but the error persists.

  7. #7
    Comment #19 from this thread was the answer that I needed. As the person said, it was as simple as removing the word "override" from EncoderButton.h. This is by far the best encoder code that I've come across, works like magic. Thanks Luni! Thanks Frank!

  8. #8
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,369
    Quote Originally Posted by Hitachii View Post
    Comment #19 from this thread was the answer that I needed. As the person said, it was as simple as removing the word "override" from EncoderButton.h. This is by far the best encoder code that I've come across, works like magic. Thanks Luni! Thanks Frank!
    Glad it works, and good to know that it handles problematic encoders as well.

    The "fix" you did with removing "override" is OK if you don't use the button features of the library. Actually, it just cheats to the compiler so that it accepts the underlying fault. The root cause of the issue is an old version of Bounce2 which ships with Teensyduino < 1.54. You can easily fix this by either installing the current (beta) version 1.54 of Teensyduino or install a current version of Bounce2 with the library manager of the Arduino IDE. Let me know if you need further support using the lib.

  9. #9
    Deleted User
    Guest
    Those CNC pulser handwheel ecoders from China are optical (!) 100PPR and the 5V version works perfectly on 3.3V as well. The detent can be removed to have a completely smooth flow, with 400 transitions per round!
    They sell for as low as 5 each if you are lucky, completely with nicely machined aluminum knob, that could as well be connected to a touch pin for touch sensing, if the encoder is mounted electrically isolated.

    So where is the use of "cheap" encoders, if you can have this professional solution for the same or little extra money?

  10. #10
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,369
    Those CNC pulser handwheel ecoders from China are optical (!) 100PPR
    Of course these encoders are perfect for some applications but they are large and the price difference is significant. A standard mech encoder is about 50ct in single quantities. People here are doing projects using 32+ Encoders per whatever device. That makes a difference of 16EUR to 160EUR for the encoders alone. Not exactly little extra money for a lot of hobby users.

    The notion of cheap, bouncing encoders most often comes from bad read out algorithms. Sometimes the algorithms are good but are done for different types of encoders. Actually, I never stumbled over a (not broken) "cheap" encoder which generated bounces or behaves strangely when read out correctly.

  11. #11
    Member
    Join Date
    Jan 2020
    Location
    Port Elizabeth
    Posts
    67
    Quote Originally Posted by luni View Post
    The notion of cheap, bouncing encoders most often comes from bad read out algorithms. Sometimes the algorithms are good but are done for different types of encoders. Actually, I never stumbled over a (not broken) "cheap" encoder which generated bounces or behaves strangely when read out correctly.
    If I may chime in here. I am using the first version of Luni's encoder library(now somewhat modified by myself) with ultra cheap Chinese encoders. Luni's library works perfectly for me. It counts reliably, with no bounces or skipping, no matter how fast I turn the encoder. The real problem is the poor mechanical durability of the cheap Chinese encoders. The shaft bush, detents and contacts wear quickly with sustained use, and the whole thing becomes increasingly sloppy over time. But then I must admit to having driven my encoders hard!

    I think it all comes down to durability and 'feel'. Are they important enough to you to warrant spending more money?

  12. #12
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    7,955
    Agreed - I had some cheap mice with a worn out wheel-encoder. The work good when they are new. After a year they begin to fail and begin to count back and forth or miss steps. I'm pretty sure they have a good algorithm inbuilt, too.

  13. #13
    Deleted User
    Guest
    Yep. Optical encoders on computer-mice do not wear, if built properly. Bearings or the plasic itself are then the weakest parts.
    The CNC encoders are optical, built like a tank, especially useful for rough use on a MIDI controller.
    One detent marks A=B=HIGH, so if the detent is removed, one gets 400 steps per round using encoder library, but with the detent, a factor 4 is needed.
    It is done here mathematically, to forget about endianness, but there has to be that remaining two bits to count in half movements that happened during relative readout with readAndReset(), so giving a non-missing readout.

    Attachment 23000

    Edit: Made this little MIDI controller thing during the Holidays lockdown out of a Teensy 4.1 (to be replaced later) and four of the handwheels with detents removed and CD tray. And it is fantastic. I really can not figure out why I did not make it earlier. It gives possibility to modify a synth with fingertips, four parameters at once.

    Attachment 23001

    And the source of that dirty hack:

    Attachment 23003

    It is MIDI Relative CC.
    Maybe I make a more sophisticated and better coded version later, but for now (and the days of lockdown) it works perfectly as-is.
    Last edited by Deleted User; 12-28-2020 at 06:23 PM.

Posting Permissions

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