Encoders jumping positive

Status
Not open for further replies.

Borogove

New member
I've got a board with four rotary encoders on it. Two of them work well, but the other two would occasionally jump positive by counts of ~8-16 while being turned in the negative/CCW direction, with the result that progress could not be made turning them CCW. This occurred no matter how fast or slow I turned the encoders.

Delving into the Encoder library code, I saw that transitions 3, 6, 9, and 12, normally considered invalid, were being counted as +/- 2. I commented out those counts and the problem cleared up entirely.

I'm guessing that (a) my un-debounced hardware is occasionally presenting invalid data, and (b) the +/- 2 counts are there to support fast-moving encoders that the Teensy isn't quite able to keep up with.

I almost reported this as an issue on the github repo but accepted the issue form's strong encouragement to come here. :)

This seems like a borderline bug. The +/- 2 counts clearly have value to some use cases, but they can ruin the functionality of the library in a basic use case. One solution would be to make the +/- 2 count an optional feature that has to be explicitly enabled. Another helpful feature would be to show a typical debouncing schematic on the Encoder page -- the protoboard photos show the necessary resistors and caps, but they aren't explained.

In any case, I have a workaround for the moment and will add hardware debounce in my next rev.
 
In any case, I have a workaround for the moment and will add hardware debounce in my next rev.

Any chance I can talk you into testing my encoder library https://github.com/luni64/EncoderTool/wiki?

  • It uses dedicated state machines for encoders with mechanical detents (at 2 or 4 quadrature "edges") which makes it absolutely bounce free without additional hardware.
  • If you need to count every edge, (e.g. for high res encoders without detents) it guarantees that you'll end up with the right count after bouncing. During the bouncing period it can not prevent rapid up/down counts. In this mode it has exactly the same behaviour as the stock encoder library.
  • You can use it in interrupt mode or in polling mode (which often is more than sufficient for mechanical encoders)
I was looking for really bad encoders to test its debouncing capabilities but didn't find any. So I would be highly interested if it is able to tame your encoders :)

Quick start guide: https://github.com/luni64/EncoderTool/wiki/Quick-start-guide
 
When I write quadrature encoder code I use the invalid transitions to increment an error count, not
the position count. Then you can programmatically check for errors if you suspect you are not
sampling the encoder often enough.
 
@luni - any chances your EncoderTool willl be available for TeensyLC? I have severe bouncing Problems over here..... many thanks in advance independent if you will make it available or not ;-)
 
Sure, I'm currently traveling but I can have a look later this week. I'm not aware of anything not compatible to T-LC. Which error message did you get?
 
Im using this Code from your WIKI as i have my Encoder on 4,5

using namespace EncoderTool;

Encoder encoder;

Code:
#include "EncoderTool.h"
using namespace EncoderTool;

Encoder encoder;

void setup()
{
    pinMode(LED_BUILTIN, OUTPUT);
    encoder.begin(4, 5);
}

elapsedMillis stopwatch;

void loop() {
    if (stopwatch > 50)
    {
        Serial.println(encoder.getValue() );
        stopwatch = 0;
    }
}

And the compiler stops with this:
Arduino: 1.8.13 (Windows 10), TD: 1.53, Board: "Teensy LC, Keyboard, 48 MHz, Smallest Code, US International"





















C:\Program Files (x86)\Arduino\arduino-builder -dump-prefs -logger=machine -hardware C:\Program Files (x86)\Arduino\hardware -tools C:\Program Files (x86)\Arduino\tools-builder -tools C:\Program Files (x86)\Arduino\hardware\tools\avr -built-in-libraries C:\Program Files (x86)\Arduino\libraries -libraries C:\Users\danie\Documents\Arduino\libraries -fqbn=teensy:avr:teensyLC:usb=keyboard,speed=48,opt=osstd,keys=usint -ide-version=10813 -build-path C:\Users\danie\AppData\Local\Temp\arduino_build_73180 -warnings=none -build-cache C:\Users\danie\AppData\Local\Temp\arduino_cache_970610 -verbose C:\Users\danie\Desktop\EncoderToolTest\EncoderToolTest.ino

