Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   Programming (http://www.chiefdelphi.com/forums/forumdisplay.php?f=51)
-   -   Why won't this PID loop stop? (http://www.chiefdelphi.com/forums/showthread.php?t=149281)

team-4480 04-07-2016 13:02

Why won't this PID loop stop?
 
Hi,

I am trying pretty hard to get this PID loop for a turnaround button using this nice example. The problem I am having is that no matter what I set the kToleranceDegrees to, the robot will still oscillate back and forth when I know for sure that it is within my tolerance. Am I forgetting to do something? I don't feel like adjusting the PID values will do anything because the robot won't even stop when the target is 90 degrees, the gyro reads 89.4 degrees and the tolerance is 10 degrees! What am I do wrong? Thanks!

Oblarg 04-07-2016 13:31

Re: Why won't this PID loop stop?
 
Quote:

Originally Posted by team-4480 (Post 1595521)
Hi,

I am trying pretty hard to get this PID loop for a turnaround button using this nice example. The problem I am having is that no matter what I set the kToleranceDegrees to, the robot will still oscillate back and forth when I know for sure that it is within my tolerance. Am I forgetting to do something? I don't feel like adjusting the PID values will do anything because the robot won't even stop when the target is 90 degrees, the gyro reads 89.4 degrees and the tolerance is 10 degrees! What am I do wrong? Thanks!

Caveat: I am only familiar with the java version of WPILib and am assuming that the functionality is the same.

The loop does not automatically stop when you're within tolerance of the setpoint. Rather, the tolerance setting is used by the onTarget() function to determine whether or not you have reached your setpoint. If you wish to stop the loop once you've reached your setpoint, you'll have to write code to disable the PID controller once onTarget() returns true. Note that you can also set a buffer length for your PID controller which will require that the average over n interations of your main loop be within the tolerance of the setpoint for onTarget() to return true, which is a good idea to prevent the loop from disabling if it overshoots the setpoint.

However, you should not need to disable the PID loop to eliminate oscillations - if your robot is oscillating around setpoint, then you need to tune it better to reduce the overshoot. If you find it difficult to reduce/eliminate the overshoot without making it difficult or impossible for the robot to actually reach the setpoint, consider implementing a "minimum output" for your PID loop rather than letting it actually go smoothly to 0.

team-4480 04-07-2016 13:40

Re: Why won't this PID loop stop?
 
Quote:

Originally Posted by Oblarg (Post 1595525)
Caveat: I am only familiar with the java version of WPILib and am assuming that the functionality is the same.

The loop does not automatically stop when you're within tolerance of the setpoint. Rather, the tolerance setting is used by the onTarget() function to determine whether or not you have reached your setpoint. If you wish to stop the loop once you've reached your setpoint, you'll have to write code to disable the PID controller once onTarget() returns true.

I did actually write code so that if it was onTarget(), it would be disabled but it never worked because I found out that if you call onTarget too often, it never returns true.

Oblarg 04-07-2016 13:47

Re: Why won't this PID loop stop?
 
Quote:

Originally Posted by team-4480 (Post 1595526)
I did actually write code so that if it was onTarget(), it would be disabled but it never worked because I found out that if you call onTarget too often, it never returns true.

You are possibly encountering a bug that was discovered this year.

Edit: Or possibly not, as a reply in that thread indicates that bug does not occur in the python version of WPILib. I'd suggest looking through the PIDController code and debugging to find why this is happening.

Edit 2: I have never worked with python myself, so perhaps I'm missing something, but it seems to me that the onTarget() function in the python WPILib doesn't actually, erm, do anything (other than throw a value error):

Code:

def onTarget(self):
    """Return True if the error is within the percentage of the total input
    range, determined by setTolerance. This assumes that the maximum and
    minimum input were set using :func:`setInput`.
    :returns: True if the error is less than the tolerance
    """
    raise ValueError("No tolerance value set when using PIDController.onTarget()")


alst 04-07-2016 18:58

Re: Why won't this PID loop stop?
 
Quote:

Originally Posted by Oblarg (Post 1595527)
Edit 2: I have never worked with python myself, so perhaps I'm missing something, but it seems to me that the onTarget() function in the python WPILib doesn't actually, erm, do anything (other than throw a value error):

Code:

def onTarget(self):
    """Return True if the error is within the percentage of the total input
    range, determined by setTolerance. This assumes that the maximum and
    minimum input were set using :func:`setInput`.
    :returns: True if the error is less than the tolerance
    """
    raise ValueError("No tolerance value set when using PIDController.onTarget()")


The onTarget method of each instance gets assigned to either PercentageTolerance_onTarget or AbsoluteTolerance_onTarget when you call setTolerance, setAbsoluteTolerance, or setPercentTolerance (i.e. you have to call one of those before calling onTarget):
https://github.com/robotpy/robotpy-w...r.py#L431-L467

virtuald 04-07-2016 19:46

Re: Why won't this PID loop stop?
 
There are a number of bugs with the current WPILib PIDController implementation. The python implementation follows the java implementation closely, so it shares these issues. Here are bug reports on WPILib's github site:
  • #29: PIDController: setSetpoint causes onTarget to be false
  • #30: PIDController: race condition for enable/disable and PIDWrite
  • #31: PIDController: getError() is incorrect when setContinuous is True

In particular, #29 is probably the one that is biting you (it bit me for a similar reason). If you keep calling setSetpoint (like that example does), each time it is called it will reset things such that onTarget is false, which means the robot will never stop oscillating.

There are a number of ways of dealing with this problem -- the easiest is to not call setSetpoint if the input is close (within 0.001) to the original input. However, this isn't satisfactory either for a number of reasons... so I ended up writing my own magicbot-compatible implementation, it'll be part of magicbot next year.

GeeTwo 04-07-2016 22:03

Re: Why won't this PID loop stop?
 
If the system has enough inertia that it continues out of the tolerance range, it will continue to oscillate. If this is your issue, I suggest a more dampening D (differential term) to bring the output back when it "overshoots" the design target.

team-4480 04-07-2016 22:43

Re: Why won't this PID loop stop?
 
Quote:

Originally Posted by virtuald (Post 1595542)
In particular, #29 is probably the one that is biting you (it bit me for a similar reason). If you keep calling setSetpoint (like that example does), each time it is called it will reset things such that onTarget is false, which means the robot will never stop oscillating.

So if I did a state machine for that setSetpoint like this:

Code:


if state == 1:
    setSetpoint(90)
    state = 2
elif state ==2:
    if onTarget():
        state=3

Would that solve the issue?

virtuald 04-07-2016 23:06

Re: Why won't this PID loop stop?
 
Quote:

Originally Posted by team-4480 (Post 1595560)
So if I did a state machine for that setSetpoint like this:

Code:


if state == 1:
    setSetpoint(90)
    state = 2
elif state ==2:
    if onTarget():
        state=3

Would that solve the issue?

That seems to be a bit more complex than necessary. First, don't ignore the other suggestions on this thread -- proper tuning will go a long way also. But, if you want onTarget to work, then a simpler solution is:

Code:

self.last = None
...


if self.last is None or abs(self.last - target) > 0.001:
    self.pid_controller.setSetpoint(target)
    self.last = target


team-4480 05-07-2016 12:28

Re: Why won't this PID loop stop?
 
Quote:

Originally Posted by virtuald (Post 1595562)
Code:

self.last = None
...


if self.last is None or abs(self.last - input) > 0.001:
    self.pid_controller.setSetpoint(input)
    self.last = input


I don't see how that would work if I were to give the input as 90, it would go through and then self.last would become 90 and then it wouldn't do anything because 90-90 is 0. For me, in order to get that to work, self.last would have to be set like this self.last = self.gyro.getYaw(). But I really don't know what I am doing with setting up PID loops so I could(and probably am) dead wrong.

virtuald 05-07-2016 15:44

Re: Why won't this PID loop stop?
 
Quote:

Originally Posted by team-4480 (Post 1595618)
I don't see how that would work if I were to give the input as 90, it would go through and then self.last would become 90 and then it wouldn't do anything because 90-90 is 0. For me, in order to get that to work, self.last would have to be set like this self.last = self.gyro.getYaw(). But I really don't know what I am doing with setting up PID loops so I could(and probably am) dead wrong.

My bad, I should have named the variable 'target', not 'input' (I've changed it above). It's the value that you pass to setSetpoint. Working through the code:

Let's say your target value is 90.

First iteration: self.last is None, setSetpoint would be called
Second iteration: self.last is 90, setSetpoint would not be called
Third iteration: self.last is 90, setSetpoint would not be called
... and so on

However, the setpoint does not get changed -- so the PIDController will still be trying to converge the output to the last setpoint that was set (which is 90). And more importantly, onTarget will work correctly, because it isn't getting reset by the call to setSetpoint.


All times are GMT -5. The time now is 09:52.

Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi