View previous topic :: View next topic |
Author |
Message |
Tom-H-PIC
Joined: 08 Sep 2003 Posts: 105 Location: New Castle, DE
|
PID control code integer math |
Posted: Mon Feb 06, 2012 9:18 am |
|
|
I have search the form for PID control using integer math.
And have found parts of code here and there in the form.
But have not found complete code for a PID control using integer math.
Am I missing it some place?
Or would someone be kind and post some in the code example for us.
Thanks
Tom |
|
|
gpsmikey
Joined: 16 Nov 2010 Posts: 588 Location: Kirkland, WA
|
|
Posted: Mon Feb 06, 2012 10:07 am |
|
|
Here was a good article I found on implementing PID - http://igor.chudov.com/manuals/Servo-Tuning/PID-without-a-PhD.pdf
The trick to doing it without having to use floating point is to scale (normalize) things when you are working with them then use multipliers/divisors etc that are factors of 2 (divide by 8 is simply shift right 3 bits). The one I built recently (for controlling the heat element on the hummingbird feeders in the winter here in the Seattle area :-) ) just used the PI portion (the hooks are there for the "D" portion, but it worked just fine as it was). There was also a good article on homebrew in a past issue of Circuit Cellar that discussed implementing the PID. June 2006 had that article. You may also find some additional information in this thread from a while back: http://www.ccsinfo.com/forum/viewtopic.php?p=151009
mikey _________________ mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3 |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Mon Feb 06, 2012 10:11 am |
|
|
I don't think you will find a cut & paste solution. You need to go through your PID algorythm by hand and see what the range of values may be for each variable. Then scale the variables into a decent integer range. Also note what might happen if any of them exceed the range, make sure it will fail gracefully and not catch fire or kill people. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Mon Feb 06, 2012 10:17 am |
|
|
The problem is that it always has to be custom tuned.
However if you post an email address to me, I'll send the 'core maths' directly from some old code I did.
Best Wishes |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Mon Feb 06, 2012 10:48 am |
|
|
The nice thing about Matlab is the ability to 'reverse engineeer' the PIC math to get the values for the PIC controller. Great for old guys like me that always move the decimal point the wrong way... |
|
|
gpsmikey
Joined: 16 Nov 2010 Posts: 588 Location: Kirkland, WA
|
|
Posted: Mon Feb 06, 2012 11:42 am |
|
|
temtronic wrote: | The nice thing about Matlab is the ability to 'reverse engineeer' the PIC math to get the values for the PIC controller.Great for old guys like me that always move the decimal point the wrong way... |
Ah ha !! Another frustrated slide rule user :-)
mikey (who comes from the era where the geeks had slide rules in leather cases on their belts ... ) _________________ mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3 |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1907
|
|
Posted: Mon Feb 06, 2012 5:36 pm |
|
|
Some old code from an old pet project of mine, a HERMS (heat exchanging recirculating mash system). PID section should be self explanatory. As has been suggested, start by reading "PID without a PhD" first and try to measure/model your system the best you can to come up with reasonable guesses for the P, I and D terms.
Code: |
#define p_gain 5 // 2^5 = 32
#define i_gain 11 // 2^11 = 2048
#define d_gain 10 // 2^10 = 1024
#define max_error 63 * (1 << (i_gain + 4))
void cycle_heaters(void) {
int m;
// lauter tun heater
if ((lauter_temp < (lauter_set_temp - 2)) && lauter_enable) {
bpin1 = 1; // turn on lauter tun heater relay
}
else if ((lauter_temp > lauter_set_temp) && lauter_enable) {
bpin1 = 0;
}
else if (!lauter_enable) {
bpin1 = 0;
}
// HE heater
// if pump is on, HE power setting is based on diff between present mash temp and mash set temp (PID)
// if pump is off, HE power setting is based on diff between present HE temp and mash set temp (thermostat)
// implementing a PID control to the mashtun power setting,
// increased resolution from 15 steps to 63. Power setting is based on the formula:
// setting = proportional term + integral term - differential term (limited to 0 - 63 range)
// proportional term = proportional gain * (set temp - present temp)
// integral term = integral gain * sum of (set temp - present temp), the sum of (set temp - present temp) is
// limited to lie within the range 0 - 63 * integral gain
// differential term = differential gain * (present temp - previous temp)
// prop gain = 32
// integral gain = 1/2048
// differential gain = 1024
error = ((int32)mash_set_temp << 4) - mash_temp_sixteenths;
if (started && piping == RECIRC) { // only calculate the PID coeff's if we're recirculating
total_error = total_error + error;
if (total_error > max_error) {
total_error = max_error;
}
else if (total_error < 0) {
total_error = 0;
}
}
p_term = error << p_gain; // "multiply"
i_term = total_error >> i_gain; // "divide"
if (total_error < 0) { // if total error is negative, must set msb's to 1's
for (m = 0; m < i_gain; m++) {
bit_set(i_term, 31 - m);
}
}
d_term = (mash_temp_sixteenths - old_mash_temp_sixteenths) << d_gain; // "multiply"
overall_gain = (p_term + i_term - d_term) >> 4;
if ((p_term + i_term - d_term) < 0) {
for (m = 0; m < 4; m++) {
bit_set(overall_gain, 31 - m);
}
}
if (overall_gain > 63) {
overall_gain = 63;
}
else if (overall_gain < 0) {
overall_gain = 0;
}
if (pump_on && piping == RECIRC) {
power_setting = overall_gain; // use PID only if we're recirculating
}
else if (he_temp < (mash_set_temp - 1)) { // ...otherwise just do a simple thermostat
power_setting = 32;
}
else if (he_temp > mash_set_temp) {
power_setting = 0;
}
print_temp((int16)power_setting, HE_POWER);
} |
|
|
|
Tom-H-PIC
Joined: 08 Sep 2003 Posts: 105 Location: New Castle, DE
|
PID control code integer math |
Posted: Wed Feb 08, 2012 6:29 am |
|
|
Thank you all for your replies and help.
Ttelmah I would really like to see your code so I sent you a PM with my email in it.
And Thanks again All
Tom |
|
|
|