C:\Program Files (x86)\Arduino\arduino-builder -compile -logger=machine -hardware C:\Program Files (x86)\Arduino\hardware -tools C:\Program Files (x86)\Arduino\tools-builder -tools C:\Program Files (x86)\Arduino\hardware\tools\avr -built-in-libraries C:\Program Files (x86)\Arduino\libraries -libraries C:\Users\danie\Documents\Arduino\libraries -fqbn=teensy:avr:teensyLC:usb=keyboard,speed=48,opt=osstd,keys=usint -ide-version=10813 -build-path C:\Users\danie\AppData\Local\Temp\arduino_build_73180 -warnings=none -build-cache C:\Users\danie\AppData\Local\Temp\arduino_cache_970610 -verbose C:\Users\danie\Desktop\EncoderToolTest\EncoderToolTest.ino

Using board 'teensyLC' from platform in folder: C:\Program Files (x86)\Arduino\hardware\teensy\avr

Using core 'teensy3' from platform in folder: C:\Program Files (x86)\Arduino\hardware\teensy\avr

Detecting libraries used...

"C:\\Program Files (x86)\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -fno-exceptions -fpermissive -felide-constructors -std=gnu++14 -Wno-error=narrowing -fno-rtti -mthumb -mcpu=cortex-m0plus -fsingle-precision-constant -D__MKL26Z64__ -DTEENSYDUINO=153 -DARDUINO=10813 -DARDUINO_TEENSYLC -DF_CPU=48000000 -DUSB_KEYBOARDONLY -DLAYOUT_US_INTERNATIONAL "-IC:\\Program Files (x86)\\Arduino\\hardware\\teensy\\avr\\cores\\teensy3" "C:\\Users\\danie\\AppData\\Local\\Temp\\arduino_build_73180\\sketch\\EncoderToolTest.ino.cpp" -o nul -DARDUINO_LIB_DISCOVERY_PHASE

Alternatives for EncoderTool.h: [EncoderTool-2.0.0@2.0.0]

ResolveLibrary(EncoderTool.h)

-> candidates: [EncoderTool-2.0.0@2.0.0]

"C:\\Program Files (x86)\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -fno-exceptions -fpermissive -felide-constructors -std=gnu++14 -Wno-error=narrowing -fno-rtti -mthumb -mcpu=cortex-m0plus -fsingle-precision-constant -D__MKL26Z64__ -DTEENSYDUINO=153 -DARDUINO=10813 -DARDUINO_TEENSYLC -DF_CPU=48000000 -DUSB_KEYBOARDONLY -DLAYOUT_US_INTERNATIONAL "-IC:\\Program Files (x86)\\Arduino\\hardware\\teensy\\avr\\cores\\teensy3" "-IC:\\Users\\danie\\Documents\\Arduino\\libraries\\EncoderTool-2.0.0\\src" "C:\\Users\\danie\\AppData\\Local\\Temp\\arduino_build_73180\\sketch\\EncoderToolTest.ino.cpp" -o nul -DARDUINO_LIB_DISCOVERY_PHASE

Using cached library dependencies for file: C:\Users\danie\Documents\Arduino\libraries\EncoderTool-2.0.0\src\EncPlexBase.cpp

Using cached library dependencies for file: C:\Users\danie\Documents\Arduino\libraries\EncoderTool-2.0.0\src\EncoderBase.cpp

"C:\\Program Files (x86)\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -fno-exceptions -fpermissive -felide-constructors -std=gnu++14 -Wno-error=narrowing -fno-rtti -mthumb -mcpu=cortex-m0plus -fsingle-precision-constant -D__MKL26Z64__ -DTEENSYDUINO=153 -DARDUINO=10813 -DARDUINO_TEENSYLC -DF_CPU=48000000 -DUSB_KEYBOARDONLY -DLAYOUT_US_INTERNATIONAL "-IC:\\Program Files (x86)\\Arduino\\hardware\\teensy\\avr\\cores\\teensy3" "-IC:\\Users\\danie\\Documents\\Arduino\\libraries\\EncoderTool-2.0.0\\src" "C:\\Users\\danie\\Documents\\Arduino\\libraries\\EncoderTool-2.0.0\\src\\Single\\attachInterruptEx.cpp" -o nul -DARDUINO_LIB_DISCOVERY_PHASE

Generating function prototypes...

