Velocity measurement DC Motor with Encoder A y B

Hi, I need measure speed of a DC Motor with built-in encoder hall.
Motor: Motor DC Link
Board: Arduino MEGA 2560
I am also using an optical sensor to detect the passage through zero degrees.

Optical Sensor:

I have a sketch for measure angular position (sawtooth signal 0°~360°):

Measure Angular Position:

Code:

const int channelPinA = 3; // Channel A Encoder
const int channelPinB = 21; // Channel B Encoder
const int sensor = 2; // Optical Sensor
int IN1 = 12; // Pin IN1 L298N
int IN2 = 13; // Pin IN2 L298N
int PWM = 11; // Pin ENA L298N

volatile int ISRCounter = 0; 
int counter = 0;
int pos = 0; // angular position

bool IsCW = true;

void setup()
{
  pinMode(channelPinA, INPUT_PULLUP);
  pinMode(channelPinB, INPUT_PULLUP);
  pinMode(sensor, INPUT_PULLUP);
  Serial.begin(115200);
  attachInterrupt(0, resetEncoder, CHANGE);
  attachInterrupt(1, doEncodeA, CHANGE);
  attachInterrupt(2, doEncodeB, CHANGE);

  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(PWM, OUTPUT);
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(PWM, 0); // duty cycle PWM 0~255
}

void loop()
{
  if (counter != ISRCounter)
  {
    counter = ISRCounter;
    pos = 0.279 * counter;
    Serial.print("Position: ");
    Serial.print(pos);
    Serial.print(" deegres\n");
  }
}

void doEncodeA()
{
  static boolean e1 = false;
  e1 = !e1;


  if (e1 == true && digitalRead(sensor))
  {

    if (digitalRead(channelPinA) == digitalRead(channelPinB))
    {
      IsCW = true;  // clockwise
      ISRCounter++;
    }
    else
    {
      IsCW = false;  // counter-clock wise
      ISRCounter--;
      if (ISRCounter < 0) ISRCounter = 1290;

    }

  }
}

void doEncodeB()
{

  static boolean e2 = false ;
  e2 = !e2;
  if (e2 == true && digitalRead(sensor))
  {

    if (digitalRead(channelPinA) != digitalRead(channelPinB))
    {
      IsCW = true; // clockwise
      ISRCounter++;
    }
    else
    {
      IsCW = false;  // counter-clock wise
      ISRCounter--;
      if (ISRCounter < 0) ISRCounter = 1290;
    }
  }
}

void resetEncoder() {

  static boolean e3 = false;
  e3 = !e3;
  if (e3 == true)
  {
    ISRCounter = 0; // paso por cero grados
  }

}

Position measurement works without problems, but I need add the measurement of angular velocity to the sketch.
Thanks! :slight_smile:

velocity = change in position / time difference. So if you record the value of micros() each time the encoder value changes you can compute velocity.

Re-computing speed on every encoder pulse will be somewhat unsteady and noisy.

Grab an averager library to average the speed over 10 pulses or whatever makes sense.

Alternatively, record the last 10 micros() and use the duration from the one that was 10 steps ago. Throw that one out each time and use that space to record the current one.

If the speed is very variable, count pulses for a specific time. That way when it stops, you don't wait forever for the 10th pulse. There are lots of tutorials online for measuring RPM this way.

MorganS:
Re-computing speed on every encoder pulse will be somewhat unsteady and noisy.

Its the best you can do without too much latency using an encoder, and if its a decent encoder will be usuable. Yes you can smooth the result if you want, but you'll sacrifice latency especially at low speed.

If the speed is very variable, count pulses for a specific time. That way when it stops, you don't wait forever for the 10th pulse. There are lots of tutorials online for measuring RPM this way.

Yes, I second that as a reasonable method for some circumstances, and the latency is at least constant, but its more complex to code.

MorganS:
Re-computing speed on every encoder pulse will be somewhat unsteady and noisy.

Grab an averager library to average the speed over 10 pulses or whatever makes sense.

Alternatively, record the last 10 micros() and use the duration from the one that was 10 steps ago. Throw that one out each time and use that space to record the current one.

If the speed is very variable, count pulses for a specific time. That way when it stops, you don't wait forever for the 10th pulse. There are lots of tutorials online for measuring RPM this way.

Thanks, How could I do what you say?

What did you find when you searched? Which of the various methods I suggested did you try and which one (that you want to try next) is giving you difficulty?

instead of averaging by collecting N points, you can do leaky integration and update an average, a[t] using a fraction of the input, s [t]. yes, there's a lag at startup if you don't initialize a [0] with the first input, s[1]

a [t] += (s [t] + a [t-1]) / N

or

a [t] += (s [t] + a [t-1]) >> I

variables should be floats

rigochox:
I am also using an optical sensor to detect the passage through zero degrees.

I used the MOCH22A sensor a lot, and it gave many false positive signals the way you use it.
I solved that by implementing a "software Schmitt trigger":