Arduino Forum

Forum 2005-2010 (read only) => General => News => Topic started by: br3ttb on Nov 11, 2008, 08:25 pm

Title: Arduino PID Library
Post by: br3ttb on Nov 11, 2008, 08:25 pm
Sadly, this is my first post on this forum, and as such, I am not allowed to post http links.  I'll remove the base tags and leave the Playgound strings.  hopefully you can can find your way there.  Sorry for the inconvenience.

I have just added my first ever contribution to the Arduino Playground.  An Arduino PID Library:  /playground/Code/PIDLibrary

The Barebones PID (/playground/Main/BarebonesPIDForEspresso) has been around for awhile, but I think this is a significant improvement.  My goal was to make a pid that was identical to those found in industry, with all the bells and whistles.

I have it listed as a Beta, and I'm open to any suggestions you may have.  Let me know what you think!

EDIT:  I forgot to add an important piece of information.  I'm a controls engineer specializing in pid control.  I do this for a living and I figured I'd share the wealth.

UPDATE:  2011-04-15  Library is out of beta (finally) (http://arduino.cc/forum/index.php/topic,58603.0.html)
Title: Re: Arduino PID Library
Post by: br3ttb on Nov 11, 2008, 08:26 pm
maybe I can post the links in a reply:
http://www.arduino.cc/playground/Code/PIDLibrary
http://www.arduino.cc/playground/Main/BarebonesPIDForEspresso
Title: Re: Arduino PID Library
Post by: ckiick on Nov 11, 2008, 11:42 pm
Thanks for the contribution!

This looks like a robust and comprehensive treatment of the PID controller.  I was looking for something like that ;).

Title: Re: Arduino PID Library
Post by: crimony on Nov 12, 2008, 12:14 am
Haven't tested it, but it looks good.

A couple of comments -

The description of SetCalcFrequency() indicates the parameter is actually a period, not a frequency. If this is the case then the function would be better named SetCalcPeriod().

The description of Reset() is overly brief. Perhaps it is due to my unfamiliarity with PID controllers, but does this function only reset the current calculated values of measured error and any accumulated integration value? Is the value of Output affected? What about the IOLimits and Tuning parameters?
Title: Re: Arduino PID Library
Post by: br3ttb on Nov 12, 2008, 06:26 am
Excellent point about the frequency. That will have to be changed.  Being a chemical and not an electrical engineer, I tend to use those terms interchangeably (the way some misuse precision and accuracy.)    stupid mistake.  looking through some manufacturers' documentation, it seems that the industry standard name is TSample or SampleTime.  not sure if this is as descriptive as CalcPeriod or not.  

I had struggled with whether or not to make Reset() public.  I doubt it will be needed.  Some manufacturers offer a similar function so I decided to as well.  Think of Reset() as the soft reset on your phone.  you could achieve the same effect by going to manual and immediately back to auto; the output would stay the same, the limits would stay the same, but the controller would "forget" everything that had happened before that point.

I appreciate the feedback.  please let me know how it works if you decide to use it.  (Sadly,)  I'm sure there's at least one or two bugs left to be found.
Title: Re: Arduino PID Library
Post by: lrr81765 on Nov 13, 2008, 06:11 pm
I am new to using a PID, but will be doing so on a home brewing project ;D

I might suggest some helper functions that allow use of a digital device to simulate PWM (like the BBPID).

I'll be giving this a run this weekend.

EDIT: or I could just read the second example  :-[
Title: Re: Arduino PID Library
Post by: neurascenic on Nov 13, 2008, 07:52 pm
Could somebody be kind enough to give and explain application concepts for PID?


Thanks!

Chris
Title: Re: Arduino PID Library
Post by: lrr81765 on Nov 13, 2008, 08:12 pm
I'll try it from the "30,000 foot view".

Imagine that you have cruise control in your car and it is set at 60 mph.

If you are traveling at 30mph and hit resume, the car should apply say 70% power to increase this speed to the target.

However, as you approach that target (say 50 mph), that throttle needs to be decreased, otherwise you will overshoot the target.

Once you reach your target, there will be times that you need to adjust the throttle to maintain that speed. You would likely do this as a small adjustment (1-2%) instead of a On/Off (0 or 100%) adjustment.

From the authors' file he writes:
*  If none of the above made sense to you, and you would like it to, go to:
*  http://www.controlguru.com .  Dr. Cooper was my controls professor, and is
*  gifted at concisely and clearly explaining PID control

I will be using it to accurately control stepped temperatures over a period of time.
Title: Re: Arduino PID Library
Post by: br3ttb on Nov 13, 2008, 08:57 pm
Larry's example is a good one.

I wanted to jump in to keep Chris from possibly becoming scared after visiting Dr. Cooper's site.  That link was put there more to answer the question: "ok, I kind of get pid and have used it, but how does it WORK"

to answer the more simple question of "why use pid?"  maybe it will help to look at something that is not pid: the kitchen stove.

when you set your oven to 350 degF, that's not actually what you get.  the oven actually cycles above and below that by maybe as much as 10 degrees.  when you get to 340, the burner turns on full blast, and when you get to 360, it shuts off completely.  this On/Off style of control is fine for a stove; it all averages out.

if, however, we took that same strategy and put it in a car, it would not work.   we would set the speed to 60mph.  when we got to 50 we would floor the gas pedal, and at 70 we would let off completely.  very uncomfortable.

so what pid lets us do is get an intermediate output value; something other than 0 and 100%.  This allows for much tighter control, which is a must for certain applications.

hope this helps,

Brett
Title: Re: Arduino PID Library
Post by: Dougl on Nov 29, 2008, 10:09 pm
would you like to see what a heating system looks like when it only has a bi-metal thermostat and what it looks like after a PID is applied? I built the BBCC system and plotted an espresso pull without the PID enabled and a pull with the PID enabled.

Check out these images:
without the PID enabled:
http://picasaweb.google.com/lh/photo/x68EzW2yrshM0udw0MJfKw

with the PID enabled:
http://picasaweb.google.com/lh/photo/cHzCR15XaT0FJJZeoWLevw

note: I have two heat settings(brew/steam) and in the test run, the temp rises to the first/brew temp and then a short while later I push the button to set the temp to the higher/steam temp. After a short period on steam, I then set the target temp back to the brew temp.

You can see that with the standard bimetal thermostat, the temp swings all over the place around the target temp but with the PID control enabled, there's a small overshoot and a quick recovery and much more stable and steady temperature held.

Doug
Title: Re: Arduino PID Library
Post by: jbsnyder on Jan 05, 2009, 03:36 am
Seems to work pretty well even for things that require rather short update intervals (10 ms), for PWM control of a motor with an encoder.  I'm not sure if it could run much faster (I haven't attempted to measure the time it takes to execute a cycle).

Is there any chance of an integer version of the library?  Integer math would certainly run faster on the ATMega168, since it's doing floating point emulation in software.  This might also cut down on footprint, but I would hope that the compiler isn't spitting out copies of all the instructions needed for fp emulation at each stage they are used.
Title: Re: Arduino PID Library
Post by: br3ttb on Jan 05, 2009, 07:58 pm
Quote
Is there any chance of an integer version of the library?


definitely.  everything's on the table.  I wrote this library for it to be used, and if there's something that people want in there I'm happy to do it.

to be honest I never thought of doing integer math. I usually use PID control on large systems (think factories,) where 100ms is the fastest a PID controller will ever have to go.  I optimized the code, but forgot how much of a hog floating point operations are.

maybe that can be the "lite" version of the library.  when I suggested that initially I was assuming that would mean a limited function set, but maybe integer math is all that's necessary.

also, while I'm typing, I'm thinking of including feed-forward capabilities in the next version (or is that "versions" now.)

I'd love to hear feedback on the above,  and if anyone has used this library to control something I'd love to hear about that too.  it may be helpful if others see how this tool is being used.
Title: Re: Arduino PID Library
Post by: retrolefty on Jan 05, 2009, 09:27 pm
How about adding autotune capablity? I know many of the standalone industrial PID controllers have that function and it can save a ton of time when trying to tune a new loop.
Title: Re: Arduino PID Library
Post by: br3ttb on Jan 05, 2009, 09:47 pm
Quote
How about adding autotune capablity?


sadly, that's one thing I can't do.  part of my employment agreement explicitly states that I can't tune loops (or write code that does same) except under the umbrella of my company.  somehow writing an entire pid controller and making it freely available is ok though.  go figure.

the library is such that someone could write a parallel program to perform autotune manipulations and get some numbers.  if anyone decides to take this on (and I don't think it looks violently dangerous) I'd be happy to include it.
Title: Re: Arduino PID Library
Post by: wiz on Jan 05, 2009, 09:56 pm
Heres a second vote for the integer version, & possibly without the input/output scaling as well.

I'm testing a system to keep two fairly rapid linear actuators synchronised with a master potentiometer & the two PID calculations each loop are sapping a lot of cycles. All I need is a straight 10bit in >> 10 bit out as fast as possible.
Title: Re: Arduino PID Library
Post by: amrphoto1 on Jan 14, 2009, 07:57 am
I am so pleased to have found the PID Library that you created, br3ttb.

It could be the perfect solution to my current challenge.  I have a question regarding the output.

The analogy that you give regarding the cruise control is a nice one, and I understand the beauty of the PID's ability to limit the overshoot by "letting up on the gas."

My basic question is how do I interpret the "Output Value?"  What does it represent?  It seems to be a "Correction Value" specifically related to the "Input Value" and the "Setpoint."  

This may seem obvious, but so far (without using the PID) I have been splitting my sensor input, which is a value between 0-255 at my desired setpoint, roughly the mid-point, and using the values on one side of the setpoint to drive a motor in one direction and the values on the other side of the setpoint to drive the motor in the opposite direction.

Thus, my question...given the one value for Output how should i interpret this value

I imagine that I could split the value and feed it into two separate PID's if that is necessary.

Thanks for any help :D





Title: Re: Arduino PID Library
Post by: br3ttb on Jan 14, 2009, 03:19 pm
what I would suggest is to have your output range from negative to positive.  (-255 to 255 say)  your code would look something like this:
Code: [Select]
double Input, Output, Setpoint;
PID pid(&Input, &Output, &Setpoint, -3,4,1);

void setup()
{

  pid.SetIOLimits(0,1023,-255,255); //tell the PID to range the output from -255 to 255
  Output = 0; //start the output "motor stopped" and vary from there

  pid.SetMode(AUTO); //turn on the PID
}


void loop()
{
  //give the PID the opportunity to compute if needed
  Input = //whatever your input is
  pid.Compute();

   if (Output>0)
   {
   //spin the motor one way at speed = Output
   }
   else if(Output<0)
   {
   //spin the motor the other way at speed = -1* Output
   }
   else
   {
   //motor stopped
   }
}



hope that helps,  Brett
Title: Re: Arduino PID Library
Post by: amrphoto1 on Jan 15, 2009, 11:52 am
Thanks so much, Brett.

I will try this solution.

Aaron
Title: Re: Arduino PID Library
Post by: zooto68 on Jan 15, 2009, 03:52 pm
Why is it so hard to find the PID Library in the playground? there seems to be no link to it at all or am i being dumb?  :-/
Title: Re: Arduino PID Library
Post by: br3ttb on Jan 15, 2009, 04:32 pm
Modesty mostly.  and fear.  I didn't want to presume to add my library to the lexicon.  at least not until I made sure that there weren't glaring errors I had missed.  it's been about 2 months now, so I feel a little more comfortable adding it.  here you go:  http://www.arduino.cc/playground/Main/GeneralCodeLibrary
Title: Re: Arduino PID Library
Post by: mem on Jan 15, 2009, 04:44 pm
br3ttb, no need to be modest ;)

I did some minor editing to the font sizes to make the page a little easier to read, hope you don't mind.
Title: Re: Arduino PID Library
Post by: zooto68 on Jan 15, 2009, 05:51 pm
Ahh glad it wasn't me being dumb then ;)

Nice to see it up there for all to see :)
Title: Re: Arduino PID Library
Post by: EvilSpeeder on Jan 21, 2009, 08:58 pm
Here's another vote for the int version.  

I'm currently trying to use your library to control motor speeds for a robot.  I haven't gotten everything working correctly yet, but I'm concerned that the arduino will not be able to run the methods in this library and still process interrupts at the required frequency (as high as 1700kHz)?  How is this done on and industrial motor controller?  Do they do the PID math on the physical motor controller, or is it done elsewhere on a main processor?
Title: Re: Arduino PID Library
Post by: br3ttb on Jan 21, 2009, 09:39 pm
I want to make sure we're on the same page here.  for simplicity's sake, I set up the library so you call .Compute() every cycle.  most of the time, the library says "I don't need to recalculate yet" and immediately spits back to the calling routine.  the recalculation happens at 1Hz by default, but can be adjusted to be slower or faster using the SetCalcFrequency function.

