Missing Encoder Steps

Hello everyone that may be reading this. I'm seeking advice as I've created a length measuring system consisting of a
Genuino MEGA 2560,

Rotary encoder with a 50mm(1.9685inch) diameter wheel,

LCD Display (Amazon.com ),

and an Anker power supply (Amazon.com )

The main problem I am seeking advice on, which is very likely a programming issue on my part is that when I move the measuring gauge i.e. wheel down the table it reads out calculating from the pulse readout, however when i return to the main position instead of being at 0 inches the lcd reads .36 for instance. It never goes back to 0. So my assumption is that I'm missing steps.

Attached is the encoder I'm currently using in quadrature, (6mm Rotary Encoder 1024 P/R - RobotShop )
I've previously used
(https://www.amazon.com/Signswise-Incremental-Encoder-Dc5-24v-Voltage/dp/B00UTIFCVA/ref=pd_sim_60_10?_encoding=UTF8&pd_rd_i=B00UTIFCVA&pd_rd_r=48MC8MBCZ5KNTWMN3MWW&pd_rd_w=cI2ET&pd_rd_wg=GKDaj&psc=1&refRID=48MC8MBCZ5KNTWMN3MWW )

However with the signswise encoder the precision just wasn't there, and i had the same problem.

Attached is my code any input is greatly appreciated.

Length_Measure.ino (2.18 KB)

If you guys have any questions regarding my setup or anything else feel free to ask.

    lcd.print(length,4) + lcd.print("in");

WTF? Why are you ADDING the values returned by the print() methods, when you don't give a rats ass what the result is?

What makes you think you are missing encoder steps? You know how many pulses should be generated when you rotate the encoder one revolution. So, put a mark on the wheel, and roll the wheel exactly one revolution in each direction, while NOT printing anything to the ssslllooowww LCD screen.

Do you get the same number of pulses in each direction?

Do you get the same results when you do print to the LCD?

I'm not adding values the lcd Prints in which stands for inches so whoever goes up to use the length measure knows the units are inches not millimeters. Forgive me if i misunderstood your first question but hopefully this answers it.

And yes the rotary encoder does read 0 at 0 and 4096pulses at a full rotation.

When I print it to the lcd at first it reads correctly but if i move the length measure quickly it messes up so when i go back to 0 I am actually reading x amount of pulses and a length of about .03inches instead of 0inches and 0 pulses.

Is there anyway to fix this, as i need the display to show the dimension.

I'm not adding values the lcd Prints

That line of code would add the return values from two calls to the function lcd.print().

If you want to print two items on the LCD, call lcd.print() twice, ending each call with a semicolon ";", just like you would with Serial.print().

For informed help with your encoder problem, please read and follow the instructions in the "How to use this forum" post. Post the code, using code tags (rather than appending it), and a wiring diagram.

When I print it to the lcd at first it reads correctly but if i move the length measure quickly it messes up so when i go back to 0 I am actually reading x amount of pulses and a length of about .03inches instead of 0inches and 0 pulses.

If you do not use the lcd, but use Serial.print() with a high baud rate like Serial.begin(115200). Do you see the same problem?

The lcd printing is slow, especially lcd.clear(), and may cause you to miss some pulses.

Write the unchanging parts of your display in setup. Do not use lcd.clear() in loop, but rather print blank spaces to clear old data before printing new values. There is no need to calculate and print at every pulse count change. Perhaps update the display every second. Work totally in raw pulse counts as much as possible and reduce the float math.

when i go back to 0 I am actually reading x amount of pulses and a length of about .03inches instead of 0inches and 0 pulses.

How long is the travel out and back? This .03" looks like you are missing two pulses. EDIT: Math error. .03 is approximately 20 pulses. pi*1.9685/4096 = .0015" per pulse.

What are you trying to measure? What accuracy is required? What linear speed is required?

OP's code

//Encoder library
#include <Encoder.h>                    
#include <Keypad.h> // OneWireKeypad Library

//Encoder Definition
Encoder encoder(2, 3);                  // Interrupts Pins

//LCD library
#include <Wire.h>
#include <LiquidCrystal_I2C.h>          

//LCD Definition
LiquidCrystal_I2C lcd(0x27, 16, 2);


//Variables
float diameter = 1.9685;                 // Shaft or Wheel Diameter on Encoder (in)
int pulse = 4096;    // Encoder Pulse

float L1 = 0;
float L2 = 0;

float length = 0;                       // Length Measure
long NewPulse;                          // Encoder Position
const float pi = 3.141592;

const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
     '4','5','6','\b',
     '1','2','3','\a',
     '7','8','9','\e',
     '*','0','\t','\f'
};

byte colPins[COLS] = {39, 38, 37, 36}; //connect to the row pinouts of the keypad
byte rowPins[ROWS] = {35, 34, 33, 32}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup()
{

  lcd.begin();                            // LCD Starting

  //Serial.begin(9600);                 // SeriPort

  lcd.backlight();
  lcd.print("length Measure");          // LCD First Message
}

void loop()
{
  long OldPulse = encoder.read();

  if (OldPulse != NewPulse)
  {
    NewPulse = OldPulse;
    float radius = diameter * pi;             // diameter Calculation
    float calc = radius / pulse;        // Divided by the calculated diameter pulse count.


    length = OldPulse * calc;        // Multiplication of 1 pulse length calculated by the obtained pulse.
    L1 = (OldPulse+1) * calc;
    L2 = (OldPulse-1) * calc;
    
    //Serial.print(OldPulse);          // Pulse Count
    //Serial.print(" -- ");
    //Serial.print(length);            // Length measure in inches.
    //Serial.println(" in");

    lcd.clear();                        // LCD Clear
    lcd.setCursor(0, 0);                // Set Cursor
    lcd.print("Pulse");                 // LCD Print

    lcd.setCursor(0, 1);
    lcd.print(OldPulse);

    lcd.setCursor(7, 0);
    lcd.print("length");

    lcd.setCursor(7, 1);
    lcd.print(length,4) + lcd.print("in");
  }
}

