How to calculate speed with incremental rotary encoder?

Hello, I need to calculate the tangential speed of a roll.
The encoder is connected directly to the roll (1/1), and is 360 points per revolution. It has 4 wires, VCC, GND, A and B. Connected to the Arduino UNO board.
I connected wire A to 2 on the arduino and wire B to 3 on the arduino.
It worked a code that reads the interruptions, on the serial monitor it showed that it added and subtracted correctly, but it gives me 720 points per revolution. Why use A and B?
To measure the tangential velocity, I imagine that I must measure the time between the points and know the diameter of the roll ...
For how long, the direction of rotation does not matter.
So should I just use an interrupt?
Could someone help me with any ideas?

Thank you all for the attention.

Without code I can only guess. But if to you count 720 you count Every transition from A only to B only and from B only to A only, instead of A only back to A only.

And yeah, just see how much time it takes to increment or decrement the counter by x. What is a good value for x depends on the expected speed. Larger x = more exact speed. Lower x = faster update of speed.

in my experience, an interrupt is needed. it's not necessary to capture all encoder event - the change from both inputs, simply the rising (or falling edge) of one input

there are two approaches

the first is to capture the time (micros()) between events, determine the average and calculate the rpm and then speed (Nenc = 720)

TwoPi * rad * 60 / (Nenc * usec  / 10^6)

the second, and suggested, it to simply count the # events between reporting periods (sec).

TwoPi * rad * 60 * (nEvents / Nenc) / sec

Post a link to the encoder's datasheet. Also, what is the maximum expected rotational speed?

Your encoder seems to be an "active" one since it takes VCC. I've only worked with passive, mechanical, encoders. But, from my experience with them I've learned there are two basic types -- those that produce a complete quadrature cycle for every change of "position" (detent) and those that a complete quadrature cycle for every 2 position changes.

If your code assumes the latter type and the hardware is actually the former type, you'll get double counting.

I've written a code that can work with both types. It's interrupt-driven and very fast. Maybe it will give you some ideas: GitHub - gfvalvo/NewEncoder: Rotary Encoder Library.

Hello, first thank you for the quick responses and attention from you!
The code I used was this:

volatile int long counterAB = 0;
uint8_t dir = 0;

void setup() {
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  Serial.begin(9600);

  attachInterrupt(digitalPinToInterrupt(2), ai0, RISING);

  attachInterrupt(digitalPinToInterrupt(3), ai1, RISING);
}

void loop() {
  Serial.println(counterAB);
}

void ai0() {

  if (digitalRead(3) == LOW) {
    dir = 1;
  }
  else {
    dir = 0;
  }
  if (digitalRead(3) == HIGH && digitalRead(2) == LOW) {
    counterAB ++;
  }
  else {
    counterAB --;
  }

  if (digitalRead(3) == LOW && digitalRead(2) == HIGH) {
    counterAB ++;
  }
  else {
    counterAB --;
  }
 
}
void ai1() {
  if (digitalRead(2) == HIGH) {
    dir = 1;
  }
  else {
    dir = 0;
  }
  if (digitalRead(2) == LOW && digitalRead(3) == HIGH) {
    counterAB --;
  }
  else {
    counterAB ++;
  }

  if (digitalRead(2) == HIGH && digitalRead(3) == LOW) {
    counterAB --;
  }
  else {
    counterAB ++;
  }
}

In this code, I think I understood why I was bending my wrists per revolution. It adds or subtracts pulses in both ai0 and ai1 ... ... is that it?
The encoder must rotate up to 9000rpm, or 150hz ...

Is 360ppr too much?
I will test all the suggestions made by you.
I will use only one interrupt.
Soon I'll post here, or more questions, or the code working ... Thanks!

gfvalvo:
Post a link to the encoder's datasheet.

720 encoder events (rising input from one input) at 9000 rpm is is 108,000 events/sec or one every 9.25 usec.

not sure there's enough time for the interrupt to capture all the events and allow some time to process them outside the interrupt.

the ISR would have to be extremely tight. the direction is simply the state of the other input. and there's little point +/- increments to the count unless you're tracking position. it should always be incremented.

the ISR becomes

void ai1() {
    dir = digitalRead(2);
    counterAB ++;
}

while the count can be either captured or reset outside of the ISR, a speed computation should not be made if the direction changes

Hello, here's how the code was:

volatile int long counterAB = 0;
uint8_t dir = 0;

volatile int long pulsos;

unsigned long tempo1 = 0;
unsigned long tempox = 0;
unsigned long tempoz = 0;

 
void setup() {
  pinMode(2, INPUT_PULLUP);           // set pin to input   (BRANCO)

  Serial.begin(250000);
  attachInterrupt(digitalPinToInterrupt(2), ai0, FALLING);
}
 
void loop() {
  Serial.println(tempoz);
  //Serial.println(pulsos);
  
}
 
void ai0() {
detachInterrupt(digitalPinToInterrupt(2));
 pulsos++;

 tempoz = millis() - tempox;
 //Serial.println(tempox);
 tempox = millis();
 attachInterrupt(digitalPinToInterrupt(2), ai0, FALLING);
}

The pulses I can read on the serial. But time does not.
The problem is in the timing. Does anyone have any suggestions?
I need to read the time between each pulse, and show it in the serial.
I forgot to say, I am using a rotary incremental encoder 360p NPN with 5vcc
Thank you all.

what do you expect the value of "tempoz" to be if rotating at 9000 rpm?

Hi Pipomi,

you are asking for details without haven given an overview about your project.
From your questions I can conclude that you are not (yet!) an expert about measuring speed with rotary encoders.

Measuring this speed is not a selfpurpose. You do something else with it.
Reading speed-values on a display at a speed of 20 values per second or more makes no sense.
The values will change faster than you any human beeing can read.

It highly depends on what you want to do with the caclulated speed in the end what will be a good solution in the end.

Example:
Can the rotational speed vary a lot from pulse to pulse? This means the speed would vary every single degree.
This might be but I guess not.

If this is would be the case it would be much better to use a high-speed microcontroller which has special rotary-encoder hardware integrated like a teensy 4.0 (just $20) programmable just the same way as an Arduino with the arduino-IDE

here is an analogon that shall show what can happen if just ask for details:

Newbee: "I want to do better cutting please help me sharpening. "
Expert: Sure I can help you. What kind of cutting-tool are you using?
Newbee: a scissor.
Expert: OK take this sharpening tool
Newbee: Yea works great Next question How can I make it cut faster I need to finish faster.
expert: Motorised scissors.
newbee Yea works great though still not fast enough.

expert: Ok can you give an overview about what you are cutting.
newbee: the green of a football-arena.
expert: Oha! take a big mowing tractor with a seven boom spindel-mower and GPS-steering

In the beginning the newbee always just told details.
The expert was assuming the newbee knows that his basic approach is well suited.
which turns out to be very bad suited
that's the reason why it is always a good idea to give an overview and to explain what shall happen in the end.

So please give a detailed description of your project.

best regards Stefan

Hello, thanks for listening.
The project is for a car dynamometer.
I need to measure the acceleration of a roller at certain times.
Every 0.2s I need to know the speed and acceleration of the roller, which is connected to the encoder (1: 1 without reduction).
(The encoder has 360ppr, 5vcc and has pin A and pin B. In this project I will use only one of the pins).
Then, with these values, create a curve, which at first, meets excel.

Thank you all

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