so most of the time Compute() kicks back "instantly."  I don't think there's an interrupt problem there.  however, on the cycles where recalculation is occurring I think there may be. I did some bench tests before I published the library the calc speed was about 12 microseconds (8.3kHz.)  so it may be possible, if the interrupt pulse is faster than that, and it comes while the pid is calculating, the signal may be missed.

I have no idea how this is done in motor controllers.  my experience is on slower moving stuff, and as a consequence it's not a problem for the pid to be "slow" as well.

I am currently working on an integer version of the library (and the crowd goes wild.)  it's not going to be anywhere as feature rich as the "full" version, but hopefully it will be much, much faster.  

Brett
Title: Re: Arduino PID Library
Post by: EvilSpeeder on Jan 21, 2009, 10:01 pm
That's kinda what I was thinking but this clarifies it much more.  I think you may right about the possibility of missing pulses while in a calculation but that's one of the many pitfalls of dead-reckoning navigation.  However, I don't think it's going to be a big problem because I think my overall error from other factors will outweigh the lost counts here and there.  It sounds like your 'full' library may work but I bet the 'lite/int' version would work a lot better!!   ;)

Thanks, this has been a big help to me!
Title: Re: Arduino PID Library
Post by: ryanjmclaughlin on Jan 22, 2009, 02:35 am
This is great!  Thanks so much, I am going to try it out soon on an oven controller.  I'll let you know how it works out.
Title: Re: Arduino PID Library
Post by: crimony on Jan 28, 2009, 12:51 am
I don't mean to nag, but that SetCalcFrequency() really needs to be changed to SetCalcPeriod(). Likewise GetCalcFreq().

IMO it's important to avoid misleading function names, particularly early in the library lifecycle, before the installed base is too large, and there's too much traction.

Apart from that it's a great library.
Title: Re: Arduino PID Library
Post by: br3ttb on Jan 28, 2009, 04:37 am
Thanks!

I think nag might be a little strong.  I've taken it as a gentle reminder.  :)

I'm working on the integer (or "lite") form.  I'll release it bundled with the pid library, and on both I'm planning on renaming it as "SampleTime", in keeping with the industry standard.

-Brett
Title: Re: Arduino PID Library
Post by: br3ttb on Feb 03, 2009, 02:36 am
ok, so I finished (or thought I finished) the integer form, and I wasn't happy.  it was only 1k smaller and 30% faster.  not good enough.  I'm going to keep working on it, but unfortunately it's going to be a while.

in the mean time, the 0.5 beta has been sitting there with it's flaws. So... I've decided to upload the next version of the beta (v0.6) without the promised integer library.  sorry about that.

at any rate, with the bad news out of the way, let's talk about the good news.  updated pid library!  bonus!  I took care of the obvious (and less obvious) snags with the library, and added a very powerful advanced feature.

"snag" fixes:
* CalcFrequency has been changed to SampleTime.  finally.
* The library now has a version-specific name: <PID_Beta6.h>  This way, you can put up your code, and even 4 years (and 20 revisions) from now, everyone will know which version of the library you used.
* I felt that SetIOLimits was a bit confusing, since for the most part,  the input limits will never be changed.  I decided to split it into two functions:  SetInputLimits and SetOuputLimits.  The output limit function was left on the standard function page, while the input limit function is now hidden on the advanced page.

advanced feature:  
Feed Forward.  good lord is this powerful.  essentially it lets you add your own knowledge to what the pid is doing.  so, if you know that the controller is about to get hit with a major disturbance, you can help it along, and address the disturbance far more effectively than using just pid alone.

take a second to look at the updated wiki (http://www.arduino.cc/playground/Code/PIDLibrary) and let me know if I missed anything!

Brett
Title: Re: Arduino PID Library
Post by: retrolefty on Feb 03, 2009, 05:01 am
Thanks for your effort on this. One question I have is how would one best invoke a reverse action control function, as required in industrial controllers for working with fail open and fail close control valves?

Thanks
Lefty
Title: Re: Arduino PID Library
Post by: br3ttb on Feb 03, 2009, 01:15 pm
Quote
how would one best invoke a reverse action control function, as required in industrial controllers for working with fail open and fail close control valves?

change the sign of the P_Param.  (I know you know what this means Lefty, but for the benefit of others reading...)

if your P_Param is 3.2 say, and the controller seems to be going in the wrong direction,( i.e. opening when it should be closing,)  you would want to change that to a -3.2.

usually it is really obvious that this needs to be changed.  the output starts to go the wrong way, which makes your input get farther from setpoint, which makes your output go FARTHER in the wrong direction.  the cycle continues until your output is pegged at one of the limits.

I was teaching a class on pid and asked "what happens if you set this wrong?"  expecting the answer above.  the answer I got was much better:  "you get a nickname"

Brett  
Title: Re: Arduino PID Library
Post by: Flotec on Feb 04, 2009, 08:35 pm
I have plans to design an autopilot for my boat and have read this post with great interest. Before starting I should want to ask you two questions that has puzzled me:
- I have seen that some boat autopilots does not need a rudder feed-back. I suppose that all PID regulators do need some sort of feed-back. Do you have any idea how they can do this?
- Some autopilot claims that they are adaptive. They can learn the characteristics of the boat. I know you cannot give us an adaptive controller, you told us that,  but can you hint to me how this is done. Is it still a PID regulator that is used with some other program tuning the parameters or do they use some other type of controller?
Title: Re: Arduino PID Library
Post by: retrolefty on Feb 04, 2009, 09:59 pm
"I have plans to design an autopilot for my boat and have read this post with great interest. Before starting I should want to ask you two questions that has puzzled me:
- I have seen that some boat autopilots does not need a rudder feed-back. I suppose that all PID regulators do need some sort of feed-back. Do you have any idea how they can do this?
- Some autopilot claims that they are adaptive. They can learn the characteristics of the boat. I know you cannot give us an adaptive controller, you told us that,  but can you hint to me how this is done. Is it still a PID regulator that is used with some other program tuning the parameters or do they use some other type of controller? "

Well all closed loop controllers need some kind of feedback measurement(s) to function, otherwise it is  'open loop' control, kind of like a steering wheel, where it's up to the human operator to know where the car is aimed at and make adjustments or not.

In the Classic PID controller the feedback is called the 'PV' for process variable. It is the actual measured temperature in a temperature controller, or the actual level measurement in a level controller. For you autopilot steering the feedback would either have to be something that can measure actual heading like a electronic compass or a GPS heading, etc. Measuring the actual rubber angle would work to a degree but wind and current variables could cause a change in heading regardless of the rudder angle. I'm not sure what the standard measurement used in for boat auto pilot controllers. Interesting applications and I would favor GPS but autopilots have been around longer then GPS so there must be other effective measurements.

Lefty


Title: Re: Arduino PID Library
Post by: Flotec on Feb 04, 2009, 10:17 pm
An autopilot use heading information from a fluxgate compass so of course that will be used as a feed-back. However in my understanding of an autopilot it usually consists of two cascaded loops. The first one for heading and the other one for setting the rudder position. The first one use heading as feed-back and the last one a "rudder feed-back unit". Some autopilot manufacturer has taken away the need fro that last unit and I just wander how that can be done.
Title: Re: Arduino PID Library
Post by: retrolefty on Feb 04, 2009, 10:51 pm
Quote
An autopilot use heading information from a fluxgate compass so of course that will be used as a feed-back. However in my understanding of an autopilot it usually consists of two cascaded loops. The first one for heading and the other one for setting the rudder position. The first one use heading as feed-back and the last one a "rudder feed-back unit". Some autopilot manufacturer has taken away the need fro that last unit and I just wander how that can be done.


Now I understand your question. Yes cascade control where the rubber has it's own PID control function allows one to optimize the controller tuning settings for the rudder controller and the heading controller independently such that the heading controller outputs a 'desired setpoint' to the rubber controller as it's PV measurement.

In such a configuration the rubber controller is said to be the slave controller and the heading controller the master controller.  It gives better controllability. However with more the powerful control possibilities with a microprocessor this can all be done inside the micro and could take advantage of feed-forward or adaptive or other 'smart' control algorithms. So I guess it's a trade off, saving the cost of the hardware needed to generate a rudder position measurement while still having good control behavior by compensating by using more advance software control features.

As a hardware guy, I would prefer having actual rubber feedback measurement in that it then is easy to add additional alarm functions if say the rubber linkage was to break and the actual rubber commands were not being performed.

Lefty
Title: Re: Arduino PID Library
Post by: br3ttb on Feb 05, 2009, 12:25 am
Quote
- Some autopilot claims that they are adaptive. They can learn the characteristics of the boat. I know you cannot give us an adaptive controller, you told us that,  but can you hint to me how this is done. Is it still a PID regulator that is used with some other program tuning the parameters or do they use some other type of controller? "


I don't think you need an adaptive controller for this situation per se.  I'm assuming that what they mean when they say "Adaptive" is that you can put it in a big boat or a small boat, and it will figure out if it needs to control aggressively or conservatively.  once the controller dials in on what type of control it needs, I would guess that it doesn't do much adapting.  this is good news for you.  you can use a pid controller and have a tuning period. "this control is a little too aggressive, let me back it off" or whatever.  after that, you should be all set.

Quote
- I have seen that some boat autopilots does not need a rudder feed-back. I suppose that all PID regulators do need some sort of feed-back. Do you have any idea how they can do this?


ok, first let me put both single-loop and cascade into words.
single loop:  "I'm not on heading.  let me adjust my signal to the rudder until I get the heading I need"
cascade: "I'm not on heading.  I need the rudder to be 5degrees off center. rudder controller, look at the rudder position and adjust until I get what I asked for"

so what's the difference?  well, in the first situation, there's no guarantee that you'll get the same rudder position every time you send, say, 50%.  actually, it's likely that you won't, because of "slop" or play in the rudder.  in the second situation, we have a dedicated controller whose job it is to make sure we get exactly what the heading controller asks for.

so the cascade is more precise because you get the rudder position you want really quickly.  does that mean that it won't work the other way?  nope.  in the single-loop setup, the heading controller is going to keep adjusting it's output until it gets what it wants.  so if sometimes centered is 50%, and other times it's 55%, it doesn't really matter. the controller will eventually find the output that gets it what it wants.

the problem is that it will have more trouble getting to the desired heading than the cascaded way.  so cascade is more complicated, but if done right it gives you better control.

(a note on nomenclature.  the cascaded controllers can be referred to as Master-Slave, Outer-Inner, or Primary-Secondary depending on who you ask.)

hope this helps

Title: Re: Arduino PID Library
Post by: Flotec on Feb 05, 2009, 07:51 am
Thank you very much br3ttb for your answer. The more expensive autopilots are really adaptive in a way that they automatically figure out the boats characteristics and adjust for that. They can even adjust for changing weather conditions. So my question is do they still use a PID controller with some intelligent program to change Kd, Ki and Kp or do they use some completely different controller? What is exactly an adaptive controller?
Title: Re: Arduino PID Library
Post by: br3ttb on Feb 05, 2009, 12:48 pm
Quote
So my question is do they still use a PID controller with some intelligent program to change Kd, Ki and Kp or do they use some completely different controller? What is exactly an adaptive controller?


adaptive control is an umbrella term for a controller that changes its behavior on the fly.  how do they do this?  I have no idea.  they could use a neural network and it would fit this definition! (although fitting one on a microcontroller would be an impressive task)

the pid library has been designed with adaptive control in mind.  Example 2 on the wiki uses a form of adaptive control, switching between aggressive and conservative tunings on the fly.

so, while I don't know how they do it, I have a feeling you could use pid.  as long as you're ok with some experimentation you should be fine.  "I know that THESE parameters work well in calm seas, while these work well in 5ft swells.  I'll automatically switch between them, or even interpolate between them, depending on the situation I'm in." if that isn't enough you can even bring in some Feed Forward control, but it's probably better to cross that bridge when we come to it.

now I should add here that I'm not a seaman, so I have very limited knowledge of "changing weather conditions" and how they affect the navigation of the boat.  my intuition is that the pid library should give you
the tools you need. if not, you've spent 0$ and learned a little about control.  ;)
Title: Re: Arduino PID Library
Post by: rodw on Mar 15, 2009, 11:45 am
Hi guys, I am a newcomer to the Arduino and this is my first post. I purchased one to do a few chores as part of a Car PC installation and have just about got the main hardware and software elements sorted out enought to actually start putting some stuff together.

I was actually thinking about addng a climate control system to my car while driving earlier today and new there were some intergrative vcontroller solutions out there and now I have found one for the Arduino! By the sound of this thread, this is exactly the sort of software I would need to add climate control.

However, in the case of airconditioning, there are two parameters to adjust, one is the temperature setting and the other is the fan speed. Could this library be adapted to control two variables in unison? to achieve the desired temperature setting?
Title: Re: Arduino PID Library
Post by: br3ttb on Mar 15, 2009, 02:32 pm
Quote
However, in the case of airconditioning, there are two parameters to adjust, one is the temperature setting and the other is the fan speed. Could this library be adapted to control two variables in unison? to achieve the desired temperature setting?


I don't see why not.  you would probably just need to do some Post-Processing on the output.  so the pid would still be computing one number, but you would massage it a little.  the easiest example of this would be to take the output of the controller and send it to BOTH the fan speed and temp setting.  so as the pid output gets larger, you ask for colder air and more of it, simultaneously.

SO:

Code: [Select]
void setup()
{

  pid.SetOutputLimits(0,255); //tell the PID to range the output from 0 to 255 (this is the default range, so this really isn't necessary(
  Output = 0; //start the output at ALL off and vary from there
  pid.SetMode(AUTO); //turn on the PID
}


void loop()
{
  //give the PID the opportunity to compute if needed
  Input = //cabin temp
  Setpoint = //desired temp
  pid.Compute();

  FanSpeed = Output;
  TempSetting = Output;
}


note, you could also set this output massaging to first speed up the fan, then adjust the temp, or vice-versa, but that would make tuning the controller (finding the right P_Param, I_Param, D_Param) a bit more difficult.

Brett
Title: Re: Arduino PID Library
Post by: rodw on Mar 15, 2009, 10:09 pm
Thanks Brett I am going to give this some consideration. If I left the fan with only 4 speeds as the original is rather than using a infinitely variable speed controller, would that make things easier or harder? Would your feed forward technique help?
Title: Re: Arduino PID Library
Post by: betwys on Mar 16, 2009, 12:40 am
Neurasonic asked for a story on PID control. Here's my take.
PID stands for proportional, Integral, differential.   What do THEY stand for? Start with comparing what you have with what you want with what you have. The difference is called the error signal.     If you use only this error signal to drive the output, you have a proportional controller (if the error signal is linear or proportional).    This can be OK, but there HAS to be an error to keep driving the output, so it's never exactly right.
OK, how about toting up the small difference, time after time, when you are as close as you can get with the proportional circuit, and driving the output with THAT too? That can work and hit the desired output on the nose.
Now what about if we next want a step change in output?
If we grow restless with a fast start, and a slower slower approach to the desired output, we can get bold. By monitoring the rate that the error signal changes we reduce the time to reach the target value, and (hopefully) minimize the over shoot and hunting chances.
Having said all that PID controllers can be a pig to tune. Some people find fuzzy logic controllers are much easier to understand and to set up.

Brian Whatcott
Altus OK
Title: Re: Arduino PID Library
Post by: retrolefty on Mar 16, 2009, 12:56 am
Quote
Having said all that PID controllers can be a pig to tune. Some people find fuzzy logic controllers are much easier to understand and to set up.


Having worked before retiring in a oil refinery I can agree that loop tuning a PID controller can sometimes be a challenge. It's not so much that it is difficult but rather it can be so time consuming that people lose patience.

One problem is that there can be such a process time delay, especially for temperature loops, that it takes some time to see if a specific tuning change made an improvement or made it worst. Some controller manufactures have added auto-loop tuning features into their PID controllers and a few I worked with worked pretty well.

Lefty
Title: Re: Arduino PID Library
Post by: Nigel on Mar 18, 2009, 03:26 am
Hi Brett

Thanks for the great library!  It's been flawless on my project.

I noticed in a few of your posts you mentioned you didn't think SetInputLimits would be used much.  I just wanted to let you know that without it, I couldn't have used the library so easily.  My process input is actually a value I'm reading on RS232 and converting to a weight from 0-0.5 grams.  I was able to set in input limits to 0, 0.5 and it works perfectly.

My next project will probably use one of the Maxim thermocouple to digital chips, and I'll once again use the setinputlimits function.  I vote to keep this in the code!  

Thanks for your contributions,
Nigel
Title: Re: Arduino PID Library
Post by: br3ttb on Mar 18, 2009, 04:55 am
So many replies, so little time:

RodW - using 4 speeds is probably the safest way to go from an equipment standpoint.  in that case, the easiest thing to try first might be an output divider.  whatever the pid is asking for, divide by the fan speed(1-2-3-4) and send that to the temp setting.  as the temp setting (not the pid output) gets close to the max, bump up your speed to the next level.  if it gets close to the min, drop the speed down one. dividing the output will have a Feedforwardesque (totally a word) effect.  the signal to the temp setting will instantly be changed when the speed changes.

Brian - I thought it stood for Proportional, Integral, Do not use.   ;)

