|
|
|
![]() |
|
|||||||
|
||||||||
![]() |
|
|
Thread Tools | Rate Thread | Display Modes |
|
|
|
#1
|
|||
|
|||
|
Help me understand PIDController::OnTarget()
Code:
bool PIDController::OnTarget()
{
bool temp;
CRITICAL_REGION(m_semaphore)
{
temp = fabs(m_error) < (m_tolerance / 100 *
(m_maximumInput - m_minimumInput));
}
END_REGION;
return temp;
}
0.05 / 100 *100 = 0.05. This means my error would have to less than 0.05 to be OnTarget regardless of setpoint. For a setpoint of 10 I would have to be within 0.05 which is 0.5%, not 5%. For a setpoint of 100 I still have to be within 0.05 which is 0.05% of 100, not 5%. Shouldn't the implementation be the percent error formula? Quote:
Code:
bool PIDController::OnTarget()
{
bool temp;
CRITICAL_REGION(m_semaphore)
{
temp = fabs(m_error)/m_setpoint < m_tolerance;
}
END_REGION;
return temp;
}
|
|
#2
|
|||
|
|||
|
Re: Help me understand PIDController::OnTarget()
If you want a tolerance of 5%, you should use a tolerance of 5.0, not 0.05. I made the same mistake.
|
|
#3
|
||||
|
||||
|
Re: Help me understand PIDController::OnTarget()
The implementation looks correct to me. It looks for the error to be less than the tolerance % of the full range. Since m_tolerance is divided by 100, I assume that 5% should be 5.0, not 0.05.
HTH |
|
#4
|
|||
|
|||
|
I'm having a little trouble figuring out where your confused, so I'm going to make two seperate explanations:
a) To get a tolerence of 5% (as in you example setpoint +- 5.0) you would pass in a tolerence of 5.0; the math converts the percentage as a value from 0 to 100 to a value of 1.00 to 0.00, and uses that for the computation. The percentage is literally a percentage value, 100 = 100%, 1.0 = 1%. It's exactly the opposite of what I expected it would be (especially in an engineering setting like this); also, to make matters worse, theres an extra unnecessary floating point division to taking place in the OnTarget function (this division should take place in the set tolerence function instead, but oh well)... b) The reason OnTarget uses the Min/Max input is fairly good actually (I actually thought at first it worked the other way, and it added a lot of complexity to this scenario) If you consider a turret, which autotargets the hoop and uses a gyro to determine it's rotation, you will frequently changing the setpoint to the angle you need to turn; however you need to be within 1deg of the hoop... If the tolerence were based on the setpoint, a 10% tolerence and a setpoint of 10deg, your target would be 10deg +-1deg, for a setpoint of 20deg, your tolerence would be 20deg+-2deg. So, in that scenario, if you wanted a 1 deg error, you would have to compute the % error based on the setpoint you chose each time it changed. Conclusion: The whole thing would be much simpler (and function the same) if tolerence simply took in a float for the acceptable error value rather than percentage. (ex SetTolerence(1.0); //Tolerence of 1 degree). Also, a word of caution... On target will return true if (m_error == 0), so you have to be sure the calculate function has run at least once after each enable before you make any action based on OnTarget(). |
|
#5
|
||||||
|
||||||
|
Re: Help me understand PIDController::OnTarget()
I think depending on your application, you could make an argument for either method.
For example, if you're controlling the angle of an arm, you probably want the same tolerance range throughout the motion of the arm (as implemented). If you're controlling the speed of a shooter, you'd want to use the percent error formula, so that you have a tighter tolerance as the speed of the wheel gets smaller. In Java, here's the java-doc for setTolerance. Code:
/**
* Set the percentage error which is considered tolerable for use with
* OnTarget. (Input of 15.0 = 15 percent)
* @param percent error which is tolerable
*/
|
|
#6
|
|||
|
|||
|
Re: Help me understand PIDController::OnTarget()
At least I undestand the intent now. I think Joe Ross gave the best answer. It makes sense in the turret application. I was using it for my shooter speed where I think percent error makes more sense.
I think percent error is more natural to me because whenever we discussed the steady state error requirements of a control loop in school we always talked about it as a percentage error of the setpoint. i.e. steady state error of +/- 2% might be a requirement. Of course I think we were always talking about controlling speed and not controlling position. I think I will add my own OnTarget implementation to the WPILib and recompile it. Something like this: Code:
bool PIDController::OnTarget(bool percent_error)
{
bool temp;
CRITICAL_REGION(m_semaphore)
{
if(percent_error)
{
temp = fabs(m_error)/m_setpoint < m_tolerance;
}
else
{
temp = fabs(m_error) < (m_tolerance / 100 *
(m_maximumInput - m_minimumInput));
}
}
END_REGION;
return temp;
}
Quote:
Quote:
Code:
void PIDController::SetInputRange(float minimumInput, float maximumInput)
{
CRITICAL_REGION(m_semaphore)
{
m_minimumInput = minimumInput;
m_maximumInput = maximumInput;
}
END_REGION;
SetSetpoint(m_setpoint);
}
|
|
#7
|
||||
|
||||
|
Re: Help me understand PIDController::OnTarget()
Quote:
The purist in me would grab copies of the variables in the critical region and move the calculation outside the critical region, but it would hardly make any difference in this case. |
|
#8
|
||||
|
||||
|
Re: Help me understand PIDController::OnTarget()
Quote:
Quote:
HTH |
|
#9
|
||||||
|
||||||
|
Re: Help me understand PIDController::OnTarget()
Quote:
I do agree it's better to override a method if possible. |
|
#10
|
|||
|
|||
|
Re: Help me understand PIDController::OnTarget()
Doesn't sound right to me either. I don't think there exists any requirement that we have to use WPILib at all when programming in C++. It is there for convenience.
Quote:
The method is virtual so this is an option. |
|
#11
|
||||
|
||||
|
Re: Help me understand PIDController::OnTarget()
Quote:
|
|
#12
|
|||
|
|||
|
Re: Help me understand PIDController::OnTarget()
Quote:
Example, in the following code the first if-statement could execute with the values of min/max input set to one set of values. The thread executing this code could then be preempted (depending on the thread priority and scheduling algorithm being used) by the application thread and the values of min/max input changed. The original thread would then continue executing the code with new values of min/max input causing undesireable results. Code:
if (fabs(m_error) > (m_maximumInput - m_minimumInput) / 2)
{
if (m_error > 0)
{
m_error = m_error - m_maximumInput + m_minimumInput;
}
else
{
m_error = m_error + m_maximumInput - m_minimumInput;
}
}
|
|
#13
|
|||
|
|||
|
Re: Help me understand PIDController::OnTarget()
Can someone explain the difference between these two uses of the semaphore? I see both being used in the PIDController class.
Code:
CRITICAL_REGION(m_semaphore)
{
}
END_REGION;
Code:
{
Synchronized sync(m_semaphore);
}
Last edited by jwakeman : 23-02-2012 at 18:59. Reason: code tags |
|
#14
|
||||
|
||||
|
Re: Help me understand PIDController::OnTarget()
Quote:
the first is a semaphore used for mutual exclusion (to protect the critical region), in this use-case the semaphore is taken before and given after a critical region of code and always in the same context - the semaphore includes the concept of ownership (by the thread/task) and recursion the second is a semaphore used for synchronization, in this use-case the semaphore is taken in one context/thread/task and given or flushed in another context - for example given/flushed in a periodic timer callback function (or maybe an interrupt service routine) and taken in a task/thread hth |
|
#15
|
|||
|
|||
|
Re: Help me understand PIDController::OnTarget()
Quote:
|
![]() |
| Thread Tools | |
| Display Modes | Rate This Thread |
|
|