PID controller using C

A

Thread Starter

Anonymous

Hello everybody:
I am working on a humidity generator project and would like to implement a PID to control the temperature and humidity in a chamber. I had earlier downloaded a source code for the PID algorithm from T. Connolly (thanks boss!!!). I modified it as much as I could to match my project but I cannot figure how to tune it. Please take a look at it and email me at [email protected] if you have any suggestion. My sincere apologies if I killed your code Connolly...

#include <stdio.h>
#include<math.h>

struct _pid {
int pv; /*integer that contains the process value*/
int sp; /*integer that contains the set point*/
float integral;
float pgain;
float igain;
float dgain;
int deadband;
int last_error;
};

struct _pid warm,cold,*pid;
int process_point, set_point,dead_band;
float p_gain, i_gain, d_gain, integral_val,new_integ;;



/*------------------------------------------------------------------------
pid_init

DESCRIPTION This function initializes the pointers in the _pid structure
to the process variable and the setpoint. *pv and *sp are
integer pointers.
------------------------------------------------------------------------*/
void pid_init(_pid *warm, int process_point, int set_point)
{
struct _pid *pid;

pid = warm;
pid->pv = process_point;
pid->sp = set_point;
}


/*------------------------------------------------------------------------
pid_tune

DESCRIPTION Sets the proportional gain (p_gain), integral gain (i_gain),
derivitive gain (d_gain), and the dead band (dead_band) of
a pid control structure _pid.
------------------------------------------------------------------------*/

void pid_tune(_pid *pid, float p_gain, float i_gain, float d_gain, int dead_band)
{
pid->pgain = p_gain;
pid->igain = i_gain;
pid->dgain = d_gain;
pid->deadband = dead_band;
pid->integral= integral_val;
pid->last_error=0;
}

/*------------------------------------------------------------------------
pid_setinteg

DESCRIPTION Set a new value for the integral term of the pid equation.
This is useful for setting the initial output of the
pid controller at start up.
------------------------------------------------------------------------*/
void pid_setinteg(_pid *pid,float new_integ)
{
pid->integral = new_integ;
pid->last_error = 0;
}

/*------------------------------------------------------------------------
pid_bumpless

DESCRIPTION Bumpless transfer algorithim. When suddenly changing
setpoints, or when restarting the PID equation after an
extended pause, the derivative of the equation can cause
a bump in the controller output. This function will help
smooth out that bump. The process value in *pv should
be the updated just before this function is used.
------------------------------------------------------------------------*/
void pid_bumpless(_pid *pid)
{

pid->last_error = (pid->sp)-(pid->pv);

}

/*------------------------------------------------------------------------
pid_calc

DESCRIPTION Performs PID calculations for the _pid structure *a. This function uses the positional form of the pid equation, and incorporates an integral windup prevention algorithim. Rectangular integration is used, so this function must be repeated on a consistent time basis for accurate control.

RETURN VALUE The new output value for the pid loop.

USAGE #include "control.h"*/


float pid_calc(_pid *pid)
{
int err;
float pterm, dterm, result, ferror;

err = (pid->sp) - (pid->pv);
if (abs(err) > pid->deadband)
{
ferror = (float) err; /*do integer to float conversion only once*/
pterm = pid->pgain * ferror;
if (pterm > 100 || pterm < -100)
pid->integral = 0.0;
else
{
pid->integral += pid->igain * ferror;
if (pid->integral > 100.0) pid->integral = 100.0;
else if (pid->integral < 0.0) pid->integral = 0.0;
}
dterm = ((float)(err - pid->last_error)) * pid->dgain;
result = pterm + pid->integral + dterm;
}
else result = pid->integral;
pid->last_error = err;
return (result);
}


void main(void)
{
float display_value;

pid = &warm;
printf("Enter the values of Process point, Set point, P gain, I gain, D gain \n");
scanf("%d%d%f%f%f", &process_point, &set_point, &p_gain, &i_gain, &d_gain);
//process_point = 30;
//set_point = 40;
//p_gain = (float)(5.2);
//i_gain = (float)(0.77);
//d_gain = (float)(0.18);
dead_band = 2;
integral_val =(float)(0.01);


pid_init(&warm, process_point, set_point);
pid_tune(&warm, p_gain,i_gain,d_gain,dead_band);
pid_setinteg(&warm,30.0);

//Get input value for process point
pid_bumpless(&warm);
int count=0;
while(count<=20)
{
// how to display output
display_value = pid_calc(&warm);
printf("%f\n", display_value);
//printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,warm.dgain);
count++;

}

}
 
T
Well I see that you made some slight modifications to the code, but Im happy that someone could use it. This was a very very simple controller that I wrote many years ago for a particular process that was relatively disturbance free and otherwise easy to control, so there is not much in the way of bells and whistles. I'v since written better (and more complex) controllers but am not at liberty to post the code (sorry, intellectual property issues + I want to keep my job) I tuned the PID controller using Zeigler Nichols method and it worked very well in that process. Do a google search on Zeigler Nichols, and check out the control engineering magazine web site, they have some articles about ZN in their archives.

 
Top