Go to Post WHAT!?!?!? YOU DON'T DEVOTE YOUR LIFE TO APPLE!?!?!?!? ;) :p - Joe Matt [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
  #1   Spotlight this post!  
Unread 30-01-2008, 17:44
SuperBK's Avatar
SuperBK SuperBK is offline
Registered User
AKA: BrianK
FRC #1225 (Amperage Robotics)
Team Role: Mentor
 
Join Date: Jan 2007
Rookie Year: 2006
Location: Henersonville, NC
Posts: 358
SuperBK is just really niceSuperBK is just really niceSuperBK is just really niceSuperBK is just really nice
PID for velocity control

We want to implement a PID for velocity control of the left and right motors. We understand how a position PID works, but for a velocity control, when the motor reaches the desired velociy, the error will be zero, therefore, it will only have the I and D terms to keep it driving. Is that enough? In this case would the integral sum never be cleared?

About resolution: Right now we get around 1200 counts per second at full speed from the gear tooth sensors. If we wait for 100ms that will give us a speed range of 0-120. Should the PID calculation only run at the same rate? If the PID loop runs ever 26 ms, it will aleady have run three times before we have a speed update. Whats a good balance of PID loop time to data update time?

Is the 26.2ms main loop stable enough to run the PID in or should it have its own timer?

Thanks,
Brian
__________________
Brian K
Team 1225 Robotics Mentor
  #2   Spotlight this post!  
Unread 30-01-2008, 22:24
Alan Anderson's Avatar
Alan Anderson Alan Anderson is offline
Software Architect
FRC #0045 (TechnoKats)
Team Role: Mentor
 
Join Date: Feb 2004
Rookie Year: 2004
Location: Kokomo, Indiana
Posts: 9,113
Alan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond reputeAlan Anderson has a reputation beyond repute
Re: PID for velocity control

There's a perfect answer to what you want. It's called "velocity PID", and it works by computing the required change in output instead of the output itself.

I spent quite some time a couple of weeks ago trying to help the TechnoKats software group implement a velocity PID routine for our robot's drive motors. I might have been doing it wrong, or I might not have been patient enough when trying to tune the PID constants, or I might just have been fighting easyC too hard. In the end, however, we discarded the idea of controlling motor speed, and instead implemented a positional PID control for the robot itself.

To get the effect of closed-loop speed control, we just move the desired robot position at the right rate, and the robot follows along smoothly. There's a similar positional PID for direction, and turning the robot at a given rate works by changing the desired direction at that rate. Feedback inputs to both PID controllers are from quadrature encoders on the drive wheel shaft. The sum of the encoder counts is used as an odometer, and the difference tells us the robot's present heading relative to when it started.
  #3   Spotlight this post!  
Unread 31-01-2008, 01:32
Uberbots's Avatar
Uberbots Uberbots is offline
Mad Programmer
AKA: Billy Sisson
FRC #1124 (ÜberBots)
Team Role: College Student
 
Join Date: Jan 2006
Rookie Year: 2005
Location: Avon
Posts: 739
Uberbots has a reputation beyond reputeUberbots has a reputation beyond reputeUberbots has a reputation beyond reputeUberbots has a reputation beyond reputeUberbots has a reputation beyond reputeUberbots has a reputation beyond reputeUberbots has a reputation beyond reputeUberbots has a reputation beyond reputeUberbots has a reputation beyond reputeUberbots has a reputation beyond reputeUberbots has a reputation beyond repute
Re: PID for velocity control

Interesting solution, alan...

with our robot we just implemented the pid loop so that the motors corrected for a desired speed, and it worked fine (well that is until the mech. team decided to take electronics into their own hands and killed the wiring...). I dont think we did anything differently from a position correction, besides differentiating position before using it as the feedback.
__________________
A few of my favorite numbers:
175 176 177 195 230 558 716 1024 1071 1592 1784 1816
RPI 2012
BREAKAWAY
  #4   Spotlight this post!  
Unread 31-01-2008, 07:01
Jon236's Avatar
Jon236 Jon236 is offline
Registered User
AKA: Jon Mittelman
FRC #2648 (Infinite Loop)
Team Role: Mentor
 
