How can I make the Arduino PID library accept a certain amount of error?

Hey guys,
Id like to control theposition of an actuator using a PID algorithm. My problem is that when the actuator comes close to its setpoint it starts oscillating. Is there a possibility to let the algorithm stop trying to correct the value if it has reached a certain span?

#include <PID_v1.h>
#define kneevl1 30
#define kneevl2 31
#define kneevr1 32
#define kneevr2 33
#define kneehl1 34
#define kneehl2 35
#define kneehr1 36
#define kneehr2 37 
double Setpoint ; // will be the desired value
double Input; // Potentiometer
double Output ; //rein oder raus
//PID parameters
double Kp=0.000000001, Ki=0, Kd=0; 
 
//create PID instance 
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, REVERSE);
 
void setup()
{
  pinMode(kneevl1,OUTPUT);
  pinMode(kneevl2,OUTPUT);
  pinMode(kneevr1,OUTPUT);
  pinMode(kneevr2,OUTPUT);
  pinMode(kneehl1,OUTPUT);
  pinMode(kneehl2,OUTPUT);
  pinMode(kneehr1,OUTPUT);
  pinMode(kneehr2,OUTPUT);
  Serial.begin(9600);   
  
  Setpoint = 600;
  //Turn the PID on
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(0,100);
  myPID.SetTunings(Kp, Ki, Kd);
  myPID.SetSampleTime(100);
}
 
void loop()
{
  
  Input = analogRead(A1);

  
  myPID.Compute();
  //Serial.println(Output);
  //map(Output,0,1024,1,2);
  Serial.println (Output);
  if(analogRead(A1)>Setpoint)
  {
    
    digitalWrite (kneevr2,LOW);
    digitalWrite (kneevr1,HIGH);
    delay(Output);
    
  }

    if(analogRead(A1)<Setpoint)
  {
    
    digitalWrite (kneevr2,HIGH);
    digitalWrite (kneevr1,LOW);
    delay(Output);
  }
  
}

Whoops it only copied only the beginning

Please edit your post to add code tags.

If the output of the PID algorithm oscillates, you have not tuned it correctly. Google "PID tuning" for tutorials.

The greatest thing about the PID algorithm is that it's 100% guaranteed to converge. The worst thing about the PID algorithm is that it's 100% guaranteed to converge.

Most implementations of the algorithm use the quick and easy way and simply allow the math to work its magic. Which is fine if you have the time and several hundred decimal points of resolution. The concept of 'close enough' is a bit more difficult to implement. The solution? Ignore all those cheap PID libraries and write your own. The algorithm is really quite simple (which is why there are so many cheap libraries), mine takes about 20 lines of code, and then you have complete control on how to deal with convergence.

Yeah I don't think these should be so low ....Kp=0.000000001, Ki=0, Kd=0

DKWatson: The greatest thing about the PID algorithm is that it's 100% guaranteed to converge. The worst thing about the PID algorithm is that it's 100% guaranteed to converge.

Most implementations of the algorithm use the quick and easy way and simply allow the math to work its magic. Which is fine if you have the time and several hundred decimal points of resolution. The concept of 'close enough' is a bit more difficult to implement. The solution? Ignore all those cheap PID libraries and write your own. The algorithm is really quite simple (which is why there are so many cheap libraries), mine takes about 20 lines of code, and then you have complete control on how to deal with convergence.

Ok could you send me this code (mybe with a little bit of explanation?) The problem is that my motor turns pretty fast so it never reaches this point of perfection it always just oscillates around it.

lenny227:
Yeah I don’t think these should be so low …Kp=0.000000001, Ki=0, Kd=0

I think they do actually because with those small values if come the closest to my desired result.

Regardless of your choice, a good starting point is:

For Kp, divide your set-pointvalue by about 100. This affects the speed at which the set-pointis reached, the amount of overshoot and how quickly is settles down.

