Go to Post Look past the robot. Look past your team. Science and technolgy are studies worth devoting your life too. - KenWittlief [more]
Home
Go Back   Chief Delphi > Technical > Programming > C/C++
CD-Media   CD-Spy  
portal register members calendar search Today's Posts Mark Forums Read FAQ rules

 
Reply
Thread Tools Rate Thread Display Modes
  #1   Spotlight this post!  
Unread 23-02-2012, 14:04
jwakeman jwakeman is offline
Registered User
FRC #0063 (Red Barons)
Team Role: Mentor
 
Join Date: Jan 2011
Rookie Year: 2010
Location: 16510
Posts: 182
jwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nice
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;
}
I'm having trouble understanding the implementation of this function. In the context that I was using it my max input was 100 and my minimum input was 0. I was using the default tolerance of 0.05 (assuming this means 5%).

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:
% error = (|Your Result - Accepted Value| / Accepted Value) x 100
Something like:
Code:
bool PIDController::OnTarget()
{
	bool temp;
	CRITICAL_REGION(m_semaphore)
	{
		temp = fabs(m_error)/m_setpoint < m_tolerance;
	}
	END_REGION;
	return temp;
}
Reply With Quote
  #2   Spotlight this post!  
Unread 23-02-2012, 14:17
rbmj rbmj is offline
Registered User
FRC #0612 (Chantilly Robotics)
Team Role: Alumni
 
Join Date: Apr 2011
Rookie Year: 2011
Location: DC Area/Fairfax County
Posts: 192
rbmj is a jewel in the roughrbmj is a jewel in the roughrbmj is a jewel in the rough
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.
Reply With Quote
  #3   Spotlight this post!  
Unread 23-02-2012, 14:21
wireties's Avatar
wireties wireties is offline
Principal Engineer
AKA: Keith Buchanan
FRC #1296 (Full Metal Jackets)
Team Role: Mentor
 
Join Date: Jan 2006
Rookie Year: 2004
Location: Rockwall, TX
Posts: 1,170
wireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond repute
Send a message via AIM to wireties
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
__________________
Fast, cheap or working - pick any two!
Reply With Quote
  #4   Spotlight this post!  
Unread 23-02-2012, 14:40
DjScribbles DjScribbles is offline
Programming Mentor
AKA: Joe S
FRC #2474 (Team Excel)
Team Role: Mentor
 
Join Date: Oct 2011
Rookie Year: 2012
Location: Niles MI
Posts: 284
DjScribbles is a splendid one to beholdDjScribbles is a splendid one to beholdDjScribbles is a splendid one to beholdDjScribbles is a splendid one to beholdDjScribbles is a splendid one to beholdDjScribbles is a splendid one to beholdDjScribbles is a splendid one to beholdDjScribbles is a splendid one to behold
Lightbulb Re: Help me understand PIDController::OnTarget()

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().
Reply With Quote
  #5   Spotlight this post!  
Unread 23-02-2012, 14:52
Joe Ross's Avatar Unsung FIRST Hero
Joe Ross Joe Ross is offline
Registered User
FRC #0330 (Beachbots)
Team Role: Engineer
 
Join Date: Jun 2001
Rookie Year: 1997
Location: Los Angeles, CA
Posts: 8,576
Joe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond repute
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
     */
Reply With Quote
  #6   Spotlight this post!  
Unread 23-02-2012, 15:06
Ether's Avatar
Ether Ether is offline
systems engineer (retired)
no team
 
Join Date: Nov 2009
Rookie Year: 1969
Location: US
Posts: 8,098
Ether has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond repute
Re: Help me understand PIDController::OnTarget()

Quote:
Originally Posted by jwakeman View Post
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;
}
On a side note:

It looks like m_tolerance, m_maximumInput, and m_minimumInput are all constants.

Take them, and the calculation, out of the critical region

Code:
bool PIDController::OnTarget()
{
	double temp;
	CRITICAL_REGION(m_semaphore)
	{
         temp=m_error;
	}
	END_REGION;
	return (fabs(temp) < (m_tolerance / 100 * (m_maximumInput - m_minimumInput)));
}