Join Date: Jan 2004
Rookie Year: 2000
Location: Windsor, Maine
Posts: 741
Jon236 has a reputation beyond reputeJon236 has a reputation beyond reputeJon236 has a reputation beyond reputeJon236 has a reputation beyond reputeJon236 has a reputation beyond reputeJon236 has a reputation beyond reputeJon236 has a reputation beyond reputeJon236 has a reputation beyond reputeJon236 has a reputation beyond reputeJon236 has a reputation beyond reputeJon236 has a reputation beyond repute
Re: PID for velocity control

So we're not the only team whose Build Team can't quite understand "What part of DON'T cut the wires don't you understand?"
__________________
Jon Mittelman

Senior Judge Advisor New England & Israel 2014-2015
Infinite Loop Mentor 2011-2015
TechnoTicks Mentor 2000-2011
Championship Chairman's Award 2009 Team236 TechnoTicks
Judge 2010-2015 Championships
Senior Judge Advisor New England District Championship 2014-2015
Judge Advisor Tel Aviv Regional 2007-2015
Judge Advisor Pine Tree Regional 2013
Maine Regional Planning Committee
New England District Planning Committee
Lead Inspector Microsoft Tel Aviv Regional 2006-2008
Judge & Lead Inspector GM/Technion Tel Aviv Regional 2006
Judge UTC Hartford Regional 2006
  #5   Spotlight this post!  
Unread 31-01-2008, 07:44
JBotAlan's Avatar
JBotAlan JBotAlan is offline
Forever chasing the 'bot around
AKA: Jacob Rau
FRC #5263
Team Role: Mentor
 
Join Date: Sep 2004
Rookie Year: 2004
Location: Riverview, MI
Posts: 723
JBotAlan has a reputation beyond reputeJBotAlan has a reputation beyond reputeJBotAlan has a reputation beyond reputeJBotAlan has a reputation beyond reputeJBotAlan has a reputation beyond reputeJBotAlan has a reputation beyond reputeJBotAlan has a reputation beyond reputeJBotAlan has a reputation beyond reputeJBotAlan has a reputation beyond reputeJBotAlan has a reputation beyond reputeJBotAlan has a reputation beyond repute
Send a message via AIM to JBotAlan Send a message via Yahoo to JBotAlan
Re: PID for velocity control

Not to threadjack TOO much, but I am curious: do I need a really high resolution for D to work properly? I just have a resolution of degrees right now, because I am scaling the input before it hits the PID. It's just way too crazy to try to tune...I have a hack in place that zeroes the I term on my steering motor (guess what we're doing for a drivetrain... ) when we're inside a deadband...but I know that's not the right way to do it.

Does D fix my overshooting problems?

JBot
__________________
Aren't signatures a bit outdated?
  #6   Spotlight this post!  
Unread 31-01-2008, 08:43
Bomberofdoom's Avatar
Bomberofdoom Bomberofdoom is offline
Biggest FIRST addict in Israel
AKA: Nir Levanon
FRC #2230 (Zcharia's Angels)
Team Role: Programmer
 
Join Date: Jan 2007
Rookie Year: 2007
Location: Israel
Posts: 471
Bomberofdoom has a reputation beyond reputeBomberofdoom has a reputation beyond reputeBomberofdoom has a reputation beyond reputeBomberofdoom has a reputation beyond reputeBomberofdoom has a reputation beyond reputeBomberofdoom has a reputation beyond reputeBomberofdoom has a reputation beyond reputeBomberofdoom has a reputation beyond reputeBomberofdoom has a reputation beyond reputeBomberofdoom has a reputation beyond reputeBomberofdoom has a reputation beyond repute
Send a message via MSN to Bomberofdoom
Re: PID for velocity control

Quote:
Originally Posted by Jon236 View Post
So we're not the only team whose Build Team can't quite understand "What part of DON'T cut the wires don't you understand?"
We're one of the teams that we need to tell our PROGRAMMING TEAM "What part of DON'T cut the PWM wires don't you understand?".

__________________
TEAM 2230 ZECHARIA'S ANGELS

2009 Microsoft Israel FRC Regional Winners!
2009 Microsoft Israel FRC Regional Chairman's Award Winners!!!
---------------------------------
2008 Microsoft Israel FRC Regional semi-finalist.
2008 Microsoft Israel FRC Regional Delphi's "Driving Tommorow's Technology" Award winner.
2008 Robot Driver
---------------------------------
2007 GM/Technion Israel FRC Regional semi-Finalist.
2007 GM/Technion Israel FRC Regional Xerox Creativity Award winner.
2007 Robot Driver.
  #7   Spotlight this post!  
