PID tuning for DC motor

Hi,

So I was trying to tune the PID control for my DC motor (set to the desired speed and get to that speed) but I didn't really get the response I want.

For these parameters: Kp = 10/3, Ki = 290/300, Kd = 10/300; this is the response I got.

Imgur

It does not really get to the set point and there's a fair bit of overshoot.

For these parameters: Kp = 10/3, Ki = 300/300, Kd = 10/300; this is the response I got.

Imgur

This time, it overshoots the setpoint and takes forever to go back.

I'm looking for somewhat less overshoot and actually reach the setpoint. The response time can be NOT instant to accommodate these requirements.

Any ideas how should I go about finding the correct parameters?

This is the code if it's helpful at all.

///////////////////////////// Library /////////////////////////////
#include <Encoder.h>
#include <PID_v1.h>

///////////////////////////// DC motors /////////////////////////////
const int int3 = A2; // motor 1
const int int4 = A3;
const int enB = 3;

/////////////////////////////
Encoder enc1(6, 7);

float countPerRotation = 2797.0;

/////////////////////////// PID ////////////////////////////
struct motorPID_parameter	{
  double Setpoint;
  double Input;
  double Output;
};

float Kp = 10/3, Ki = 290/300, Kd = 10/300;
struct motorPID_parameter motor1;

float pwm1 = 0;
PID motorPID1(&motor1.Input, &motor1.Output, &motor1.Setpoint, Kp, Ki, Kd, DIRECT);

////////////////// For keeping track of time ////////////////
unsigned long start0 = 0;
unsigned int elapsedTime0 = 0;

int time_frame0 = 100;

///////////////// For calculate displacement ///////////////
long int displacement1 = 0;
long int posPrevious1 = 0;

float speed1 = 0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  pinMode(int3, OUTPUT);
  pinMode(int4, OUTPUT);
  pinMode(enB, OUTPUT);

  analogWrite(enB, 0);

  // PID1 initialize
  motorPID1.SetMode(AUTOMATIC);
  motorPID1.SetTunings(Kp, Ki, Kd);
  motorPID1.SetOutputLimits(-255,255);
  motorPID1.SetSampleTime(100);

  motor1.Setpoint = -30;

  start0 = millis();
}

void loop() {
  // put your main code here, to run repeatedly:
  elapsedTime0 = millis() - start0;
  if (elapsedTime0 > time_frame0)	{
  	start0 = millis();
  	
  	displacement1 = (enc1.read() - posPrevious1);
  	posPrevious1 = enc1.read();
  	speed1 = (displacement1 / countPerRotation) / (time_frame0 / 1000.0) * 60; // rpm
     
 	  Serial.print(speed1);
    Serial.print(" ");
    Serial.println(motor1.Setpoint);

  	motor1.Input = speed1;
    motorPID1.Compute();
    pwm1 = motor1.Output;

  	if (pwm1 > 0)	{
        digitalWrite(int3, 1);
        digitalWrite(int4, 0);
        analogWrite(enB, pwm1);

      } else {
        digitalWrite(int3, 0);
        digitalWrite(int4, 1);
        analogWrite(enB, -pwm1);
    }
    
  }
}

speed_test3.ino (2.2 KB)

There are some examples out there on how to tune PID loops - each case is individual and you can’t just put some values in.
Google and you tube

Hi,
Try;

float Kp = 10.0/3.0;
float Ki = 290.0/300.0;
float Kd = 10.0/300.0;

You are calculating float values with integer values.
What model Arduino are you using?
Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Tom... :slight_smile: