View Single Post
  #8   Spotlight this post!  
Unread 03-03-2013, 13:25
Kevin Sevcik's Avatar
Kevin Sevcik Kevin Sevcik is offline
(Insert witty comment here)
FRC #0057 (The Leopards)
Team Role: Mentor
 
Join Date: Jun 2001
Rookie Year: 1998
Location: Houston, Texas
Posts: 3,721
Kevin Sevcik has a reputation beyond reputeKevin Sevcik has a reputation beyond reputeKevin Sevcik has a reputation beyond reputeKevin Sevcik has a reputation beyond reputeKevin Sevcik has a reputation beyond reputeKevin Sevcik has a reputation beyond reputeKevin Sevcik has a reputation beyond reputeKevin Sevcik has a reputation beyond reputeKevin Sevcik has a reputation beyond reputeKevin Sevcik has a reputation beyond reputeKevin Sevcik has a reputation beyond repute
Send a message via AIM to Kevin Sevcik Send a message via Yahoo to Kevin Sevcik
Re: Stablized shooter & Claculating distance by vision

Quote:
Originally Posted by Doron_Sivan View Post
Kevin, we need to get to the wanted rpm progressively. We could use only PID to get fast but progressively to the wanted rpm and then adjust it with F P and I. I didn't understant though what did you change in the I in your special PIDController.
Second thing first, I'm not changing how I is used, just how/when the error is integrated. It happens in the Calculate function.
Code:
void PIDController::Calculate()
{
//SNIP
	if (enabled)
	{
		float input = pidInput->PIDGet();
		float result;
		PIDOutput *pidOutput;
		{
//SNIP
			if(m_I != 0)
			{
				double potentialIGain = (m_totalError + m_error) * m_I;
				if (potentialIGain < m_maximumOutput)
				{
					if (potentialIGain > m_minimumOutput)
						m_totalError += m_error;
					else
						m_totalError = m_minimumOutput / m_I;
				}
				else
				{
					m_totalError = m_maximumOutput / m_I;
				}
			}
			m_result = m_P * m_error + m_I * m_totalError + m_D * (m_error - m_prevError) + m_setpoint * m_F;
			m_prevError = m_error;
//SNIP
}
Versus:
Code:
void AdvPIDController::Calculate()
{
// SNIP
	if (enabled)
	{
		float input = pidInput->PIDGet();
		float result;
		float m_interror;
		PIDOutput *pidOutput;
		{
//SNIP
			if(m_I != 0)
			{
				m_result = m_P * m_error + m_I * m_totalError + m_D * (m_error - m_prevError) + m_setpoint * m_F;
				m_interror = m_error;
				if ((m_result <= m_minimumOutput || m_result >= m_maximumOutput) && ((m_interror * m_error) > 0))
				{
					m_interror = 0;
				}
				double potentialIGain = (m_totalError + m_interror) * m_I;
				if (potentialIGain < m_maximumOutput)
				{
					if (potentialIGain > m_minimumOutput)
						m_totalError += m_interror;
					else
						m_totalError = m_minimumOutput / m_I;
				}
				else
				{
					m_totalError = m_maximumOutput / m_I;
				}
			}

			m_result = m_P * m_error + m_I * m_totalError + m_D * (m_error - m_prevError) + m_setpoint * m_F;
			m_prevError = m_error;
//SNIP
}
It's a subtle difference, but important. The stock WPI code keeps integrating until the integral action is large enough that it saturates the output all by itself. In a slow reacting system, that can leave you with a lot of integral action to dissipate once you get to your setpoint. That leads to a ton of overshoot. My version doesn't add to integral action as long as the output is saturated from all the control action. So you're not building up a huge amount of integral action while the system is saturated and getting up to your setpoint as fast a it physically can.

Alright, to your first point. You want to get to your setpoint progressively? Like you want to slowly ramp up to your target RPM for some reason? Most people tune their closed loop speed controllers for three things: minimum time to reach (or re-reach) a setpoint, minimum error at steady state, and good robustness to a changing battery voltage. The idea being that you want to be able to just tell the system a setpoint and know it's going to get there and stay there. If you're using a PID controller, you should set up your gains to achieve this and leave them alone after that, for the most part. Changing gains on the fly can cause instabilities if you're not very careful about things.

Slowly changing your setpoint is certainly achievable, but you should do that separately from tuning your PID. For that, you should have a separate class that limits how quickly the PID setpoint can change. So you'd have a currentSetpoint variable, and compare that to the commandedSetpoint, and if the difference is greater than rampRate, you add or subtract rampRate from the currentSetpoint. Otherwise you set them equal. That means your setpoint will only change by a small amount per cycle, so it will slowly ramp up or down.
__________________
The difficult we do today; the impossible we do tomorrow. Miracles by appointment only.

Lone Star Regional Troubleshooter