"C:\\Program Files (x86)\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -fno-exceptions -fpermissive -felide-constructors -std=gnu++14 -Wno-error=narrowing -fno-rtti -mthumb -mcpu=cortex-m0plus -fsingle-precision-constant -D__MKL26Z64__ -DTEENSYDUINO=153 -DARDUINO=10813 -DARDUINO_TEENSYLC -DF_CPU=48000000 -DUSB_KEYBOARDONLY -DLAYOUT_US_INTERNATIONAL "-IC:\\Program Files (x86)\\Arduino\\hardware\\teensy\\avr\\cores\\teensy3" "-IC:\\Users\\danie\\Documents\\Arduino\\libraries\\EncoderTool-2.0.0\\src" "C:\\Users\\danie\\AppData\\Local\\Temp\\arduino_build_73180\\sketch\\EncoderToolTest.ino.cpp" -o "C:\\Users\\danie\\AppData\\Local\\Temp\\arduino_build_73180\\preproc\\ctags_target_for_gcc_minus_e.cpp" -DARDUINO_LIB_DISCOVERY_PHASE

"C:\\Program Files (x86)\\Arduino\\tools-builder\\ctags\\5.8-arduino11/ctags" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "C:\\Users\\danie\\AppData\\Local\\Temp\\arduino_build_73180\\preproc\\ctags_target_for_gcc_minus_e.cpp"

Compiling sketch...

"C:\\Program Files (x86)\\Arduino\\hardware\\teensy/../tools/precompile_helper" "C:\\Program Files (x86)\\Arduino\\hardware\\teensy\\avr/cores/teensy3" "C:\\Users\\danie\\AppData\\Local\\Temp\\arduino_build_73180" "C:\\Program Files (x86)\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-g++" -x c++-header -Os --specs=nano.specs -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -fno-exceptions -fpermissive -felide-constructors -std=gnu++14 -Wno-error=narrowing -fno-rtti -mthumb -mcpu=cortex-m0plus -fsingle-precision-constant -D__MKL26Z64__ -DTEENSYDUINO=153 -DARDUINO=10813 -DARDUINO_TEENSYLC -DF_CPU=48000000 -DUSB_KEYBOARDONLY -DLAYOUT_US_INTERNATIONAL "-IC:\\Program Files (x86)\\Arduino\\hardware\\teensy\\avr/cores/teensy3" "C:\\Users\\danie\\AppData\\Local\\Temp\\arduino_build_73180/pch/Arduino.h" -o "C:\\Users\\danie\\AppData\\Local\\Temp\\arduino_build_73180/pch/Arduino.h.gch"

Using previously compiled file: C:\Users\danie\AppData\Local\Temp\arduino_build_73180\pch\Arduino.h.gch

"C:\\Program Files (x86)\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-g++" -c -Os --specs=nano.specs -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -fno-exceptions -fpermissive -felide-constructors -std=gnu++14 -Wno-error=narrowing -fno-rtti -mthumb -mcpu=cortex-m0plus -fsingle-precision-constant -D__MKL26Z64__ -DTEENSYDUINO=153 -DARDUINO=10813 -DARDUINO_TEENSYLC -DF_CPU=48000000 -DUSB_KEYBOARDONLY -DLAYOUT_US_INTERNATIONAL "-IC:\\Users\\danie\\AppData\\Local\\Temp\\arduino_build_73180/pch" "-IC:\\Program Files (x86)\\Arduino\\hardware\\teensy\\avr\\cores\\teensy3" "-IC:\\Users\\danie\\Documents\\Arduino\\libraries\\EncoderTool-2.0.0\\src" "C:\\Users\\danie\\AppData\\Local\\Temp\\arduino_build_73180\\sketch\\EncoderToolTest.ino.cpp" -o "C:\\Users\\danie\\AppData\\Local\\Temp\\arduino_build_73180\\sketch\\EncoderToolTest.ino.cpp.o"

Compiling libraries...

Compiling library "EncoderTool-2.0.0"

Using previously compiled file: C:\Users\danie\AppData\Local\Temp\arduino_build_73180\libraries\EncoderTool-2.0.0\EncPlexBase.cpp.o

Using previously compiled file: C:\Users\danie\AppData\Local\Temp\arduino_build_73180\libraries\EncoderTool-2.0.0\EncoderBase.cpp.o

"C:\\Program Files (x86)\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-g++" -c -Os --specs=nano.specs -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -fno-exceptions -fpermissive -felide-constructors -std=gnu++14 -Wno-error=narrowing -fno-rtti -mthumb -mcpu=cortex-m0plus -fsingle-precision-constant -D__MKL26Z64__ -DTEENSYDUINO=153 -DARDUINO=10813 -DARDUINO_TEENSYLC -DF_CPU=48000000 -DUSB_KEYBOARDONLY -DLAYOUT_US_INTERNATIONAL "-IC:\\Users\\danie\\AppData\\Local\\Temp\\arduino_build_73180/pch" "-IC:\\Program Files (x86)\\Arduino\\hardware\\teensy\\avr\\cores\\teensy3" "-IC:\\Users\\danie\\Documents\\Arduino\\libraries\\EncoderTool-2.0.0\\src" "C:\\Users\\danie\\Documents\\Arduino\\libraries\\EncoderTool-2.0.0\\src\\Single\\attachInterruptEx.cpp" -o "C:\\Users\\danie\\AppData\\Local\\Temp\\arduino_build_73180\\libraries\\EncoderTool-2.0.0\\Single\\attachInterruptEx.cpp.o"

C:\Users\danie\Documents\Arduino\libraries\EncoderTool-2.0.0\src\Single\attachInterruptEx.cpp:41:5: error: too many initializers for 'void (* const [24])()'

};

^

Using library EncoderTool-2.0.0 at version 2.0.0 in folder: C:\Users\danie\Documents\Arduino\libraries\EncoderTool-2.0.0

Error compiling for board Teensy LC.



Hope this helps as i have no clue what it means....
 
Ok, I see what's wrong and it is probably already fixed in the current code. If you used the current release (v2.0) can you please replace it by the current version from master and give that a try?
 
I just saw that I already prepared a new release a couple of weeks ago...just released it. You can try if v2.1.0 fixes the issue
 
luni, thanks for the superfast response. Ill give it a try tomorrow an come back to you asap. Many thanks!!
 
@fdaniels: Can you give v2.2.1 a try? https://github.com/luni64/EncoderTool/releases

New features:
  • Compatibility to T-LC
  • Reduced memory footprint
Bugfixes:
  • Selecting plain vanilla void(*)(...) callbacks works now and is recommended for memory challenged boards.

In case your T-LC project is memory limited you can save a few bytes by configuring the library to use plain vanilla void(*)(...) callbacks instead of the default std::function<> type callbacks (see comment in config.h).
 
Last edited:
Dear luni,

I removed the old library and tried the new one, sadly with no success. Trying to compile the Code above i now get:



In file included from C:\Users\danie\Documents\Arduino\libraries\EncoderTool-2.2.1\src/EncoderBase.h:2:0,
from C:\Users\danie\Documents\Arduino\libraries\EncoderTool-2.2.1\src/Multiplexed/EncPlexBase.h:4,
from C:\Users\danie\Documents\Arduino\libraries\EncoderTool-2.2.1\src/Multiplexed/EncPlex74165.h:5,
from C:\Users\danie\Documents\Arduino\libraries\EncoderTool-2.2.1\src/EncoderTool.h:3,
from C:\Users\danie\Desktop\sketch_oct06a\sketch_oct06a.ino:1:
C:\Users\danie\Documents\Arduino\libraries\EncoderTool-2.2.1\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 LC.


As you are in Germany (at least according to your Profile) id like to offer sending you a LC, if you have none at hand. Just let me know.

EDIT: i changed the Pins to 14,15 as these are the ones used in my Project.
 
The error you now get is due to an old version of Bounce2 which is required to debounce the pushbutton. Unfortunately the one which comes with Teensyduino is a bit outdated.
Since you are not the first stumbling about it, I added a corresponding comment the documentation. I try to remove the dependency in a later version.

Fixing the issue is simple: just replace Bounce2 with a current version from here: https://github.com/thomasfredericks/Bounce2.
 
luni, thanks for your help and superfast response!

I replaced Bounce2 with the newest Version and now it compiles flawless.

Sadly, it skips Clicks, im using this Code:

Code:
#include "EncoderTool.h"
using namespace EncoderTool;

    Encoder encoder;                     // single, directly connected encoder
    int encValue=0;
    int encOldValue=0;

    
void setup()
{
   //pinMode(14, INPUT_PULLUP);
   //   pinMode(16, INPUT_PULLUP);

    encoder.begin(14,16);              // A=0, B=1
    
}

elapsedMillis stopwatch = 0;

void loop()
{
    encValue = encoder.getValue(); // get current value

    if (encValue != encOldValue){
      Serial.println(encValue);
      encOldValue = encValue;
    }
    
  }

Turning the Encoder slowly it takes 1 - 6 Clicks in either direction to change the Value, i tried 2 different Encoders (of this Type: https://www.reichelt.de/drehimpulse...kal-stec12e08-p73923.html?&trstct=pos_2&nbc=1), tried using external 100K Pullups, tried CountMode::half, CountMode::quarter, CountMode::quarterInv.

Any Ideas?
 
Just had a look at the pinout. Pin 16 doesn't have interrupt capability on the LC. 14, 15 have. So, this makes sense.
 
No problem at all. Let me know if you stumble over anything else or miss some functionality.
 
Hi Luni,
I have tried your library and it certainly solves my debounce issues. However I am seeing an issue with my encoder. I only seem to get a position increment every second detent with the encoder I am using. Previously, using the standadrd Encoder library I was counting a pulse at each detent and also between detents. So, I wrote code to ignore the one in between. I can live with it this way but I was thinking there must be a way to configure your library for my encoder? I see you have something called countMode in the library but I can't figure out how to use it. In my tests I am using the simple Hello Encoder sample you provided. Any help would be welcome. I've only been playing with encoders and Teensy for about a week so sorry if I am not giving enough info or using the wrong nomenclature.

Thanks for providing this.
 
Hi Luni,
I have tried your library and it certainly solves my debounce issues. However I am seeing an issue with my encoder. I only seem to get a position increment every second detent with the encoder I am using. Previously, using the standadrd Encoder library I was counting a pulse at each detent and also between detents. So, I wrote code to ignore the one in between. I can live with it this way but I was thinking there must be a way to configure your library for my encoder? I see you have something called countMode in the library but I can't figure out how to use it. In my tests I am using the simple Hello Encoder sample you provided. Any help would be welcome. I've only been playing with encoders and Teensy for about a week so sorry if I am not giving enough info or using the wrong nomenclature.

Thanks for providing this.

Well, must be some law of the universe that says when you ask for help, you will find the answer. Usually by reading the documentation more carefully. The following solved my issue.

encoder.begin(10, 11, CountMode::half);

Thanks just the same, this works really well.
 
Well, must be some law of the universe that says when you ask for help, you will find the answer.
Yes, paragraph II of this law is, whenever you build a minimal example to show the problem it goes away:)

...using the standard Encoder library I was counting a pulse at each detent and also between detents. So, I wrote code to ignore the one in between.

tl;dr:
This, or dividing results by 4 or 2, works for simple applications. However, there is a reason why encoders come with 2 or 4 counts per detent -> It opens the possibility to implement dedicated algorithms which completely debounce the encoders. Therefore the EncoderTool has algorithms for (hopefully) each type of encoders (CountMode::half, CountMode::quarter, CountMode::full).

The very good algorithm implemented in the standard encoder lib is optimized for counting all edges of the quadrature signal (i.e., full count mode) and guarantees that after the bouncing the count is correct. However, during the bouncing it can generate some up/down counts which can not be avoided in this count mode. FrankB derived a version from the standard encoder lib using an algorithm optimized for the quarter count mode: https://github.com/FrankBoesing/EncoderBouncehttps://github.com/FrankBoesing/EncoderBounce

As long as one uses the encoder for set point applications (digital pot, etc) up/down counts during bouncing usually are no problem at all. If, however you are using encoders for menu applications or do some event driven stuff, the up/down counts can generate nasty effects. I recommend to use the quarter and half count modes whenever possible to avoid bouncing in those cases.
tl;dr
 
Last edited:
@borogove, I have had that same problem, and in every case it has been a poor connection. You might want to be sure that your wiring is solid on the encoders causing issues.
 
Status
Not open for further replies.
Back
Top