Unread 31-01-2008, 10:34
Mr. Lim Mr. Lim is offline
Registered User
AKA: Mr. Lim
no team
Team Role: Leadership
 
Join Date: Jan 2004
Rookie Year: 1998
Location: Toronto, Ontario
Posts: 1,125
Mr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond repute
Re: PID for velocity control

Quote:
Originally Posted by SuperBK View Post
We want to implement a PID for velocity control of the left and right motors. We understand how a position PID works, but for a velocity control, when the motor reaches the desired velociy, the error will be zero, therefore, it will only have the I and D terms to keep it driving. Is that enough? In this case would the integral sum never be cleared?

About resolution: Right now we get around 1200 counts per second at full speed from the gear tooth sensors. If we wait for 100ms that will give us a speed range of 0-120. Should the PID calculation only run at the same rate? If the PID loop runs ever 26 ms, it will aleady have run three times before we have a speed update. Whats a good balance of PID loop time to data update time?

Is the 26.2ms main loop stable enough to run the PID in or should it have its own timer?

Thanks,
Brian
Brian, I'm referencing Kevin Watson's Navigation code that can be found at: http://frc.kevin.org/frc/2005/. It includes both speed and velocity PID control routines. We've used these in the past with a good amount of success. They can provide a good reference for what you're doing.

The code samples the change in encoder pulses each 26ms cycle, and that's your PID input. The PID and speed updates are both done in the 26 ms cycle, and it appeared to be stable enough, as the main loop is timer driven as well. We used this with Grayhill encoders pulsing at under 2000pps at full speed, and got good velocity control.

Regarding "I," when we hit our desired velocity, the system overshot until negative error, and eventually our "I" term decayed. Under straight driving conditions, it wasn't really that noticeable, because the system reacts fast enough that a large I never really accumulates. This WAS really noticeable when we turned our robot about its axis. The system didn't react as fast because there is a lot more resistance turning on axis, than driving in a straight line, so "I" had the opportunity to wind up a lot more. This resulted in a lot of overshoot... uncontrollable overshoot.

Do you really need an "I" term at all in velocity control? Maybe , because your system's characteristics change depending on whether you're going straight, or turning, or whether you're being pushed. "I" is a pretty good way of handling all those difference situations, except for the overshoot it causes.

You'll find that a lot of teams do talk about interesting ways to selectively use "I" in velocity control, but I'm definitely not the right person to be commenting about that!

-Shawn...
  #8   Spotlight this post!  
Unread 31-01-2008, 17:20
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: PID for velocity control

We measure the period between the pulses from our quadrature encoders (setting up timer 2 as a rolling counter). Then you get more bandwidth on the feedback than you can possibly use. Of course you have to put together a nifty way to do 1/x using integer math to derive the velocity.

The I term is supposed to help the wheel match the target velocity over long periods of time. Its probably not necessary for this application, P and D are more critical. If you do use the I term, it is common to have an I limit so you don't accumulate error (as described in last post). And the I term is typically quite small compared to P and D.

HTH

Last edited by wireties : 31-01-2008 at 17:24.
  #9   Spotlight this post!  
Unread 31-01-2008, 19:01
psy_wombats's Avatar
psy_wombats psy_wombats is offline
Registered User
AKA: A. King
FRC #0467 (Duct Tape Bandits)
Team Role: Programmer
 
Join Date: Jan 2007
Rookie Year: 2007
Location: Shrewsbury MA
Posts: 95
psy_wombats has a spectacular aura aboutpsy_wombats has a spectacular aura aboutpsy_wombats has a spectacular aura about
Re: PID for velocity control

So, looking at Kevin Watson's velocity PID code...

Chiefly I'm looking at the differences between the normal position-based code and the velocity, as we currently have a working normal PID. Looks like it comes down to this line:
Code:
motor_info[motor].vel = ((vel_last * 9) + (motor_info[motor].pos - pos_last) * HZ) / 10;
Now, I understand that acceleration is being calculated rather than velocity like the position PID, but, two questions to Kevin or whoever might be knowledgeable:
1 - Where exactly is the 9/10 bit coming from? Is some form of scaling the old value? If not, how was it derived?
2 -What is the purpose of the hertz? I know what it is, just not what it does.

Sorry, I know I could just replicate that line, but I'm apprehensive about adopting code I have no idea what does. Any help is appreciated.
  #10   Spotlight this post!  
Unread 01-02-2008, 21:53
EricS-Team180's Avatar
EricS-Team180 EricS-Team180 is offline
SPAM, the lunchmeat of superheroes!
AKA: Eric Schreffler
FRC #0180 (SPAM)
Team Role: Engineer
 
Join Date: Apr 2002
Rookie Year: 2001
Location: Stuart, Florida
Posts: 561
EricS-Team180 has a reputation beyond reputeEricS-Team180 has a reputation beyond reputeEricS-Team180 has a reputation beyond reputeEricS-Team180 has a reputation beyond reputeEricS-Team180 has a reputation beyond reputeEricS-Team180 has a reputation beyond reputeEricS-Team180 has a reputation beyond reputeEricS-Team180 has a reputation beyond reputeEricS-Team180 has a reputation beyond reputeEricS-Team180 has a reputation beyond reputeEricS-Team180 has a reputation beyond repute
Re: PID for velocity control

Quote:
Originally Posted by psy_wombats View Post
So, looking at Kevin Watson's velocity PID code...

Looks like it comes down to this line...
Code:
motor_info[motor].vel = ((vel_last * 9) + (motor_info[motor].pos - pos_last) * HZ) / 10;
1 - Where exactly is the 9/10 bit coming from? Is some form of scaling the old value? If not, how was it derived?
2 -What is the purpose of the hertz? I know what it is, just not what it does.
Looks to me like 90% of the last pass speed + 10% of the current speed (current position - last pass position for 1 pass in the loop)

...where you take that change in position (for 1 pass) times the passes/second (HZ or hertz) to change it to units to match vel_last

That's a low pass filter on speed, whose purpose is to reduce noise in the signal.
__________________

Don't PANIC!
S. P. A. M.

Last edited by EricS-Team180 : 01-02-2008 at 21:56.
  #11   Spotlight this post!  
Unread 01-02-2008, 22:30
Mr. Lim Mr. Lim is offline
Registered User
AKA: Mr. Lim
no team
Team Role: Leadership
 
Join Date: Jan 2004
Rookie Year: 1998
Location: Toronto, Ontario
Posts: 1,125
Mr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond reputeMr. Lim has a reputation beyond repute
Re: PID for velocity control

As above, the 9/10 section is a less expensive way of "taking the average of the last 10 samples"...

Nice in case a GTS or encoder vibrates across a transition, which results in a few phantom pulses. It won't cause a huge reaction in your system.

The HZ is a scale factor for the 26ms cycle period. The parameter for setting velocity is in pulses per second, so muliplying by HZ will convert from pulses per cycle to pulses per second.

Last edited by Mr. Lim : 01-02-2008 at 22:37.
  #12   Spotlight this post!  
Unread 01-02-2008, 23:30
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: PID for velocity control

One way to help solve the problem is to implement Feed Forward. The basic idea behind Feed Foward is to utilize any extra information you know to make the controller more accurate and responsive.

For driving, the best feed forward information to utilize is your desired drive velocity. If you want to drive at 1/2 of full speed, it takes a certain power level to be applied to each wheel. That number won't change too much, or at least more than your PID controller can't deal with. You can implement that term by adding in a power value to the PID controller that you look up in a lookup table using the goal velocity.

You can have as much fun as you want imagining all sorts of feed forward ideas to implement that will help model what power you need to give the motors before the PID controller deals with the last little bit. I have always wanted to figure out how to get the controller to add in extra power when it knows it wants to accelerate, but I haven't figured out how to model that yet to implement it.
  #13   Spotlight this post!  
Unread 02-02-2008, 16:34
Jared Russell's Avatar
Jared Russell Jared Russell is offline
Taking a year (mostly) off
FRC #0254 (The Cheesy Poofs), FRC #0341 (Miss Daisy)
Team Role: Engineer
 
Join Date: Nov 2002
Rookie Year: 2001
Location: San Francisco, CA
Posts: 3,078
Jared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond reputeJared Russell has a reputation beyond repute
Re: PID for velocity control

A couple things to keep in mind here:

The standard POSITION PID loop might look something like this:

output = Kp*e_pos + Ki*e_pos_sum + Kd*e_pos_delta;

Where output is the output.
e_pos is the error in position = desired_pos - actual_pos
e_pos_sum is the sum of the position errors = e_pos_sum + e_pos
e_pos_delta is the derivative of the error = e_pos - e_pos_last

