Você está na página 1de 15

Implementing a PID Controller Using a PIC

INTRODUCTION:

Continuous processes have been controlled by feedback loops since the late
1700’s. In 1788, James Watt used a flyball governor on his steam engine to
regulate its speed. The Taylor Instrument Company implemented the first fully
functional Proportional, Integral and Derivative (PID) controller in 1940.

Although feedback control has come a long way since James Watt, the basic
approach and system elements have not changed. There are several elements
within a feedback system; for discussion purposes, we will use a motor position
control system as our model in the descriptions below.

• Plant
• Sensors
• Setpoint
• Error Signal
• Controller – Intentionally left for last, this is the most significant element of a
control system. The Controller is responsible for several tasks and is the link that
connects together all of the physical and nonphysical elements. It measures the
output signal of the Plant’s Sensors, processes the signal and then derives an error
based on the signal measurement and the Setpoint. Once the sensor data has
been collected and processed, the result must be used to find PID values, which
then must be sent out to the Plant for error correction. The rate at which all of this
happens is dependent upon the Controller’s processing power. This may or may
not be an issue depending on the response characteristic of the Plant. A
temperature control system is much more forgiving on a Controller’s processing
capabilities than a motor control system. Figure 1 shows a basic block diagram of a
feedback control system.
OBJECTIVES:
General: Implementing a tuned PID motor position Controller using a PIC

 Discuss in detail the three elements of a PID Controller: Proportional,


Integral and Derivative.

 Discuss a code PID routine on a PIC device.

 Discuss the implementation PID that has the flexibility of adapting to


different systems, but is capable of being specifically tuned later on.

 Discuss the details of tuning a PID once implementation has been


completed.

Material:

Software:

-CCS C Compiler.

-Proteus.

-PICkit 2 ( programmer )

Hardware:

- Microcontroller 18f4550 (Crystal 40 MHz)

- Driver L298D, AND gate 7408

-Potentiometers, LCD 16x2, resistors, push buttons, etc.


PID
In implementing the PID controller, there are 3 terms which are based off the error
measurement.

Equation 1:

In this system, the sign of the controller’s output, C(t), always will be positive

For determine the direction in which the motor will turn, is necessary to use
additional flags (front direction, rear direction) in order to control Driver L298D

The magnitude of C(t) directly corresponds to the duty cycle of the PWM in the
ECCP module, determining the speed at which the motor will turn.

PID IN A DIGITAL SYSTEM

Converting over to a digital system, Y(t) is measured by an A/D converter. In order


to implement the PID controller, the PICmicro® microcontroller will have to do
some approximations of integral and derivative terms.

Proportional

The proportional term is the simplest of the three and is also the most commonly
found control technique in a feedback system. The proportional gain (kp) is
multiplied by the error. In this application note, the error is a 10-bit value, error. The
amount of correction applied to the system is directly proportional to the error. As
the gain increases, the applied correction to the Plant becomes more aggressive.
This type of Controller is common for driving the error to a small, but non-zero
value, leaving a steady state error. This is the reason for proportional control not
being enough in some systems, thereby requiring integral and derivative control to
come into play, separately or together (i.e., PI, PD or PID Controller).

Equation 2

PROPORTIONAL TERM = Kp * error

Derivative

We can use the following difference equations for our approximation.

Equation 3:

Where E(n) is the current error, E(n-1) is the previous error and TS is our sampling
period. Equation 2 is the approximate slope of the tangent line at E(t) (rise/run).

The derivative term makes an adjustment based on the rate at which the Plant
output is changing from its Setpoint.
A notable characteristic in this type of control is when the error is constant, or at
the maximum limit, the effect is minimal. There are some systems where
proportional and/or integral do not provide enough control. In these systems,
adding in the derivative term completes the control requirements.

Equation 4

DERIVATIVE TERM = Kd * (error * error_anterior)

Integral

Unlike proportional control, which looks at the present error, integral control looks
at past errors. Given this, the accumulative error (sum of all past errors) is used to
calculate the integral term, but at fixed time intervals.

