How to tune a PID loop?

Hi all, I was wondering if anybody here knows how to properly tune a PID loop? I am working on a self balancing robot, but can't for the life of me figure out how to get the loop tuned. Here is my loop:

void Filter()
{
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); //Get accelerometer/gyroscope readings
  Angle_Raw = (atan2(ay, ax) * 180 / pi + Angle_offset); //Angle Position
  omega =  gz / Gyr_Gain + Gry_offset; // Angular Velocity
  unsigned long now = millis(); //Time program has been running
  float dt = (now - preTime) / 1000.00; //Sample time in seconds
  preTime = now;
  float K = 0.8;
  float A = K / (K + dt);
  Angle_Filtered = A * (Angle_Filtered + omega * dt) + (1 - A) * Angle_Raw;
}

void PIDloop()
{   
    kp = 10; //10
    ki = 0; //
    kd = 0; //

  unsigned long now = millis(); //Time program has been running
  timeChange = (now - lastTime); //Prevent integer overflow issue
  lastTime = now; //Set time measurement was taken
  
  error = Angle_Filtered;  // Proportion
  errSum += error * timeChange;  // Integration
  dErr = (error - lastErr) / timeChange;  // Differentiation
  Output = kp * error + ki * errSum + kd * dErr; //Calculated Output
  lastErr = error; //Reset for next loop
  
  Motor1 = constrain(Output - Turn_Speed + Run_Speed, -90, 90);
  Motor2 = constrain(Output + Turn_Speed + Run_Speed, -90, 90);
  Serial.print(error );
}

The Kp value works as expected, causing the output to directly correlate to the tilt angle and angular velocity, but I can't get the Ki or Kd values to do anything of use. Any ideas here?

Well i am working on a Quadcopter autopilot and i used the instructions from wikipedia: http://en.wikipedia.org/wiki/PID_controller

About in the middle of the page you will find Manual tuning with a nice table. And then just try it over and over and over...

The basic process to get it sorta-kinda working is fairly simple:

Set I and D to 0, then gradually increase P and test operation until it becomes unstable (typically it will either slam hard in one direction, or oscillate, perhaps violently). When you reach that point, reduce P until the instability goes away. Even cutting it in half at this point is not unreasonable. You should be able to get it to respond properly to disturbances, though it will probably not always settle in quite the right final position.

SLOWLY increase I. I value will typically be much smaller than P, like 5-10X smaller. This should get it to settle quickly on the correct final position. If I is too high, it will again become unstable, and you'll have to back off. The primary effect of too much I will be over-shoot on moves. When you increase I from 0, you should find the robot reaches a stable position more quickly, with little, if any, overshoot. If you go too high on I it will over-shoot, and oscillate around the set point. I don't know what PID code you're using, but if it doesn't have "anti-windup" in the I term, you'll probably have problems.

Once P and I are set, you can TRY increasing D. D will again typically be much smaller than I. And, a little D can go a long way, and cause serious instability. In all probablity, you won't want to use D at all and if you do, you may find it necessary to modify the PID to add a low-pass filter to the D term.

Once you've made one pass through, things are working ok, make a second pass, starting with the values derived above, and see how far you can increase P, then I. Iterate until you can no longer increase P.

Depending on how sensitive your robot is, you may find you need a fairly high update rate on the PID. It is also important that the PID be updated at very regular intervals. If the timing is varying all over the place, it will drive the PID crazy, and be difficult or impossible to make it stable.

Regards, Ray L.

Thank you very much to both of you. It turns out that sample time was the biggest issue the whole time. I dropped the sample time from 50ms down to 20ms, and the oscillations were pretty much gone. There is still plenty of work to do, but the bot balances for at least a few seconds now.

Ray, I shall follow your procedure again and try for better results. It definitely seems to work for me. Thank you very much.

Glad to see it's at least moving in the right direction. You may find 20mSec is still too slow.... On a 16MHz Arduino, you should be able to run down to about 5-10mSec.

Regards, Ray L.

Hey guys, I've got it balancing okay now, but it drifts in one direction after correcting itself one time. Any idea what value I should adjust?