(Yes, I know there are other ways to write the PID equation - I usually use the recursive discrete form so I don't need to keep track of an error sum, but I digress...).

This loop, if well tuned, should provide pretty good position control. But what about VELOCITY? Speed is the first derivative of position - so we could differentiate the position loop with respect to time to obtain a velocity controller.

I will use the D() operator to represent taking the time derivative.

D(output) = Kp*D(e_pos) + Ki*D(e_pos_sum) + Kd*D(e_pos_delta);

So far so good. What's the derivative of the output? Well, that's the change in output over time, so D(output) = output - output_last.

Whats the derivative of e_pos? Remember that e_pos itself is (desired_pos - actual_pos). It's derivative would simply replace "pos" with "vel".

e_vel = D(e_pos) = desired_vel - actual_vel.
e_vel_sum = D(e_pos_sum) = e_vel_sum + e_vel.
e_vel_delta = D(e_pos_delta) = e_vel - e_vel_last.

Putting it all together, you get:

output - output_last = Kp*e_vel + Ki*e_vel_sum + Kd*e_vel_delta;

Let's rearrange...

output = output_last + Kp*e_vel + Ki*e_vel_sum + Kd*e_vel_delta;

or...

output += Kp*e_vel + Ki*e_vel_sum + Kd*e_vel_delta;
(assuming output is global or static and persists between loop iterations)

So that's how you'd make a velocity controller. Note that the constants will be different than from the positional case (obviously).

One other thing - most of the time, people only care about closed loop velocity control in a robot in order to GO STRAIGHT. Having two separate PID controllers (one for each side) is one way to do this. But what if I bump the robot off course? The two sides will independently stabilize near the setpoint after the disturbance, but the entire robot may be pointed in a new direction.

Without giving everything away, what if your error term was not (desired - actual), but rather (left_actual - right_actual)? With some changes to the above equation, and a nonzero Ki, the robot will correct its course as it drives, effectively slowing down one motor when the other gets slowed down because of the environment.
  #14   Spotlight this post!  
Unread 04-02-2008, 23:16
SuperBK's Avatar
SuperBK SuperBK is offline
Registered User
AKA: BrianK
FRC #1225 (Amperage Robotics)
Team Role: Mentor
 
Join Date: Jan 2007
Rookie Year: 2006
Location: Henersonville, NC
Posts: 358
SuperBK is just really niceSuperBK is just really niceSuperBK is just really niceSuperBK is just really nice
Re: PID for velocity control

Thanks for the great replies. It validates that we should keep working on it and that it can work. So far it kinda works, but we have to turn down the proportional gain so far that it actually ramps to the desired velocity because if its highter it will oscillate around the desired velocity. Then since the proportional gain is so low, it can't make small changes to reach the desired speed. Adding in some integral makes it go crazy - it needs to be scaled way back and limited.

One problem we have is that there is a lag from the time you tell the motor to go and the time it starts moving. I see it with prints. You can see it in normal mode where you just assign the pwm value from the joystick. By the time the motor actually starts moving, it has already ran the PID a few times and cranked up the drive too high. Therefore the wheels starts spinning faster than they should. The same thing happens when holding a wheel and you let go and it spins faster for a short time. Each time through the velocity loop it adds to the drive.

Also, we are using gear tooth sensors, not encoders. We cannot tell the direction, so we assume the speed is in the direction we are pointing the joystick. At first we were using the value of the previouls drive, but if it crosses 127, then it will think the speed is going the wrong way. The GTS give us 1200 counts per seconds at full speed. We time it for 50ms and that gives us a relative "speed" of 0-60. Then we try to scale that 0-60 so it looks like the 0-255that comes from the joystick. The joystick minus the speed is our error.

I'm thinking of trying some "feed forward" that starts the wheel off moving at a value close to where it should be, then let the PID home it in. It seems like we need to allow time for the system to react before adjusting it again.

Thanks,
Brian
__________________
Brian K
Team 1225 Robotics Mentor
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

Similar Threads
Thread Thread Starter Forum Replies Last Post
Integral Window for PID Control phrontist Programming 2 16-02-2008 17:32
paper: PID Control Theory for FRC Programming Matt Krass Programming 17 24-05-2007 03:28
What constants are u using for high velocity PID Salik Syed Programming 3 18-02-2006 23:22
Problems Using PID for Velocity Astronouth7303 Programming 6 10-02-2006 09:00
Manual Velocity PID, anyone successful? Chris_Elston Programming 20 31-01-2006 20:51


All times are GMT -5. The time now is 19:13.

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