Go to Post Sometimes our greatest failures lay the foundations for our greatest success. - =Martin=Taylor= [more]
Home
Go Back   Chief Delphi > Technical > Programming
CD-Media   CD-Spy  
portal register members calendar search Today's Posts Mark Forums Read FAQ rules

 
Closed Thread
Thread Tools Rate Thread Display Modes
  #16   Spotlight this post!  
Unread 17-11-2011, 21:16
AustinSchuh AustinSchuh is offline
Registered User
FRC #0971 (Spartan Robotics) #254 (The Cheesy Poofs)
Team Role: Engineer
 
Join Date: Feb 2005
Rookie Year: 1999
Location: Los Altos, CA
Posts: 803
AustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond repute
Re: Team 254 2011 FRC Code

Quote:
Originally Posted by Jared341 View Post
Austin,

Could you or one of your programmers explain the rationale behind the design of your victor_linearize function? You average 5th and 7th order polynomials together, but it isn't obvious why you do this.

Thanks

This question was brought on by this thread: http://www.chiefdelphi.com/forums/sh...02#post1085502
Sure. I wrote this function in 2010, so I'm quite qualified to answer any questions.

Here is the data and the three polynomials that are in the function.



I generated the red data points by putting the robot up on blocks and applying PWM to the motors. I then read out the wheel speed at steady state for various PWM values.