Brian & Lefty - I find that the blessing and the curse of the PID is it's ease of configurability.  you can get a control loop to "good 'nuf" pretty quickly.  the problem is that sometimes that's a ways away from "good."  I'd say, as far as arduino is concerned, simple fuzzy logic is the right place to start.  that can get real complicated real quickly though, and at that point it's time for this library (IMO)

Nigel - Fear Not!  I'm not getting rid of Input Limits by any means.  I just separated them out into a separate function (SetInputLimits) to help the uninitiated.  this is already complicated enough.

Brett
Title: Re: Arduino PID Library
Post by: psyber on Aug 21, 2009, 01:40 am
br3ttb,

You might want to include a default constructor in your next build.  This might be my lack of experience with this platform but the following would not compile:
Code: [Select]

include <WProgram.h>
include<PID_Beta6.h>
class foo{
public:
PID myPID;
}


Apparently it would not compile b/c it could not find a matching function call to PID();

I am new to this particular platform, so I could be missing something, however to get this to work in my class I had add the default constructor to your code and recompile.  

Otherwise your package looks good.
Title: Re: Arduino PID Library
Post by: br3ttb on Aug 21, 2009, 02:31 am
I never considered that people would be embedding my class into another class.  COOL!

The reason I didn't go with a default constructor is that for the pid to run correctly, it HAS to have the things specified in the current constructor (input, output, setpoint, tuning parameters.)   I figured that would be a gentle way to get people to specify them.

maybe a middle of the road option would be to include a default constructor but have it commented out?  if you're writing a new class you'll likely have the know-how to find/ uncomment.  if you're the standard Arduino user you'll notice no change.  thoughts?

Brett
Title: Re: Arduino PID Library
Post by: betwys on Aug 21, 2009, 02:35 am
[his example 1]
********************************************************
* PID Simple Example
* Reading analog input 0 to control analog PWM output 3
********************************************************/

#include <PID_Beta6.h>

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1);

void setup()
{
 //initialize the variables we're linked to
 Input = analogRead(0);
 Setpoint = 100;

 //turn the PID on
 myPID.SetMode(AUTO);
}

void loop()
{
 Input = analogRead(0);
 myPID.Compute();
 analogWrite(3,Output);
}

***************************************
[Your non-working example]
include <WProgram.h>
include<PID_Beta6.h>
class foo{
public:
PID myPID;
}

*******************************

I guess I don't understand your critique - your example stuff doesn't look like his example stuff????

Can you 'splain the problem in words of at most two syllables?  :)

Brian W
Title: Re: Arduino PID Library
Post by: retrolefty on Aug 21, 2009, 02:36 am
Class? The only thing I recall about class is that if your late too often you could receive saturday detention.  ;)

Lefty
Title: Re: Arduino PID Library
Post by: br3ttb on Aug 21, 2009, 12:44 pm
Brian:

psyber is using the library in a way I never even considered.  Most people will take the pid library and use it right in their Arduino program, the way my example illustrates.

the way I understand it, psyber encountered a problem trying to embed a pid within a library of his own creation.  On the library creation side, the rules are a little different.  To make it work, he needed to -very lightly- massage the pid library code.  His suggestion was aimed at saving the next guy some trouble.

Lefty:  This is all I know about class ;) : http://www.imdb.com/name/nm0001627/

Brett
Title: Re: Arduino PID Library
Post by: dogsop on Aug 21, 2009, 03:47 pm
Here is another vote for making it easier to embed the PID library in another class. I was in the process of creating a motor control class which would embed a PID controller to set the PWM signal to the motor when I saw psyber's post.

Edit:
It may not be necessary to add a default constructor. I haven't tested this yet but it does compile.

test.pde
Code: [Select]
#include<PID_Beta6.h>
#include "foo.h"

foo myFoo;

setup()
{
}

loop()
{
}


foo.h
Code: [Select]
class foo
{
public:
  foo();

  PID myPID;
  double Input;
  double Output;
  double Setpoint;
}


foo.cpp
Code: [Select]
#include "PID_Beta6.h"
#include "foo.h"

foo::foo() : myPID(&Input, &Output, &Setpoint,2,5,1)
{
  // initialize foo
}


I had to look up initialization lists, in my real life I've never used them. In another environment I'd include a pointer to a PID object in my class and use new to create it in the constructor.

Title: Re: Arduino PID Library
Post by: Actives on Aug 21, 2009, 05:35 pm
I has use this libary to control angle of robot arm, it work as well on fixed setpoint.

if my setpoint is change it will not go to setpoint, it have offset. i try to increase D parameter, i would not help.

i guess my problem is my motor start moving at PWM 80%. when is start moving it's very fast and on next sampling it already overshoot.

anyone have some idea to slove this. ;)
Title: Re: Arduino PID Library
Post by: br3ttb on Aug 21, 2009, 07:40 pm
Quote
on next sampling it already overshoot. anyone have some idea to slove this.


