Welcome to Control.com, the global online

community of automation professionals.

community of automation professionals.

Our Advertisers

PID controller using C

Need some help to tune the PID algorithm below written in C...

By Anonymous on 17 August, 2003 - 8:52 pm

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 dmuthu@ku.edu 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++;

}

}

By T. Connolly on 19 August, 2003 - 10:31 am

1 out of 1 members thought this post
was helpful...

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.

By Patrik Johansson on 28 August, 2003 - 2:57 pm

Hi, feel free to download my program for PI tuning called Tune Guide. The program use Ziegler-Nichols, Cohen-Coon, Lambdatune and a new method called AMIGO witch is wery powerfull. Go to http://hem.fyristorg.com/PI_Tune/index.htm

good luck.