0
\$\begingroup\$

I asked this question at stack overflow but i did not receive any replies, i think it was the wrong place to ask, so i am re-posting it here.

Short question: How wise is it to change the PID formula/equation based on the needs of your project?

Is it really a technique a proffesional would use?

Longer question: I am making my first PID in embedded MCU (Atmega328p).

I have a hotplate and i want it to reach a certain temperature, and i made it, easy.

As a reference for my PID i followed electronoob's tutorial. what i dont understand from his tutorial, is the line 171 of his code:

  pid_i = pid_i+(ki*error);  

His integral is using the error instead of the dt (time lapse). I see in the video (and i understand why he does that)

He actually does this:

/*The integral part should only act if we are close to the
desired position but we want to fine tune the error. That's
why I've made a if operation for an error between -2 and 2 degree.
*/
if(-3 <error <3)
{
  pid_i = pid_i+(ki*error);  
}

So the question is how wise is it to change the default PID equations to match your project?

What would you consult me to do to my present/future projects regarding changing the basic PID formula?

\$\endgroup\$
7
  • 1
    \$\begingroup\$ his timestep, dt, is implicitly the repeat time of his loop calculations. When writing simulation code, you tend to normalise everything to seconds so you can understand what you're doing. When implementing that in the target, it's common to roll the value of dt up with the constants, so you can simply accumulate errork, instead of errork*dt \$\endgroup\$
    – Neil_UK
    Jan 30, 2021 at 10:23
  • \$\begingroup\$ I get that, but i am more asking about changing the pid_i (integral) which should be pidIi=pid_i+(ki*dt) . He instead replaces dt with the error, which is irrelevant from the dt. \$\endgroup\$ Jan 30, 2021 at 10:30
  • 1
    \$\begingroup\$ \$PID_i=k_i\int{\varepsilon dt}\$ and aproximately translates to the formula in the program if it is executed at every dt. Your way of thinking pidIi=pid_i+(ki*dt) is not correct, as it misses the most relevant part -error. \$\endgroup\$ Jan 30, 2021 at 12:38
  • 1
    \$\begingroup\$ dt is a fixed value so integrating that would just give a never-ending ramp. The integral should contain the sum of all errors since the device powered up so \$ k_i \int e\ dt \$ is correct. In many systems a limit is applied to the integral to prevent "wind-up" which would occur if, for some reason, the system could not reach the set point. \$\endgroup\$
    – Transistor
    Jan 30, 2021 at 12:40
  • 1
    \$\begingroup\$ My opinion: Yes, feel free to change it. I am not a professional EE by a longshot, but I have implemented several "PID" ish systems in microcontrollers, including with multiple cascading loops, that have been happily chugging away for tens of millions of precision measurements and control operations. I would say don't get too fixated on the PID form, there are many alternatives. I would also say that the difference between an okay implementation and a good one is almost entirely about details to do with the saturation logic for rate and value, and how it interacts with other loops. \$\endgroup\$
    – Pete W
    Jan 30, 2021 at 15:42

3 Answers 3

3
\$\begingroup\$

My answer to Understanding the flow of a PI controller may be useful (or not!). In it I give a simplistic example of PI control for a car's cruise control.

I don't like the sample code comment "The integral part should only act if we are close to the desired position but we want to fine tune the error." Here's why:

enter image description here

Figure 3. The classic PID control function. Source: Wikipedia - PID controller.

  1. The classic PID control function has no if statement in it. The integrator, if implemented, is running continuously from power-up.
  2. As explained in my linked answer, P-only control will never reach the target (unless there is overshoot) and will settle down with an offset. In your implementation, if the offset is greater than your ±3° then your integral control will never turn on and the offset will never be eliminated.

As pointed out in the linked answer, when the integral action zeros the error the contribution of the proportional action is zero and the output depends only on the integral action.

\$\endgroup\$
2
  • \$\begingroup\$ "The classic PID control function has no if statement in it." -- just fyi, that is true in an academic sense, but even the cheapest industrial PID controller contains logic to deal with saturation, often referred to by the archaic term "Anti-Reset-Windup". \$\endgroup\$
    – Pete W
    Feb 1, 2021 at 20:19
  • 1
    \$\begingroup\$ Thanks, @PeteW. I mentioned anti-windup in another answer recently - I thought it was this one. You're correct and I had never considered that as an if. The OP's sample code was doing something much weirder though and was only switching on the integrator once close to the setpoint and that was what I was trying to address. \$\endgroup\$
    – Transistor
    Feb 1, 2021 at 20:27
2
\$\begingroup\$

Ye, you can change.

He wanted a control of +/- 2 degrees, you might need a range of +/- 4 degrees for your project.

So it can be changed according to the circumstances. You just need to understand your own project to know what assumptions are valid.

\$\endgroup\$
1
  • \$\begingroup\$ You are right. But i think @Transistor has a more valid answer, as explained by his 2.) explanation. My system wont reach the desired value OR there will be an overshoot, and later it will be settle itself with an offset. \$\endgroup\$ Jan 30, 2021 at 14:52
2
\$\begingroup\$

Here is a (slightly simplified) code snippet of the integrator-suppression logic I have been using for several years. Posting it in case it may be helpful.

The first feature here, is that the positive and negative saturation cases have their own logic.

Secondly, is the external rise/fall suppress flag, but you don't need to worry about that for temperature control. But in general, if there is an inner loop, it is helpful for the outer loop to know when the inner loop is saturating or rate limited, so I'm leaving it in just to illustrate that point.

Thirdly, for temperature control, output-rate-limit is probably a non issue.

    if
        (
            (pid_config->Ti == 0)
            ||
            (
                (fxdpt_err < 0)
                &&
                (
                    external_integ_suppress_fall_flag
                    ||
                    output_saturated_low
                    ||
                    output_rate_at_limit_low
                )
            )
            ||
            (
                (fxdpt_err > 0)
                &&
                (
                    external_integ_suppress_rise_flag
                    ||
                    output_saturated_high
                    ||
                    output_rate_at_limit_high
                )
            )
        )
    {
        // for any of above conditions, integral accumulator remains unchanged
    } else {
        // otherwise, add onto integral accumulator as normal
    }

Besides this, you should enforce a limit the integral accumulator, which for configuration purposes can be non-dimensionalized vs the full-scale input, full-scale output, and various Kp Ki terms etc.

Final footnote:

Another thing that makes a pleasant PID controller is set-point-rate limits. It is not hard but not entirely trivial, needs logic to make it "do the right thing" when a change in set point results in a sudden direction change while ramping. If interested, ask.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.