you can use the SetSampleTime() function to make the pid sample more quickly. (http://www.arduino.cc/playground/Code/PIDLibraryAdvancedMethods)

Brett
Title: Re: Arduino PID Library
Post by: Ro-Bot-X on Aug 23, 2009, 02:08 pm
I want to make a motor controller that uses distance as the target but is able to accelerate until reaches a certain speed (sometimes is max speed), continue with that speed until almost at destination and decelerate until it reaches the target distance and stops. Sometimes I need to make small adjustments and speed never reaches the set speed and needs to decelerate because it reaches the destination.
Any advices on how to do that?
Thanks.
Title: Re: Arduino PID Library
Post by: br3ttb on Aug 23, 2009, 02:41 pm
Quote
Can this PID library include a function to accelerate from 0 to SetSpeed and continue at that speed until the SetPoint is reached (because it will automatically decelerate before reaching the SetPoint)?

I have tried to do a function that accelerates until Speed = SetSpeed and only then activate the PID controller, but sometimes I need to make small corrections so the Speed never reaches SetSpeed. Can this be done in the PID controller?


I don't think so. the pid is a "simple" control element whose job is to make Input = Setpoint.  once you want to do more complicated things, you'll need to make the pid part of a larger control strategy.  it sounds like that's what you're trying to do anyway, so let's talk about that.

First, I'm not sure I completely understand your application.  You use both SetSpeed and SetPoint in your question.  I'm would assume that Speed is the output from the pid, and Setpoint is the value you want the PID Input to achieve.  I'm not sure though.

I don't want to give you bad advice at this point.  Could you give a description of what it is you're trying to do in the real world (i.e.  "I've got this thermonuclear jetpack, and I'm tyring to control take-off velocity. my inputs and outputs are...")  I'll be able to give better advice once I know what it is you're trying to do.

Brett

Title: Re: Arduino PID Library
Post by: psyber on Aug 23, 2009, 09:58 pm
Quote

foo.cpp
Code:

#include "PID_Beta6.h"
#include "foo.h"

foo::foo() : myPID(&Input, &Output, &Setpoint,2,5,1)
{
  // initialize foo
}




I had to look up initialization lists, in my real life I've never used them. In another environment I'd include a pointer to a PID object in my class and use new to create it in the constructor.



Nice!  I figured there was some way to do it without monkeying around with the original library.  I just wish there was a more intuitive method as my C/C++ is extremely rusty.  I don't think this is covered in any of my old textbooks either.   >:(

br3ttb:
As for the middle ground solution, I see no difference between you adding the code and then commenting it out, and having a developer simply add the code.  In either case someone still has to edit the class and rebuild the library.



 




 
Title: Re: Arduino PID Library
Post by: spamiam on Sep 17, 2009, 01:00 am
I hate to resurrect this old thread, but it is a good one, and the PID software looks really good.

Before finding this thread, I wrote my own.  I was particularly interested to see how wind-up was handled.  I saw that the Integral term was not incremented when the output was maxed.  

This seems like a great idea, but doesn't it cause a bit of a glitch when the output drops down from max?  Maybe the integral term is well below the value resulting in maximum output due to some other factor such as the differential.

Is this really going to make much of a glitch under these circumstances?  I suspect that a "properly" tuned loop will not have such odd behaviour that the differential can push the output that far up/down.

I attempted to limit wind-up by not allowing the integral term to exceed the value that results in full output on its own.  Is this not good enough?

-Tony
Title: Re: Arduino PID Library
Post by: br3ttb on Sep 17, 2009, 01:13 pm
Quote
doesn't it cause a bit of a glitch when the output drops down from max?

I haven't noticed this.  the inclusion of the (err>0) and (err<0) are supposed to (and seem to) keep this from happening

Quote
limit wind-up by not allowing the integral term to exceed the value that results in full output on its own.  Is this not good enough?

the short answer is "yes."   It's not as simple with the form of the pid I'm using, because I have a bias term in the mix.  I'm in the process of migrating the library toward the method you describe.  

Brett
Title: Re: Arduino PID Library
Post by: Datapolo on Oct 16, 2009, 10:10 am
Brett, nice library and easy to use and tidies up my code nicely. Any news on the 'lite'version for basic functionality?

Cheers,
Mike
Title: Re: Arduino PID Library
Post by: br3ttb on Oct 16, 2009, 12:48 pm
Quote
Any news on the 'lite'version for basic functionality?


I've actually decided to ditch the idea of a lite version.  Instead I'm working on reducing the footprint of the full version.  The next revision of the library is almost done.  it uses integer math throughout, so it's about half the size and 10X faster.

Brett

[edit]On second thought I may be able to add some preprocessor flags to remove a lot of the extra functionality, resulting in a lite library.  I'll see what I can do[/edit]
Title: Re: Arduino PID Library
Post by: Datapolo on Oct 16, 2009, 12:57 pm
Sounds brill! Look forward to using it.

Mike
Title: Re: Arduino PID Library
Post by: pacofvf on Oct 25, 2009, 12:50 am
Before everything... It's just an advice,I don't want to look pretentious... :-[
I don't understand why you have problems making your PID faster....maybe because I've never used it :P . Sometimes the measurement is not at the same frequency than the Computing frequency, maybe you can't achieve the maximum speed because you are not using timer interrupts, and almost every PID ready-to-use software made by big companies uses timer interrupts. When you use timer interrupts the only limit is the clock speed and the timer's pre-escalator, ahh one last thing, the common acronyms are:
Set Point, (SP)
input: PV (Present Value)
output: MV(manipulated variable)
error
dt : (delta t) that's what you call calc period
Kp
Ki,Ti (I prefer Ki than Ti, where Ki=Kp/Ti)
Kd,Td (same with Kd, Kd=Kp*Td)

EDIT: PV: process variable
Title: Re: Arduino PID Library
Post by: retrolefty on Oct 25, 2009, 01:50 am
Quote
input: PV (Present Value)


I was taught that PV = Process Variable

Lefty

Title: Re: Arduino PID Library
Post by: Coding Badly on Oct 25, 2009, 02:44 am
Quote
I was taught that PV = Process Variable


Ditto.
Title: Re: Arduino PID Library
Post by: pacofvf on Oct 25, 2009, 03:11 am
Of course you are right, PV is process variable,  there is a present value, but that is not it.  ;) LOL
Title: Re: Arduino PID Library
Post by: br3ttb on Oct 26, 2009, 07:23 pm
Quote
I don't understand why you have problems making your PID faster


the issue isn't with when the computation occurs, it's with how long the computation takes when it's excecuted.  the computation fires at whatever interval the user desires (set by the SetSampleTime function)  the interrupt idea is interesting.  I'll have to look into that.

what I was talking about when I said "faster" was the computation itself.  the fewer processor cycles it takes to perform its calculation, the more time the arduino has to do other things.  and, just as a point of pride, I want the pid to be as efficient as possible.

as far as abbreviations, some are certainly more common than others, but they do vary from manufacturer to manufacturer.  off the top of my head:
Process Variable: PV, ME
SetPoint: SP, SV
Controller Output: CO,  CV, OUT, OT, OP.

dt is commonly used.  I settled on SampleTime (which is also commonly used) because I felt it was easier to understand.  

at any rate, give the library a shot!  I'd love to hear any more suggestions you might have.

Brett
Title: Re: Arduino PID Library
Post by: pacofvf on Oct 26, 2009, 11:56 pm
I've just looked at the source, and it looks very well, I can see that you have done something to prevent windup, I also preffer the Ideal form of the PID algorithm, everything is done efficiently (computing time-speaking), maybe millis() is taking too much, I don't see where else the code could be made more efficient, I will try to do it with interrupts and I will let you know if it works better, also I'm going to implement a kalman filter, so maybe that will be my first contribution to the arduino project, for those who don't know what I'm talking about, a kalman filter must be used with accelerometers and many other sensors..
Title: Re: Arduino PID Library
Post by: SteNull on Feb 05, 2010, 09:02 am
Thanx for an splendid lib, just the interrupt part missing for me to be 100% satisfied  8-) and maybe a Tracking value/Tracking active.

By the way PV is often referred as "Process Value" in engineering terms  ::)
Title: Re: Arduino PID Library
Post by: SteNull on Feb 18, 2010, 09:13 am
oh! and i wanna ad one more thing to my wish list, Master/Slave config for cascade regulation. :D
Title: Re: Arduino PID Library
Post by: Flotec on Feb 22, 2010, 06:25 pm
There is no problem to run it in master slave configuration. Just run it twice with different inputs. We have used this successfully.
Title: Re: Arduino PID Library
Post by: SteNull on Feb 22, 2010, 08:20 pm
ok nice. I had some ideas that master needed feedback from slave.
Title: Re: Arduino PID Library
Post by: jeff_witz on Feb 24, 2010, 01:44 pm
Last year I have trained a student during 3 month in order to make a complex regulation, for this purpose we have developed and implemented the Broïda method that allows to identity PID coefficient by measuring the response of the open loop system to square by measuring an amplitude and two time (at 0.28*deltaA* and 0.40*deltaA) it gives parameters depending of the kind of PID you want (with or without overshoot). This method seems to work up to the 6th order.
What do you think about coding this into the arduino platform ?
I think it can works on a lot of cases !
Title: Re: Arduino PID Library
Post by: LanceKifer on Jun 10, 2010, 05:05 pm
I am having trouble getting this PID to work with my application.

I am doing a research project where I am required to have a trough fill with water to sub - millimeter accuracy. I have determined the best way for me to do this is to use a laser pointing horizontally across the trough with a photodiode on the other side that the laser will be pointed at. When the water level becomes high enough the light beam will be broken and the voltage reading from the photodiode will drop.
I have a test circuit built (just the photodiode and a LED). With no obstruction between the LED and photodiode I get .013V from the photodiode, and that drops to .03V when you put an obstruction between the two.

So I edited the example code to this
Code: [Select]

#include <PID_Beta6.h>

/********************************************************
* PID Simple Example
* Reading analog input 0 to control analog PWM output 3
********************************************************/



//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,5,1,1);

void setup()
{
 //initialize the variables we're linked to
 Input = analogRead(0);
 Setpoint = 100;

 //turn the PID on
 myPID.SetMode(AUTO);
 
 Serial.begin(9600);
}

void loop()
{
 Input = analogRead(0);
 Serial.print("Output value: ");
 Serial.println(Output);
 myPID.Compute();
 analogWrite(3,Output);
}


I have this hooked up to an oscilloscope and I can see that the voltage will pulse, but I only see that happen right when I turn the Arduino on.
I am brand new to PID and Arduino, I spent all day reading with no luck.
Can anyone give me some advice on how to get this to work? I can't get the right tuning parameters or even know what they mean entirely or approximate values to use.
I am also unsure about the setpoint... does everyone else just randomly enter in values for these until they get the appropriate results or is there some method of finding the tuning parameters I need?
Title: Re: Arduino PID Library
Post by: pwillard on Jun 10, 2010, 07:59 pm

Setting PID values correctly is truly an art/science that does seem to get the experts some nice paychecks...

Your application seems more like an ON OFF design from what I can tell... the PID library works best if the feedback about what you are trying to measure/control is changing as it get close to set point.  Like a temperature reading, for example.

A PID tries to adjust it's output based on the input error...   but in your case... it sort of like playing 1...2...3... RED LIGHT!  if you have ever played that game... you might know what I mean...

You have an action with inertia... water feed.... and you want it to stop at an instant in time with little warning...  which sounds pretty hard to do to me...

I'm not claiming to be a PID expert though... maybe I can be corrected by one of the guru's here...
Title: Re: Arduino PID Library
Post by: KenH on Jun 13, 2010, 07:39 pm
You are wanting to fill with very much accuracy - does the tank drain any during this time?

You might consider measuring the level, then as the level approaches setpoint, start slowing the fill, until as setpoint is reached, the fill rate is at zero.  This method would use a PID controller.

BTW, this deserves a thread of it's own.

Good luck and have fun.

Ken H>
Title: Re: Arduino PID Library
Post by: GoZeR on Jun 22, 2010, 11:06 pm
Hey All,

This is my first post on the Fourms, but I have been playing with the Arudino for about 3 months now.

I am trying to learn PID using this library and have set up a circuit with a photoresistor and an LED.  This circuit works per the AnalogReadWrite built in example (changed to output on digital pin 3 however).  

I am having trouble making the PID library work at all.  I have set up the serial monitor to check the Output from the library, and I do not get a response.  Any help would be appreciated!


Code: [Select]

/********************************************************
* PID Simple Example
* Reading analog input 0 to control analog PWM output 3
********************************************************/

#include <PID_Beta6.h>

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,2,1);

void setup()
{
 //initialize the variables we're linked to
 Input = analogRead(0);
 Setpoint = 250;
 Serial.begin(9600);

 //turn the PID on
 myPID.SetMode(AUTO);
}

void loop()
{
 Input = analogRead(0);
 myPID.Compute();
 analogWrite(3,Output);
 Serial.println(Input);
 //Serial.println(Output);
}


Title: Re: Arduino PID Library
Post by: novice on Jun 24, 2010, 02:52 pm
Hi br3ttb,

I appreciate the work you have done on this topic.

If you make improvements like the using interrupts idea ... please keep us informed.
Title: Re: Arduino PID Library
Post by: LanceKifer on Jul 01, 2010, 04:23 pm
So I have got the PID working for my research project and I've got to say it's really helped a lot! I'm glad I considered the Arduino and this PID library, br3ttb this thing is awesome and very useful thanks for putting in the time to make this!

One concern though... I have to control a very very precise water pump that uses an analog input to control the speed of the pump.
http://www.instechlabs.com/OEM/pumps/p625.php
here is the pump... Do you think the PWM will be able to simulate the analog signal well enough for something like this? I guess I don't really know how closely the PWM simulates analog....

Thanks!
Title: Re: Arduino PID Library
Post by: br3ttb on Jul 01, 2010, 07:17 pm
Lance,
it's hard to know if you could "fake out" the pump. that is, it wants 0-? volts, while you'd be rapidly pulsing 5V.  it might be worth looking into a DAC (full disclosure, I'm a Chem-E, and my electrical advice should be viewed with suspicion.)

this may be a good place to start: http://www.arduino.cc/playground/Main/InterfacingWithHardware (scroll down to ADC/DAC)

Brett
Title: Re: Arduino PID Library
Post by: zer0vector on Jul 07, 2010, 04:14 pm
Brett,

I am building a simple temperature controller and I'm attempting to use your PID library.  The arduino reads the temperature from an LM35 and then outputs a slow PWM pulse to a solid state relay which will switch a standard electrical output.  I figure I'll plug in either a water bath heater or an electric smoker to the outlet, it seems like it should work just as well for either application.  Anyhow, I don't have much of the hardware yet (it's all on order), but I put together the code and I wanted to make sure I was utilizing the PID library correctly.  As you can see, I'm using the Timer1 library to run a 1 second PWM pulse.  I wouldn't think a heating element would need anything faster than that.  The PID output adjusts the duty cycle of the pulse:

Code: [Select]
#include <TimerOne.h>      
#include <PID_Beta6.h>

double Input, Output;                                  //PID variables
double Setpoint = 140;                               //PID setpoint in Farenheit

int thermPin = 0;                                    //input read pin for LM35 is Analog Pin 0
int controlPin = 9;                                           //Output PWM pin to Solid State Relay
                           
int val;

PID pid(&Input, &Output, &Setpoint, 3,4,1);            //Setup the PID calculation

void setup()
{

        pinMode(controlPin, OUTPUT);              //Setup the pin to control the relay

        pid.SetOutputLimits(0,1023);             //tell the PID to range the output from 0 to 1023
        Output = 1023;                                     //start the output at its max  and let the PID adjust it from there
        pid.SetMode(AUTO);                               //turn on the PID

     Timer1.initialize();                              //turn on the Timer, default 1 second frequency
     Timer1.pwm(controlPin, (int)Output);      //start PWM on pin 9 with a 100% duty cycle
 
}

void loop()
{
   
        val = analogRead(thermPin);                                                        //read the value of LM35
        Input = ((5.0 * val * 100.0 / 1023.0) * 9.0 / 5.0) + 32.0;       //convert voltage to temperature(F)

        pid.Compute();                                                      //give the PID the opportunity to compute if needed

     Timer1.setPwmDuty(controlPin, (int)Output);            //Set the duty cycle of the PWM according to the PID output

}
 

Any comments or tips would be very much appreciated.

-zv
Title: Re: Arduino PID Library
Post by: br3ttb on Jul 07, 2010, 04:32 pm
first off, there's a timer library?!  why did I not know this?