Reply With Quote
  #7   Spotlight this post!  
Unread 23-02-2012, 15:40
jwakeman jwakeman is offline
Registered User
FRC #0063 (Red Barons)
Team Role: Mentor
 
Join Date: Jan 2011
Rookie Year: 2010
Location: 16510
Posts: 182
jwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nice
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:
Originally Posted by DjScribbles View Post
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).
I also agree with this.


Quote:
Originally Posted by Ether View Post
On a side note:
It looks like m_tolerance, m_maximumInput, and m_minimumInput are all constants.
I think the reason they are part of the critical region is that they are accessed in the calculation of the output of the controller and can also be modified at any time by the application threads via methods such as this one.

Code:
void PIDController::SetInputRange(float minimumInput, float maximumInput)
{
	CRITICAL_REGION(m_semaphore)
	{
		m_minimumInput = minimumInput;
		m_maximumInput = maximumInput;	
	}
	END_REGION;

	SetSetpoint(m_setpoint);
}
Reply With Quote
  #8   Spotlight this post!  
Unread 23-02-2012, 15:44
Ether's Avatar
Ether Ether is offline
systems engineer (retired)
no team
 
Join Date: Nov 2009
Rookie Year: 1969
Location: US
Posts: 8,098
Ether has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond reputeEther has a reputation beyond repute
Re: Help me understand PIDController::OnTarget()

Quote:
Originally Posted by jwakeman View Post
I think the reason they are part of the critical region is that they are accessed in the calculation of the output of the controller and can also be modified at any time by the application threads via methods such as this one.

Code:
void PIDController::SetInputRange(float minimumInput, float maximumInput)
{
	CRITICAL_REGION(m_semaphore)
	{
		m_minimumInput = minimumInput;
		m_maximumInput = maximumInput;	
	}
	END_REGION;

	SetSetpoint(m_setpoint);
}
Fair enough. They're not constants.

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.


Reply With Quote
  #9   Spotlight this post!  
Unread 23-02-2012, 16:30
wireties's Avatar
wireties wireties is offline
Principal Engineer
AKA: Keith Buchanan
FRC #1296 (Full Metal Jackets)
Team Role: Mentor
 
Join Date: Jan 2006
Rookie Year: 2004
Location: Rockwall, TX
Posts: 1,170
wireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond repute
Send a message via AIM to wireties
Re: Help me understand PIDController::OnTarget()

Quote:
Originally Posted by Ether View Post
On a side note:

It looks like m_tolerance, m_maximumInput, and m_minimumInput are all constants.

Take them, and the calculation, out of the critical region
They are class members but still - good advice. Critical regions should contain as little code as possible.
__________________
Fast, cheap or working - pick any two!
Reply With Quote
  #10   Spotlight this post!  
Unread 23-02-2012, 16:35
wireties's Avatar
wireties wireties is offline
Principal Engineer
AKA: Keith Buchanan
FRC #1296 (Full Metal Jackets)
Team Role: Mentor
 
Join Date: Jan 2006
Rookie Year: 2004
Location: Rockwall, TX
Posts: 1,170
wireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond reputewireties has a reputation beyond repute
Send a message via AIM to wireties
Re: Help me understand PIDController::OnTarget()

Quote:
Originally Posted by jwakeman View Post
I think I will add my own OnTarget implementation to the WPILib and recompile it.
Just override the class (or copy it) - we can't recompile the lib and even if we could the FIRST infrastructure checks the MD5 checksum.

Quote:
Originally Posted by jwakeman View Post
I think the reason they are part of the critical region is that they are accessed in the calculation of the output of the controller and can also be modified at any time by the application threads via methods such as this one.
True but these class members are native machine word-sized thus changing them is an atomic operation in this context. It may not be desirable but it won't screw up.

HTH
__________________
Fast, cheap or working - pick any two!
Reply With Quote
  #11   Spotlight this post!  
