Measure and calculate the speed of the DC motor with encoder

Hello,
I would like to regulate a DC motor to a desired speed using a PID controller. The speed is measured via rotary encoder.
That's why I want to measure and calculate the speed first

I have an error in the code
I would be grateful if someone could help me.


//Encoder pin
const int encoderPinA = 2;

// MD30C PWM connected to pin 10
#define PWM 12
// MD30C DIR connected to pin 12  
#define DIR 10

//Encoder variables
volatile unsigned long encoder_Position;
unsigned long newposition_encoder;
unsigned long oldposition_encoder = 0;

//Time variables
unsigned long newtime = 0;
unsigned long oldtime = 0;

float encoder_rpm;
float Input;
float Output= 250;
int PPR = 100;// From encoder How Many Pulses Pur Revolution
const int interval = 1000; //choose interval is 1 second (1000 milliseconds)

void setup() {
  // DC motor
  pinMode(PWM, OUTPUT);
  pinMode(DIR, OUTPUT);

  pinMode (encoderPinA, INPUT_PULLUP);
 
  attachInterrupt (digitalPinToInterrupt (encoderPinA), doEncoderA, FALLING);
  Serial.begin (115200);
}

float read_speed(void)
{
  if(millis() - newtime > interval)
  {
  newposition_encoder = encoder_Position;
  newtime = millis();
  encoder_rpm = ((newposition_encoder - oldposition_encoder)*60 * 1000UL) /PPR/(newtime-oldtime);
  oldposition_encoder = newposition_encoder;
  oldtime = newtime;
}
  return encoder_rpm;
}

void doEncoderA()
{
    encoder_Position++;
}

void loop() {
  Input = read_speed();
  analogWrite(PWM, Output);
  digitalWrite(DIR, LOW);

   Serial.print(" Input = ");
  Serial.print(Input);
  Serial.print("  Output = ");
  Serial.print(Output);
  Serial.println();
  
}

Please post the entire compiler error message by cutting and pasting it from the IDE.

I mean the measurement result is wrong

 Input = 88.00  Output = 250.00
 Input = 88.00  Output = 250.00
 Input = 88.00  Output = 250.00
 Input = 88.00  Output = 250.00

Please explain how you know the measurement is wrong, and state what it should be.

DC motor and encoder are like so connect

22794326c8d6c264a521fd0b059857ce26bf7d2e_1

I might expect ~250 like output here

...but you haven't explained why.

if i set a dc motor to a fixed speed then encoder should measure the same speed

Where did you do that? You only set the PWM value. Where is the PWM value to RPM translation?

PWM value is not the same as RPM. There is not even a linear relationship between them.

@anon57585045 @jremington thank you very much for the hint

I was looking for the conversion formula, unfortunately I couldn't find it

The RPM versus PWM percentage curve will depend on your motor, the load on the motor, the motor driver, the motor power supply voltage, the PWM frequency and the PWM percentage.

You will have to determine the curve yourself.

Here is a typical example for a free running motor:

This should be in a "critical section":

if(millis() - newtime > interval)
  {
    newtime += interval;
    nointerrupts();
    newposition_encoder = encoder_Position;
    interrupts();
...
   ...
    
  

Don't count pulses, count their period.

do you have any idea how i should do that

Note the millis() when you see the 1st pulse. Subtract it from the millis() at the start of the next pulse. Inverse of period is frequency. Divide by pulses per revolution.

Google;

arduino tacho

You will find it surprising that you are not the first to do this.

Tom.... :smiley: :+1: :coffee: :australia:

@madmark2150 @TomGeorge
Thanks for the tip.
can you please tell me what is still missing in the code?


//Encoder pin
const int encoderPinA = 5;

// MD30C PWM connected to pin 11
#define PWM 11
// MD30C DIR connected to pin 10  
#define DIR 10
//*******************************************************

//******************************
//Encoder variables
/*
volatile unsigned long encoder_Position;
unsigned long newposition_encoder;
unsigned long oldposition_encoder = 0;

//Time variables
unsigned long newtime = 0;
unsigned long oldtime = 0;
*/

double encoder_rpm;
double Input;
double rps;
double Output= 50.0;
double PPR = 100.0;// From encoder How Many Pulses Pur Revolution
const int interval = 1000; //choose interval is 1 second (1000 milliseconds)

void setup() {
  // DC motor  
  pinMode(PWM, OUTPUT);
  pinMode(DIR, OUTPUT);

  pinMode (encoderPinA, INPUT_PULLUP);
 
  //attachInterrupt (digitalPinToInterrupt (encoderPinA), doEncoderA, RISING);
  Serial.begin (115200);

}
double read_speed(void)
{
       
      double f = pulseIn(encoderPinA, HIGH);
      //double f = FreqMeasure.countToFrequency(FreqMeasure.read(encoderPinA));
      //convert F to rps :
      rps=f/PPR;
      //convert rps to rpm :
      encoder_rpm=rps*60;

  return encoder_rpm;
}

//void doEncoderA()
//{
//    encoder_Position++;
//}

void loop() {
  Input = read_speed();
  analogWrite(PWM, Output);
  digitalWrite(DIR, LOW);
  
  uint32_t now = millis();
  Serial.print(now); 

   Serial.print(" Input = ");
  Serial.print(Input);
  Serial.print("  Output = ");
  Serial.print(Output);
  Serial.println();
  
}

Why do you think something is missing?

Describe what you expected to happen, and what happens instead.

I want to measure the RPM with encoder count period to determine RPM of the motor

this comes out

19:24:55.129 -> 1012 Input = 28967.40  Output = 40.00
19:24:55.223 -> 1106 Input = 29364.60  Output = 40.00
19:24:55.317 -> 1202 Input = 29649.60  Output = 40.00
19:24:55.410 -> 1297 Input = 29695.80  Output = 40.00
19:24:55.504 -> 1394 Input = 29846.40  Output = 40.00
19:24:55.597 -> 1490 Input = 29460.00  Output = 40.00
19:24:55.691 -> 1587 Input = 29737.20  Output = 40.00

the equal or almost equal the Input value to the Output value, the better

You never modify the variable 'Output'. It looks like you modified the code without mentioning it, because in the posted code, it's initialized to 50.0 and in the printout it's 40. In any case, if you expect the output to change, you have to write code that changes it.

Apart from that, the program doesn't do any speed curve translation as mentioned in reply #11. There is no theoretical linear relationship between a PWM value and some RPM. You have to estimate, calibrate, or compute one.

Is 28,000 RPM not correct? How do you know?