your code looks good.  be advised that you will need to adjust the tuning parameters (3,4,1) depending on what you're connected to.  it's unlikely that the default values will give you the response you want, or that the same values will work for both the water bath heater and smoker.

Brett
Title: Re: Arduino PID Library
Post by: zer0vector on Jul 07, 2010, 04:40 pm
Thanks for the quick reponse!

Yeah, I understand about the tuning parameters, I guess I'll just have to eyeball things until I get them set up right.  Like I said, nothing is built just yet, it's still diagrams and connections floating around in my head.  I've heard it'll probably take a long time (hours? days?) to tune due to the slow response of my systems (I'm thinking the smoker will probably be faster than the water bath though).  

The Timer1 library is something I stumbled upon while trying to figure out how to slow down the arduino PWM.  I think I understood the software "window" method that you wrote into the second example on the PID library page, but it seemed like there must be a better way.  I don't claim to understand it completely, but it seems like just the ticket for what I'm trying to do:

http://www.arduino.cc/playground/Code/Timer1

Thanks again!

-zv
Title: Re: Arduino PID Library
Post by: eecharlie on Jul 10, 2010, 10:10 am
Question: I'm trying to put together a PID controller with a sample period of 1min or greater, because I'm controlling a heating element or fridge compressor that I don't want to switch on and off like crazy.

I'm running into problems when I try to set the sample time above 32767ms... which caused me to poke around and notice that there seems to be a discrepancy between SetSampleTime(int) and unsigned long tSample. Am I missing something, or should SetSampleTime() take an unsigned long?

Thanks!
Title: Re: Arduino PID Library
Post by: zer0vector on Jul 10, 2010, 01:15 pm
I'm not sure about the sampletime issue, the author is in probably a better position to answer that, but for a long PWM frequency like that, it's probably best you just write a window-like function similar to the one in the second example on the PID library page (he uses a 4 second frequency I think).  It doesn't matter how fast it samples, only how fast the output is switched.

Set outputlimits to 0 to 59 and declare a windowstarttime = millis()/60000 to get it in minutes.

Then
Code: [Select]


if((millis()/60000)-windowstarttime > 60) windowstarttime += 60;

if(Output > (millis()/60000)-windowstarttime) digitalWrite(pin, HIGH);
else digitalWrite(pin, LOW);



I think that should do it.
Title: Re: Arduino PID Library
Post by: br3ttb on Jul 10, 2010, 01:33 pm
Quote
Am I missing something, or should SetSampleTime() take an unsigned long?


wow.  that is something I never thought would occur.  if I remeber correctly the backend variable (tSample) is an unsigned long because it's being compared to millis() and I wanted to make sure there were no casting issues.

in my experience, the only reason to make your sample time large is if you have to.  in plants with 20k pid loops there are legitimate processing issues, so they need to sacrifice on some loops and make the value bigger.  it didn't occur to me to allow it to be huge in the arduino setting.

instead of making the sample time really large, I'd recommend dealing with your concens on the Output side. you'll get your desired effect if you set up an output window as I did in Example 2 here: http://www.arduino.cc/playground/Code/PIDLibrary

you're free to set up a 10minute window, then have the pid tell you for how much of that window you should be on.  while the pid will be evaluating once a second (or every 30 seconds, whatever) your final control element will have a duty cycle of 10minutes.

and of course, the longer your duty cycle, the looser your control will be.  it's a balance you have to strike when you're using pid with an On/Off final control element.  that's why in industry it's generally connected to something that can range between 0-100%: valves, VFDs, gas flow to a burner, etc.

hope that helps,

Brett

Update: in the time it too me to craft my longwinded response, zer0vector jumped in with something much clearer.   ;)
Title: Re: Arduino PID Library
Post by: eecharlie on Jul 10, 2010, 06:39 pm
Ah, ok, I haven't seen that before and should have read the example even though it didn't initially appear relevant.

So with that window logic, over the course of one window period, you're comparing the PID commanded control to an increasing ramp function, and turning the heat on or off depending on whether it's above or below. In a pathological scenario, couldn't your system respond in a way that made the control oscillate as often as every PID cycle? Granted, you would have to have horribly mis-tuned the PID controller, but it seems like it's generally inviting Murphy's Law if something else funny happens (the fridge door is left open?). Is it not worth adding some logic to enforce, say, only 2 control signal transitions during one window period?

And perhaps a better question for the chemical engineer is, are there specific rules of thumb on time separation of turning a fridge compressor on and off?

Thanks for the fast response!

Title: Re: Arduino PID Library
Post by: br3ttb on Jul 11, 2010, 01:42 am
first off,  I don't have any refrigerator-specific on/off style experience. the closest I've come is cryogenic distillation (which is AWESOME by the way.)  that isn't an on/off process though.  I can speculate with the best of 'em though.

Quote
In a pathological scenario, couldn't your system respond in a way that made the control oscillate as often as every PID cycle?


I have actually encountered this, and not just with a poorly tuned controller.  if the door is opened at just the right moment, the pid output could move in such a way that the compressor chatters.

this poses a tricky problem.   your transition enforcement fix would work, but if you're in minute 2 of your time window when the door opens, you want to respond NOW.  if you're restricted, you have to wait 8 minutes before the compressor kicks in to correct.  if that's fine, you're done.  if not...

maybe you could tie into the door open sensor; the one that turns on the light?  it seems that that's the major disturbance to the fridge process.  if you know when the door is open you can make more informed choices (e.g. chatter mitigation when the door opens, but allowing it to act as it wants as soon as the door closes)
Title: Re: Arduino PID Library
Post by: eecharlie on Jul 12, 2010, 06:36 pm
I decided not to worry about minimum off or on time any further - I'm still leaving the thermostat my fridge came with intact, but cranked all the way up, and the the fridge cost less than my Arduino + OneWire temp sensor.

I agree that you'd want the compressor to turn on as soon as a disturbance is detected. At the same time, I'd like to insist on protecting against pathological disturbances. So, my solution allows a single "on" window during each PWM period, and that window is pushed to the end of the period. So, the compressor can turn on at any time if the PID suddenly increases the demanded control effort, and if the compressor is already on and the control saturates, the compressor will just stay on right into the next PWM period. It can also turn off ahead of original schedule if there's a negative disturbance. What do you think?

I'm currently cleaning up my code but I can post that if there's interest.
Title: Re: Arduino PID Library
Post by: br3ttb on Jul 12, 2010, 07:03 pm
Quote
my solution allows a single "on" window during each PWM period, and that window is pushed to the end of the period


I think that's an elegant solution for this process.  since your disturbance spikes will be increases in temperature, it's unlikely that you'll encounter a situation where the pid wants to suddenly back off.
Title: Re: Arduino PID Library
Post by: eecharlie on Jul 12, 2010, 07:59 pm
By the way, why on earth is the I parameter equal to the reciprocal of the gain as it appears in the PID algorithm? This cost me a few hours to figure out, especially since there's a conditional that checks for 0, further complicating the behavior...  could this at least be very clearly documented/pointed out? Did I miss it somewhere?
Title: Re: Arduino PID Library
Post by: br3ttb on Jul 12, 2010, 08:48 pm
Quote
By the way, why on earth is the I parameter equal to the reciprocal of the gain as it appears in the PID algorithm?


sorry for the confusion.  there's various forms of the pid equation.  (http://en.wikipedia.org/wiki/PID_controller scroll down to "Alternative nomenclature and PID forms")

they're mathematically equivalent, but the one listed as the "standard form" is the one i chose.  it's a little more work on the backend as you mentioned, but I find it easier to tune.  if you know the time constant of the process, you just make that the I term, then adjust P to get more aggressive or conservative)
Title: Re: Arduino PID Library
Post by: pwillard on Jul 15, 2010, 04:31 am
Brett, ZeroVector ... You  guys rock!

ZV, The Timer Library you used was the answer I'd been searching for.   I had no clue about it and it allowed me to have much better control over my Kiln temperature with correct PWM output settings.

I use an SSR to control a 2000 Degree F, 20 Amp Kiln.  I have now been able to reach my goal of 1290F and was hovering between +/- 6 degrees with minimal overshoot.  I was thrilled!
Title: Re: Arduino PID Library
Post by: sunjh831 on Jul 18, 2010, 08:26 am
Thanks!that is i 'm looking for.
Title: Re: Arduino PID Library
Post by: laxman098 on Jul 19, 2010, 08:21 am
I'll remove the base tags and leave the Playgound strings. :( ::)
Title: Re: Arduino PID Library
Post by: br3ttb on Jul 27, 2010, 08:00 pm
I started a new thread specific to PID Tuning:http:// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1280251311
Title: Re: Arduino PID Library
Post by: alicemirror on Aug 02, 2010, 08:42 am
Hi, sorry for this out-of-topic post, but I have no idea of the person I need to contact.  Do you have any idea or contact to post news topics on this area? I have new products recently developed, for Arduino board that I think are interesting for the community. What is the way?

Thank you in advance for your help. Enrico Miglino
conTESTI.eu electronics
http://www.contesti.eu/projects
Title: Re: Arduino PID Library
Post by: Tweaked on Aug 14, 2010, 10:44 pm
Brett,
If you're still considering an integer version, here's a technique I've found worthwhile.  Convert everything to long variable type, then assume 12 decimal places.  I use the following:

#define floatToFix(a) ((long)((a)*4096.0)) // mult by 2^12 to use floats in fixed point math
#define fixToFloat(a) ((float)((a)/4096.0)) // div by 2^12 to convert back to float
#define multFix(a,b) ((long)((((long)(a))*((long)(b)))>>12))

for analog reads,

 a1 = analogRead(pin);
 aIn1 = (long)a1 << 12; // add 12 decimal places

this approach speeds up the math without losing precision or accuracy.

hth,
Billy
Title: Re: Arduino PID Library
Post by: br3ttb on Aug 16, 2010, 03:02 pm
Quote
#define multFix(a,b) ((long)((((long)(a))*((long)(b)))>>12))


one of the main issues I've been wrestling with on the integer library is ensuring that overflow doesn't happen.  I haven't tried this, but if a and b were big enough wouldn't a*b overflow?
Title: Re: Arduino PID Library
Post by: Tweaked on Aug 16, 2010, 03:54 pm
Brett,
If this overflows, you could reduce the number of bit-shifts or use 'long long' int64_t data type which should not overflow.  I'm fumbling my way through modifying the library, and will email it to you for performance baseline testing for speed and accuracy.

Billy
Title: Re: Arduino PID Library
Post by: Tweaked on Aug 18, 2010, 04:28 pm
Brett,
The integer version of the library is functional, with one caveat... the output increments from 0 to 127 then increments from -128 to -1.  It's like the 8th bit is being used for sign.  I've renamed the library to PID_Beta6b in order to maintain the integrity of the original library and to make it easy to switch back and forth.  Here's the first half of the code:

Code: [Select]

#include <wiring.h>
#include <PID_Beta6b.h>


/* Standard Constructor (...)***********************************************
*    constructor used by most users.  the parameters specified are those for
* for which we can't set up reliable defaults, so we need to have the user
* set them.
***************************************************************************/
PID::PID(double *Input, double *Output, double *Setpoint, double Kc, double TauI, double TauD)
{

 PID::ConstructorCommon(Input, Output, Setpoint, Kc, TauI, TauD);  
 UsingFeedForward = false;
 PID::Reset();

 
}

/* Overloaded Constructor(...)**********************************************
*    This one is for more advanced users.  it's essentially the same as the
* standard constructor, with one addition.  you can link to a Feed Forward bias,
* which lets you implement... um.. Feed Forward Control.  good stuff.
***************************************************************************/
PID::PID(double *Input, double *Output, double *Setpoint, double *FFBias, double Kc, double TauI, double TauD)
{

 PID::ConstructorCommon(Input, Output, Setpoint, Kc, TauI, TauD);  
 UsingFeedForward = true;                        //tell the controller that we'll be using an external
 long myBias = (*FFBias * 4096.0);                  //bias, and where to find it
 PID::Reset();

}

/* ConstructorCommon(...)****************************************************
*    Most of what is done in the two constructors is the same.  that code
* was put here for ease of maintenance and (minor) reduction of library size
****************************************************************************/
void PID::ConstructorCommon(double *Input, double *Output, double *Setpoint, double Kc, double TauI, double TauD)
{
 PID::SetInputLimits(0, 1023);                        //default the limits to the
 PID::SetOutputLimits(0, 255);                        //full ranges of the I/O

 tSample = 1000;                              //default Controller Sample Time is 1 second

 PID::SetTunings(Kc, TauI, TauD);

 nextCompTime = millis();
 inAuto = false;
 myOutput = Output;
 myInput = Input;
 mySetpoint = Setpoint;
}


