Electronic – PID Run Away Motor Control

dc motormotormotor controllerpid controller

I have a PID controlling a DC motor. I am attempting to control the speed of the motor very precisely. My controller allows me to change the direction of the motor and give it a pwm for speed. Therefore, I have a PID that has a plus and minus maximum and minimum. In order to speed up the device and slow down the device quick enough. The output of the PID is for the pwm and therefore is a absolute value of the PID, just changing a direction pin when PID < 0. I am using the opposite direction of the motor only as a braking system. Thus the motor should always be going in one direction but should slow it self down faster by applying reverse torque.

I am writing C firmware in MCUXpresso. The graphs come from sending data over UART to an Arduino to graph data easily.

My problem is that sometimes when the process variable hits 0 or close to it, the PID inverts and needs to go negative and thus spins the motor at full speed in the opposite direction. The two pictures below show the certain cases of when it happened. The red line is the set point and the blue line is the process variable.

The code controlling the device and PID is below.

I am having a hard time understanding why the PID would run away like this. Any help would be amazing. Thank you!

enter image description here

enter image description here

Main Control

int dir = FORWARD; //Controls direction of motor

motorPID.setpoint = vehicleSpeed;

motorPID.input = SM_GetRPM();

motorPID.input = motorPID.input * speedConversion;

UART_SendPID((uint8_t)motorPID.input, (uint8_t)motorPID.setpoint);

PID_Compute(&motorPID);

if(motorPID.output < 0){
    dir = BACKWARD;
}

if(motorPID.setpoint == 0){
    motorPID.output = 0;
}

if(motorPID.input > 60){
    MC_SetMotorSpeed(0, dir);
    int test = 0;
}

MC_SetMotorSpeed(abs(motorPID.output),dir);

PID Code

//Find all error variables
self->lastError = self->error;
double input = self->input;                         //Only so input can't change during compute
self->error = self->setpoint - input;
self->integral += self->error;
double derivative = self->error - self->lastError;

//Anti-integral Windup
if(self->integral > self->Outmax)
    self->integral = self->Outmax;
else if(self->integral < self->Outmin)
    self->integral = self->Outmin;

//Calculate PID
self->output = (self->Kp*self->error) + (self->Ki * self->integral) + (self->Kd * derivative);

//Set limits
if(self->output > self->Outmax)
    self->output = self->Outmax;
else if(self->output < self->Outmin)
    self->output = self->Outmin;

EDIT: Turns out this was a combined error of the problem described and a hardware issue.

Best Answer

Try changing the line that reads

self->integral += self->error;

to

self->integral += self-> Ki * self->error;

and match that by changing the line that reads

self->output = (self->Kp*self->error) + (self->Ki * self->integral) + (self->Kd * derivative);

to

self->output = (self->Kp*self->error) + self->integral + (self->Kd * derivative);

That will scale the integral term correctly for your integrator limiting step.