Measuring Speed and Distance with Incremental Rotary Encoder

Hello all looking for some help. I have tried may things one the past 3 days but cannot seem to figure it out, this community has been very helpful in the past.

Components:
1 - Arduino Nano 33 IoT
1 - Omron E6B2-CWZ6C Encoder, 1024 ppr 5-24 vdc, as a string potentiometer set up, 3 m wire.
2 - 10k resistors

The diagram below shows the hook up information. Right now I just have the Arduino plugged into my computer via the mini usb on the nano 33.

The code below is a basic sketch that I have been able to use and it works when moving at slow speed.

// Pins used for the encoder
const int encoderPinA = 2;
const int encoderPinB = 3;

// Variables for tracking the encoder position
volatile int encoderPos = 0;
volatile int aPosition = 0;
volatile int lastAPosition;


void setup() {
Serial.begin(115200);

pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);
aPosition = digitalRead(encoderPinA);
lastAPosition = aPosition;
}

void loop() {
  
  aPosition = digitalRead(encoderPinA);

  // Check if there's a change in encoder pin A
  if (aPosition != lastAPosition) {
    if (digitalRead(encoderPinB) != aPosition) {
      encoderPos--;
    }
    else {
      encoderPos++;
     }
     Serial.println(encoderPos);
  }

  lastAPosition = aPosition;

}

I can user the encoderPos to determine the speed and distance with some math, I think I have got that under control, the issue I am having is that when the string is pulled to rotate the encoder at a high speed, it seems the encoder is moving faster than it can read or skips some readings.

Ideally, the encoder position should always be 0 when the string is fully retracted, but if I pull the string fast, and retract slow, the position is less than 0 (and if pulled slow and retracted fast, it is a positiver number), making me think its moving too fast to get a proper reading.

I have tried different baud rates, I have tried reading each pulse and aggregating the readings, I have tried with an Arduino nano 33 IoT and a node 32, (16hz vs 80hz I believe), Ive tried to incorporate the z output wire to read a full rotation but again these get missed at high speeds leading me to believe its related to the speed and moving to fast to register a reading. Another interesting note, with this code, it should never be incrementing and subtracting at the same time (its either being pulled or retracted) but I have gotten readings were, mid pull, it is subtracting, and continues to add for a split second after I have stopped pulling.

If you have made it this far, I appreciate it, almost done.

I do not imagine I'll be needing to measure anything faster than 2 m/s, more than 2 m total and measuring to the nearest cm will work, even if the error is 1-2 cm I could live with that.

Do you see anything wrong with the wiring, code or my logic with this project?
Would less ppr actually make this more accurate for me?
Some resources mentioned it takes time to serial.print which could be an issue, how would you set up a test to see if the printing is the problem, if you can't see what the reading or encoderPos is?

Thank you so much!

Yes, that is the problem. That Serial.println() is far, far slower to execute than all the other code lines, even at fast baud rates. @Delta_G says that digitalRead() is "slow" compared to reading the hardware ports/pins directly, which is true, but digitalRead() is lightning fast compared to Serial.println(). So digitalRead() is really not the problem here, I suspect.

But as you also point out, if you can't see the encoder position, you can't achieve your project to measure speed and distance. Sooner or later you need to output something, but as soon as you do that, you risk missing pulses from the encoder.

I think you need to be using hardware interrupts. These will not miss the pulses from the encoder, even if a Serial.print() or other complex calculation is being executed at the moment the pulse occurs.

I think the code you copied originally used hardware interrupts, but at some point you removed the use of hardware interrupts. The clue that tells me that is the use of the volatile keyword, which serves no purpose in your code right now, but is important if interrupts are used.

Why not use an encoder library? The one written by Paul Stoffregen should work well.

2 Likes

Could you post your Velocity calculation?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.