/* SetInputLimits(...)*****************************************************
*      I don't see this function being called all that much (other than from the
*  constructor.)  it needs to be here so we can tell the controller what it's
*  input limits are, and in most cases the 0-1023 default should be fine.  if
*  there's an application where the signal being fed to the controller is
*  outside that range, well, then this function's here for you.
**************************************************************************/
void PID::SetInputLimits(double INMin, double INMax)
{
     //after verifying that mins are smaller than maxes, set the values
     if(INMin >= INMax) return;

     //rescale the working variables to reflect the changes
     lastInput = multFix(lastInput,divFix(floatToFix(INMax - INMin),inSpan));
     accError = multFix(accError,divFix(floatToFix(INMax - INMin),inSpan));

     //make sure the working variables are
     //within the new limits
     if (lastInput > 1<<12) lastInput = 1<<12;
     else if (lastInput < 0L) lastInput = 0L;
     
     
           inMin = floatToFix(INMin);
     inSpan = floatToFix(INMax - INMin);
}

/* SetOutputLimits(...)****************************************************
*     This function will be used far more often than SetInputLimits.  while
*  the input to the controller will generally be in the 0-1023 range (which is
*  the default already,)  the output will be a little different.  maybe they'll
*  be doing a time window and will need 0-8000 or something.  or maybe they'll
*  want to clamp it from 0-125.  who knows.  at any rate, that can all be done
*  here.
**************************************************************************/
void PID::SetOutputLimits(double OUTMin, double OUTMax)
{
     //after verifying that mins are smaller than maxes, set the values
     if(OUTMin >= OUTMax) return;

     //rescale the working variables to reflect the changes
     lastOutput = multFix(lastOutput,divFix(floatToFix(OUTMax - OUTMin),outSpan));

     //make sure the working variables are
     //within the new limits
     if (lastOutput > 1<<12) lastOutput = 1<<12;
     else if (lastOutput < 0L) lastOutput = 0L;

     outMin = floatToFix(OUTMin);
     outSpan = floatToFix(OUTMax - OUTMin);
}

/* SetTunings(...)*************************************************************
* This function allows the controller's dynamic performance to be adjusted.
* it's called automatically from the constructor, but tunings can also
* be adjusted on the fly during normal operation
******************************************************************************/
void PID::SetTunings(double Kc, double TauI, double TauD)
{
     //verify that the tunings make sense
     if (Kc == 0.0 || TauI < 0.0 || TauD < 0.0) return;

     //we're going to do some funky things to the input numbers so all
     //our math works out, but we want to store the numbers intact
     //so we can return them to the user when asked.
     P_Param = Kc;
     I_Param = TauI;
     D_Param = TauD;
     
     //convert Reset Time into Reset Rate, and compensate for Calculation frequency
     double tSampleInSec = ((double)tSample / 1000.0);
     double tempTauR;
     if (TauI == 0)
           tempTauR = 0;
     else
           tempTauR = (1.0 / TauI) * tSampleInSec;  

     if (inAuto)
     {      //if we're in auto, and we just change the tunings, the integral term
           //will become very, very, confused (trust me.) to achieve "bumpless
           // transfer" we need to rescale the accumulated error.
           if(tempTauR != 0.0) //(avoid divide by 0)
                 accError = multFix(accError,divFix(multFix(kc,taur),floatToFix(Kc * tempTauR)));
           else
                 accError = 0L;
     }
     
     kc = floatToFix(Kc);
     taur = floatToFix(tempTauR);
     taud = floatToFix(TauD / tSampleInSec);
}

/* Reset()*********************************************************************
*      does all the things that need to happen to ensure a bumpless transfer
*  from manual to automatic mode.  this shouldn't have to be called from the
*  outside. In practice though, it is sometimes helpful to start from scratch,
*  so it was made publicly available
******************************************************************************/
void PID::Reset()
{

     if(UsingFeedForward)
       bias = divFix((*myBias - outMin),outSpan);
     else
       bias = divFix((floatToFix(*myOutput) - outMin),outSpan);
     
       lastOutput = (long)bias;
     lastInput = divFix((floatToFix(*myInput) - inMin),inSpan);

     // - clear any error in the integral
     accError = 0L;

}

/* SetMode(...)****************************************************************
* Allows the controller Mode to be set to manual (0) or Automatic (non-zero)
* when the transition from manual to auto occurs, the controller is
* automatically initialized
******************************************************************************/
void PID::SetMode(int Mode)
{
     if (Mode!=0 && !inAuto)
     {      //we were in manual, and we just got set to auto.
           //reset the controller internals
           PID::Reset();
     }
     inAuto = (Mode!=0);
}

/* SetSampleTime(...)*******************************************************
* sets the frequency, in Milliseconds, with which the PID calculation is performed      
******************************************************************************/
void PID::SetSampleTime(int NewSampleTime)
{
     if (NewSampleTime > 0)
     {
           //convert the time-based tunings to reflect this change
           taur = multFix(taur,floatToFix((double)NewSampleTime/(double)tSample));
           accError = multFix(accError,floatToFix((double)tSample/(double)NewSampleTime));
           taud = multFix(taud,floatToFix((double)NewSampleTime/(double)tSample));
           tSample = (unsigned long)NewSampleTime;
     }
}
Title: Re: Arduino PID Library
Post by: Tweaked on Aug 18, 2010, 04:32 pm
And here's the last portion (wouldn't all fit in one post):
Code: [Select]
/* Compute() **********************************************************************
*     This, as they say, is where the magic happens.  this function should be called
*   every time "void loop()" executes.  the function will decide for itself whether a new
*   pid Output needs to be computed
*
*  Some notes for people familiar with the nuts and bolts of PID control:
*  - I used the Ideal form of the PID equation.  mainly because I like IMC
*    tunings.  lock in the I and D, and then just vary P to get more
*    aggressive or conservative
*
*  - While this controller presented to the outside world as being a Reset Time
*    controller, when the user enters their tunings the I term is converted to
*    Reset Rate.  I did this merely to avoid the div0 error when the user wants
*    to turn Integral action off.
*    
*  - Derivative on Measurement is being used instead of Derivative on Error.  The
*    performance is identical, with one notable exception.  DonE causes a kick in
*    the controller output whenever there's a setpoint change. DonM does not.
*
*  If none of the above made sense to you, and you would like it to, go to:
*  http://www.controlguru.com .  Dr. Cooper was my controls professor, and is
*  gifted at concisely and clearly explaining PID control
*********************************************************************************/
void PID::Compute()
{
     justCalced=false;
     if (!inAuto) return; //if we're in manual just leave;

     unsigned long now = millis();

     //millis() wraps around to 0 at some point.  depending on the version of the
     //Arduino Program you are using, it could be in 9 hours or 50 days.
     //this is not currently addressed by this algorithm.

     //here's an attempt to address the millis() wrap issue:

     if (now < tSample) nextCompTime = tSample;
     
                                                     
     //...Perform PID Computations if it's time...
     if (now>=nextCompTime)                                          
     {
           
           //pull in the input and setpoint, and scale them into percent span
           long scaledInput = divFix((floatToFix(*myInput) - inMin),inSpan);
           if (scaledInput>(1<<12)) scaledInput = 1<<12;
           else if (scaledInput<0L) scaledInput = 0L;

           long scaledSP = divFix((floatToFix(*mySetpoint) - inMin),inSpan);
           if (scaledSP>(1<<12)) scaledSP = 1<<12;
           else if (scaledSP<0L) scaledSP = 0L;
           
           //compute the error
           long err = scaledSP - scaledInput;
           
           // check and see if the output is pegged at a limit and only
           // integrate if it is not. (this is to prevent reset-windup)
           if (!(lastOutput >= 1<<12 && err>0L) && !(lastOutput <= 0L && err<0L))
           {
                 accError = accError + err;
           }                                                

           // compute the current slope of the input signal
           long dMeas = (scaledInput - lastInput);      // we'll assume that dTime (the denominator) is 1 second.
                                         // if it isn't, the taud term will have been adjusted
                                         // in "SetTunings" to compensate

           //if we're using an external bias (i.e. the user used the
           //overloaded constructor,) then pull that in now
           if(UsingFeedForward)
           {
                 bias = divFix((*myBias - outMin),outSpan);
           }


           // perform the PID calculation.  
           long output = bias + multFix(kc,(err + multFix(taur,accError) - multFix(taud,dMeas)));

           //make sure the computed output is within output constraints
           if (output < 0L) output = 0L;
           else if (output > 1<<12) output = 1<<12;

           lastOutput = output;            // remember this output for the windup
                                   // check next time            
           lastInput = scaledInput;      // remember the Input for the derivative
                                   // calculation next time

           //scale the output from percent span back out to a real world number
               *myOutput = fixToFloat(multFix(output,outSpan) + outMin);

           nextCompTime += tSample;                        // determine the next time the computation
           if(nextCompTime < now) nextCompTime = now + tSample;      // should be performed      

           justCalced=true;  //set the flag that will tell the outside world that the output was just computed
     }                                                


}


/*****************************************************************************
* STATUS SECTION
* These functions allow the outside world to query the status of the PID
*****************************************************************************/

bool PID::JustCalculated()
{
     return justCalced;
}
int PID::GetMode()
{
     if(inAuto)return 1;
     else return 0;
}

double PID::GetINMin()
{
     return fixToFloat(inMin);
}
double PID::GetINMax()
{
     return fixToFloat(inMin + inSpan);
}
double PID::GetOUTMin()
{
     return fixToFloat(outMin);
}
double PID::GetOUTMax()
{
     return fixToFloat(outMin+outSpan);
}
int PID::GetSampleTime()
{
     return tSample;
}
double PID::GetP_Param()
{
     return P_Param;
}
double PID::GetI_Param()
{
     return I_Param;
}

double PID::GetD_Param()
{
     return D_Param;
}


ps. I also made a feeble stab at millis() rollover protection, not sure if it'll work...
Title: Re: Arduino PID Library
Post by: Tweaked on Aug 18, 2010, 04:36 pm
And lastly, the modified header file:
Code: [Select]
#ifndef PID_Beta6b_h
#define PID_Beta6b_h

#define floatToFix(a) ((long)((a)*4096.0))                   // mult by 2^12 to use floats in fixed point math
#define fixToFloat(a) ((double)((a)/4096.0))                   // div by 2^12 to convert back to float
#define multFix(a,b) ((long)((((long)(a))*((long)(b)))>>12))    // bit-shift right 12 to maintain 12 assumed decimal places
#define divFix(a,b) ((long)(((long)(a)<<12)/((long)(b))))        // make Numerator 8:24 int before dividing

class PID
{


 public:

 #define AUTO      1
 #define MANUAL      0
 #define LIBRARY_VERSION      0.6b

 //commonly used functions **************************************************************************
   PID(double*, double*, double*,        // * constructor.  links the PID to the Input, Output, and
       double, double, double);          //   Setpoint.  Initial tuning parameters are also set here

   PID(double*, double*, double*,        // * Overloaded Constructor.  if the user wants to implement
       double*, double, double, double); //   feed-forward

   void SetMode(int Mode);               // * sets PID to either Manual (0) or Auto (non-0)

   void Compute();                       // * performs the PID calculation.  it should be
                                         //   called every time loop() cycles. ON/OFF and
                                         //   calculation frequency can be set using SetMode
                                         //   SetSampleTime respectively

   void SetInputLimits(double, double);  //Tells the PID what 0-100% are for the Input

   void SetOutputLimits(double, double); //Tells the PID what 0-100% are for the Output


 //available but not commonly used functions ********************************************************
   void SetTunings(double, double,       // * While most users will set the tunings once in the
                   double);              //   constructor, this function gives the user the option
                                         //   of changing tunings during runtime for Adaptive control

   void SetSampleTime(int);              // * sets the frequency, in Milliseconds, with which
                                         //   the PID calculation is performed.  default is 1000

   void Reset();                         // * reinitializes controller internals.  automatically
                                         //   called on a manual to auto transition

   bool JustCalculated();                // * in certain situations, it helps to know when the PID has
                                         //   computed this bit will be true for one cycle after the
                                         //   pid calculation has occurred
   

  //Status functions allow you to query current PID constants ***************************************
   int GetMode();
   double GetINMin();
   double GetINMax();
   double GetOUTMin();
   double GetOUTMax();
   int GetSampleTime();
   double GetP_Param();
   double GetI_Param();
   double GetD_Param();


 private:

   void ConstructorCommon(double*, double*, double*,           // * code that is shared by the constructors
       double, double, double);

  //scaled, tweaked parameters we'll actually be using
   long kc;                      // * (P)roportional Tuning Parameter
   long taur;                    // * (I)ntegral Tuning Parameter
   long taud;                    // * (D)erivative Tuning Parameter

  //nice, pretty parameters we'll give back to the user if they ask what the tunings are
   double P_Param;
   double I_Param;
   double D_Param;


   double *myInput;              // * Pointers to the Input, Output, and Setpoint variables
   double *myOutput;             //   This creates a hard link between the variables and the
   double *mySetpoint;           //   PID, freeing the user from having to constantly tell us
                                 //   what these values are.  with pointers we'll just know.

