Está en la página 1de 8

Congreso Internacional de Ingeniería Mecánica, Mecánica Eléctrica y Mecatrónica (CIIMMEM’2012), Universidad Católica de

Santa María, Arequipa, Perú.

Diseño de un Controlador PID para un Sistema


de Equilibrio Bi-Hélice
G. Alarcón, D. Lajo, autores
Programa profesional de Ingeniería Mecánica, Mecánica Eléctrica y Mecatrónica, Universidad Católica de
Santa María, Arequipa, Perú – gustavoagacitua.89@gmail.com, daniel_lc89@hotmail.com

 De la ecuación podemos hacer las siguientes afirmaciones:

Resumen—Este trabajo se enfoca en el diseño de un  e(t): Error de la señal.


controlador PID de calidad industrial, para un sistema de  u(t): Salida del controlador y entrada de control al
equilibrio bi-hélice, el cual contara con tres grados de libertad. proceso.
 Kp: Ganancia Proporcional.
Para facilitar el desarrollo de la investigación, solo se utilizara
un grado de libertad en la sintonización de las ganancias mediante
 Ti: Constante de Tiempo Integral
los métodos de Ziegler y Nichols.  Td: Constante de Tiempo Derivativo

Abstract-- This work focuses on the design of an industrial Del diagrama de bloques determinamos lo siguiente:
grade PID controller for a system of bi-helix balance, which will
have three degrees of freedom.  El primer bloque de control (proporcional) consiste
en el producto entre la señal de error y la constante
To facilitate the development of research, will be used only one proporcional, quedando un error en estado
degree of freedom in tuning the gains by the methods of Ziegler
estacionario casi nulo (off-set).
and Nichols.
 El segundo bloque de control (integral) tiene como
I. INTRODUCCIÓN propósito disminuir y eliminar el error en estado
estacionario, provocado por el modo proporcional
E n esta introducción, se verán los parámetros básicos a tener
en cuenta sobre el control proporcional, integral, derivativo
(PID); el objetivo de este trabajo no es desarrollar el análisis
y el punto de consigna, integrando esta desviación
en el tiempo y sumándola a la acción proporcional.
 El tercer bloque de control (Derivativo) considera
teórico del PID, si no, ver su aplicación en un sistema real, la tendencia del error y permite una recuperación
utilizando un microcontrolador programado en un lenguaje de rápida de la variable después de presentarse una
alto nivel, como puede ser C. perturbación en el proceso.
II. ECUACIÓN DEL PID Explicado lo anterior, tenemos el siguiente código:
De la documentación existente sobre sistemas de control
relacionados con el control PID, podemos destacar la siguiente /* Variables utilizadas en el controlador PID. */
ecuación. unsigned long lastTime;
double Input, Output, Setpoint;
( ) double errSum, lastErr;
( ) ( ) ∫ ( ) double kp, ki, kd;
void Compute()
{
Esta ecuación puede ser graficada mediante un diagrama de /* Cuanto tiempo pasó desde el último cálculo. */
bloques, el cual ayudara a tener una idea más clara. unsigned long now = millis();
double timeChange = (double)(now - lastTime);
/* Calculamos todas las variables de error. */
double error = Setpoint - Input;
errSum += (error * timeChange);
double dErr = (error - lastErr) / timeChange;
/* Calculamos la función de salida del PID. */
Output = kp * error + ki * errSum + kd * dErr;
/* Guardamos el valor de algunas variables para
el próximo ciclo de cálculo. */
lastErr = error;
lastTime = now;
Fig.1 Diagrama de bloques del controlador PID }
/* Establecemos los valores de las constantes para
*
Universidad Católica de Santa María. la sintonización. */

