Pid 1 PDF

Descargar como docx, pdf o txt
Descargar como docx, pdf o txt
Está en la página 1de 13

Instituto Tecnológico de Puebla

Robótica y Mecatrónica

José Rafael Mendoza Vazquez

“Control PID”

Jesús Jair Chavez Mozo


Isaac Natanael Ramirez Ortiz
Procoro Hernandez Vazquez
José Luis Ramirez Morales
Diego Benjamin Parra Meléndez
Jesús Gaspar Hurtado
Introducción
El control PID (Proporcional, Integral, Derivativo) es un método ampliamente
utilizado en el campo de la ingeniería de control para regular sistemas dinámicos.
Este proyecto se centra en explorar y analizar el funcionamiento del control PID,
así como su aplicación en diferentes contextos industriales y de automatización. El
objetivo principal es comprender cómo el control PID puede mejorar la estabilidad,
precisión y respuesta de sistemas en tiempo real, contribuyendo así a la
optimización de procesos y sistemas automatizados.

Marco Teórico
El control PID es un sistema de control de bucle cerrado que utiliza tres términos
principales para ajustar y mantener la salida de un sistema cerca de un valor
deseado, conocido como el setpoint.

Estos términos son:


1. Proporcional (P): Este término proporciona una respuesta proporcional al error
actual, lo que significa que la salida del controlador es proporcional al error entre el
valor deseado y el valor real. El término proporcional es crucial para reducir el
error estático y mejorar la precisión del sistema.
2. Integral (I): El término integral acumula el error a
lo largo del tiempo y produce una respuesta que se
incrementa con el tiempo si el error persiste. Esto
ayuda a eliminar el error en estado estacionario y a mejorar
la respuesta transitoria del sistema.
3. Derivativo (D): Este término anticipa la tendencia del error en el futuro,
proporcionando una respuesta que es proporcional a la tasa de cambio del error.
El término derivativo mejora la estabilidad del sistema al reducir la oscilación y
mejorar el tiempo de respuesta.
La combinación de estos tres términos en el control PID permite ajustar el
comportamiento del sistema de acuerdo con las características específicas de la
planta y los requisitos de rendimiento.
Materiales
 Arduino UNO
 Puente H
 Motor con encoder
 Fuente de alimentación
 Cables o Jumpers
Desarrollo
Primero se debe conocer las salidas del motor con el que se vaya a trabajar
tomando en cuenta las respectivas conexiones que irán al Arduino UNO y al
puente H respectivamente.
El motor elegido en esta práctica se trata de un JGY-370.

Regularmente estas salidas se representan con colores característicos pasa una


mejor interpretación y comprensión del circuito que vamos a elaborar.
Programa
#include <PID_v1.h> // Librería PID de Brett Beauregard:
https://playground.arduino.cc/Code/PIDLibrary
// ********************************************** I/O
**********************************************************************
const byte encA =3; // Entrada de la señal
A del encoder.
const byte encB = 2; // Entrada de la
señal B del encoder.

const byte PWMA = 6; // Salida PWM a la primera patilla del motor a


través de un puente H.
const byte PWMB = 5; // Salida PWM a la segunda patilla del motor a
través de un puente H.
const byte motorA = 8;
const byte motorB = 9;
// ************************************************ Variables PID
*****************************************************************
double Setpoint = 0.0, Input = 0.0, Output = 0.0; // Setpoint=Posición
designada; Input=Posición del motor; Output=Tensión de salida para el motor.
double kp = 0.0, ki = 0.0, kd = 0.0; // Constante proporcional, integral
y derivativa.
double outMax = 0.0, outMin = 0.0; // Límites para no sobrepasar la
resolución del PWM.
double Grados=0.0, Respuesta=0.0;
// **************************************************** Otras Variables
***********************************************************
volatile long contador = 0; // En esta variable se guardará los pulsos del
encoder y que interpreremos como ángulo
byte ant = 0, act = 0; // Sólo se utiliza los dos primeros bits de estas
variables y servirán para decodificar el encoder. (ant=anterior, act=actual.)
byte cmd = 0; // Un byte que utilizamos para la comunicación serie.
(cmd=comando.)
unsigned int tmp = 0; // Variable que utilizaremos para poner el tiempo
de muestreo.
const byte ledok = 13; // El pin 13 de los Arduinos tienen un led que
utilizo para mostrar que el motor ya ha llegado a la posición designada.
//

**********************************************************************************************
**********************************

PID myPID(&Input, &Output, &Setpoint, 0.0, 0.0, 0.0, DIRECT); // Parámetros y


configuración para invocar la librería.

void setup() // Configuramos los pines de entrada/salida y