I will check serial print and get back to you on this. In terms of accuracy, it has to be as dead on accurate as possible hence the reason for this encoder and .0015inch per pulse. It is being used to measure distance on a flip stop on a sliding table saw. In terms of linear speed, i can move the flip stop 60inches in about 10 seconds so about 100rpm and this is max. Usually i would go very small increments as i need precise read out and only change the readout by about 6inches so 1 rotation. I will try to post a picture of the prototype, maybe that will help

So i did serial print and below are some of my test results

test 1
started at -117
full rotation 3960 4077 difference
back to starting point -120 4080 difference

so 3 pulse difference so minimal but it is there

test 2
start -118
full rotation 3954 4072 difference
back to start -139 4093 difference
full rotation 4013 4152 difference
back -70 4083 difference
full rotation 4018 4088 difference
back -88 4106 difference

assuming the 4152 and 4106 are outliers due to human error. average pulses per rotation come out to 4084p/r and the encoder should be reading 4096p/r so im missing about 12 steps so about .018 accuracy loss. Any further suggestions?

And both the lcd and serial print showed the same pulses.

From the code in @cattledog's post #5 it appears that the encoder update is polled rather than interrupt driven. Have you ruled out using interrupts?

From the code in @cattledog's post #5 it appears that the encoder update is polled rather than interrupt driven. Have you ruled out using interrupts?

I'm do not use the library Encoder.h, but my understanding is that if you supply the instantiation with two external interrupt pin numbers it will use interrupts.

Encoder encoder(2, 3); // Interrupts Pins

How do you determine a full rotation?

That specs you linked for that encoder show that there may be an index pin (Z) output. What encoder counts do you see back and forth between index pulses?

Yes i was under the impression that i was using interrupts correctly by connecting the encoder to the interrupts.

Unfortunately full rotation can have human errors but it should be close. I placed a reference point on the wheel and one on the fence it glides on. And thats how i came up with full rotations.

In terms of index pin z i disregarded this pin and didnt connect it as the first encoder (signswise also linked above) i used only had x and y input and it had the same issue im encountering with this one. And using other forums i didnt see anyone that had a use or wrote a code for Z hence the reason for me diregarding it.

I ran one other test. I ran it from 1 fence end to the other and back and below are some of the results
Start 0.0000
Max 57.6933
Back again 0.0030
57.6872
-0.0045
57.6621
-0.0121
57.6631
-0.0272
57.6510
-0.0408

And when i reset the module i received the same results in the same order.

Move OldPulse to global variable and make a call to encoder.read() in Setup to initialize it. Verify that you have Gray code encoder with 1024 “pulses” per revolution. No sure how you reading 4096 pulses per revolution, but that is not the issue anyway.

You need to look very carefully at the data sheet for the relationship between the quadrature pulses and the index pulse. It looks like there are four quadrature transitions between the leading and trailing edges of the index pulse, so how you use the index pulse will matter for the count you see.

I would recommend working exclusively with raw counts, and leave out the float math until you understand fully what you are seeing.

You can also try reading the encoder at half resolution (one interrupt pin and one standard i/o pin). If you are indeed missing counts because of the speed of the encoder, you should see less effect with half the interrupts.

I placed a reference point on the wheel and one on the fence it glides on. And thats how i came up with full rotations.

I'm actually of the opinion that your encoder reading is correct, and there are issues with your how you are trying to validate its performance. Moving a wheel back and forth to see if you can be accurate to .0015 is not something to eyeball. If you come to a hard stop and zero the count, and then move out to another stop(or some number of index pulse interrupts) is the count repeatable for multiple measurements in the same direction?

cattledog:
I'm actually of the opinion that your encoder reading is correct, and there are issues with your how you are trying to validate its performance. Moving a wheel back and forth to see if you can be accurate to .0015 is not something to eyeball. If you come to a hard stop and zero the count, and then move out to another stop(or some number of index pulse interrupts) is the count repeatable for multiple measurements in the same direction?

I will try tomorrow and zero at each stop see if i get the same counts in each direction. As to zeroing and starting at one stop and going from one stop (hard stops) to the next back and forth the results are shown in my previous reply
Start 0.0000
Max 57.6933
Back again 0.0030
57.6872
-0.0045
57.6621
-0.0121
57.6631
-0.0272
57.6510
-0.0408
Ill also try paul stoffregen sample program to just see if the pulses add up when sliding from one hard stop to the next.

So how would i go about implementing z index?

Anyone have any suggestions on how to implement the z index into my current code?

Anyone have any suggestions on how to implement the z index into my current code?

And yes the rotary encoder does read 0 at 0 and 4096 pulses at a full rotation.

The suggestion for the index code was to confirm that you are seeing 4096 pulse between index pulses.

If you have indeed confirmed that you get 4096 pulse with a complete rotation, than any errors you see must be due to either missing pulses because you go too fast, or mechanical issues of backlash, slippage, etc.

You can put an interrupt on the z pulse pin, and read the pulse count of the encoder when it is triggered. You might see a difference counts between fast and slow movement to the stop, it which case you are missing pulses.

Did you change your code to work solely with counts, and not the float math until you understand things? Did you change your code to use Serial instead of lcd until you understand things?