PID oversimplified?

Hi Everyone,

I've made reference to a PID loop I've written out in a few posts and I'm beginning to question whether I have way over simplified things or if it is something that should be functional. Below is the loop.

long output (int setpoint, int Input, int Kp, int Ki, int Kd, int delaytime)  {

  //Create running varibales to store continual data in
  static float integral_prior = 0;
  static float error_prior = 0;

  //Calculate error
  static float error = setpoint - Input;

  //Calculate integral value
  float integral = integral_prior + error * delaytime;
  float derivative = (error - error_prior) /delaytime;

  //Calculate output value
  long output = Kp * error + Ki * integral + Kd * derivative;

  //Store previous values
  error_prior = error;
  integral_prior = integral;

  //Set and calculate iteration time
  delay(delaytime);
  return output;

I have tested this loop and managed to get oscillations and mentioned in a previous post. This is something I believe to be indicative of something at least partially working. When I contrast this to available PID libraries I question whether I have extremely over simplified things as the libraries tend to be pages and pages of code as opposed to my humble few lines! It's probably quite obvious but I've quite literally taken the pseudo code from the PID equation and turned it into function I can call in my loop.

I haven't been able to stabilise the oscillation to get smooth results yet. Is there any suggestions as to any way I can improve this or any tips when it comes to tuning? I've been reading into PID Autotune but had some issues getting it to work with my PID loop. I'd much prefer to use the loop I made myself as I understand it well and am able to manipulate it in any way which i need to so I'm keen on getting this working as opposed to spending a bunch of times making sense of the libraries and trying to force them to fit my application.

Any criticism and advice would be greatly appreciated.

Take a look at this series describing the design and operation of the Arduino PID Library: Improving the Beginner’s PID – Introduction « Project Blog

The link at the top of the page takes you through a series of 9 more pages covering various aspects of the design. Decide for yourself.

I might be wrong but, aren't you missing the brackets in this line?

float integral = (integral_prior + error) * delaytime;

I haven't been able to stabilise the oscillation to get smooth results yet.

There are systematic approaches to selecting the constants. Google "PID tuning" for some tutorials.

The equations for PID are very simple, but they are only applicable to second order systems that behave according to certain assumptions (linearity, etc.). If those assumptions aren't appropriate, you can expect trouble.

  //Set and calculate iteration time
  delay(delaytime);
  return output;

...is a mistake. You've introduced dead time. The sequence needs to be read inputs, calculate new output, output, delay.

Good catch!

Knowing the response time of what you're controlling, then calling your function at a regular interval (ideally 3-10x faster) will be really helpful and make tuning much easier (and possible). Yes, dead time kills controllability (easily avoided in your code), but some dead time in a system is usually unavoidable. Some tuning rules are better suited for this (i.e. Cohen-Coon) which can handle dead time up to twice as long as the response time. You've made a good start ... good luck with your project!

amanbasra:

  //Calculate error

static float error = setpoint - Input;

Ooh. Initialized static. That's an interesting choice for a variable that's supposed to have a fresh value with each call. I have no idea how that will behave. I suspect it will not work the way you expect. Thank you for an interesting new perspective.

(Lordy I hate C / C++. Checking the standards document should not be a requirement for using a programming language.)

amanbasra:
Hi Everyone,

Hello!

amanbasra:
...I'm beginning to question whether I have way over simplified things...

I suspect, in the near future, you will be learning about output clamping and anti-windup.

gfvalvo:
Take a look at this series describing the design and operation of the Arduino PID Library: Improving the Beginner’s PID – Introduction « Project Blog

The link at the top of the page takes you through a series of 9 more pages covering various aspects of the design. Decide for yourself.

Thanks for pointing me to that! Makes it a lot easier to wrap my head around how the library works when theres a breakdown like that. Definitely a lot advantages to using the library so it seems sensible to take advantage of the library now I have a better understanding of how it works without having to have had tried to figure out the code and make assumptions as to why certain lines had been added.

mikistikis:
I might be wrong but, aren't you missing the brackets in this line?

float integral = (integral_prior + error) * delaytime;

I thought so too. I did originally have it in brackets but each example of pseudo code for the equation displayed it without so presumable the order is intended to be that way...

jremington:
There are systematic approaches to selecting the constants. Google "PID tuning" for some tutorials.

The equations for PID are very simple, but they are only applicable to second order systems that behave according to certain assumptions (linearity, etc.). If those assumptions aren't appropriate, you can expect trouble.

Thanks for the suggestion and explanation, very helpful as always! A lot of the examples of tuning I've come across are examples where it is easy to test the loops output. The problem is my project is RC rocket of sorts which is difficult to test without building some sort of rig to do so on. It's also not feasible to do something like this indoors as the sheer loudness of the motor and weather hasn't really allowed me to get out and make a test rig. I'm really eager to give it its best chance at surviving its first few take offs so I can rapidly improve, add features and fine tune based off of the results. I'm sensing based off of other similar projects this is going to have to include a chunk of trial and error and perhaps a few RUDs are just to be inevitable.

I had debated this a bit! Initially I had just been using millis to track the iteration time and didn't have a delay at all. After seeing several examples online I saw that delays where being used a lot which seemed somewhat counter intuative, surely the less delay, the more responsive and accurate the loop will operate. Nonetheless I shall move the delay to after the output has been calculated.

dlloyd:
Knowing the response time of what you're controlling, then calling your function at a regular interval (ideally 3-10x faster) will be really helpful and make tuning much easier (and possible). Yes, dead time kills controllability (easily avoided in your code), but some dead time in a system is usually unavoidable. Some tuning rules are better suited for this (i.e. Cohen-Coon) which can handle dead time up to twice as long as the response time. You've made a good start ... good luck with your project!

I'm controlling servos. According to the data sheet the servos speed is 12ms/60 degrees. I have read on some other posts that I can expect around 10ms response time, so 10ms between when the write command is sent and when the servo actually moves. These are arbitrary numbers read online so presumably the best way to get to a optimised loop would be to as accurately as possible measure these to be able to accounts for them accordingly. Thanks for your input!

Oops! Could definitely explain why my most recent test with just a self balancing platform (just familiarise myself with tuning and using the loop to then be able to implement in my main project) started to fail miserably after modifying the statics. Definitely not intentional! Must've mistaken the error with the error_prior and just made both static by mistake.

I suspect, based off the information I've already had my eyes opened to through this thread, that I'll be learning a lot more about all aspects of PID loops! Socrates had a point when he said the more you know the less you know!

amanbasra:
Initially I had just been using millis to track the iteration time and didn't have a delay at all.

How you track time is irrelevant.

That the PID loop has to wait for a response to occur is important.

At some point you will also be introduced to variable loop timing.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.