Eliminating SS oscillation with a PID loop.

Hi everyone,

I’m using an Arduino to control the position of a linear motor that has a built in optical encoder for feedback. Additionally, i’m using a motor driver so that I can run the motor off of a 24 VDC system. I’ve been using the PID Library description to help walk me through writing the code for a PID loop. As of now I have it running and it will go to the right set point (usually). However, at some set points I get a lot of steady state oscillation. If I let the controller send the full power of 255 to the motor then it has way too much over shoot and just oscillates, also the optical encoder can’t register the position because it’s moving too fast. I’ve reduced the max velocity to 130 and that helps some. Also, if I alter the delays in between the changing PWM signals that seems to make a difference as well. So I guess what I’m asking is there any material out there that involves honing in on the best velocities and delays or is it just a game of trial and error?
I’m picking up on a project where someone else left off and I’m fairly new to Arduino, so if something I say doesn’t make any sense I apologize.
I’ve attached the code for reference.

PID_application_v2.ino (9.08 KB)

3ms delays are huge, try 300us instead. Any latency is the enemy of stability in a PID loop.

I have no idea what this line does:

    // Convert output to analog value corresponding to velocity
    velocity = round(output * 255 / (setpoint * Kp + Kd * (setpoint / dt) + Ki * setpoint * millis()));

except that it looks highly suspect and is non-linear (PIDs are meant to be part of a linear system).

Surely

  velocity = round (abs (output)) ;

Will give you a more plausible result? This is the output value passed to analogWrite, with
the sign being taken care of by choosing Direction1 or Driection2

I suspect you are driving the motor driver in fast or slow decay modes, rather than
synchronous rectification, so linearity is probably compromised somewhat by this.

Thanks for the input Mark. Sorry it took so long to respond, I had to do some research on the stuff you said because I didn't really know what it meant and then I was fairly sick for a few days. I tried the longer delays and those helped but I think the bulk of my problem was coming from integrator wind up. I found a good paper on it from Cal Tech that took a different approach than the one in the PID library. Thanks for your help though.

I think the bulk of my problem was coming from integrator wind up

That is the very last thing I would suspect.

I tried the longer delays and those helped

Hard to imagine why, but then it is obvious that you are on the wrong track entirely.

Google "PID tuning" for tutorials, and make sure that your loop interval is constant and chosen appropriately, with sampling at least 10 times faster than the system time constant.

    // Convert output to analog value corresponding to velocity
    velocity = round(output * 255 / (setpoint * Kp + Kd * (setpoint / dt) + Ki * setpoint * millis()));

The integrator is winding up because millis() does.

I suppose that bizarre line of code could explain the problem.