How to test PID code?
SRLM
Posts: 5,045
I am quite stuck on this one. I have written some PID code that will take inputs (measured, setpoint, kp, ki, kd, base, and divisor) and will output a servo pulse.
I am trying to test the PID object with the setup shown in the pictures. Basically, it's a Ping mounted on a stick on a servo body (foreground servo), whose horn is attached to another servo's horn, whose body is fastened. This allows me to create automatic test routines where one servo is rotated in a set pattern, and the other servo has to compensate. However, for now I just leave the fixed servo (in the background) stationary.
The problem that I am having is that the output always oscillates except for when the measurement is very near to the setpoint to start. I've also noticed that for some positions the Ping measures a really high value, which probably indicates that the wave is reflecting towards the ceiling, instead of back towards the ping.
Another problem is that for some values of k* is that it will oscillate really quickly around the setpoint. I think this may have to do with the slip in the two sets of servo gears, which is pretty significant (a few degrees).
I tried to put in some code that smooths out the sensor readings by averaging it with a sensor reading history, but that didn't seem to do much. I then tried to limit all measurements to within 20% of the last measurement, but that didn't work either.
I have been testing this with various combinations of values for kp, ki, and divisor, and so far none are stable everywhere. I'm fairly confident in my actual PID code, but if I can't test it I can't say for sure that it is good. Any suggestions?
Post Edited (SRLM) : 11/1/2009 6:27:06 PM GMT
I am trying to test the PID object with the setup shown in the pictures. Basically, it's a Ping mounted on a stick on a servo body (foreground servo), whose horn is attached to another servo's horn, whose body is fastened. This allows me to create automatic test routines where one servo is rotated in a set pattern, and the other servo has to compensate. However, for now I just leave the fixed servo (in the background) stationary.
The problem that I am having is that the output always oscillates except for when the measurement is very near to the setpoint to start. I've also noticed that for some positions the Ping measures a really high value, which probably indicates that the wave is reflecting towards the ceiling, instead of back towards the ping.
Another problem is that for some values of k* is that it will oscillate really quickly around the setpoint. I think this may have to do with the slip in the two sets of servo gears, which is pretty significant (a few degrees).
I tried to put in some code that smooths out the sensor readings by averaging it with a sensor reading history, but that didn't seem to do much. I then tried to limit all measurements to within 20% of the last measurement, but that didn't work either.
I have been testing this with various combinations of values for kp, ki, and divisor, and so far none are stable everywhere. I'm fairly confident in my actual PID code, but if I can't test it I can't say for sure that it is good. Any suggestions?
Post Edited (SRLM) : 11/1/2009 6:27:06 PM GMT
Comments
Also the quick look at your PID code, I didn't see a limit on the Ki term. Its very useful to make sure there is a limt on the Ki term, its very easy for this term to get very large.
I would think based on your notes that the first order of business is to resolve the Ping misreads. Consider a deadband region near the set point to help shut down the oscillations. Set D to 0 for now, it really adds to oscillations and may not even be needed. You need a maximum limit for the Integral, like a cap so it cannot go above a certain point, then you need to experiment with the rate at which it accumulates, a slower accumulation will help get rid of oscillations. Start out with very low P values just to get started, then add in some I. My PID project requires 100 P to 10 I, 0 D. But I found it mandatory to set the max I. Not sure if this helps but I spent hundreds of hours on PID recently, not with Ping however.
I had found the wikipedia article on how to tune a PID loop, and tried using the manual method: en.wikipedia.org/wiki/PID_controller#Loop_tuning
I tried most of my tests that way (000 then increasing kp, cutting, and increasing ki). I haven't even touched the kd yet.
I have added a limit to the ki term that appears to be okay. I tried the limit fairly small, but it could theoretically hit the limit in no more than 20 iterations. It appeared to effectively cut off the impact of the integral, so I have increased it some.
@Todd Chapman
This is my first PID code. I've seen it before in books and videos, but never actually tried it out. First steps...
loop speed
accumulation rate
Slow down the accumulator in the beginning and see what happens. When I was going through it, I used an LCD to output the error, and the PID output going to PSMASM to drive the motor. With the LCD it slows things down but you can get a better understanding of how it is working. I found absolutely nothing on the net after much effort that worked for me. I finally just started from scratch and built a PID engine that tracked an error. After much work I got it down and really enjoy having that semi-under control.
Take a look at my engine to see if it helps. There are parts that are only going make sense relative to my code though, ie status, ClosingTripLevelOffset, fault. Pos is what the engine is going to chase, using an encoder for feedback.
From main program:
PUB PidStart
pid.start(@pos, @status, @fault, @ClosingTripLevelOffset, 100, 10, 0, 35000)
I constantly am tweaking the cap and accumulation rate to get the best performance for any given situation.
Post Edited (Todd Chapman) : 11/2/2009 3:56:11 AM GMT