configuramos el terminal serie.
{
Serial.begin(115200); // Configura la velocidad en baudios del terminal
serie.
pinMode(PWMA, OUTPUT); // Declara las dos salidas PWM para el
control del motor (pin 5).
pinMode(PWMB, OUTPUT); // (pin 6).
pinMode(motorA, OUTPUT); //ESTO ES UNA ADAPTACION PARA MI
PUENTE H QUE IMPLEMANTO
pinMode(motorB, OUTPUT);
digitalWrite(PWMA, LOW); // Y ambas salidas las inicializa a cero.
digitalWrite(PWMB, LOW);

TCCR0B = TCCR0B & B11111000 | 1; // Configuración de la frecuencia del


PWM para los pines 5 y 6.
// Podemos variar la frecuencia del PWM con un número de
1 (32KHz) hasta 7 (32Hz). El número que pongamos es un divisor de frecuencia.
Min.=7, Max.=1. Está a la máxima frecuencia y es como mejor resultado me ha
dado y además es silencioso.
attachInterrupt(digitalPinToInterrupt(encA), encoder, CHANGE); // En cualquier
flanco ascendente o descendente
attachInterrupt(digitalPinToInterrupt(encB),
encoder, CHANGE); // en los pines 2 y 3, actúa la
interrupción.

outMax = 255.0; // Límite máximo del PWM.


outMin = -outMax; // Límite mínimo del PWM.

tmp = 25; // Tiempo de muestreo en milisegundos.

kp = 4; // Constantes PID iniciales. Los valores son los adecuados


para un encoder de 334 ppr,
ki = 8; // pero como el lector de encoder está diseñado como x4
equivale a uno de 1336 ppr. (ppr = pulsos por revolución.)
kd = 3;

myPID.SetSampleTime(tmp); // Envía a la librería el tiempo de muestreo.


myPID.SetOutputLimits(outMin, outMax);// Límites máximo y mínimo;
corresponde a Max.: 0=0V hasta 255=5V (PWMA), y Min.: 0=0V hasta -255=5V
(PWMB). Ambos PWM se convertirán a la salida en valores absolutos, nunca
negativos.
myPID.SetTunings(kp, ki, kd); // Constantes de sintonización.
myPID.SetMode(AUTOMATIC); // Habilita el control PID (por defecto).
Setpoint = (double)contador; // Para evitar que haga cosas extrañas al
inciarse, igualamos los dos valores para que comience estando el motor parado.

imprimir(3); // Muestra los datos de sintonización y el tiempo de


muestreo por el terminal serie.
}
void loop()
{
//El valor de 3.711111111 sale entre la razón de 1336 pulsos
y 360 grados, como una vuelta completa en el motor son 1336 pulsos del
encoder,entonces en grados son 360
//Y como el sistema funciona con base en los pulsos, por ejemplo, el calculo del
error se realiza entre los pulsos requeridos por el setpoint menos los pulsos
contados
//Se hace la divición de 1336/360 que da igual a 3.711111, entonces cuando se
ingrese en el setpoint una posición en grados por ejemplo 180° este valor en el
programa
//se mulriplicará por 3.7111 para que puede hacer el calculo del error en pulsos.

Setpoint=Grados*7.4305555556; //Es para ingresar valores de 0 a 360 grados


como setpoint, asi cuando se le ingrese un valor a la variable grados desde el
serialploter, el valor introducido se multiplicara por 3.71111 y hara la conversion de
grados a pulsos que es lo que lee la variable contador para hacer el calculo del
error.
Respuesta=contador/7.4305555556; //En este caso el contador que seria la
respuestas en forma de pulsos, sera divida por 3.71111, para que en la grafica de
respuesta muestre grados en lugar de pulsos.

Input = (double)contador; // Lectura del encoder óptico. El valor del


contador se incrementa/decrementa a través de las interrupciones externas (pines
2 y 3).

while(!myPID.Compute()); // Mientras no se cumpla el tiempo de muestreo,


se queda en este bucle.

// *********************************************** Control del Motor


*************************************************
if (((long)Setpoint - contador) == 0)// Cuando está en el punto designado, parar el
motor.
{
digitalWrite(PWMA, LOW); // Pone a 0 los
dos pines del puente en H.
digitalWrite(PWMB, LOW);
digitalWrite(motorA, LOW);
digitalWrite(motorB, LOW);
digitalWrite(ledok, HIGH); // Se enciende el led (pin 13) para avisar
visualmente que está en la posición designada.
}
else // En caso contrario hemos de ver si el motor ha de ir
hacia delante o hacia atrás. Esto lo determina el signo de la variable "Output".
{
if (Output > 0.0) // Mueve el motor hacia delante con el PWM
correspondiente a su posición.
{
digitalWrite(motorA, HIGH);
digitalWrite(motorB, LOW);
digitalWrite(PWMB, LOW); // Pone a 0 el segundo pin del puente en H.
analogWrite(PWMA, abs(Output)); // Por el primer pin sale la señal PWM.
Serial.println("adelante ");
}
else // Mueve el motor hacia atrás con el PWM
correspondiente a su posición.
{
digitalWrite(motorA, LOW);
digitalWrite(motorB, HIGH);
digitalWrite(PWMB, LOW); // Pone a 0 el primer pin del puente en H.
analogWrite(PWMA, abs(Output)); // Por el segundo pin sale la señal PWM.
Serial.println("atras ");
}
}
// Recepción de datos para posicionar el motor, o
modificar las constantes PID, o el tiempo de muestreo.
Admite posiciones relativas y absolutas.
if (Serial.available() > 0) // Comprueba si ha recibido algún dato por el
terminal serie.
{
cmd = 0; // Por seguridad "limpiamos" cmd.
cmd = Serial.read(); // "cmd" guarda el byte recibido.
if (cmd > 31)
{
byte flags = 0; // Borramos la bandera que decide lo que
hay que imprimir.
if (cmd > 'Z') cmd -= 32; // Si una letra entra en minúscula la
covierte en mayúscula.

// Decodificador para modificar las constantes PID.


switch(cmd) // Si ponemos en el
terminal serie, por ejemplo "p2.5 i0.5 d40" y pulsas enter tomará esos valores y
los cargará en kp, ki y kd.
{ // También se puede
poner individualmente, por ejemplo "p5.5", sólo cambiará el parámetro kp, los
mismo si son de dos en dos.
case 'P': kp = Serial.parseFloat(); myPID.SetTunings(kp, ki, kd); flags = 1;
break; // Carga las constantes y presenta en el terminal serie los valores de las
variables que hayan sido modificadas.
case 'I': ki = Serial.parseFloat(); myPID.SetTunings(kp, ki, kd); flags = 1;
break;
case 'D': kd = Serial.parseFloat(); myPID.SetTunings(kp, ki, kd); flags = 1;
break;
case 'T': tmp = Serial.parseInt(); myPID.SetSampleTime(tmp); flags = 1;
break;
case 'G': Grados = Serial.parseFloat();
flags = 2; break; // Esta línea permite introducir una
posición absoluta. Ex: g180 (y luego enter) e irá a
esa posición.
case 'K': flags = 3; break; // Se puede
introducir la letra k para poder observar en el serialploter los parametros de las
constantes anteriores
}
digitalWrite(ledok, LOW); // Cuando entra una posición nueva se apaga el
led y no se volverá a encender hasta que el motor llegue a la posición que le
hayamos designado.

imprimir(flags);
}
}
Serial.print(Grados);
Serial.print(" ");
Serial.println(Respuesta);
}
// Encoder x4. Cuando se produzca cualquier cambio en el encoder esta parte
hará que incremente o decremente el contador.
void encoder()
{
ant=act; // Guardamos el valor 'act' en 'ant' para convertirlo en
pasado.
act=PIND & 12; // Guardamos en 'act' el valor que hay en ese
instante en el encoder y hacemos un
// enmascaramiento para aislar los dos únicos bits que
utilizamos para esta finalidad.
if(ant==12 && act==4) contador++;// Incrementa el contador si el encoder se
mueve hacia delante.
if(ant==4 && act==0) contador++;
if(ant==0 && act==8) contador++;
if(ant==8 && act==12) contador++;

if(ant==4 && act==12) contador--;// Decrementa el


contador si el encoder se mueve hacia atrás.
if(ant==0 && act==4) contador--;
if(ant==8 && act==0) contador--;
if(ant==12 && act==8) contador--;
}