For Ki and Kd, start with about 10% of Kp. These two don't have a lot to do with stable targets, like reaching and maintaining a temperature and are more in play with following a changing set-point, but the formula needs them.

Ok ill try that.

Sadly it doesnt seem to be working very well. I think my motor is just moving to fast. I need to get a certain degre of tolerance in there

a) No, I won't send you code. This is not a free software house, we help you with your code.

b) Here's a link to some good info.

c) Why are you using PID to control a motor? Maybe cruise control for your car or some other application with a variable load, but an actuator?

Well what Ive got is somewhat of a servo unit. So the actuator also turns a potentiometer so I can read out the position. I originally tried it with some code I scrambled together myself but that didnt work terribly reliable. I was told to look into the PID algorithm because apparently this is the technique hobby servos use.

I don't think using a delay is the right way to program this, cause your pid values will not continuously be calculated. You should use timers with micros() or millis() instead and what actuator are you using?

Ok ill try that
its a selfmade linear actuator

AaronSilas: Well what Ive got is somewhat of a servo unit. So the actuator also turns a potentiometer so I can read out the position. I originally tried it with some code I scrambled together myself but that didnt work terribly reliable. I was told to look into the PID algorithm because apparently this is the technique hobby servos use.

If you look at the code in the PID library you will see that the core of it is the calculations for the I, P and D terms. The rest of the library is just "fluff" to create a "black box" that should work for any project. If you extract the core formulas it makes the concept much easier to understand.

Basically the I-term is incremented (or decremented) by a proportion of the error - it is an accumulating function so the value increases if the error persists for longer. And the P-term is a direct proportion of the error - the bigger the error the greater the correction. The D-term takes account of the rate-of-change of the error and can probably be ignored. The K values are the proportions to be used.

For a servo all the terms should go to zero when the servo is at the desired position. With your own code it is easy to arrange that.

...R

All right
I think ive got something that works. Ive basically juust lowered the resolution of the values from the potentiometer. By doing that it has more time to stop and doesnt oscillate anymore.

#include <PID_v1.h>
#define kneevl1 30
#define kneevl2 31
#define kneevr1 32
#define kneevr2 33
#define kneehl1 34
#define kneehl2 35
#define kneehr1 36
#define kneehr2 37 
double Setpoint ; // will be the desired value
double Input; // Potentiometer
double Output ; //rein oder raus
//PID parameters
double Kp=0.03, Ki=0.6, Kd=0.6; 
 
//create PID instance 
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
 
void setup()
{
  pinMode(kneevl1,OUTPUT);
  pinMode(kneevl2,OUTPUT);
  pinMode(kneevr1,OUTPUT);
  pinMode(kneevr2,OUTPUT);
  pinMode(kneehl1,OUTPUT);
  pinMode(kneehl2,OUTPUT);
  pinMode(kneehr1,OUTPUT);
  pinMode(kneehr2,OUTPUT);
  Serial.begin(9600);   
  
  Setpoint = 8;
  //Turn the PID on
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(0,100);
  myPID.SetTunings(Kp, Ki, Kd);
  myPID.SetSampleTime(100);
}
 
void loop()
{
  
  Input = map(analogRead(A1),400,680,0,10);
   Serial.println("INPUT ");
  Serial.println(Input);
  
  myPID.Compute();

  //Serial.println (Output);
  if(map(analogRead(A1),400,680,0,10)>Setpoint)
  {
     Serial.println("out");
    digitalWrite (kneevr2,LOW);   //out
    digitalWrite (kneevr1,HIGH);
    delay(Output);
  }

    if(map(analogRead(A1),400,680,0,10)<Setpoint)
  {
     Serial.println("in");
    digitalWrite (kneevr2,HIGH); //in
    digitalWrite (kneevr1,LOW);
    delay(Output);
  }

  
    if(map(analogRead(A1),400,680,0,10) == Setpoint)
  {
    
    digitalWrite (kneevr2,LOW);
    digitalWrite (kneevr1,LOW);
  }
  
}