a word
Chuck
• 14.3k
• 2
• 14
• 40
1. You can't use established tuning guidelines to tune the system, so you're guessing at the gains, then
2. Once you do finally find good gains, your system becomes highly sensitive to changes in logic, which means you'll have to re-tune (again, entirelyentirely by guessing) again.
Chuck
• 14.3k
• 2
• 14
• 40

No, but you do need to calculate the P/I/D terms correctly. You have:

I = I + previous_I;


followed by:

previous_I = I;


With

I = 0;
previous_I = 0;


declared at the start. So your I term will always be zero here. What it should be is:

error = reference - feedback;
P_error = error;
I_error = I + (error*timeStep);
D_error = (error - previous_error)/timeStep;
prevous_error = error;


That is the most bullet-proof way to implement the PID loop. If your loop time is relatively stable, then you can absorb the time steps (the elapsed time between function calls) into the control gains:

P_term = P_gain * P_error;
I_term = I_gain * I_error;
D_term = D_gain * D_error;


Expanding this:

P_term = P_gain * (error);
I_term = I_gain * (<sum_0^k>(error*timeStep));
D_term = D_gain * ((error - previous_error)/timeStep);


I used a <sum_0^k> term (the "sum from zero to k") there to highlight the fact the integral term is a numeric integral composed of:

I_error = (error_0 * timeStep_0) + (error_1 * timeStep_1) + ... + (error_k * timeStep_k);


And if your timeStep is constant at every point, then you can factor it out and say:

I_error = timeStep*(error_0 + error_1 + ... + error_k);


So, regrouping the PID terms:

P_term = (P_gain) * error;
I_term = (I_gain*timeStep) * (<sum_0^k>error);
D_term = (D_gain/timeStep) * (error - previous_error);


At last, you can see that, if your time steps are relatively constant, you can say:

Effective_P_gain = P_gain;
Effective_I_gain = I_gain*timeStep;
Effective_D_gain = D_gain/timeStep;

P_error = error;
I_error = I_error + error;
D_error = error - previous_error;
previous_error = error;


Here you can see that I_error accumulates the error terms. I frequently see the timeStep being left off of the PID error terms, which I grudgingly accept because, as shown above, it's mathematically possible to do, but the problem is that:

1. If you build modular code (which you should), then gain values you test when you're just doing motor tuning may fail when you add more detailed logic (or remove faulty logic) later in the development cycle. This is because addition or removal of program logic will alter the total time between function calls. The PID loop becomes highly sensitive to logic changes and thus also becomes very difficult to tune.
2. You can't use empirical tuning methods like Ziegler-Nichols because those tuning methods require you to be using the true PID gains, not the modified gains. The timeStep term scales the integral and derivative gains, and the values diverge pretty quickly.

If your sample time is 10Hz, then your time step is (1/10) seconds, so integral gain is reduced by a factor of ten and your derivative gain is increased by a factor of ten, meaning they're a factor of ONE HUNDRED apart from one another. Ziegler-Nichols and others requires you to tune one gain until you see a particular system response, then set the remaining gains based on a formula that uses the first gain as an input.

If your gains aren't scaled correctly, those tuning methods will all fail. Now you're having twice the difficulty in tuning your PID controller:

1. You can't use established tuning guidelines to tune the system, so you're guessing at the gains, then
2. Once you do finally find good gains, your system becomes highly sensitive to changes in logic, which means you'll have to re-tune (again, entirely by guessing) again.

It's a huge time suck and a big distraction from the project.