   long *myBias;                 // * Pointer to the External FeedForward bias, only used
                                 //   if the advanced constructor is used
   bool UsingFeedForward;        // * internal flag that tells us if we're using FeedForward or not

   unsigned long nextCompTime;   // * Helps us figure out when the PID Calculation needs to
                                 //   be performed next
                                 //   to determine when to compute next
   unsigned long tSample;        // * the frequency, in milliseconds, with which we want the
                                 //   the PID calculation to occur.
   bool inAuto;                  // * Flag letting us know if we are in Automatic or not

   long lastOutput;              // * remembering the last output is used to prevent
                                 //   reset windup.
   long lastInput;               // * we need to remember the last Input Value so we can compute
                                 //   the derivative required for the D term
   long accError;                // * the (I)ntegral term is based on the sum of error over
                                 //   time.  this variable keeps track of that
   long bias;                    // * the base output from which the PID operates
   

   
   long inMin, inSpan;           // * input and output limits, and spans.  used convert
   long outMin, outSpan;         //   real world numbers into percent span, with which
                                 //   the PID algorithm is more comfortable.

   bool justCalced;              // * flag gets set for one cycle after the pid calculates
};
#endif

Title: Re: Arduino PID Library
Post by: juliandasilva on Sep 16, 2010, 04:24 pm
Yesterday, we uploaded two post by mistake in the "Processing Front-End for the PID Library" thread. Those posts should be here:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1243714052/36#36
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1243714052/37#37

As explained there, we made minor modifications to the PID, reducing a bit the flash footprint, and adding some small improvements for the compiler (such as const and inlines), and eliminating one of the constructors and the ConstructorCommon member by adding a default value to a param.

Regards,
Julián
http://robotgroup.com.ar
Title: Re: Arduino PID Library
Post by: kaya13 on Nov 01, 2010, 02:12 pm
     Hi guys, and Brett. First of all thank you for your huge contributions on PID library, it was just the thing needed. Im kind of new to Arduino and PID's too. I have designed PID compensators in control fundamentals class but newer used it as a code on a real system :)
    I have a little problem using PID lib. Its actually very user friendly but im trying to control my quadrotor using pid lib.  I use pitch, roll angle values from Ardu Imu V2 as an inputs of PID, trying to get output values as esc pwm's. I dont have problems reading from Imu but i dont get output changes. IMU values change like 300 times but output changes 1 or 2 times, or  never change sometimes. I have changed the sampiling period of PID a few times but i couldnt find the solution any way. Any suggestions on that ? Thanks...



Update :
 I think i found my mistake, sorry about that. I wasnt careful about PID input variables. I use integer for my pitch, roll, yaw values which is ok for me. My ( int ) pitch doesnt match PID ( double ) Input so PID.Compute calculate just once or a few times.

So, now the question is do we have stable working int version of PID lib ? Or i guess i need a conversion. Thanks...
Title: Re: Arduino PID Library
Post by: gadman58 on Nov 06, 2010, 03:43 pm
I would also like to say many thanks to Brett and all those who have commented and gave suggestion in this forum.
I am new as well just got my first Arduino UNO 3 weeks ago.

My wife bought a used manual kiln for doing fused glass and I was able to convert it to a controller base one, using your PID library.
I ended up using this formula to get the setpoint to work for both going up in temperature and down, for the annealing phase.

Code: [Select]
Setpoint = (((double)(millis()-RampStartTime))/(m_AmntTime*3600000)*m_TempDif)+m_StartTemp;


Thanks again
Glenn
Title: Re: Arduino PID Library
Post by: zuldelacueva on Nov 07, 2010, 08:50 am
very interesting
Title: Re: Arduino PID Library
Post by: zer0vector on Nov 19, 2010, 02:37 am
Hey all,

I've finished up the code for a standalone sous vide controller with a small LCD screen and a 3-button interface.  I'm using the one-wire DS18B20 temperature sensor for input and a solid state relay receives the output.  

All the parts are here, and everything works, I just need to put it together now.  I figured I'd post the code for others to critique:

Code: [Select]

#include <TimerOne.h>
#include <PID_Beta6.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>
#include <Button.h>

#define ONE_WIRE_BUS 9

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int controlPin = 10;

int upButtonPin = 6;
int downButtonPin = 7;
int selButtonPin = 8;

Button upButton = Button(upButtonPin, PULLDOWN);
Button downButton = Button(downButtonPin, PULLDOWN);
Button selButton = Button(selButtonPin, PULLDOWN);

double params[4] = {140, 90,300,0};
char param_char[4] = {'S', 'P', 'I', 'D'};
double increment[4] = {1, 5, 5, 5};

double Input, Output;                            
double Setpoint = params[0];                          
double Bias = 200;

float temperature = 0;                            
int menuPos = 0;
int loopDelay = 0;

PID pid(&Input, &Output, &Setpoint, &Bias, params[1], params[2], params[3]);

void setup()
{
 /*Serial.begin(9600);*/
 pinMode(controlPin, OUTPUT);  
 
 sensors.begin();

 pid.SetOutputLimits(0,1023);  
 Output = 0;
 pid.SetMode(AUTO);

 Timer1.initialize();
 Timer1.pwm(controlPin, Output);
 

 lcd.begin(16, 2);
 lcd.clear();
 lcd.print("Arduino PID");
 lcd.setCursor(0,1);
 lcd.print("Controller");
 /*Serial.print("Arduino PID Controller\n");*/
 delay(5000);
 lcd.clear();
}

void loop()
{
 sensors.requestTemperatures();
 temperature = sensors.getTempFByIndex(0);

 Input = (double)temperature;
 if(Setpoint - Input > 3){
   Setpoint -= 5;
   pid.Compute();
   Setpoint += 5;
 }
 else{
   pid.Compute();
 }
 
 Timer1.setPwmDuty(controlPin, (int)Output);
 delay(loopDelay);
 
 lcd.setCursor(0,0);
 lcd.print("T:");
 lcd.print(temperature,1);
 lcd.setCursor(9,1);
 lcd.print("O:");
 lcd.print(Output,0);
 lcd.setCursor(0, 1);
 lcd.print("S:");
 lcd.print(Setpoint,0);

 /*Serial.print("T:");
 Serial.print(temperature);
 Serial.print("\t");
 Serial.print("O:");
 Serial.print(Output,0);
 Serial.print("\t");
 Serial.print("S:");
 Serial.print(Setpoint,0);
 Serial.print("\n");*/
 
 if(selButton.uniquePress()) {
   lcd.clear();
   for(menuPos = 0; menuPos < 4; ){
     lcd.setCursor(0,0);
     lcd.print(param_char[menuPos]);
     lcd.print(": ");
     lcd.print(params[menuPos],0);

     /*Serial.print(param_char[menuPos]);
     Serial.print(": ");
     Serial.print(params[menuPos],0);      
     Serial.print("\n");*/

     if (upButton.uniquePress()) {        
       params[menuPos] += increment[menuPos];
     }
     if (downButton.uniquePress()) {        
       params[menuPos] -= increment[menuPos];
     }
     if(selButton.uniquePress()) {
       menuPos++;
       lcd.clear();
     }
   }
   Setpoint = params[0];
   pid.SetTunings(params[1], params[2], params[3]);
   lcd.clear();
 }
}  


All the commented out serial stuff is from testing before my LCD came.  Let me know if you have any questions or advice on something I could do better.

PS - I just realized scanning my code here that the menu loop keeps the PID from calculating, so if it was left in that mode the output would never change.  I guess I'll work a button timer in there to jump back to the main loop if you don't do anything for 5 seconds or so.


Title: Re: Arduino PID Library
Post by: AlanHacked on Nov 21, 2010, 09:26 am
Hi, I just got my Arduino last week and have been playing around with it. Im working on part of a robot that is a turntable. Basically a disc with a friction drive (1 DC motor) that needs to rotate to specific locations. I had previously coded it in basic with my own PID but i wanted it to work with my new arduino. I ran across your library and had some questions. How is it that the direction of the motor is changed? not sure if i missed something but i cant seem to find where to define a pin for direction of the motor. The code i have so far is below, the position of the turntable is read with a potentiometer. Any help is appreciated.  :D

Code: [Select]
/*
Created by Alan Sanchez 2010
*/

#include <PID_Beta6.h>
double Setpoint, Input, Output;
PID pid(&Input, &Output, &Setpoint,5,30,1);


//VARIABLES//

int motorpwm = 3;
int direc = 2;
int button = 12;
int pos;
int photo;

void setup() {
 
 Serial.begin(9600);
 pinMode(motorpwm, OUTPUT);
 //pinMode(direc, OUTPUT);
 pinMode(button, INPUT);    //declare button pin as input
 Input = analogRead(A0);
 Output = 0;
 pid.SetOutputLimits(0,500);
 pid.SetMode(AUTO);       //turn on PID
 Setpoint = 313;
 
}


void loop() {
 
 digitalWrite(direc, HIGH);
     if (digitalRead(button) == HIGH){       //if button is pressed go to end()
         Serial.println("button has been pressed");
           while(1) {
               //pos = analogRead(A0);      //read pot in analog pin A0
               //photo = analogRead(A1);    //read photosensor in analog pin A1
           
               Input = analogRead(A0);
               pid.Compute();
               analogWrite(motorpwm, Output/4);
           
           Serial.print("Pot Value = ");   //print pot value
           Serial.print(Input, DEC);
           Serial.print("     ");
           Serial.print("Output = "); //print photo value
           Serial.println(Output/4, DEC);
           }
   analogWrite(motorpwm, 0);
     }
}


Title: Re: Arduino PID Library
Post by: br3ttb on Nov 21, 2010, 02:05 pm
Quote
How is it that the direction of the motor is changed?


I understand your question to mean that the motor seems to be going backwards, forcing you away from setpoint.  if this is the case, you need to change the sign of the P term.  so instead of:
Code: [Select]
PID pid(&Input, &Output, &Setpoint,5,30,1);


you want:
Code: [Select]
PID pid(&Input, &Output, &Setpoint,-5,30,1);
Title: Re: Arduino PID Library
Post by: AlanHacked on Nov 21, 2010, 05:41 pm
no, what i meant to ask is how does the PID switch the direction of the motor to deal with overshoot. The way it is right now it just stops but because of inertia it wont stop at the correct spot, and if it goes past the set point there is no bringing it back.
Title: Re: Arduino PID Library
Post by: AlanHacked on Nov 21, 2010, 06:03 pm
actually if it isnt supported, i guess what i could do is switch direction depending on error something like:


Code: [Select]


if (Error<0) {
Pterm = -5
else if (Error>0)
Pterm = 5
}



Title: Re: Arduino PID Library
Post by: br3ttb on Nov 21, 2010, 06:44 pm
Quote
no, what i meant to ask is how does the PID switch the direction of the motor to deal with overshoot