Unread 23-02-2012, 17:24
Joe Ross's Avatar Unsung FIRST Hero
Joe Ross Joe Ross is offline
Registered User
FRC #0330 (Beachbots)
Team Role: Engineer
 
Join Date: Jun 2001
Rookie Year: 1997
Location: Los Angeles, CA
Posts: 8,576
Joe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond repute
Re: Help me understand PIDController::OnTarget()

Quote:
Originally Posted by wireties View Post
Just override the class (or copy it) - we can't recompile the lib and even if we could the FIRST infrastructure checks the MD5 checksum.
I've never heard that before. Where did you hear it? I would have thought that Joe Hershberger would have mentioned the MD5 check instead of helping with instructions on how to rebuild the library in the following thread. http://www.chiefdelphi.com/forums/sh...ad.php?t=89131

I do agree it's better to override a method if possible.
Reply With Quote
  #12   Spotlight this post!  
Unread 23-02-2012, 18:40
jwakeman jwakeman is offline
Registered User
FRC #0063 (Red Barons)
Team Role: Mentor
 
Join Date: Jan 2011
Rookie Year: 2010
Location: 16510
Posts: 182
jwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nice
Re: Help me understand PIDController::OnTarget()

Quote:
Originally Posted by Joe Ross View Post
I've never heard that before. Where did you hear it?
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:
Originally Posted by Joe Ross View Post
I would have thought that Joe Hershberger would have mentioned the MD5 check instead of helping with instructions on how to rebuild the library in the following thread. http://www.chiefdelphi.com/forums/sh...ad.php?t=89131
Makes sense, I was on that thread and that is where I learned to do the recompile.

Quote:
Originally Posted by Joe Ross View Post
I do agree it's better to override a method if possible.
The method is virtual so this is an option.
Reply With Quote
  #13   Spotlight this post!  
Unread 23-02-2012, 18:53
jwakeman jwakeman is offline
Registered User
FRC #0063 (Red Barons)
Team Role: Mentor
 
Join Date: Jan 2011
Rookie Year: 2010
Location: 16510
Posts: 182
jwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nice
Re: Help me understand PIDController::OnTarget()

Quote:
Originally Posted by wireties View Post
True but these class members are native machine word-sized thus changing them is an atomic operation in this context. It may not be desirable but it won't screw up.
I think you're correct that there is no danger of segmentation faults. However, if access to the variables is not synchronized then the potential for logic errors exist.

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;
       }
}
Reply With Quote
  #14   Spotlight this post!  
Unread 23-02-2012, 18:58
jwakeman jwakeman is offline
Registered User
FRC #0063 (Red Barons)
Team Role: Mentor
 
Join Date: Jan 2011
Rookie Year: 2010
Location: 16510
Posts: 182
jwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nice
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
Reply With Quote
  #15   Spotlight this post!  
Unread 23-02-2012, 19:46
vamfun vamfun is offline
Mentor :Contol System Engineer
AKA: Chris
FRC #0599 (Robodox)
Team Role: Engineer
 
Join Date: Jan 2009
Rookie Year: 2003
Location: Van Nuys, California
Posts: 182
vamfun is a glorious beacon of lightvamfun is a glorious beacon of lightvamfun is a glorious beacon of lightvamfun is a glorious beacon of lightvamfun is a glorious beacon of lightvamfun is a glorious beacon of light
Send a message via AIM to vamfun
Re: Help me understand PIDController::OnTarget()

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;
       }
}
Now that you brought this code up, would someone mind explaining why it is there? What is maximumInput and minimumInput? They both have a default value of zero. If maximumInput = 1 and minimumInput = -1 then the error is being biased by -2 for m_error>0 and 2 for m_error<0 if abs(m_error) > 1. So lets say that m_error = 1.2 then m_error is biased to become -.8 . What is this accomplishing?

Last edited by vamfun : 23-02-2012 at 20:00.
Reply With Quote
Reply


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump


All times are GMT -5. The time now is 03:01.

The Chief Delphi Forums are sponsored by Innovation First International, Inc.


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