View previous topic :: View next topic |
Author |
Message |
Carlos Barberis Guest
|
Anyone written a simple PID routine for a PIC??? |
Posted: Sun Feb 17, 2002 4:19 am |
|
|
HI
I am looking for a simple pid routine to control a small heater using the pwm output of the pic. Any hints would be appreciated.
___________________________
This message was ported from CCS's old forum
Original Post ID: 2637 |
|
|
Eric Minbiole Guest
|
Re: Anyone written a simple PID routine for a PIC??? |
Posted: Sun Feb 17, 2002 7:04 am |
|
|
:=I am looking for a simple pid routine to control a small heater using the pwm output of the pic. Any hints would be appreciated.
I recently finished a project that leviated a metal ball using an electromagnet. It used a PIC to control a PID loop which kept the ball floating stabily.
Here's the code for my PID loop. I'm sure it's not the best PID code out there, but it should give you a starting point to work from. The only tricky part of the code is in calculating the differential term. Rather than taking the difference of two adjacent samples, I averaged 4 old samples, and 4 new samples, and took the difference between the averages. This made the loop more immune to noisy samples.
Hope it helps!
// control loop constants
float Kp; // proportional gain
float Ki; // integral gain
float Kd; // differential gain
// terms
float Tp; // proportional term
float Ti; // integral term
float Td; // differential term
// circular queue vars
int i = 0;
signed long error_history[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
int8 queue_pos = 0;
int8 temp_pos;
signed long prev_ave;
signed long cur_ave;
signed long error;
signed long DeDt; // change in error over time
signed int32 error_sum = 0; // sum of errors, for integral term
signed long desired_power;
int8 power;
int8 setpoint;
float temp_float;
// **** set the loop constants (Kp, Ki, Kd) to something useful
// main control loop
while (1)
{
// calculate the raw error
// negative = disc too low
error = (signed long)read_adc() - setpoint;
// calculate the proportional term
Tp = -Kp * error;
// calculate the integral term
error_sum = error_sum + (signed int32)error;
temp_float = error_sum;
Ti = Ki * temp_float;
// use a circular queue to save a history of the last 8 samples
// this will be used to calculate the differential term
error_history[queue_pos] = error;
queue_pos++;
queue_pos &= 0x07; // keep in 0..7 range
temp_pos = queue_pos;
// calculate the average for the 4 oldest samples
for (i = 0, prev_ave = 0; i < 4; i++)
{
prev_ave += error_history[temp_pos];
temp_pos++;
temp_pos &= 0x07;
}
// calculate the average for the 4 most recent samples
for (i = 0, cur_ave = 0; i < 4; i++)
{
cur_ave += error_history[temp_pos];
temp_pos++;
temp_pos &= 0x07;
}
// calculate the differential term
DeDt = prev_ave - cur_ave;
Td = Kd * DeDt;
// calculate the desired power
desired_power = (signed long)(Tp + Td + Ti);
// set the correct power
if (desired_power < 0)
power = 0;
else if (desired_power > 255)
power = 255;
else
power = desired_power;
set_output_power(power); // this could be pwm duty, etc
// wait between samples
delay_ms(2);
}
___________________________
This message was ported from CCS's old forum
Original Post ID: 2639 |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Re: Anyone written a simple PID routine for a PIC??? |
Posted: Mon Feb 18, 2002 6:29 am |
|
|
This is turned out to be a really easy way to impliment a PID control. It works good if it's tuned right. I use this to heat a heat exchanger with a variable heat load. My pulse width is 20 seconds and sampel rate is 5 times per pulse. Any of the number can be changed.
All variables are floats
//PID PWM calculation routine for SupplyTemperature
errorNOW = Setpoint - SupplyTemperature;
PWMonTIME = PWMonTIME + (PWMp * errorNOW ) + (PWMi * (errorNOW - (PWMd * (errorNOW - errorLAST))));
errorLAST = errorNOW;
if (PWMon > 190) PWMon = 190; //maximum on time
if (PWMon < 10) PWMon =10; //minimum on time
PWMoff = 200 - PWMon;
:=HI
:=I am looking for a simple pid routine to control a small heater using the pwm output of the pic. Any hints would be appreciated.
___________________________
This message was ported from CCS's old forum
Original Post ID: 2658 |
|
|
future
Joined: 14 May 2004 Posts: 330
|
|
Posted: Wed Dec 22, 2004 9:14 pm |
|
|
Are PWMp, PWMi and PWMd values from 0 to 1?
I want to use PID to control a stepper motor, so it has to know how many steps and direction to apply to correct the error. |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
Posted: Fri Dec 24, 2004 1:30 pm |
|
|
future wrote: | Are PWMp, PWMi and PWMd values from 0 to 1?
I want to use PID to control a stepper motor, so it has to know how many steps and direction to apply to correct the error. |
I can't remember but looking at the formula it looks like between -1 and 1. |
|
|
sonicdeejay
Joined: 20 Dec 2005 Posts: 112
|
|
Posted: Sat Feb 04, 2006 8:26 am |
|
|
thx guys...been looking for this too...I will study the code... |
|
|
sonicdeejay
Joined: 20 Dec 2005 Posts: 112
|
Re: Anyone written a simple PID routine for a PIC??? |
Posted: Sun Feb 05, 2006 8:09 pm |
|
|
Eric Minbiole wrote: | :=I am looking for a simple pid routine to control a small heater using the pwm output of the pic. Any hints would be appreciated.
I recently finished a project that leviated a metal ball using an electromagnet. It used a PIC to control a PID loop which kept the ball floating stabily.
Here's the code for my PID loop. I'm sure it's not the best PID code out there, but it should give you a starting point to work from. The only tricky part of the code is in calculating the differential term. Rather than taking the difference of two adjacent samples, I averaged 4 old samples, and 4 new samples, and took the difference between the averages. This made the loop more immune to noisy samples.
Hope it helps!
// control loop constants
float Kp; // proportional gain
float Ki; // integral gain
float Kd; // differential gain
// terms
float Tp; // proportional term
float Ti; // integral term
float Td; // differential term
// circular queue vars
int i = 0;
signed long error_history[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
int8 queue_pos = 0;
int8 temp_pos;
signed long prev_ave;
signed long cur_ave;
signed long error;
signed long DeDt; // change in error over time
signed int32 error_sum = 0; // sum of errors, for integral term
signed long desired_power;
int8 power;
int8 setpoint;
float temp_float;
// **** set the loop constants (Kp, Ki, Kd) to something useful
// main control loop
while (1)
{
// calculate the raw error
// negative = disc too low
error = (signed long)read_adc() - setpoint;
// calculate the proportional term
Tp = -Kp * error;
// calculate the integral term
error_sum = error_sum + (signed int32)error;
temp_float = error_sum;
Ti = Ki * temp_float;
// use a circular queue to save a history of the last 8 samples
// this will be used to calculate the differential term
error_history[queue_pos] = error;
queue_pos++;
queue_pos &= 0x07; // keep in 0..7 range
temp_pos = queue_pos;
// calculate the average for the 4 oldest samples
for (i = 0, prev_ave = 0; i < 4; i++)
{
prev_ave += error_history[temp_pos];
temp_pos++;
temp_pos &= 0x07;
}
// calculate the average for the 4 most recent samples
for (i = 0, cur_ave = 0; i < 4; i++)
{
cur_ave += error_history[temp_pos];
temp_pos++;
temp_pos &= 0x07;
}
// calculate the differential term
DeDt = prev_ave - cur_ave;
Td = Kd * DeDt;
// calculate the desired power
desired_power = (signed long)(Tp + Td + Ti);
// set the correct power
if (desired_power < 0)
power = 0;
else if (desired_power > 255)
power = 255;
else
power = desired_power;
set_output_power(power); // this could be pwm duty, etc
// wait between samples
delay_ms(2);
}
___________________________
This message was ported from CCS's old forum
Original Post ID: 2639 |
hi there...
seem like the code isn't totally complete...
Isn't it suppose to include looping code rite??
can u post the complete code?
thx
sonic |
|
|
andibaciu
Joined: 06 Feb 2006 Posts: 6
|
|
Posted: Fri Feb 23, 2007 6:51 am |
|
|
@Eric Minbiole
can you put the principle how to set the Kp, Ki, Kd ???
any help is good .... |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Fri Feb 23, 2007 8:55 am |
|
|
andibaciu wrote: | @Eric Minbiole
can you put the principle how to set the Kp, Ki, Kd ???
any help is good .... |
Read Tim Westcott's excellent article, PID Without a PhD: http://www.embedded.com/2000/0010/0010feat3.htm |
|
|
kilarn Guest
|
PID values |
Posted: Thu Apr 02, 2009 10:08 am |
|
|
A good place to start for values is to do a quick search for the Ziegler-Nichols Decay ratio technique... this is only a starting place though...
The best method I have found is to use Root Locus with a program like MATLAB... but this again depends on how well you have modeled your design.
Also to find the Kp you can use a Routh Array and/or what is called the Magnitude condition.
These all come from classical control theory.
Hope this helps. |
|
|
mmprestine
Joined: 13 Jan 2004 Posts: 29 Location: Green Bay, Wisconsin
|
|
|
|