ah.  in that case, take a look at  Post 16  (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1226431507/16#16) on this thread.  maybe that will help.

Brett
Title: Re: Arduino PID Library
Post by: AlanHacked on Nov 21, 2010, 09:56 pm
that works! thank you

this is what the code looks like now
Code: [Select]
/*
Created by Alan Sanchez 2010
*/

#include <PID_Beta6.h>
double Setpoint, Input, Output;
PID pid(&Input, &Output, &Setpoint,3,30,5);


//VARIABLES//

int motorpwm = 5;
int direc = 4;
int button = 2;
int pos;
int photo;

void setup() {
 
 Serial.begin(9600);
 pinMode(motorpwm, OUTPUT);
 pinMode(direc, OUTPUT);
 pinMode(button, INPUT);    //declare button pin as input
 Input = analogRead(A0);
 Output = 0;
 pid.SetOutputLimits(-400,400);
 pid.SetMode(AUTO);       //turn on PID
 Setpoint = 313;
 
}


void loop() {
 
 //digitalWrite(direc, HIGH);
     if (digitalRead(button) == HIGH){       //if button is pressed go to end()
         Serial.println("button has been pressed");
           while(1) {
               //pos = analogRead(A0);      //read pot in analog pin A0
               //photo = analogRead(A1);    //read photosensor in analog pin A1
           
               Input = analogRead(A0);
               pid.Compute();
             
               if (Output < 0) {
               digitalWrite(direc, LOW);
               }
               else if (Output>0) {
                 digitalWrite(direc, HIGH);
               }
               else {
                 Output=0;
               }
               int drive = Output/4;
               analogWrite(motorpwm, drive);
           
          Serial.print("Pot Value = ");   //print pot value
          Serial.print(Input, DEC);
          Serial.print("     ");
          Serial.print("Output = "); //print photo value
          Serial.println(drive, DEC);
           }
     }
}




all thats left to do is fine tune the PID. Again thanks for the library, it saves soooo much time.
Title: Re: Arduino PID Library
Post by: AlanHacked on Nov 22, 2010, 08:29 am
actually, ive been noticing that the Output value doesnt change when i set ranges for output from -255 to 255 . it just goes to max or min no matter what the gains are. as soon as comment out the limits it starts working again. any idea what might be causing this?

code below:
Code: [Select]
/*
Created by Alan Sanchez 2010
*/

#include <PID_Beta6.h>
double Setpoint, Input, Output;
PID pid(&Input, &Output, &Setpoint,4,35,10);


//VARIABLES//

int motorpwm = 5;
int direc = 4;
int button = 2;
int pos;
int photo;

void setup() {
 
 Serial.begin(9600);
 pinMode(motorpwm, OUTPUT);
 pinMode(direc, OUTPUT);
 pinMode(button, INPUT);    //declare button pin as input
 Input = analogRead(A0);
 Output = 0;
 pid.SetInputLimits(0,1023);
 pid.SetOutputLimits(-255,255);
 pid.SetMode(AUTO);       //turn on PID
 Setpoint = 313;
 
}


void loop() {
 
 //digitalWrite(direc, HIGH);
     if (digitalRead(button) == HIGH){       //if button is pressed go to end()
         Serial.println("button has been pressed");
           while(1) {
               //pos = analogRead(A0);      //read pot in analog pin A0
               //photo = analogRead(A1);    //read photosensor in analog pin A1
           
               Input = analogRead(A0);
               pid.Compute();
             
               if (Output < 0) {
               digitalWrite(direc, LOW);
               }
               else if (Output>0) {
                 digitalWrite(direc, HIGH);
               }
               else {
                 Output=0;
               }
               int drive = abs(Output)/4;
               analogWrite(motorpwm, drive);
           
          //Serial.print("Pot Value = ");   //print pot value
          Serial.println(Input, DEC);
          //Serial.print("     ");
          //Serial.print("Drive = "); //print photo value
          Serial.println(Output, DEC);
          //Serial.print("     ");
          //Serial.print("Direc = "); //print photo value
          //Serial.println(direc, DEC);          
         }
     }
}


Title: Re: Arduino PID Library
Post by: richardkalaf on Nov 24, 2010, 06:41 pm
Hello Brett,

First of all GREAT WORK!!

Your library has saved me a lot of time.

But i´m having a small problem. For some reason using the Processing Front End, everything works great, but when i try to edit manually the values and click to send it to Arduino, it just comes back to the original values.

As i couldn´t figure out what is wrong, since the communication seems to be ok, and i can see Processing IS sending something to arduino, and the arduino portion seems to be alright.. i had the ideia to have the best of both worlds anyway. I addes 3 pots to manually contro e P.I and D values. I would watch the values and the result on the Processing Front End, and manually adjust the values via the potentiometers.

The only problem now is that for some reason, pid.SetTunings doesn´t seem to change the values correctly.

Remember the Example 2 ? Well i´m doing exactly the same thing exept for the setpoint ramp stuff. Mine´s fixed.

Here´s the relevant portion of my code. I´m using it to stabilize de Y axis of a UAV. It´s loaded into a test platform where i have a horizontal arm being held in place by a fixed vertical arm. It has a motor on each side, and they try to keep the arm stable and leveled. Any disturbances should be imediately compensated.

Code: [Select]
double Input, Output, Setpoint;
PID pid(&Input, &Output, &Setpoint, 3,9,3);
// PID pid(&Input, &Output, &Setpoint,potPin1,potPin2,potPin3);
double Outputinv;
unsigned long serialTime; //this will help us know when to talk with processing

const int buttonPin = 52;
int buttonState = 0;

void setup() {
 static int i;
 Serial.begin(57600);
  pinMode(13, OUTPUT);
  servoL.attach(2);
  servoR.attach(3);
 pinMode(buttonPin, INPUT);

 
  pid.SetInputLimits(-80,89);
  pid.SetOutputLimits(900,1200); //tell the PID to range the output from 1000 to 2000
  Output = 900; //start the output at min and let the PID adjust it from there
 
  pid.SetMode(AUTO); //turn on the PID
  pid.SetSampleTime(10);
Setpoint = 57;

Code: [Select]
void loop() {
 
  buttonState = digitalRead(buttonPin);
 if (buttonState == HIGH) {  
   initmotors();  
   delay(2000);
 }
 
 getEstimatedInclination();

pot1Value = analogRead(potPin1);
  pot1Value = pot1Value /100;
   pot2Value = analogRead(potPin2);
  pot2Value = pot2Value /100;
   pot3Value = analogRead(potPin3);
  pot3Value = pot3Value /100;

pid.SetTunings(potPin1,potPin2,potPin3);

Input = (RwEst[1]*100);
  pid.Compute();
  servoR.writeMicroseconds(Output);
  Outputinv = map(Output, 900, 1200, 1200, 900);
  servoL.writeMicroseconds(Outputinv);
 
    if(millis()>serialTime)
 {
   SerialReceive();
   SerialSend();
   serialTime+=500;
 }
 
 
}


Any help would be much appreciated.


Title: Re: Arduino PID Library
Post by: AlanHacked on Nov 24, 2010, 06:47 pm
hello everyone, I gave up using the library for my DC motor project. I was just wasting too much time and getting nowhere. However I wrote my own PID. Code is attached below for anyone to use if they run into the same problems. It will allow you to switch motor directions to do precise positioning with a DC motor, all you have to do is adjust the gains to suit your needs.

-Alan

Code: [Select]
/*
Created by Alan Sanchez 2010
*/

//VARIABLES//

 int motorpin = 5;
 int drive;
 int direc = 4;
// int direc;
 int button = 2;
 int pos;
 int photo;
 int target = 313;
 
//PID Variables//

 int kp = 90;
 int ki = 2;
 int kd = 100;
 int error;
 int last;
 int P;
 int I;
 int D;
 int integral = 0;
 int inthresh = 25;
 int nMet;
 int nMetReq = 5;
 int Emax = 2;
 int Vmax = 2;
 int V;
 
void setup() {
 
 Serial.begin(9600);
 pinMode(motorpin, OUTPUT);
 pinMode(direc, OUTPUT);
 pinMode(button, INPUT);    //declare button pin as input

}


void loop() {
// direc = HIGH;
 //digitalWrite(direc, HIGH);
     analogWrite(motorpin,0);
     int state = digitalRead(button);
     if (state == HIGH){       //if button is pressed begin PID
         Serial.println("button has been pressed");
           while(1) {
               pos = analogRead(A0);      //read pot in analog pin A0
               photo = analogRead(A1);    //read photosensor in analog pin A1        
               drive = PID();             //get drive val from PID
               analogWrite(motorpin, drive); //send PID drive command to motor
               Serial.print("nMet =    ");
               Serial.println(nMet,DEC);
               //Check nMet, if satisfied end program.
               if(abs(error) < Emax && abs(V) < Vmax) {
                 nMet = nMet+1;
                 if(nMet > nMetReq) {
                   analogWrite(motorpin, 0);
                   Serial.println("Target reached :D");
                   end();
                 }
               }
                   
          //Serial.print("Pot Value = ");   //print pot value
          //Serial.print(pos, DEC);
          //Serial.print("     ");
          Serial.print("Drive = "); //print drive value
          Serial.print(drive, DEC);
          Serial.print("     ");
          Serial.print("Direc = "); //print direc
          Serial.println(direc, DEC);          
           }
       
     }
}

//PID: Calculates PID drive value.
int PID()
{
   //Serial.println("inside PID");
   error = target-pos;
   //Serial.print("abs(error)=");
   //Serial.println(abs(error),DEC);
   if (abs(error) < inthresh) {
   integral = integral + error;
   }
   else {
     integral = 0;
   }
   //Serial.println(integral,DEC);
  P = error*kp;
  I = integral*ki;
  D = V*kd;
  drive = P+I+D;
    Serial.print("P+I+D=  ");
    Serial.println(drive, DEC);
    if (drive<0) {
      digitalWrite(direc, LOW);
    }
    else if (drive>0) {
      digitalWrite(direc, HIGH);
    }
    else {
      drive=0;
    }
    Serial.print("direc_inside=  ");
    Serial.println(direc, DEC);
 drive = abs(drive)/50;
  Serial.print("drive1=  ");
    Serial.println(drive, DEC);
 drive = min(drive, 170);
    Serial.print("drive2=  ");
    Serial.println(drive, DEC);
 drive = max(drive, 80);
    Serial.print("drive 3  ");
    Serial.println(drive, DEC);
 last = pos;
 return(drive);
}

//end program
int end() {
 Serial.println("Program will now end");
 while(1);
}

Title: Re: Arduino PID Library
Post by: richardkalaf on Nov 26, 2010, 04:51 am
Never mind, i got it to work. Still don´t know what was causing the error though. I just deleted that portion of the code and re-typed it, and when i tried to compile, it did with no errors this time. Go figure.

Anyways, i´m still trying to get the tunings right. That is one hard task to acomplish.

Here´s my first test with manual tuning:

http://www.youtube.com/watch?v=VYc8Z-bmEcs

I wonder if i ever am going to see that "axis" stable.

Either i am too "intelectually challenged" , or there´s a looot of smart guys out there, because so many people seem to have built this kind of UAV´s seemingly with no big problems at all..

Maybe there´s an easier implementation of PID for a UAV that works better, with a fast response time and an easier way of tuning it.

One more thing, during the tests i have noticed that after a few minutes of continuous running of the engines, they start to stress out and they characteristics change a bit (sensitivity to commands and stuff). Isn´t there a way of implementing some kind of "dynamic tuning" system?

Thanks !
Title: Re: Arduino PID Library
Post by: fiveohhh on Jan 08, 2011, 06:35 am
Quote
Hey all,

I've finished up the code for a standalone sous vide controller with a small LCD screen and a 3-button interface.  I'm using the one-wire DS18B20 temperature sensor for input and a solid state relay receives the output.  


I'm planning on doing the same thing in a few weeks here(with an lm335 though).  What did you do to waterproof the sensor?
Title: Re: Arduino PID Library
Post by: bubulindo on Jan 08, 2011, 10:35 am
Quote

Anyways, i´m still trying to get the tunings right. That is one hard task to acomplish.


There are some manuals around the web. Have you got feedback sent to the computer so you can see the response and measure overshoot, settling time, etc, etc??

I find this one to be acceptable. http://www.expertune.com/tutor.html
Wikipedia's article is a good reference for this also.

Also, if you go through ATMEL's application notes, they have application note 221 for AVR that is the implementation of a PID in C for AVR. You can get some info from that too.
Title: Re: Arduino PID Library
Post by: kanne on Jan 08, 2011, 10:47 am
There are some interger versions available e.g. google for:
AVR221: Discrete PID controller on tinyAVR and megaAVR devices
Title: Re: Arduino PID Library
Post by: richardkalaf on Jan 08, 2011, 03:58 pm
Thanks for the replies guys!

As a matter of fact i´ve found out that the analog accelerometers and Gyros i was using as an input for the PID were too noisy. Even kalman filtered data produced noise that reflected on the output as exagerated or undesirable behaviour.
I got in touch with an italian gentleman that has tested the stabilization with a similar setup to mine, and he told me he used the "Wii Nunchuk + Wii Motion Plus" IMU approach, as they are now well-known devices and output directly to I2C (no noise).

I´m currently about to finish building my second prototype and start experimenting again.

I´ll keep your advices in mind and let you know in a few days how it goes.

Title: Re: Arduino PID Library
Post by: zer0vector on Jan 08, 2011, 05:02 pm
fiveohhh
Quote
I'm planning on doing the same thing in a few weeks here(with an lm335 though).  What did you do to waterproof the sensor?


I had nothing but trouble with the LM temperature sensors.  I couldn't get stability regardless of the resistors I used.  Averaging might work better for you than me, but I had enough and just gave up.

The one-wire sensors from Maxim are accurate and dead easy with the existing libraries.  

Anyway, I've waterproofed one or the other a few different ways.  The best I've come up with so far is putting the chip in a piece of heatshrink tubing, filing the tubing with silicone sealant, letting the sealant almost set, then heat shrinking the tubing to tighten it all up.  It's the best compromise between waterproof and quick temperature response that I've had so far.  

Good luck!
Title: Re: Arduino PID Library
Post by: fahadmirza on Jan 23, 2011, 11:31 am
Hi br3ttb,
             Nice work out there. Library is awesome.I am still studying, not implemented yet. But I like to ask you something. There is a function that is:

void SetSampleTime(int NewSampleTime)
{
   if (NewSampleTime > 0)
   {
     //convert the time-based tunings to reflect this change
     taur *= ((double)NewSampleTime)/((double) tSample);
     accError *= ((double) tSample)/((double)NewSampleTime);
     taud *= ((double)NewSampleTime)/((double) tSample);
     tSample = (unsigned long)NewSampleTime;
   }
}

I am confused about this line:   taud *= ((double)NewSampleTime)/((double) tSample);
Shouldn't it be:     taud /= ((double)NewSampleTime)/((double) tSample);
                    or  taud *= ((double)) tSample/((double) NewSampleTime);

I mean: taud=TauD/tSampleInSec , right?