void imprimir(byte flag) // Imprime en el terminal serie los datos de las contantes
PID, tiempo de muestreo y posición. En los demás casos sólo imprime la posición
del motor.
{
if ((flag == 1) || (flag == 3))
{
Serial.print("KP="); Serial.print(kp);
Serial.print(" KI="); Serial.print(ki);
Serial.print(" KD="); Serial.print(kd);
Serial.print(" Time="); Serial.println(tmp);
}
}
Cada una de las líneas de código tiene su respectiva explicación de su función
dentro del programa.
El programa se deberá cargar a la placa de programación Arduino UNO y por
medio de nuestro equipo de cómputo vamos hacer uso del software del mismo
nombre “Arduino” y posteriormente controlar desde la máquina el ángulo deseado.

Conclusión
En resumen, el control PID es una técnica versátil y eficaz para regular sistemas
dinámicos en una amplia variedad de aplicaciones industriales y de
automatización. A través de la comprensión y la implementación adecuada de los
términos proporcional, integral y derivativo, es posible mejorar significativamente la
estabilidad, precisión y respuesta de los sistemas en tiempo real. Sin embargo, es
importante destacar que el diseño y la sintonización del control PID pueden ser un
desafío, ya que requieren un conocimiento profundo de la dinámica del sistema y
una cuidadosa optimización de los parámetros del controlador. En última instancia,
el control PID sigue siendo una herramienta fundamental para el control de
procesos y sistemas en la ingeniería moderna, contribuyendo a la eficiencia,
seguridad y fiabilidad de una amplia gama de aplicaciones industriales.

También podría gustarte