1
Congreso Internacional de Ingeniería Mecánica, Mecánica Eléctrica y Mecatrónica (CIIMMEM’2012), Universidad Católica de
Santa María, Arequipa, Perú.
void SetTunings(double Kp, double Ki, double Kd) errSum += error;
{ double dErr = (error - lastErr);
kp = Kp; // Calculamos la función de salida del PID.
ki = Ki; Output = kp * error + ki * errSum + kd * dErr;
kd = Kd; // Guardamos el valor de algunas variables para el
} próximo ciclo de cálculo.
lastErr = error;
El programa anterior funciona correctamente, pero tiene lastTime = now;
limitaciones en cuanto a su aplicación a un sistema real. Para }
que se comporte como un PID de nivel industrial, hay que }
/* Establecemos los valores de las constantes para
tener en cuenta otros parámetros; el algoritmo del PID funciona
la sintonización.
mejor si se ejecuta a intervalos de tiempo regulares, si se Debido a que ahora sabemos que el tiempo entre
incorpora el concepto de tiempo dentro del PID, se puede muestras es constante,
llegar a simplificar los cálculos. no hace falta multiplicar una y otra vez por el
cambio de tiempo; podemos
ajustar las constantes Ki y Kd, obteniendose un
III. DISEÑO DEL CONTROLADOR resultado matemático equivalente
pero más eficiente que en la primera versión de la
El diseño de nuestro controlador parte del PID de nivel función. */
principiante, el cual depuraremos hasta obtener un controlador void SetTunings(double Kp, double Ki, double Kd)
de nivel industrial. {
double SampleTimeInSec = ((double)SampleTime)/1000;
A. El Problema: Periodo de Funcionamiento kp = Kp;
Los PID de nivel principiante, están diseñados para ki = Ki * SampleTimeInSec;
kd = Kd / SampleTimeInSec;
ejecutarse a periodos irregulares, esto puede traer 2 problemas:
}
void SetSampleTime(int NewSampleTime)
 Se tiene un comportamiento inconsistente del PID, {
debido a que en ocasiones se lo ejecuta regularmente y if (NewSampleTime > 0)
a veces no. {
 Hay que realizar operaciones matemáticas extras para /* si el usuario decide cambiar el tiempo de
calcular los términos correspondientes a la parte muestreo durante el funcionamiento, Ki y Kd tendrán
que ajustarse para reflejar este cambio. */
derivada e integral del PID, ya que ambos son
double ratio = (double)NewSampleTime /
dependientes del tiempo. (double)SampleTime;
ki *= ratio;
La Solución kd /= ratio;
Hay que asegurar el funcionamiento periodico del PID SampleTime = (unsigned long)NewSampleTime; }}
basado en un tiempo de ejecución predeterminado. El PID
decide si debe hacer cálculos o retornar de la función. Una vez Los Resultados
que nos aseguremos que el PID se ejecuta a intervalos
regulares, los cálculos correspondientes a la parte derivada e  Independientemente de cuan frecuente sea llamada la
integral se simplifican. función para calcular el PID, el algoritmo de control
será evaluado a tiempos regulares.
El Código  Debido a la expresión (int timeChange = (now -
lastTime);) no importa cuando millis() se hace cero
// Variables utilizadas en el controlador PID. nuevamente, ya que al tiempo actual, se le resta el
unsigned long lastTime; tiempo transcurrido.
double Input, Output, Setpoint;  Como el tiempo de muestreo ahora es constante, no
double errSum, lastErr; necesitamos calcular permanentemente las constantes de
double kp, ki, kd;
int SampleTime = 1000; // Seteamos el tiempo de
sintonización. Con lo cuál nos ahorramos cálculos cada
muestreo en 1 segundo. vez que procesamos el PID.
void Compute()  Se debe tener en cuenta que es posible mejorar la
{ gestión de los tiempos de muestreos mediante
unsigned long now = millis(); interrupciones, pero queda a cargo del diseñador la
int timeChange = (now - lastTime); implementación y prueba de este concepto.
// Determina si hay que ejecutar el PID o retornar
de la función.
if(timeChange>=SampleTime)
{
// Calcula todas las variables de error.
double error = Setpoint - Input;

2
Congreso Internacional de Ingeniería Mecánica, Mecánica Eléctrica y Mecatrónica (CIIMMEM’2012), Universidad Católica de
Santa María, Arequipa, Perú.

B. El Problema: Derivative Kick double errSum, lastInput;


La modificación desarrollada a continuación, cambiará double kp, ki, kd;
levemente el término derivativo con el objetivo de eliminar el int SampleTime = 1000; // Tiempo de muestreo de 1
segundo.
fenómeno “Derivative Kick”.
void Compute()
Este fenómeno, se produce por variaciones rápidas en la {
señal de referencia r(t), que se magnifican por la acción unsigned long now = millis();
derivativa y se transforman en componentes transitorios de int timeChange = (now - lastTime);
gran amplitud en la señal de control. if(timeChange>=SampleTime)
{
// Calcula todas las variables de errores.
double error = Setpoint - Input;
errSum += error;
double dInput = (Input - lastInput);
// Calculamos la función de salida del PID.
Output = kp * error + ki * errSum - kd * dInput;
// Guardamos el valor de algunas variables para el
próximo ciclo de cálculo.
lastInput = Input;
lastTime = now;
}
}
void SetTunings(double Kp, double Ki, double Kd)
{
double SampleTimeInSec = ((double)SampleTime)/1000;
kp = Kp;
ki = Ki * SampleTimeInSec;
kd = Kd / SampleTimeInSec;
}
Fig.2 Derivative Kick void SetSampleTime(int NewSampleTime)
{
La grafica anterior ilustra el problema. Siendo el error = if (NewSampleTime > 0)
setpoint – entrada, cualquier cambio en la consigna, causa un {
cambio instantáneo en el error; la derivada de este cambio es double ratio = (double)NewSampleTime /
(double)SampleTime;
infinito (en la práctica, dt no es cero, igualmente, el valor
ki *= ratio;
termina siendo muy grande). Esto produce un sobre-pico muy kd /= ratio;
alto en la salida, que podemos corregir de una manera muy SampleTime = (unsigned long)NewSampleTime;
sencilla. }
}
La Solución
Las modificaciones son bastante sencillas. Estamos
remplazando la derivada positiva del error con la derivada
negativa de la entrada. En lugar de recordar el último valor del
error, ahora recordamos el último valor que tomó la entrada.
Entonces, cuando el setpoint es constante.
El Resultado

Con esto resulta que la derivada del error es igual a la


derivada negativa de la entrada, salvo cuando el setpoint está
cambiando.
Esto acaba siendo una solución perfecta. En lugar de añadir
(Kd*error derivado), restamos (Kd*valor de entrada
derivado). Esto se conoce como el uso de “Derivada de la
medición”.

El Código

// Variables utilizadas en el controlador PID.


unsigned long lastTime;
double Input, Output, Setpoint; Fig.3 Sobre-picos Eliminados

3
Congreso Internacional de Ingeniería Mecánica, Mecánica Eléctrica y Mecatrónica (CIIMMEM’2012), Universidad Católica de
Santa María, Arequipa, Perú.

Se puede observar como los picos en la salida han sido introducimos dentro del cálculo. Al parecer, no se ha realizado
eliminados. Este factor de corrección se aplica a sistemas muy nada extraño, pero en la práctica ésta acción resulta en una
sensibles a dichas vibraciones; en un horno por ejemplo, donde gran diferencia en la función de la salida del PID.
la inercia térmica es muy grande, el efecto de dichos picos es Ahora tomamos el error y lo multiplicamos por el valor de
despreciable. Por lo tanto no sería necesario tener en cuenta Ki en ese momento, luego almacenamos la suma de los
esta corrección. diferentes errores multiplicados por la constante Ki. Esto
resulta en una función de salida, suave y sin sobre saltos, con la
C. El problema: Cambios en la Sintonización ventaja de no tener que utilizar matemática adicional para ello.
La posibilidad de cambiar la sintonización del PID, mientras
el sistema está corriendo, es la característica más respetable del El Código
algoritmo del sistema de control.
// Variables utilizadas en el controlador PID.
unsigned long lastTime;
double Input, Output, Setpoint;
double ITerm, lastInput;
double kp, ki, kd;
int SampleTime = 1000; // Tiempo de muestreo: 1
segundo.
void Compute()
{
unsigned long now = millis();
int timeChange = (now - lastTime);
if(timeChange>=SampleTime)
{
// Calcula todos los errores.
double error = Setpoint - Input;
ITerm += (ki * error);
Fig.4 Ruido introducido por re-sintonización
double dInput = (Input - lastInput);
// Calculamos la función de salida del PID.
Los PID principiantes, de hecho, actúan de forma errática si Output = kp * error + ITerm - kd * dInput;
queremos configurar los valores de sintonización mientras el // Guardamos el valor de algunas variables para el
sistema se encuentra en marcha. próximo recálculo.
lastInput = Input;
La siguiente tabla muestra el estado del PID antes y después lastTime = now;
de que los parámetros han cambiado. }
}
void SetTunings(double Kp, double Ki, double Kd)
{
double SampleTimeInSec = ((double)SampleTime)/1000;
kp = Kp;
ki = Ki * SampleTimeInSec;
La salida se reduce a la mitad debido a que el término kd = Kd / SampleTimeInSec;
}
integral se reduce rápidamente.
void SetSampleTime(int NewSampleTime)
{
Esto sucede debido a la interpretación de la integral. Esta if (NewSampleTime > 0)
interpretación funciona bien hasta que Ki cambia. Entonces, la {
suma de todos los errores se multiplica con el valor de Ki, double ratio = (double)NewSampleTime /
siendo esto algo que definitivamente no queremos. Nosotros (double)SampleTime;
solo queremos que afecte a los valores que estén por adelante. ki *= ratio;
kd /= ratio;
Por ejemplo: Si nosotros modificamos Ki, en un tiempo t = 5
SampleTime = (unsigned long)NewSampleTime;
segundos. Necesitamos que el impacto de este cambio solo }
afecte a los valores de Ki que se modifican en un tiempo mayor }
a t = 5 segundos.
Remplazamos la variable errSuma, por una variable
La Solución compuesta llamada Iterm. Suma Ki*error en lugar de
La solución a este problema no es del todo elegante, pero solamente el error. Por último, como el cálculo de Ki está
consiste en re-escalar la suma del error, doblando el valor de embebido en el término integral, se elimina de la ecuación
Ki o reduciendo la suma de los errores a la mitad. principal del PID
Esto quita el ruido del término integral, solucionando el
problema.
En lugar de tener el término integral fuera de la integral, lo

4
Congreso Internacional de Ingeniería Mecánica, Mecánica Eléctrica y Mecatrónica (CIIMMEM’2012), Universidad Católica de
Santa María, Arequipa, Perú.

El Resultado El problema se manifiesta en forma de retrasos extraños. En


la imagen anterior podemos observar que el valor de la salida,
está muy por encima del límite. Cuando el valor del setpoint
cae por debajo de un valor determinado, el valor de salida
decrece por debajo de la línea límite de 255 (5 voltios).

La solución se puede dar en dos pasos.

La Solución – Paso 1

Fig.5 Corrección de término Integral

Con las modificaciones hechas, los cambios en la Fig.7 Reducción sustancial de la saturación
sintonización del término integral no afectan al rendimiento
general de nuestro sistema, ya que tiene en cuenta la Existen varios métodos para mitigar el efecto WindUp, pero
modificación en cada instancia de error, sumándose al total. la que nosotros utilizaremos es la siguiente: Decirle al PID
cuáles son los límites de salida. En el código que se mostrara
D. El Problema: Reset WindUp adelante, se observara que ahora hay una función
SetOutputLimits( ). Esta función controla el crecimiento del
término Integral, deteniendo su funcionamiento cuando este
alcanza el límite configurado.

La Solución – Paso 2
Observando el gráfico anterior, si bien hemos reducido
sustancialmente el retraso inducido por el WindUp, no hemos
resuelto todo el problema. Aun hay una diferencia, entre lo que
el PID piensa que está enviando, y lo que está enviando
efectivamente.
Aunque el término integral ha sido acotado de forma segura,
el término Proporcional y Derivativo añaden pequeños
valores, dando un resultado superior al límite de salida. Esto es
inaceptable. Dado que si el usuario llama a la función
“SetOutputLimits( )” tiene que asumir que eso significa “la
salida se mantendrá dentro de estos valores ”. Así que el paso 2
Fig.6 Efecto WindUp
consistirá en una suposición valida. Además de la restricción
del término Integral, hay que acotar el valor de salida para que
El efecto WindUp aparece al arrancar el sistema o en se mantenga dentro de los límites.
cualquier otra situación, donde aparece un error muy grande Uno se puede preguntar, ¿Por qué acotamos el término
durante un tiempo prolongado. Esto hará que el término integral y la salida? Esto se debe a lo siguiente: Por más que
integral aumente para reducir el error. Pero si nuestro actuador pongamos límites al valor que puede tomar la salida, el término
es limitado, con esto nos referimos a que la tensión que Integral seguirá creciendo, introduciendo errores en la salida.
podemos aplicar se encuentra entre los 0 y 5 voltios (0 a 255,
modulación por ancho de pulso de 8 bits), se saturará, pero el El código
termino integral seguirá creciendo. Cuando el error se reduce,
la parte integral también comenzara a reducirse, pero desde un // Variables de trabajo.
unsigned long lastTime;
valor muy alto, llevando mucho tiempo hasta que logre la double Input, Output, Setpoint;
estabilidad, generando fluctuaciones exageradamente grandes. double ITerm, lastInput;

5
Congreso Internacional de Ingeniería Mecánica, Mecánica Eléctrica y Mecatrónica (CIIMMEM’2012), Universidad Católica de
Santa María, Arequipa, Perú.
double kp, ki, kd;
int SampleTime = 1000; // Tiempo de muestreo de 1
segundo.
double outMin, outMax;
void Compute()
{
unsigned long now = millis();
int timeChange = (now - lastTime);
if(timeChange>=SampleTime)
{
// Calcula todos los errores.
double error = Setpoint - Input;
ITerm+= (ki * error);
if(ITerm> outMax) ITerm= outMax;
else if(ITerm< outMin) ITerm= outMin;
double dInput = (Input - lastInput);
// Calculamos la función de salida del PID. Fig.8 Eliminación del WindUp
Output = kp * error + ITerm- kd * dInput;
if(Output > outMax) Output = outMax; El Problema: PID On/Off
else if(Output < outMin) Output = outMin;
Supongamos que en algún momento del programa deseamos
// Guardamos el valor de algunas variables para el
próximo recálculo. forzar la salida a un valor determinado (0 por ejemplo), usando
lastInput = Input; la siguiente rutina:
lastTime = now;
} void loop()
} {
void SetTunings(double Kp, double Ki, double Kd)
{
Compute();
double SampleTimeInSec = ((double)SampleTime)/1000; Output=0; }
kp = Kp;
ki = Ki * SampleTimeInSec; De esta manera, no importa el valor de salida que haya
kd = Kd / SampleTimeInSec; computado el PID, nosotros simplemente determinamos su
} valor manualmente. Esto en la práctica es erróneo ya que
void SetSampleTime(int NewSampleTime)
introducirá errores en el PID: Dirá, yo estoy variando la
{
if (NewSampleTime > 0) función de salida, pero en realidad no pasa nada. Como
{ resultado, cuando pongamos nuevamente el PID en
double ratio = (double)NewSampleTime / funcionamiento, tendremos un cambio brusco y repentino en el
(double)SampleTime; valor de la función de salida, dando como resultado dos
ki *= ratio; problemas:
kd /= ratio;
SampleTime = (unsigned long)NewSampleTime;
}
 Encender y Apagar el PID
}  Errores de Estabilización al Encender el PID
void SetOutputLimits(double Min, double Max) nuevamente.
{
if(Min > Max) return; La Solución
outMin = Min; La solución al problema de On/Off es tener un medio para
outMax = Max; encender y apagar el PID de vez en cuando. Los términos
if(Output > outMax) Output = outMax;
else if(Output < outMin) Output = outMin;
comunes para estos estados son “Manual” (ajustar el valor de
if(ITerm> outMax) ITerm= outMax; la salida manualmente) y “Automatic” (el PID ajusta
else if(ITerm< outMin) ITerm= outMin; automáticamente la salida). El código a continuación muestra
} la función Mode.

El Resultado // Variables de trabajo.


unsigned long lastTime;
Este código elimina el WindUp de nuestro sistema. Además, la double Input, Output, Setpoint;
salida permanecerá dentro de los límites configurados. Esto double ITerm, lastInput;
double kp, ki, kd;
quiere decir que podemos configurar el rango de valores
int SampleTime = 1000; // Tiempo de muestreo 1
máximos y mínimos que necesitemos en la salida. segundo.
double outMin, outMax;
bool inAuto = false;
#define MANUAL 0

6
Congreso Internacional de Ingeniería Mecánica, Mecánica Eléctrica y Mecatrónica (CIIMMEM’2012), Universidad Católica de
Santa María, Arequipa, Perú.
#define AUTOMATIC 1 if(ITerm> outMax) ITerm= outMax;
void Compute() else if(ITerm< outMin) ITerm= outMin;
{ }
if(!inAuto) return;
unsigned long now = millis(); Se ha modificado “setMode( )” para detectar el paso de
int timeChange = (now - lastTime); manual a automático y se ha añadido la función de
if(timeChange>=SampleTime)
“initialize()”. En esta función controla el término Integral
{
// Calculamos todos los errores. (Iterm = salida) y la entrada (LastInput = entrada), para
double error = Setpoint - Input; mantener la derivada de la adición. El término proporcional no
ITerm+= (ki * error); se basa en la información del pasado, por lo que no necesita
if(ITerm> outMax) ITerm= outMax; ningún tipo de inicialización.
else if(ITerm< outMin) ITerm= outMin;
double dInput = (Input - lastInput); El Resultado
// Calculamos la función de salida del PID.
Output = kp * error + ITerm- kd * dInput;
if(Output > outMax) Output = outMax;
else if(Output < outMin) Output = outMin;
// Guardamos el valor de algunas variables para el
próximo recálculo.
lastInput = Input;
lastTime = now;
}
}
void SetTunings(double Kp, double Ki, double Kd)
{
double SampleTimeInSec = ((double)SampleTime)/1000;
kp = Kp;
ki = Ki * SampleTimeInSec;
kd = Kd / SampleTimeInSec;
}
void SetSampleTime(int NewSampleTime)
{
if (NewSampleTime > 0)
Fig.9 Eliminación de ruido al encendido y apagado
{
double ratio = (double)NewSampleTime /
(double)SampleTime; Se puede observar que una inicialización adecuada, da como
ki *= ratio; resultado, una transferencia de manual a automático sin
kd /= ratio; perturbaciones: exactamente lo que se pretendía conseguir
SampleTime = (unsigned long)NewSampleTime;
} E. El Problema: Dirección del PID
} Los procesos a los cuales un PID estará enlazado, se dividen
void SetOutputLimits(double Min, double Max)
en 2 grupos: de acción directa y de acción inversa. Todos los
{
if(Min > Max) return; casos vistos hasta el momento han sido de acción directa, por
outMin = Min; lo tanto, un incremento en la entrada, da como resultado un
outMax = Max; incremento en la salida. En el caso de los procesos de acción
if(Output > outMax) Output = outMax; inversa, es todo lo contrario.
else if(Output < outMin) Output = outMin; En un refrigerador, por ejemplo, un aumento en la acción de
if(ITerm> outMax) ITerm= outMax; enfriamiento, causa una disminución de la temperatura. Para
else if(ITerm< outMin) ITerm= outMin;
que el PID funcione en un proceso de acción inversa, los
}
void SetMode(int Mode) signos de Kp, Ki y Kd deben ser negativos.
{ Esto no es un problema por si mismo, pero el usuario debe
bool newAuto = (Mode == AUTOMATIC); elegir el signo correcto, y asegurarse de que todo los
if(newAuto && !inAuto) parámetros tengan el mismo signo.
{ // Para cambiar de manual a automático,
inicializamos algunos parámetros. La Solución
Initialize();
Para hacer el proceso un poco más simple y elegante, se
}
inAuto = newAuto; requiere que los parámetros Kp, Ki y Kd sean >= 0. Si el
} usuario está trabajando en un proceso de acción inversa, se
void Initialize() especifica por separado, utilizando la función
{ SetControllerDirection(), esto asegura que los parámetros
lastInput = Input; tienen el mismo signo.
ITerm = Output;

7
Congreso Internacional de Ingeniería Mecánica, Mecánica Eléctrica y Mecatrónica (CIIMMEM’2012), Universidad Católica de
Santa María, Arequipa, Perú.

El Código {
if(Min > Max) return;
// Variables de trabajo. outMin = Min;
unsigned long lastTime; outMax = Max;
double Input, Output, Setpoint; if(Output > outMax) Output = outMax;
double ITerm, lastInput; else if(Output < outMin) Output = outMin;
double kp, ki, kd; if(ITerm> outMax) ITerm= outMax;
int SampleTime = 1000; // Tiempo de muestreo 1 else if(ITerm< outMin) ITerm= outMin;
segundo. }
double outMin, outMax; void SetMode(int Mode)
bool inAuto = false; {
#define MANUAL 0 bool newAuto = (Mode == AUTOMATIC);
#define AUTOMATIC 1 }
#define DIRECT 0
#define REVERSE 1
int controllerDirection = DIRECT;
void Compute() RECONOCIMIENTOS
{
if(!inAuto) return; Agradecemos a Dios, nuestros padres, familia y al profesor
unsigned long now = millis(); Kenzaburo Seki de JICA, por darnos la confianza y el apoyo
int timeChange = (now - lastTime); en nuestros sueños y proyectos profesionales.
if(timeChange>=SampleTime)
{ REFERENCIAS
// Calculamos todos los errores.
double error = Setpoint - Input;
[1] Ingeniería de Control Moderna – 4ta Edición, Katsuhiko Ogata, Pearson-
ITerm+= (ki * error); Prince Hall
if(ITerm> outMax) ITerm= outMax; [2] Electrónica de Potencia – Componentes, topología y Equipos, Salvador
else if(ITerm< outMin) ITerm= outMin; Martinez García y Juan Andrés Gualda Gil, Thomson.
double dInput = (Input - lastInput); [3] Mecatrónica – Sistemas de control electrónico en la ingeniería mecánica
// Calculamos la función de salida del PID. y eléctrica, 4ta Edición, W. bolton.
Output = kp * error + ITerm- kd * dInput; [4] Arduino Playground, métodos de Control.
[5] Arduino Cookbook, Michael Margolis, O’REILLY
if(Output > outMax) Output = outMax;
[6] Investigación sobre el PID en Arduino, Obra liberada bajo licencia
else if(Output < outMin) Output = outMin; Creative Commons by-nc-sa, Moyano Jonathan Ezequiel.
// Guardamos el valor de algunas variables para el [7] Controladores PID – Control Automático I, Virginia Mazzone,
próximo recálculo. Universidad Nacional de Quilmes, Marzo 2002 .
lastInput = Input;
lastTime = now;
}
}
void SetTunings(double Kp, double Ki, double Kd)
{
if (Kp<0 || Ki<0|| Kd<0) return;
double SampleTimeInSec = ((double)SampleTime)/1000;
kp = Kp;
ki = Ki * SampleTimeInSec;
kd = Kd / SampleTimeInSec;
if(controllerDirection ==REVERSE)
{
kp = (0 - kp);
ki = (0 - ki);
kd = (0 - kd);
}
}
void SetSampleTime(int NewSampleTime)
{
if (NewSampleTime > 0)
{
double ratio = (double)NewSampleTime /
(double)SampleTime;
ki *= ratio;
kd /= ratio;
SampleTime = (unsigned long)NewSampleTime;
}
}
void SetOutputLimits(double Min, double Max)

También podría gustarte