# PID controller issue

Recently I've successfully implemented PID controller for my robot's moving motors. Now the system can automatically adjust it's speed depending on different situations: increase it if something blocks robot's movement, decrease it if robot moves to fast and so on and so on. But with it system gained specific feature: after stop of the movement (sending zero speed from the joystick) integral error doesn't go to zero, it stays active resulting some signal on the output of pid controller. Check the diagrams:

On the upper diagram you can see 4 variables changing with time:

'LeftWheel.target_ticks_speed' - speed which is sent from joystick

'actual_speed' - measured on the run

'speed_error' - difference between joystick speed and actual

'calc_pwm_value.summary' - output of pid controller which goes directly on motor

On the below diagram there are 3 components of the pid controller: proportional, integral and derivative.

As you can see at the time stamp 48.600 'speed_error' goes to zero but integral error and summary of pid controller save some value.

Does anybody encountered issues like that in their pid controller implementations? I'm just not sure is math model should be improved somehow? Or speed setting mechanism should be reworked? Any comments or thougths would be appreciated.

Posting here C code of pid controller math model:

#include "pid.h"

#define K_P 1.0f
#define K_I 0.2f
#define K_D 0.5f

/* Used for testing in STM studio*/
/*float sum_prop = 0;
float sum_int = 0;
float sum_diff = 0;*/

static inline float prop_compute(float error)
{
return error * K_P;
}

static inline float int_compute(float error, float* int_error)
{
float sum = 0;
sum = *int_error + (K_I * error);
*int_error = sum;
return sum;
}

static inline float diff_compute(float error, float* der_error)
{
float sum = 0;
sum = K_D * (error - *der_error);
*der_error = error;
return sum;
}

void pid_calculate(int16_t error, pid_entity* process)
{
/* Used for testing in STM studio*/
/*sum_prop = prop_compute(error);
sum_int = int_compute(error);
sum_diff = diff_compute(error);
result = sum_prop + sum_int + sum_diff;*/

process->prop_calc = prop_compute(error);
process->integral_calc = int_compute(error, &(process->integral_error));
process->derivative_calc = diff_compute(error, &(process->derivative_error));

process->summary = process->prop_calc + process->integral_calc + process->derivative_calc;


Controllers I’ve developed turn on the $$I$$ gain when within $$x$$ counts of the final state, or after they are 90% to that state. This decreases overshoot but still allows the $$I$$ term to eliminate steady-state offsets. Some motor controllers will have a “settling” signal that you can use to turn on the $$I$$ gain.