Basically, every time the fixed interval expires, the current error at that moment is
added to the error variable. A motor system would require a shorter sample period
than a temperature system, because the time of response
Equation 5

If the integral sample period was too fast or the integral constant was too big in the
system, the accumulative error would add too quickly to give the system a chance
to respond, thereby not allowing it to ever stabilize. Another element in integral
control to consider is ‘wind-up’.
Wind-up occurs when the accumulative error keeps increasing because the Plant
output is saturated. This event can be avoided by setting limits to the accumulative
error. It can also be eliminated by not executing the integral term when the Plant
output is saturated.
Another characteristic is excessive gain that can create an unstable condition
within the system, causing it to oscillate. The integral gain must be thoroughly
tested for all possible situations to find the best overall value.
In conclusion, as the accumulative error increases, the integral term has a greater
effect on the Plant.

Equation 6

INTEGRAL TERM = (Ki * error) + (error_enterior)


Tuning

There are several different ways to tune a PID Controller for system optimization.
The code in this application note is loosely defined, giving it the flexibility to be
tuned for a specific application (i.e., motor control, temperature, actuator, etc.).
Tuning a PID Controller can be somewhat difficult and time consuming and should
be completed in a systematic fashion.

1. Run the system in an open loop and measure its response over time. Based on
the measured response, you will get an idea for which PID term is needed most.
2. Determine the application requirements: Plant response time, which PID term
will have the most affect and accumulative error limits.

Example tuning:

The system response of a temperature controlled environment is shown in Figures


5 through 7.
Figure 5 shows the graphic response for a proportional only feedback loop. As
shown, none of the gain values can reach the input signal and maintain that level.
All four gain values have settled at a non-zero value.

Figure 6 shows the graphic response of a Proportional/Integral (PI) Controller. The


high integral gain dominates the response (see line with diamond shapes).

With a tuned proportional and integral gain, the system does settle to its Setpoint,
which is why PI control is adequate in many systems. The disadvantage is the time
required for it to settle (t = 3), which brings us to PID control.
Figure 7 shows the graphic response of a PID Controller. This graph is very similar
to the PI graph (Figure 6), except that the PID control takes half as long as the PI
control to settle (t = 1.5) as the Setpoint.
PID Output

The PID output is calculated after the proportional, integral and derivative terms
have been determined. In addition to this calculation the user must modify flags
(front direction, rear direction) to decide which direction the Plant will be driven.

Equation 7

PID = PROPORTIONAL TERM + INTEGRAL TERM + DERIVATIVE


TERM
Flowchart
Code PID
if (SetPoint > Posicion)
{
Error_F = (SetPoint) - (Posicion); //Cálculo error
Tp_F = (Kp * Error_F); //Cálculo del término Proporcional
Ti_F = (Ki * Error_F) + (Ti_Anterior_F); //Cálculo del término Integral
Td_F = ( Kd ) * (Error_F - Error_Anterior_F);//Cálculo del término Derivativo
PID_F = (Tp_F) + (Ti_F) + (Td_F); //Cálculo PID

//---Anti-windup
if (PID_F > Lim_Max) //Ajusta Salida PID_F si mayor que Lim_Max
{PID_F = Lim_Max;}

//---Sentido de giro
output_high(PIN_C0); //Mt Front enable
output_low(PIN_C1); //Mt Rear disable

//---Carga PID a PWM


PWM = PID_F;
set_pwm1_duty(PWM);

//---Actualiza variables
Ti_Anterior_F = Ti_F;
Error_Anterior_F = Error_F;

}
Schematic Capture (Proteus 8)
Full code c
#include <PID_SPI__USB_18F4550.h>

#device ADC=10

#FUSES NOWDT //No Watch Dog Timer


#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled
(Legacy mode)

#use delay(crystal=40000000)

#define LCD_RS_PIN PIN_D0