From there, I tried to fit the data. I first started with a 5th order odd polynomial (The + and - response should be the same, which means that f(x) = -f(-x)). It is shown in green. That wasn't a great fit, so I tried a 7th order polynomial, shown in blue. Neither of them were great fits. They are not monatonically increasing functions. When you drive the robot with them, the robot doesn't feel like the throttle is a consistent function, and it feels weird (it has been a while, and feelings don't translate to words so well.)

From there, on a whim, I tried averaging the two functions. This actually turned out quite well. But, when I put it on the robot, it felt like the power was reduced too much at low speeds. To try to compensate for this, I added in a bit of y=x to get the equation shown in the legend above for the pink plot and to boost the power applied at low speeds. This is what is in use today in the victor_linearize function.
  #17   Spotlight this post!  
Unread 20-11-2011, 20:01
otherguy's Avatar
otherguy otherguy is offline
sparkE
AKA: James
FRC #2168 (The Aluminum Falcons)
Team Role: Mentor
 
Join Date: Feb 2010
Rookie Year: 2009
Location: CT
Posts: 443
otherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to behold
Re: Team 254 2011 FRC Code

Is there a reason you choose to use a polynomial function instead of a piecewise linear function?

From your empirical data it looks like no more than 5 linear sections (see red lines in figure below) would be needed to characterize the curve quite well.

This would significantly cut down on the number of computations needed to return a result, and in this case it look like it might even more accurately fit the input data.


Last edited by otherguy : 20-11-2011 at 20:04.
  #18   Spotlight this post!  
Unread 21-11-2011, 19:36
Ether's Avatar
Ether Ether is offline
systems engineer (retired)
no team
 
Join Date: Nov 2009
Rookie Year: 1969
Location: US
Posts: 8,125
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: Team 254 2011 FRC Code

Quote:
Originally Posted by otherguy View Post
This would significantly cut down on the number of computations needed to return a result
Did you do an analysis to determine whether the piecewise linear code plus the conditional logic it requires executes faster than the single polynomial ?

If speed is what you need, it's hard to beat a complete lookup table (no interpolation required):

http://www.chiefdelphi.com/forums/sh...1&postcount=12


  #19   Spotlight this post!  
Unread 21-11-2011, 19:39
AdamHeard's Avatar
AdamHeard AdamHeard is offline
Lead Mentor
FRC #0973 (Greybots)
Team Role: Mentor
 
Join Date: Oct 2004
Rookie Year: 2004
Location: Atascadero
Posts: 5,526
AdamHeard has a reputation beyond reputeAdamHeard has a reputation beyond reputeAdamHeard has a reputation beyond reputeAdamHeard has a reputation beyond reputeAdamHeard has a reputation beyond reputeAdamHeard has a reputation beyond reputeAdamHeard has a reputation beyond reputeAdamHeard has a reputation beyond reputeAdamHeard has a reputation beyond reputeAdamHeard has a reputation beyond reputeAdamHeard has a reputation beyond repute
Send a message via AIM to AdamHeard
Re: Team 254 2011 FRC Code

Quote:
Originally Posted by otherguy View Post
Is there a reason you choose to use a polynomial function instead of a piecewise linear function?

From your empirical data it looks like no more than 5 linear sections (see red lines in figure below) would be needed to characterize the curve quite well.

This would significantly cut down on the number of computations needed to return a result, and in this case it look like it might even more accurately fit the input data.

It's easier to generate the polynomial with software (completely avoiding any transcription by hand or hand calcs). This is unless there is a piece-wise linear approximation tool I am unaware of.

Also, for simple math, it's not really a concern when running on the cRio.
  #20   Spotlight this post!  
Unread 22-11-2011, 11:19
JesseK's Avatar
JesseK JesseK is offline
Expert Flybot Crasher
FRC #1885 (ILITE)
Team Role: Mentor
 
Join Date: Mar 2007
Rookie Year: 2005
Location: Reston, VA
Posts: 3,722
JesseK has a reputation beyond reputeJesseK has a reputation beyond reputeJesseK has a reputation beyond reputeJesseK has a reputation beyond reputeJesseK has a reputation beyond reputeJesseK has a reputation beyond reputeJesseK has a reputation beyond reputeJesseK has a reputation beyond reputeJesseK has a reputation beyond reputeJesseK has a reputation beyond reputeJesseK has a reputation beyond repute
Re: Team 254 2011 FRC Code

Don't forget that another option is pre-processing of lookup tables, if the memory will hold it. 256 data points, 1 per PWM step, would be easy to calculate during sensor initialization and also cut down on cycles. Preprocessing it instead of pre-programming it also allows you to make adjustments to parameters before each match (if needed).

I agree that it's probably not needed for the cRIO, but was very useful for old-school quadrotors on primitive processors. It also helped back in the 90's with signal processing algorithms that needed to be realtime.

Theoretically one could pre-process all of the possible motor outputs versus inputs such that a lookup was done given sensor/driver input instead of a calculation -- but that's a bit overboard.
__________________

Drive Coach, 1885 (2007-present)
CAD Library Updated 5/1/16 - 2016 Curie/Carver Industrial Design Winner
GitHub

Last edited by JesseK : 22-11-2011 at 11:23.
  #21   Spotlight this post!  
Unread 22-11-2011, 11:24
Andrew Schreiber Andrew Schreiber is offline
Joining the 900 Meme Team
FRC #0079
 
Join Date: Jan 2005
Rookie Year: 2000
Location: Misplaced Michigander
Posts: 4,080
Andrew Schreiber has a reputation beyond reputeAndrew Schreiber has a reputation beyond reputeAndrew Schreiber has a reputation beyond reputeAndrew Schreiber has a reputation beyond reputeAndrew Schreiber has a reputation beyond reputeAndrew Schreiber has a reputation beyond reputeAndrew Schreiber has a reputation beyond reputeAndrew Schreiber has a reputation beyond reputeAndrew Schreiber has a reputation beyond reputeAndrew Schreiber has a reputation beyond reputeAndrew Schreiber has a reputation beyond repute
Re: Team 254 2011 FRC Code

Quote:
Originally Posted by JesseK View Post
Don't forget that another option is pre-processing of lookup tables, if the memory will hold it. 256 data points, 1 per PWM step, would be easy to calculate during sensor initialization and also cut down on cycles ('triple sin wave ftw'). Preprocessing it instead of pre-programming it also allows you to make adjustments to parameters before each match (if needed).

I agree that it's probably not needed for the cRIO, but was very useful for old-school quadrotors on primitive processors. It also helped back in the 90's with signal processing algorithms that needed to be realtime.
Interestingly, we can specify 256 unique positions (0-255) but only a portion of them produce unique outputs on the Victor. http://www.ifirobotics.com/forum/viewtopic.php?t=317
__________________




.
  #22   Spotlight this post!  
Unread 22-11-2011, 11:52
Ether's Avatar
Ether Ether is offline
systems engineer (retired)
no team
 
Join Date: Nov 2009
Rookie Year: 1969
Location: US
Posts: 8,125
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: Team 254 2011 FRC Code

Quote:
Originally Posted by JesseK View Post
Don't forget that another option is pre-processing of lookup tables, if the memory will hold it. 256 data points, 1 per PWM step, would be easy to calculate during sensor initialization and also cut down on cycles.
See the link in Post 18 of this thread.


  #23   Spotlight this post!  
Unread 22-11-2011, 11:56
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: Team 254 2011 FRC Code

Quote:
Originally Posted by AustinSchuh View Post
I generated the red data points by putting the robot up on blocks and applying PWM to the motors. I then read out the wheel speed at steady state for various PWM values.
Can you mention the software you used to generate the plots? Is it homegrown software or commercial? The screenshot looks like ZedGraph...
  #24   Spotlight this post!  
Unread 22-11-2011, 11:58
Ether's Avatar
Ether Ether is offline
systems engineer (retired)
no team
 
Join Date: Nov 2009
Rookie Year: 1969
Location: US
Posts: 8,125
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: Team 254 2011 FRC Code

Quote:
Originally Posted by jwakeman View Post
Can you mention the software you used to generate the plots? Is it homegrown software or commercial? The screenshot looks like ZedGraph...
It's gnuplot. Free. Highly recommended.

http://www.gnuplot.info/


Last edited by Ether : 22-11-2011 at 12:00. Reason: added link
  #25   Spotlight this post!  
Unread 03-12-2011, 00:53
otherguy's Avatar
otherguy otherguy is offline
sparkE
AKA: James
FRC #2168 (The Aluminum Falcons)
Team Role: Mentor
 
Join Date: Feb 2010
Rookie Year: 2009
Location: CT
Posts: 443
otherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to behold
Re: Team 254 2011 FRC Code

Quote:
Originally Posted by Ether View Post
Did you do an analysis to determine whether the piecewise linear code plus the conditional logic it requires executes faster than the single polynomial ?

If speed is what you need, it's hard to beat a complete lookup table (no interpolation required):

http://www.chiefdelphi.com/forums/sh...1&postcount=12

They aren't using a single polynomial, they're using a 5th order poly and 7th order poly, then averaging the two.

The only reason I asked the question is because I looked at their code, and it seemed pretty involved for something that needs to be calculated every time you want to send an output to a motor controller.

Code:
double RobotState::victor_linearize(double goal_speed)
{
	const double deadband_value = 0.082;
	if (goal_speed > deadband_value)
		goal_speed -= deadband_value;
	else if (goal_speed < -deadband_value)
		goal_speed += deadband_value;
	else
		goal_speed = 0.0;
	goal_speed = goal_speed / (1.0 - deadband_value);

	double goal_speed2 = goal_speed * goal_speed;
	double goal_speed3 = goal_speed2 * goal_speed;
	double goal_speed4 = goal_speed3 * goal_speed;
	double goal_speed5 = goal_speed4 * goal_speed;
	double goal_speed6 = goal_speed5 * goal_speed;
	double goal_speed7 = goal_speed6 * goal_speed;

	// Constants for the 5th order polynomial
	double victor_fit_e1		= 0.437239;
	double victor_fit_c1		= -1.56847;
	double victor_fit_a1		= (- (125.0 * victor_fit_e1  + 125.0 * victor_fit_c1 - 116.0) / 125.0);
	double answer_5th_order = (victor_fit_a1 * goal_speed5
					+ victor_fit_c1 * goal_speed3
					+ victor_fit_e1 * goal_speed);

	// Constants for the 7th order polynomial
	double victor_fit_c2 = -5.46889;
	double victor_fit_e2 = 2.24214;
	double victor_fit_g2 = -0.042375;
	double victor_fit_a2 = (- (125.0 * (victor_fit_c2 + victor_fit_e2 + victor_fit_g2) - 116.0) / 125.0);
	double answer_7th_order = (victor_fit_a2 * goal_speed7
					+ victor_fit_c2 * goal_speed5
					+ victor_fit_e2 * goal_speed3
					+ victor_fit_g2 * goal_speed);


	// Average the 5th and 7th order polynomials
	double answer =  0.85 * 0.5 * (answer_7th_order + answer_5th_order)
			+ .15 * goal_speed * (1.0 - deadband_value);

	if (answer > 0.001)
		answer += deadband_value;
	else if (answer < -0.001)
		answer -= deadband_value;

	return answer;
}

They clearly have a handle on things, so I was wondering if this approach provided them something over what I teach my kids (the piecewise linear approach described previously)

here's the code one of my kids came up with as part of a pre-season homework assignment a few weeks ago. "scale" is a 2d array of points characterizing the piecewise function. The benefit of implementing it this way is that you can modify your array of points at any time, to tweak behavior, without having to modify your code.
Code:
    static double getInterpolatedAxis(double input){
        for(int i=0;i<scale.length-1;i++){
             if(input<scale[i][0]&&input>scale[i+1][0]){
                double slope=(scale[i+1][1]-scale[i][1])/(scale[i+1][0]-scale[i][0]);//get slope
                double intercept = (-1*slope*scale[i][0])+scale[i][1];
                return (slope*input)+intercept;
            }
        }
    }
Anyone who's been through an Algebra 1 class should be able to quickly grasp the math. Added bonus of them getting to apply existing classroom knowledge.
  #26   Spotlight this post!  
Unread 03-12-2011, 01:03
otherguy's Avatar
otherguy otherguy is offline
sparkE
AKA: James
FRC #2168 (The Aluminum Falcons)
Team Role: Mentor
 
Join Date: Feb 2010
Rookie Year: 2009
Location: CT
Posts: 443
otherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to beholdotherguy is a splendid one to behold
Re: Team 254 2011 FRC Code

Quote:
Originally Posted by AdamHeard View Post
It's easier to generate the polynomial with software (completely avoiding any transcription by hand or hand calcs). This is unless there is a piece-wise linear approximation tool I am unaware of.

Also, for simple math, it's not really a concern when running on the cRio.
No tool is needed, you simply identify the X and Y coordinates of points that define the lines.

My team dumps these points into a 2d array and uses the point slope formula to calculate the output for any given input.

Quote:
Don't forget that another option is pre-processing of lookup tables, if the memory will hold it. 256 data points, 1 per PWM step, would be easy to calculate during sensor initialization and also cut down on cycles. Preprocessing it instead of pre-programming it also allows you to make adjustments to parameters before each match (if needed).
Agreed, we could pre-compute a lookup table, but unless we compute for all possible inputs we'll have to quantize the output or interpolate between the points.

The main reason why we don't take this approach on my team is because of the flexibility provided by the piecewise function. We can code our method once and set it up to operate on a 2d array of x,y coordinates. Changing that array is SUPER simple if we need to do so later on, and won't require any changes to the supporting code.
  #27   Spotlight this post!  
Unread 03-12-2011, 02:36
AustinSchuh AustinSchuh is offline
Registered User
FRC #0971 (Spartan Robotics) #254 (The Cheesy Poofs)
Team Role: Engineer
 
Join Date: Feb 2005
Rookie Year: 1999
Location: Los Altos, CA
Posts: 803
AustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond reputeAustinSchuh has a reputation beyond repute
Re: Team 254 2011 FRC Code

Quote:
Originally Posted by otherguy View Post
They aren't using a single polynomial, they're using a 5th order poly and 7th order poly, then averaging the two.
Given how overpowered the cRIO actually is, this doesn't use much compute power. It is only calculated 200 times a second (Could be a different amount, it has been a while). We don't come close to running out of compute power, so why worry?

Once we had a working solution, we stopped working on it. There are more numerically efficient ways to get a similar answer, but we moved on to more important problems once we had a working answer. Now that I look at it in more detail, we could probably cut out half the compute cycles in the function without much work (Bring it down to around 10 multiplies, probably even less). You can read my description above for how I came up with the functions themselves. They really aren't that hard to fit.

I'm a big fan of smooth motion. I don't like corners, or corner cases. Unless there were a good number of segments to the piecewise fit, it would have "corners" that I could "feel" as I drive it. When I tried driving with the original 5th order polynomial, I could feel the oscillations in the result and didn't like it at all. And hand fiddling with the piecewise function to get it to feel nice and match well would be as much work as the polynomial. Also, I read Adam's statement as saying that trying to automatically fit piecewise lines to the points is a lot harder than just fitting a polynomial. If you look at the source data that I started from, it is a bit noisy. Just interpolating between the points would be sub-optimal.
  #28   Spotlight this post!  
Unread 03-12-2011, 09:16
Ether's Avatar
Ether Ether is offline
systems engineer (retired)
no team
 
Join Date: Nov 2009
Rookie Year: 1969
Location: US
Posts: 8,125
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: Team 254 2011 FRC Code


Quote:
Originally Posted by otherguy View Post
They aren't using a single polynomial, they're using a 5th order poly and 7th order poly, then averaging the two.
What do you get when you add two polynomials together? They could have gotten the same result with a single polynomial:

If P is a 7th degree poly, and R is a 5th degree poly, then Q = a*P+b*R is a 7th degree polynomial ("a" and "b" are constants).

I was trying to point out that it is not immediately obvious that a piecewise linear function "would significantly cut down on the number of computations needed to return a result" compared to a single polynomial. I inferred, based on the context, that you intended the word "computations" to imply "processing speed" and include not just arithmetic but conditional logic and branching as well.


By the way, if you use two nx1 arrays instead of one nx2 array it saves cycles computing the indices. And if you pre-sort your [x[],y[]] points so they are in increasing order by x[], you can save a few cycles in your table lookup logic by eliminating one of the tests. Assuming x[0,1,..n] and y[0,1,...n] are tables of X and Y data values, and [x[n],y[n]] is a sentinel point to assure the function always returns a value:

for (i=1,i<=n,i++) if (ax<x[i]) return y[i]+(ax-x[i])/(x[i-1]-x[i])*(y[i-1]-y[i]);

Depending on the compiler, it might save a few more cycles to use pointer arithmetic to scan the x[] table.




Last edited by Ether : 03-12-2011 at 09:40.
  #29   Spotlight this post!  
Unread 08-12-2011, 12:34
Thad House Thad House is online now
Volunteer, WPILib Contributor
no team (Waiting for 2021)
Team Role: Mentor
 
Join Date: Feb 2011
Rookie Year: 2010
Location: Thousand Oaks, California
Posts: 1,107
Thad House has a reputation beyond reputeThad House has a reputation beyond reputeThad House has a reputation beyond reputeThad House has a reputation beyond reputeThad House has a reputation beyond reputeThad House has a reputation beyond reputeThad House has a reputation beyond reputeThad House has a reputation beyond reputeThad House has a reputation beyond reputeThad House has a reputation beyond reputeThad House has a reputation beyond repute
Re: Team 254 2011 FRC Code

Quote:
Originally Posted by AustinSchuh View Post
Given how overpowered the cRIO actually is, this doesn't use much compute power. It is only calculated 200 times a second (Could be a different amount, it has been a while). We don't come close to running out of compute power, so why worry?

Once we had a working solution, we stopped working on it. There are more numerically efficient ways to get a similar answer, but we moved on to more important problems once we had a working answer. Now that I look at it in more detail, we could probably cut out half the compute cycles in the function without much work (Bring it down to around 10 multiplies, probably even less). You can read my description above for how I came up with the functions themselves. They really aren't that hard to fit.

I'm a big fan of smooth motion. I don't like corners, or corner cases. Unless there were a good number of segments to the piecewise fit, it would have "corners" that I could "feel" as I drive it. When I tried driving with the original 5th order polynomial, I could feel the oscillations in the result and didn't like it at all. And hand fiddling with the piecewise function to get it to feel nice and match well would be as much work as the polynomial. Also, I read Adam's statement as saying that trying to automatically fit piecewise lines to the points is a lot harder than just fitting a polynomial. If you look at the source data that I started from, it is a bit noisy. Just interpolating between the points would be sub-optimal.
When I was looking at the code and converting it to LabView, I realized that there are 3 calculated constants that you could replace if you quickly wanted to speed up the function. Both victor_fit_a1 and victor_fit_a2 are constants that are calculated, that you could replace with actual constants Also for the answer function .85*.5 can be combined if you need a little extra resources.
__________________
All statements made are my own and not the feelings of any of my affiliated teams.
Teams 1510 and 2898 - Student 2010-2012
Team 4488 - Mentor 2013-2016
Co-developer of RobotDotNet, a .NET port of the WPILib.
  #30   Spotlight this post!  
Unread 08-12-2011, 12:57
Ether's Avatar
Ether Ether is offline
systems engineer (retired)
no team
 
Join Date: Nov 2009
Rookie Year: 1969
Location: US
Posts: 8,125
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: Team 254 2011 FRC Code

Quote:
Originally Posted by sst.thad View Post
When I was looking at the code and converting it to LabView, I realized that there are 3 calculated constants that you could replace if you quickly wanted to speed up the function. Both victor_fit_a1 and victor_fit_a2 are constants that are calculated, that you could replace with actual constants Also for the answer function .85*.5 can be combined if you need a little extra resources.
Those calculations are done at compile time, not run time. Changing them will not speed up the code.



Closed Thread


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 01:05.

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