SET PID to control speed of a motor at constant speed? or other problem?

Hello,

I bought a motor with encoder.

I 'm using the PID algorithm to control the motor speed by L298P DC motor driver board (given by the constructor).

I have a L298N which is supplied in 12 volt, 1 A in order to a good voltage to the motor because

The Motor operating voltage: 3~7.5V (Rated voltage 6V).

Am I right?

In the results below, I set speed at 666 and pulse should be the same result (almost) but actually it isn’t.

Pulse: 655.00
val_output129.70
Pulse: 660.00
val_output130.20
Pulse: 669.00
val_output123.80
Pulse: 646.00
val_output148.10
Pulse: 671.00
val_output131.10
Pulse: 675.00
val_output124.70
Pulse: 666.00
val_output130.60
Pulse: 674.00

How can I have a constant speed?

By setting the constants of the P I D ?

I put the code below

//This is the DFRobot TT Micro DC geared motor with encoder.
//It is a motor with a 120:1 gearbox and an integrated quadrature encoder that provides
// a resolution of 16 pulse single per round giving a maximum output of 1920 within one round. 


//The sample code for driving one way motor encoder
#include <PID_v1.h>
const byte encoder0pinA = 2;//A pin -> the interrupt pin 0
const byte encoder0pinB = 3;//B pin -> the digital pin 3

//Ports de commande du moteur C
int motorPinC1 = 13; //13 pin to set H BRIDGE of L298N
int motorPinC2 = 12; //12 pin to set H BRIDGE of L298N
const int enablePinC= 11; //11 //  Commande de vitesse moteur, to Output ENA pour L298 the second


byte encoder0PinALast;
double duration,abs_duration;//the number of the pulses
boolean Direction;//the rotation direction 
boolean result;

double val_output;//Power supplied to the motor PWM value.
double Setpoint;
double Kp=0.6, Ki=5, Kd=0;  // Problem with Kp, Ki and Kd???
PID myPID(&abs_duration, &val_output, &Setpoint, Kp, Ki, Kd, DIRECT); 
 
void setup()
{  
   Serial.begin(9600);//Initialize the serial port
   pinMode(motorPinC1, OUTPUT);   //L298N Control port settings direction of motor C (originaly L298P)
   pinMode(motorPinC2, OUTPUT);  //L298N Control port settings direction of motor C
   pinMode(enablePinC, OUTPUT);  // powerRate to control speed of motor C
   Setpoint =666;  //Set the output value of the PID
   myPID.SetMode(AUTOMATIC);//PID is set to automatic mode
   myPID.SetSampleTime(100);//Set PID sampling frequency is 100ms
  EncoderInit();//Initialize the module
}
 
void loop()
{   
      advance();//Motor Forward
      abs_duration=abs(duration);
      result=myPID.Compute();//PID conversion is complete and returns 1
      if(result)
      {
        Serial.print("Pulse: ");
        Serial.println(duration); 
        duration = 0; //Count clear, wait for the next count
        Serial.print("val_output"); Serial.println(val_output);
       
      }
        

}
 
void EncoderInit()
{
  Direction = true;//default -> Forward  
  pinMode(encoder0pinB,INPUT);  
  attachInterrupt(0, wheelSpeed, CHANGE);
}
 
void wheelSpeed()
{
  int Lstate = digitalRead(encoder0pinA);
  if((encoder0PinALast == LOW) && Lstate==HIGH)
  {
    int val = digitalRead(encoder0pinB);
    if(val == LOW && Direction)
    {
      Direction = false; //Reverse
    }
    else if(val == HIGH && !Direction)
    {
      Direction = true;  //Forward
    }
  }
  encoder0PinALast = Lstate;
 
  if(!Direction)  duration++;
  else  duration--;

}
void advance()//Motor Forward
{
     digitalWrite(motorPinC1,HIGH);
     digitalWrite(motorPinC2,LOW);
     
     analogWrite(enablePinC,val_output);
}
void back()//Motor reverse
{
      digitalWrite(motorPinC1,LOW);
     digitalWrite(motorPinC2,HIGH);
     
     analogWrite(enablePinC,val_output);
}

void Stop()//Motor stops
{
     digitalWrite(enablePinC, LOW); 
}

Should I make an average of pulse detected?

I don't understand the numbers in your Original Post - for example 655 and 129.7. What do they represent and what output would you like to achieve?

Why are you wasting time in wheelSpeed() checking the direction. You already know the direction.

Your PID calculation seems to be based on the number of interrupts rather than the time between pulses or the time for a complete revolution. The number of interrupts is no measure of time.

Don't use floating point values where they are not appropriate. Counting is a whole-number process.

You should not read a multi-byte value from an ISR like this

abs_duration=abs(duration);

because the value can change while the bytes are being read. You need to copy the value to a working variable while interrupts are off - like this

noInterrupts();
   latestDurationCount = duration;
interrupts();
abs_duration = abs(latestDurationCount);

...R

bvking:
How can I have a constant speed?

By setting the constants of the P I D ?

Yes. You have to TUNE the PID controller constants to work on your motor and load.

There is a PID Autotune Library that might help:
https://playground.arduino.cc/Code/PIDAutotuneLibrary

Robin2:
I don't understand the numbers in your Original Post - for example 655 and 129.7. What do they represent and what output would you like to achieve?

The number of interrupts DOES indicate speed, because the PID compute function only actually does the PID calculations every 100 mSec. So, the number of encoder counts occurring during that 100mSec is a direct measure the motor speed.
Regards,
Ray L.

bvking:
Should I make an average of pulse detected?

How do you intend to average a discrete event?

You might want to average the number of times that discrete event occurs in some period of time, but that is completely different from what you asked.

RayLivingston:
The number of interrupts DOES indicate speed, because the PID compute function only actually does the PID calculations every 100 mSec.

Maybe. It is certainly not obvious from the code and it seems a rather haphazard way to measure speed.

In my own motor control code I measure the time for each revolution and call the PID calculation after every revolution. It easily holds speed within +/- 1% at a wide range of different speeds.

...R

Hi everyone.

Thanks for yours answers.

Actually, I just change that

myPID.SetSampleTime(100);//Set PID sampling frequency is 100ms

to

myPID.SetSampleTime(10);

When I put 5 ms, it look like slightly better.

Now, I will need some mathematical theory in music, or wave physical theory.

PID autotune inspire me.

Thanks to all