Arduino-PID-Library icon indicating copy to clipboard operation
Arduino-PID-Library copied to clipboard

Delays in loop() cause erratic PID.compute() values

Open owhite opened this issue 7 years ago • 4 comments

I'm using the PID Library for a balancing robot and it seems to be exhibiting strange behavior.

You can view the complete code here:

https://github.com/owhite/balancing_bot/blob/master/src/balancing.ino

but I believe the relevant section is here:

void loop() {  

 .
 .
 .
  tmp2 = micros();
  MPUupdate();
  tmp1 = micros();

  pid.Compute();

  tmp3 = tmp1 - tmp2;
  Serial.print(position);
  Serial.print(" ");
  Serial.print(output);
  Serial.print(" ");
  Serial.println(tmp3);
  
  // send output/PWM to the motors    

 .
 .
 .
}

The issue is this. MPUupdate() sets position by performing an I2C call to a MPU9250 module, and it returns position - the tilt of the MPU09250. Then the code calls pid.Compute(). The problem is that some calls to MPUupdate() take a lot longer than others and when it does the return values from pid.Compute() jump to some extreme value.

This is an example of print output:

179.87 3.82 72
179.87 3.82 72
179.87 3.82 71
179.87 3.82 74
179.87 3.82 70
179.87 41.32 757 (see below)
179.87 41.32 71
179.87 41.32 71
179.87 41.32 71
179.87 41.32 72
179.87 3.93 71
179.87 3.93 71
179.87 3.93 71
179.87 3.93 71
179.87 3.93 71
179.87 3.93 70
179.87 3.93 71
179.87 3.93 71
179.87 3.93 74
179.87 3.93 71
179.87 3.93 71
179.87 16.02 760
179.87 16.02 71
179.87 16.02 70
179.87 16.02 71
179.87 16.02 72
179.87 3.97 71
179.87 3.97 71
179.87 3.97 71
179.87 3.97 75
179.87 3.97 71
179.87 -10.11 757
179.87 -10.11 71
179.87 -10.11 75
179.87 -10.11 70
179.87 3.93 71
179.87 3.93 72
179.87 3.93 70

The fifth line down from that out is an example.

179.87 41.32 757 

Where I have an unusually long delay time and it gives me a much larger PID value even though the position is the same. So basically when there is a long call to the MPU it screws up my pid values, and then my balancing robot jitters. Any suggestions?

owhite avatar Apr 24 '17 03:04 owhite

Hm, and then there's this post on your original blog

Coding Badly says: I think moving the time calculations out of Compute is a good idea but it does create a potential pitfall for new users. The calculations will not be accurate if more than SampleTime has elapsed between calls. This could be difficult (or impossible) to debug. I suggest adding a check for “(grossly) exceeded SampleTime”. If the SampleTime has been exceeded, set a flag. This gives the user a convenient way to check for an overrun.

which probably makes me one of those new users. I guess the question is how to fix the situation. If I am able to pass the algorithm the elapsed time, would it still work okay?

owhite avatar Apr 24 '17 12:04 owhite

@owhite please see: https://github.com/br3ttb/Arduino-PID-Library/pull/9. Then simply call:

myPID.SetSampleTime(0);

Lauszus avatar Apr 25 '17 21:04 Lauszus

Also check out my PID implementation for my flight controller: https://github.com/Lauszus/LaunchPadFlightController/blob/master/src/PID.c and the PID code for the Balanduino balancing robot: https://github.com/TKJElectronics/Balanduino/blob/master/Firmware/Balanduino/Motor.ino.

Lauszus avatar Apr 25 '17 21:04 Lauszus

@owhite please see: #9. Then simply call:

myPID.SetSampleTime(0);

This does not work! If you look at the SetSampleTime() code

void PID::SetSampleTime(int NewSampleTime)
{
   if (NewSampleTime > 0)
   {
      double ratio  = (double)NewSampleTime
                      / (double)SampleTime;
      ki *= ratio;
      kd /= ratio;
      SampleTime = (unsigned long)NewSampleTime;
   }
}

You can see that if '0' is passed in as 'NewSampleTime', the value of 'SampleTime' will not be changed! The 'if' statement needs to be changed to 'if (NewSampleTime >= 0)

Frank

paynterf avatar Apr 07 '21 19:04 paynterf