#define LCD_RW_PIN PIN_D1
#define LCD_ENABLE_PIN PIN_D2
#define LCD_DATA4 PIN_D4
#define LCD_DATA5 PIN_D5
#define LCD_DATA6 PIN_D6
#define LCD_DATA7 PIN_D7

#include <lcd.c>
void main()
{//Void main
//------------Variables-----------------------
float SetPoint =102.4; //Valor Posicion Deseada
float Kp = 1; //Constante Proporcional
float Ki = 1; //Constante Integral
float Kd = 1; //Constante Diferencial

int16 Time = 250 ; //Tiempo de Muestreo [ms]


int Div_Error=10;

//int16 DatoEncoder; //Lectura Tarjeta Encoder


float Posicion; //Valor Posicion Medido

float Error_F = 0; //Error


float Error_R = 0;
float Tp_F = 0; //Termino Proporcional
float Tp_R = 0;
float Ti_F = 0; //Termino Integral
float Ti_R = 0;
float Td_F = 0; //Termino Derivativo
float Td_R = 0;
float PID_F = 0; //Valor PID
float PID_R = 0;

int16 Lim_Max = 1000; //Límites máximo de control


//int16 Lim_Min = 128; //Límites mínimo de control
int16 PWM; //Ciclo de Trabajo PWM

int16 Error_Anterior_F= 0; //Error Estado Anteriro


int16 Error_Anterior_R= 0;
float Ti_Anterior_F = 0; //Termino Integral Estado Anterior
float Ti_Anterior_R = 0;

//-----------Configuracion Modulos----------------
//Entradas Salidas Proposito General
SET_TRIS_E (0x0F); // E3,E2,E1,E0 are inputs
//---Modulo CAD
setup_adc_ports (AN0_TO_AN5);//Para ADC
setup_adc(ADC_CLOCK_INTERNAL);//Relog de ADC
//---Modulo Comunicacion SPI

//---Modulo PWM
//Period_PWM = [(PR2+1)*4*Tosc*Prescale]
//Tocs = 1/Value_crystal
//Resolution "Bits" = {log[4(PR2+1)]} / {log(2)}
int Postscaler = 1;//Nota: No se usa para el PWM
int PR2 = 0xFF; //Period_PWM=204.8us
setup_timer_2(T2_DIV_BY_4,PR2,Postscaler);//Frecuencia_PWM=4.882MHz
setup_ccp1(CCP_PWM); //Resolucion 10 bits
//---Periferico LCD
lcd_init();
printf(lcd_putc, "\f Motor CC Pos\nSintonizador PID");
delay_ms(3000);
//----------Programa-----------
while(TRUE)
{//Ciclo Infinito
if (input(pin_d3) == TRUE)
{Div_Error=1;
}
else
{Div_Error=10;
}

if (input(pin_E1) == TRUE)
{//Sintoniza PID
//pwm off
set_adc_channel(0); //Selecciona CH0
delay_us(20); //Retardo para obtener lectura completa 8 Bits
SetPoint = read_adc(); //Guarda Set_Point
SetPoint = (SetPoint) / (Div_Error);
set_adc_channel(1); //Selecciona CH1
delay_us(20); //Retardo para obtener lectura completa 8 Bits
Kp = read_adc(); //Guarda Kp
Kp = ((Kp) / (64)) + (1);
set_adc_channel(2); //Selecciona CH2
delay_us(20); //Retardo para obtener lectura completa 8 Bits
Ki = read_adc(); //Guarda Ki
Ki = ((Ki) / (1024)) + (0.01);
set_adc_channel(3); //Selecciona CH3
delay_us(20); //Retardo para obtener lectura completa 8 Bits
Kd = read_adc(); //Guarda Kd
Kd = ((Kd) / (16)) + (1);
set_adc_channel(5); //Selecciona CH4
delay_us(20); //Retardo para obtener lectura completa 8 Bits
Time = read_adc(); //Guarda time ms
Time = (Time) / (2);
printf(lcd_putc, "\fSp=%3.1f t=%lums\nPID %2.1f %1.2f %2.0f",SetPoint,Time,Kp,Ki,Kd);
delay_ms(100);
}

if (input(pin_E2) == TRUE)//Motor a Set_Point


{
//---Obtiene Valor Posicion
set_adc_channel(4); //Selecciona CH4
delay_us(20); //Retardo para obtener lectura completa 8 Bits
Posicion = read_adc(); //Guarda posicion
Posicion = (Posicion) / (Div_Error);
set_adc_channel(0); //Selecciona CH0
delay_us(20); //Retardo para obtener lectura completa 8 Bits
SetPoint = read_adc(); //Guarda Set_Point
SetPoint = (SetPoint) / (Div_Error);
//----------PDI_A--------------------------
if (SetPoint > Posicion)
{Error_F = (SetPoint) - (Posicion); //Cálculo error[grados]
Tp_F = (Kp * Error_F); //Cálculo del término Proporcional
Ti_F = (Ki * Error_F) + (Ti_Anterior_F); //Cálculo del término Integral
Td_F = ( Kd ) * (Error_F - Error_Anterior_F);//Cálculo del término Derivativo
PID_F = (Tp_F) + (Ti_F) + (Td_F); //Cálculo PID
//---Anti-windup
if (PID_F > Lim_Max) //Ajusta Salida PID_F si mayor que Lim_Max
{PID_F = Lim_Max;}
//---Sentido de giro
output_high(PIN_C0); //Mt Front
output_low(PIN_C1);
//---Carga PID a PWM
PWM = PID_F;
set_pwm1_duty(PWM);
//---Actualiza variables
Ti_Anterior_F = Ti_F;
Error_Anterior_F = Error_F;
Ti_Anterior_R = 0;
Error_Anterior_R = 0;
printf(lcd_putc, "\fErr=%2.0f-%2.0f=%2.0f
\n%3.0f+%3.0f+(%3.0f)",SetPoint,Posicion,Error_F,Tp_F,Ti_F,Td_F);
}
//------------PDI_R-----------------------
if (SetPoint < Posicion)
{Error_R = (Posicion) - (SetPoint) ; //Cálculo error[grados]
Tp_R = (Kp * Error_R); //Cálculo del término Proporcional
Ti_R = (Ki * Error_R) + (Ti_Anterior_R); //Cálculo del término Integral
Td_R = ( Kd ) * (Error_R - Error_Anterior_R);//Cálculo del término Derivativo
PID_R = (Tp_R) + (Ti_R) + (Td_R); //Cálculo PID
//---Anti-windup
if (PID_R > Lim_Max) //Ajusta Salida PID si mayor que Lim_Max
{PID_R = Lim_Max;}
//---Sentido de giro
output_low(PIN_C0); //MT_Rear
output_high(PIN_C1);
//---Carga PID a PWM
PWM = PID_R;
set_pwm1_duty(PWM);
//---Actualiza variables
Ti_Anterior_R = Ti_R;
Error_Anterior_R = Error_R;
Ti_Anterior_F = 0;
Error_Anterior_F = 0;
printf(lcd_putc, "\fErr=%2.0f-%2.0f=-%2.0f
\n%3.0f+%3.0f+(%3.0f)",SetPoint,Posicion,Error_R,Tp_R,Ti_R,Td_R);
}
//-------Set Point----------------------
//if (SetPoint == Posicion)
//{printf(lcd_putc, "\fErr=%2.0f-%2.0f= 0 \n Set Point ok",SetPoint,Posicion,);
//set_pwm1_duty(192); //Asigna u = (PWM * 19v) / 1024
//output_low(PIN_C0); //Disable Motor_Front
//output_high(PIN_C1); //Enable Motor_Rear
//delay_us(50);
//output_low(PIN_C0); //Disable Motor_Rear
//output_high(PIN_C1); //Enable Motor_Front
//delay_us(50);
//}
delay_ms(Time); //Tiempo de muestreo
}

}//Fin Ciclo Infinito

}//Fin Void main

Você também pode gostar