Saltar al contenido
Control Automático Educación

Control PID en PIC Motor-Generador

En esta entrada veremos como implementar un control PID en PIC sobre un sistema conformado por dos motores DC utilizando el compilador CCS C y explicando en detalle los conceptos del Controlador Digital PID.

Esta entrada contiene dos videos adicionales que explican en detalle el procedimiento y si te interesan estos temas, te invito a suscribirte al canal de YouTube para que no te pierdas los nuevos videos:

Si te interesa, puedes ver otras entradas donde implementamos el Control PID en PIC o Arduino para otros procesos:

Planta de Motores DC: Motor – Generador

Antes de realizar el control pid para motor dc con pic debemos inicialmente entender el comportamiento del sistema.

El proceso escogido para implementar el control PID en un microcontrolador PIC es conocido como Motor-Generador conformado por dos motores de corriente directa DC de 12v y es mostrado en la siguiente fotografía:

Motor-Generador

El funcionamiento del proceso es el siguiente:

Este proceso consta de dos motores DC de 12 voltios los cuales están acoplados en sus ejes por medio de poleas.

Uno de estos motores funciona propiamente como motor, entonces cuando dicho motor es excitado con un voltaje de alimentación comienza a girar a una velocidad proporcional al voltaje de entrada.

El giro del motor hace que el eje del segundo motor (Conocido como generador) comience a girar debido al acople entre ejes.

Cuando el eje del generador está en movimiento, este comienza a generar voltaje directo el cual puede ser tomado de los dos terminales del motor.

Aquí tenemos un sistema a ser Controlado:

  • Como variable manipulada tendremos el Voltaje de Entrada del Motor
  • Como variable controlada tendremos el Voltaje generado por el Generador.

Adicionalmente puede ser observado en la fotografía, que el sistema cuenta con dos bombillos que simularán la carga del sistema, esto seria la perturbación que constantemente afectan los sistemas de control.

Nuestro control debe ser lo suficientemente robusto para rechazar esas perturbaciones y llevar la variable controlada de nuevo para el Set-Point.

DESCARGAR DIAGRAMA DEL CIRCUITO

El circuito básico de este proceso MOTOR-GENERADOR puede ser descargado dando click al siguiente enlace

Para este ejemplo inicialmente debemos obtener el modelo matemático del proceso (Identificar la planta) y posteriormente con la función de transferencia identificada haremos la implementación de PID con PIC. Estos fueron los mismos pasos que utilizamos en la entrada anterior del PID del horno.

Identificación del Proceso Motor – Generador

Mostraré un procedimiento para realizar la identificación del proceso, pero aquí les dejaré su primera tarea.

Lo ideal es que lo siguiente que vamos a ver ustedes lo implementen con una comunicación serial (Click aca para ver entrada de comunicación serial), enviando los datos al computador para poder obtener la curva de reacción del proceso y posteriormente obtener la función de transferencia.

Si desean tener un ejemplo de como hacer eso, pueden ver como se hizo la identificación de un horno de temperatura con PIC enviando los datos al computador y realizando la identificación con el software de Matlab.

puede interesarte alguna de estas entradas del sitio web:

Como en este momento no poseo un FT232 para poder comunicar el PIC con mi Computador, decidí por hacer una identificación un poco más manual, utilizando un LCD 4×20.

El circuito para realizar la identificación del sistema con los Motores DC es el siguiente:

PID con PIC

NOTA: En este circuito se aplica lo aprendido en la entrada del Teclado Matricial 4×4 y como se está utilizando un LCD4x20, ya habíamos visto que el compilador CCS C Compiler ya trae lista la librería para trabajar con este teclado, pero solo sirve para el PUERTO B, por eso en el video de la identificación de Youtube, se muestra como hacer la modificación de la libreria para que trabaje con el PUERTO D.

La idea para el modelado de los motores DC a través de una identificación del procesos consiste en lo siguiente:

Tenemos nuestro proceso MOTOR-GENERADOR, el cual no tenemos idea de cual puede ser su representación matemática para poder sintonizar nuestro controlador PID, pero la idea entonces es obtener el modelo del motor de corriente directa acoplado al motor que sirve como generador.

Procedimiento de la identificación del sistema

Para el modelado matemático de los motores DC vamos a obtener su Función de Transferencia en el dominio de Laplace, es decir que utilizaremos la teoría de Control Lineal.

Todos los procesos en la industria y en la vida real en si, son procesos NO LINEALES, recayendo entonces en la teoría no lineal que es mucho mas compleja.

Ahora, dado que en la industria en la mayoría de los casos, los procesos siempre están trabajando sombre un punto de operación (Un mismo setpoint) y raramente son movidos para otro punto de operación, podemos aproximar ese proceso no lineal en un modelo Lineal por medio de una función de transferencia.

Entonces realizaremos el siguiente procedimiento:

  1. Exitaremos el sistema motor – generador con un set-point o un escalón del mismo valor al punto de operación donde queremos operar el proceso, para este ejemplo yo exité el sistema con un escalón del 40%, colocando entonces un PWM en la salida del CCP1 un ancho de pulso proporcional al 40% (Ver entrada del PWM con PIC).
  2. Establezco el tiempo de muestreo en que quiero tomar datos del MOTOR-GENERADOR (Dado que este sistema es sumamente Rápido, coloque un periodo de muestreo de 10ms).
  3. De esa manera el PIC exita el motor por causa de los 40% del PWM y comienza a guardar los valores de voltaje generados por el motor generador cada 10ms.
  4. Estos datos los guarda en un vector de 45 posiciones.
  5. Una vez las 45 posiciones son llenadas, el PIC coloca el PWM en Cero y muestra todos los datos en la pantalla del LCD. Este código de identificación se encuentra al Final de este Post o también en el Video de Youtube, donde se explica en detalle.

Convertir Señal PWM a Voltaje Continuo

Como la Planta MOTOR-GENERADOR solo acepta en su entrada voltaje continuo DC de 0 a 5 voltios, y nosotros estamos generando un PWM, es necesario transformar o convertir ese PWM en un valor de voltaje continuo que dependa del ancho de pulso.

Para eso se implementa el siguiente filtro pasa bajos que hace esa función.

Filtro Pasa Bajos

Análisis de los Datos de la Planta

Los datos de voltaje mostrados en el LCD, los copie en un archivo de excel junto con los datos de tiempo (periodo de muestreo) y los datos de entrada o escalón (que son los 40%). Estos datos los muestro tanto en Voltaje como en Porcentaje.

La respuesta obtenida en porcentaje se muestra a continuación:

Identificacion del Motor-Generador

Tipicamente, todo proceso industrial es representado por funciones de transferencia de primer o segundo orden.

A continuación es expuesto un modelo de primer orden con retardo sobre el cual vamos a trabajar para poder modelar el comportamiento de nuestra planta.

P(s)=\dfrac{Ke^{-\theta s}}{\tau s +1}

El modelo está representado en su forma continua, es decir en el dominio de Laplace. donde K es la ganancia del sistema, \tau es la constante de tiempo del proceso y \theta es el retardo del proceso.

Vemos que la gráfica el voltaje generado (linea azul) comienza en 0% y llega hasta 32% y que para conseguir esta respuesta tuvimos que alimentar el motor con una exitación del 40% (linea naranja). Así podemos obtener la ganancia del proceso con la siguiente formula:

K=\dfrac{Y_{final}-Y_{inicial}}{U_{final}-U_{inicial}}

K=\dfrac{32-0}{40-0}=0.8

Notemos que el voltaje generado (linea zul), al comienzo ella se demora en comenzar a subir, ese tiempo que ella se queda en cero, es conocido como el retardo del sistema y en este caso equivale a 0,03 segundos o 30ms.

\theta=30

Observemos que el voltaje generado en la gráfica, se comienza a estabilizar mas o menos a los 0.26 segundos, pero debemos restarle los 0,03 segundos del retardo, entonces el tiempo de establecimiento seria 0,23 segundos, así podemos obtener la constante de tiempo de la variable temperatura con la siguiente formula:

T_{establecimieto}=4\tau

O sea que el \tau=57,5.

Así que en términos generales, nuestro proceso del MOTOR GENERADOR está representado por la siguiente función de transferencia:

P(s)=\dfrac{0,8e^{-30 s}}{57,5 s +1}

Con nuestro proceso de los motores DC identificado podemos calcular los parámetros del control pid para motor dc con pic (k_p,t_i,t_d), para eso utilizamos cualquiera de las tres técnicas vistas en la entrada el PID del horno.

Suscríbete a este sitio WEB para estar enterado de las nuevas entradas!

Comprar Componentes en Amazon

Los motores DC de 6V-12V son una excelente opción para proyectos de automatización casera debido a su alto torque y velocidad variable. Poseen un diseño compacto y una gran eficiencia energética para proyectos de bricolaje y robótica. Tal como el montaje mostrado aquí del Motor-Generador, adquiere tus motores directamente en Amazon.

Algoritmo de Control PID

En este sitio web hemos hablado várias veces de los algoritmos de control, en especial del control PID.

PID sintonia

El concepto que veremos a continuación puedes aplicarlo a cualquier otro sistema como por ejemplo realizar un control de velocidad pid con pic.

Una ves tenemos nuestro modelo matemático que representa nuestro proceso MOTOR-GENERADOR en el escalón del 40%, podremos calcular nuestro control PID en PIC para que controle adecuadamente el proceso en ese punto de operación.

Para este caso PARTICULAR de mi MOTOR-GENERADOR, es un proceso de muy baja NO LINEALIDAD, es decir que tiene un comportamiento casi lineal, entonces voy a poder controlar con facilidad el proceso en cualquier punto de operación diferente a el 40%. Esto en la mayoría de los procesos NO sucede.

Sistema de Control con PIC

Vamos a detallar como implementar el control PID digital con PIC paso a paso, para eso vamos a utilizar el control discreto PID que vimos en la entrada pasada  dado por:

C(z^{-1})=\dfrac{u(k)}{e(k)}=\dfrac{q_0+q_1z^{-1}+q_2z^{-2}}{1-z^{-1}}

donde:

q_0=k_p\left [ 1+\dfrac{T}{2t_i}+\dfrac{t_d}{T} \right ]

q_1=-k_p\left [ 1-\dfrac{T}{2t_i}+\dfrac{2t_d}{T} \right ]

q_2=\dfrac{k_pt_d}{T}

Con esto, la ley de control que vamos a ingresar a nuestro PIC sale del control PID discreto (Despejando u)

u(k)(1-z^{-1})=q_0e(k)+q_1z^{-1}e(k)+q_2z^{-2}e(k)

u(k)-u(k)z^{-1}=q_0e(k)+q_1z^{-1}e(k)+q_2z^{-2}e(k)

u(k)=u(k)z^{-1}+q_0e(k)+q_1z^{-1}e(k)+q_2z^{-2}e(k)

aplicando transformada inversa Z obtenemos la ecuacion en diferencias:

u(k)=u(k-1)+q_0e(k)+q_1e(k-1)+q_2e(k-2)

Como tiempo de muestreo para el control PID utilizamos el criterio:

T=\dfrac{\tau}{20}=\dfrac{57,5}{20}=2,87\approx 3ms

NOTA: Como vemos el tiempo de muestreo debe ser de 3ms, o sea que realmente debe ser rápido nuestro microcontrolador para poder alcanzar tal velocidad, para ello por la alta velocidad lo más recomendable es usar un cristal externo de 20.000Mhz. En mi caso personal, no cuento con este cristal, entonces voy a tener que implementarlo con un cristal de 4.000Mhz, por lo que no voy a poder cumplir el criterio del tiempo de muestreo. Esto me puede traer serios problemas de estabilidad, pero al hacer las pruebas, mi periodo de muestreo alcanzado fue de 11ms y el sistema consiguió responder adecuadamente, principalmente porque todavía es 5 veces menor que  la constante de tiempo. Si se hubieran presentado problemas de estabilidad por causa que no puedo respetar el periodo de muestreo, lo que hubiera hecho es ponderar un poco el error del controlador PID, es decir multiplicar el error por valores entre (0 – 1).

Código del Control PID en PIC Motor Generador

A continuación se presenta el código de ejemplo del control PID con PIC para que lo copies y lo pegues en tu compilador y puedas reproducirlo.

Puedes realizar este control PID en PIC en un 16F887, 16F877A, 18F4550 o cualquier otro microcontrolador que dispongas.

Recuerda que para ver el código debes compartir el contenido de este blog para que más personas se beneficien de esta información.

Descargar librería del LCD4x20 para puertoD:

Código de la Identificación del Sistema Motor Generador

#INCLUDE <16F887.h>
#DEVICE ADC=10
#USE DELAY(CLOCK=4000000)
#FUSES XT,NOPROTECT,NOWDT,NOBROWNOUT,PUT,NOLVP
#DEFINE USE_PORTB_KBD   //Por defecto el teclado se conecta al puerto D,
                        //como el microcontrolador que se esta usando
                        //no tiene puerto D se conecta al puerto B.*/
#INCLUDE <LCD420D.C>
#INCLUDE <KBD4x4.C>  //Incluir en el encabezado el driver para
                      //manejar el teclado telefónico MODIFICADO
#include <stdlib.h>
#include <string.h>

#use     standard_io(b) 
#define  KEYHIT_DELAY   200    //Tiempo de espera del teclado en milisegundos
#byte PORTB= 6
#byte PORTC= 7
#BYTE PORTA= 5
#BYTE PORTD= 8

int16 adc,control=0;
long T=100; //100 ms
float R=0;
char c;
int opcion=0;


/*===========================================================================*/
/*=======================       FUNCION TECLA         =======================*/
/*===========================================================================*/
//Funcion encargada de esperar a que se presione una tecla 
char tecla(void)
{
   char c;
   do{ //espera hasta que se presione una tecla
      c=kbd_getc(); //Captura valor del teclado
     }
   while(c=='
#INCLUDE <16F887.h>
#DEVICE ADC=10
#USE DELAY(CLOCK=4000000)
#FUSES XT,NOPROTECT,NOWDT,NOBROWNOUT,PUT,NOLVP
#DEFINE USE_PORTB_KBD   //Por defecto el teclado se conecta al puerto D,
//como el microcontrolador que se esta usando
//no tiene puerto D se conecta al puerto B.*/
#INCLUDE <LCD420D.C>
#INCLUDE <KBD4x4.C>  //Incluir en el encabezado el driver para
//manejar el teclado telefónico MODIFICADO
#include <stdlib.h>
#include <string.h>
#use     standard_io(b) 
#define  KEYHIT_DELAY   200    //Tiempo de espera del teclado en milisegundos
#byte PORTB= 6
#byte PORTC= 7
#BYTE PORTA= 5
#BYTE PORTD= 8
int16 adc,control=0;
long T=100; //100 ms
float R=0;
char c;
int opcion=0;
/*===========================================================================*/
/*=======================       FUNCION TECLA         =======================*/
/*===========================================================================*/
//Funcion encargada de esperar a que se presione una tecla 
char tecla(void)
{
char c;
do{ //espera hasta que se presione una tecla
c=kbd_getc(); //Captura valor del teclado
}
while(c=='\0'); 
return(c);
}
/*===========================================================================*/
/*=======================    FUNCION TECLA CON TIMER  =======================*/
/*===========================================================================*/
// Pregunta por una Tecla por un tiempo, si no hay actividad, deja de preguntar
// y deja que el PIC continue con su trabajo
char tecla_time(void) {
char c='\0';
unsigned int16 timeout;
timeout=0;
c=kbd_getc(); //Captura valor del teclado
while(c=='\0' && (++timeout< (KEYHIT_DELAY*100)))
{
delay_us(10);
c=kbd_getc(); //Captura valor del teclado
}
return(c);
}
/*===========================================================================*/
/*============   FUNCION PARA DIGITAR ESCALÓN/SETPOINT  =====================*/
/*===========================================================================*/
long escalon(int nd)
{
//Esta funcion captura el escalon desde el teclado, si el proceso está tomando
//datos el escalon sirve para exitar el sistema, por otro lado si el sistema
//está controlando, el escalo sirve para establecer el setpoint del sistema
long val;
int i;
char str[5]; //Variable tipo String
str[0]='0';
for(i=0;i<nd;i++)
{
c=tecla();  //Lee el valor del teclado y espera hasta que alguna tecla se pulse
if(c!='*'){
//Muestra el digito presionado en el LCD
lcd_gotoxy(5+i,4);
lcd_putc(c);
//Almacena el dato presionado en la variable String
str[i]=c;
}
else{i=nd;} //Si se presiona * sale del For      
}
val = atol(str); //Convierte el String en un valor numerico
return(val);
}
/*===========================================================================*/
/*======================= IDENTIFICACION DEL SISTEMA  =======================*/
/*===========================================================================*/
void identificacion(void)
{
int16 dat[45]; //Variable guarda 45 datos de la identificacion
float aux;
int i,ban=0;
LCD_PUTC("TOMANDO DATOS....");
control=R*10;
set_pwm1_duty(control); //Exita el sistema
for(i=0;i<45;i++)
{
//Lee los datos
dat[i]=read_adc(); //Leer ADC
//dat[i]=adc*5000.0/1024.0;
delay_ms(T);
}
set_pwm1_duty(0); //Desactiva el sistema
LCD_PUTC("\f");
//Muestra los datos en la pantalla del LCD utilizando la tecla A para subir
//y utilizando la tecla B para bajar, estos datos deben ser graficados (EXCEL)
//para poder montar la curva de reacción del sistema y poder determinar los
//Parametros de la Planta
i=0;
while(ban==0)
{
aux=dat[i]*5000.0/1024.0;
lcd_gotoxy(1,1);
printf(lcd_putc,"%d. %1.3f",i+1,aux/1000);
aux=dat[i+1]*5000.0/1024.0;
lcd_gotoxy(1,2);
printf(lcd_putc,"%d. %1.3f",i+2,aux/1000);
aux=dat[i+2]*5000.0/1024.0;
lcd_gotoxy(1,3);
printf(lcd_putc,"%d. %1.3f",i+3,aux/1000);
aux=dat[i+3]*5000.0/1024.0;
lcd_gotoxy(1,4);
printf(lcd_putc,"%d. %1.3f",i+4,aux/1000);
c=tecla();      //Lee el valor del teclado y espera hasta que alguna tecla se pulse
i =(c=='B' && i!=41) ? i+1:i; //Si es B incremente i
i =(c=='A' && i!=0) ? i-1:i; //Si es A decremente i
ban =(c=='*') ? 1:0;   //Si es * salga del while
}
}
/*===========================================================================*/
/*=======================    FUNCION DEL PRINCIPAL    =======================*/
/*===========================================================================*/
void main()
{
port_b_pullups (0xFF);  //Utiliza las resistencias PULL UP internas del puerto B
set_tris_c(0);
set_tris_d(0);
setup_timer_2(t2_div_by_4,249,1);   //Configuracion de Timer 2 para establecer frec. PWM a 1kHz
setup_ccp1(ccp_pwm);                //Configurar modulo CCP1 en modo PWM
set_pwm1_duty(0);                   //Dejo en cero la salida PWM
setup_adc_ports(sAN0);              //Configurar ADC (Lectura de temperatura)
setup_adc(adc_clock_internal);      //Reloj interno para la conversion analoga digital)
set_adc_channel(0);                 //Seleccionar Canal 0 para sensor de Temperatura
LCD_INIT();                         //Inicializo el LCD
LCD_PUTC("\f");                     //Limpio el LCD
while(1)
{
lcd_gotoxy(1,1);
LCD_PUTC("TOMAR DATOS PLANTA");
lcd_gotoxy(1,2);
LCD_PUTC("Escalon(0-100):");
lcd_gotoxy(1,3);
LCD_PUTC("y presione *");
lcd_gotoxy(1,4);
LCD_PUTC("SP:           ");
R=escalon(3); //Llama la funcion para digitar el escalon de exitacion
//Valida si R esta entre 0 y 100 (Esto es otra forma de usar el if - else)
R =(R > 100) ? 100:R;
//Muestra el SETPOINT en pantalla
lcd_gotoxy(1,4);
printf(lcd_putc,"SP: %3.1f",R);
delay_ms(2000);
//Aprovecho la funcion escalon para digitar el periodo de muestreo
lcd_gotoxy(1,2);
LCD_PUTC("Periodo de M(0-1000):");
lcd_gotoxy(1,3);
LCD_PUTC("y presione *");
lcd_gotoxy(1,4);
LCD_PUTC(" T:        ");
T=escalon(4);
//Muestra el periodo de muestreo en pantalla
lcd_gotoxy(1,4);
printf(lcd_putc,"T: %ld  ",T);
delay_ms(2000);
LCD_PUTC("\f");
identificacion();
opcion=0; //Regresa al menu principal
}
}
'); return(c); } /*===========================================================================*/ /*======================= FUNCION TECLA CON TIMER =======================*/ /*===========================================================================*/ // Pregunta por una Tecla por un tiempo, si no hay actividad, deja de preguntar // y deja que el PIC continue con su trabajo char tecla_time(void) { char c='
#INCLUDE <16F887.h>
#DEVICE ADC=10
#USE DELAY(CLOCK=4000000)
#FUSES XT,NOPROTECT,NOWDT,NOBROWNOUT,PUT,NOLVP
#DEFINE USE_PORTB_KBD   //Por defecto el teclado se conecta al puerto D,
//como el microcontrolador que se esta usando
//no tiene puerto D se conecta al puerto B.*/
#INCLUDE <LCD420D.C>
#INCLUDE <KBD4x4.C>  //Incluir en el encabezado el driver para
//manejar el teclado telefónico MODIFICADO
#include <stdlib.h>
#include <string.h>
#use     standard_io(b) 
#define  KEYHIT_DELAY   200    //Tiempo de espera del teclado en milisegundos
#byte PORTB= 6
#byte PORTC= 7
#BYTE PORTA= 5
#BYTE PORTD= 8
int16 adc,control=0;
long T=100; //100 ms
float R=0;
char c;
int opcion=0;
/*===========================================================================*/
/*=======================       FUNCION TECLA         =======================*/
/*===========================================================================*/
//Funcion encargada de esperar a que se presione una tecla 
char tecla(void)
{
char c;
do{ //espera hasta que se presione una tecla
c=kbd_getc(); //Captura valor del teclado
}
while(c=='\0'); 
return(c);
}
/*===========================================================================*/
/*=======================    FUNCION TECLA CON TIMER  =======================*/
/*===========================================================================*/
// Pregunta por una Tecla por un tiempo, si no hay actividad, deja de preguntar
// y deja que el PIC continue con su trabajo
char tecla_time(void) {
char c='\0';
unsigned int16 timeout;
timeout=0;
c=kbd_getc(); //Captura valor del teclado
while(c=='\0' && (++timeout< (KEYHIT_DELAY*100)))
{
delay_us(10);
c=kbd_getc(); //Captura valor del teclado
}
return(c);
}
/*===========================================================================*/
/*============   FUNCION PARA DIGITAR ESCALÓN/SETPOINT  =====================*/
/*===========================================================================*/
long escalon(int nd)
{
//Esta funcion captura el escalon desde el teclado, si el proceso está tomando
//datos el escalon sirve para exitar el sistema, por otro lado si el sistema
//está controlando, el escalo sirve para establecer el setpoint del sistema
long val;
int i;
char str[5]; //Variable tipo String
str[0]='0';
for(i=0;i<nd;i++)
{
c=tecla();  //Lee el valor del teclado y espera hasta que alguna tecla se pulse
if(c!='*'){
//Muestra el digito presionado en el LCD
lcd_gotoxy(5+i,4);
lcd_putc(c);
//Almacena el dato presionado en la variable String
str[i]=c;
}
else{i=nd;} //Si se presiona * sale del For      
}
val = atol(str); //Convierte el String en un valor numerico
return(val);
}
/*===========================================================================*/
/*======================= IDENTIFICACION DEL SISTEMA  =======================*/
/*===========================================================================*/
void identificacion(void)
{
int16 dat[45]; //Variable guarda 45 datos de la identificacion
float aux;
int i,ban=0;
LCD_PUTC("TOMANDO DATOS....");
control=R*10;
set_pwm1_duty(control); //Exita el sistema
for(i=0;i<45;i++)
{
//Lee los datos
dat[i]=read_adc(); //Leer ADC
//dat[i]=adc*5000.0/1024.0;
delay_ms(T);
}
set_pwm1_duty(0); //Desactiva el sistema
LCD_PUTC("\f");
//Muestra los datos en la pantalla del LCD utilizando la tecla A para subir
//y utilizando la tecla B para bajar, estos datos deben ser graficados (EXCEL)
//para poder montar la curva de reacción del sistema y poder determinar los
//Parametros de la Planta
i=0;
while(ban==0)
{
aux=dat[i]*5000.0/1024.0;
lcd_gotoxy(1,1);
printf(lcd_putc,"%d. %1.3f",i+1,aux/1000);
aux=dat[i+1]*5000.0/1024.0;
lcd_gotoxy(1,2);
printf(lcd_putc,"%d. %1.3f",i+2,aux/1000);
aux=dat[i+2]*5000.0/1024.0;
lcd_gotoxy(1,3);
printf(lcd_putc,"%d. %1.3f",i+3,aux/1000);
aux=dat[i+3]*5000.0/1024.0;
lcd_gotoxy(1,4);
printf(lcd_putc,"%d. %1.3f",i+4,aux/1000);
c=tecla();      //Lee el valor del teclado y espera hasta que alguna tecla se pulse
i =(c=='B' && i!=41) ? i+1:i; //Si es B incremente i
i =(c=='A' && i!=0) ? i-1:i; //Si es A decremente i
ban =(c=='*') ? 1:0;   //Si es * salga del while
}
}
/*===========================================================================*/
/*=======================    FUNCION DEL PRINCIPAL    =======================*/
/*===========================================================================*/
void main()
{
port_b_pullups (0xFF);  //Utiliza las resistencias PULL UP internas del puerto B
set_tris_c(0);
set_tris_d(0);
setup_timer_2(t2_div_by_4,249,1);   //Configuracion de Timer 2 para establecer frec. PWM a 1kHz
setup_ccp1(ccp_pwm);                //Configurar modulo CCP1 en modo PWM
set_pwm1_duty(0);                   //Dejo en cero la salida PWM
setup_adc_ports(sAN0);              //Configurar ADC (Lectura de temperatura)
setup_adc(adc_clock_internal);      //Reloj interno para la conversion analoga digital)
set_adc_channel(0);                 //Seleccionar Canal 0 para sensor de Temperatura
LCD_INIT();                         //Inicializo el LCD
LCD_PUTC("\f");                     //Limpio el LCD
while(1)
{
lcd_gotoxy(1,1);
LCD_PUTC("TOMAR DATOS PLANTA");
lcd_gotoxy(1,2);
LCD_PUTC("Escalon(0-100):");
lcd_gotoxy(1,3);
LCD_PUTC("y presione *");
lcd_gotoxy(1,4);
LCD_PUTC("SP:           ");
R=escalon(3); //Llama la funcion para digitar el escalon de exitacion
//Valida si R esta entre 0 y 100 (Esto es otra forma de usar el if - else)
R =(R > 100) ? 100:R;
//Muestra el SETPOINT en pantalla
lcd_gotoxy(1,4);
printf(lcd_putc,"SP: %3.1f",R);
delay_ms(2000);
//Aprovecho la funcion escalon para digitar el periodo de muestreo
lcd_gotoxy(1,2);
LCD_PUTC("Periodo de M(0-1000):");
lcd_gotoxy(1,3);
LCD_PUTC("y presione *");
lcd_gotoxy(1,4);
LCD_PUTC(" T:        ");
T=escalon(4);
//Muestra el periodo de muestreo en pantalla
lcd_gotoxy(1,4);
printf(lcd_putc,"T: %ld  ",T);
delay_ms(2000);
LCD_PUTC("\f");
identificacion();
opcion=0; //Regresa al menu principal
}
}
'; unsigned int16 timeout; timeout=0; c=kbd_getc(); //Captura valor del teclado while(c=='
#INCLUDE <16F887.h>
#DEVICE ADC=10
#USE DELAY(CLOCK=4000000)
#FUSES XT,NOPROTECT,NOWDT,NOBROWNOUT,PUT,NOLVP
#DEFINE USE_PORTB_KBD   //Por defecto el teclado se conecta al puerto D,
//como el microcontrolador que se esta usando
//no tiene puerto D se conecta al puerto B.*/
#INCLUDE <LCD420D.C>
#INCLUDE <KBD4x4.C>  //Incluir en el encabezado el driver para
//manejar el teclado telefónico MODIFICADO
#include <stdlib.h>
#include <string.h>
#use     standard_io(b) 
#define  KEYHIT_DELAY   200    //Tiempo de espera del teclado en milisegundos
#byte PORTB= 6
#byte PORTC= 7
#BYTE PORTA= 5
#BYTE PORTD= 8
int16 adc,control=0;
long T=100; //100 ms
float R=0;
char c;
int opcion=0;
/*===========================================================================*/
/*=======================       FUNCION TECLA         =======================*/
/*===========================================================================*/
//Funcion encargada de esperar a que se presione una tecla 
char tecla(void)
{
char c;
do{ //espera hasta que se presione una tecla
c=kbd_getc(); //Captura valor del teclado
}
while(c=='\0'); 
return(c);
}
/*===========================================================================*/
/*=======================    FUNCION TECLA CON TIMER  =======================*/
/*===========================================================================*/
// Pregunta por una Tecla por un tiempo, si no hay actividad, deja de preguntar
// y deja que el PIC continue con su trabajo
char tecla_time(void) {
char c='\0';
unsigned int16 timeout;
timeout=0;
c=kbd_getc(); //Captura valor del teclado
while(c=='\0' && (++timeout< (KEYHIT_DELAY*100)))
{
delay_us(10);
c=kbd_getc(); //Captura valor del teclado
}
return(c);
}
/*===========================================================================*/
/*============   FUNCION PARA DIGITAR ESCALÓN/SETPOINT  =====================*/
/*===========================================================================*/
long escalon(int nd)
{
//Esta funcion captura el escalon desde el teclado, si el proceso está tomando
//datos el escalon sirve para exitar el sistema, por otro lado si el sistema
//está controlando, el escalo sirve para establecer el setpoint del sistema
long val;
int i;
char str[5]; //Variable tipo String
str[0]='0';
for(i=0;i<nd;i++)
{
c=tecla();  //Lee el valor del teclado y espera hasta que alguna tecla se pulse
if(c!='*'){
//Muestra el digito presionado en el LCD
lcd_gotoxy(5+i,4);
lcd_putc(c);
//Almacena el dato presionado en la variable String
str[i]=c;
}
else{i=nd;} //Si se presiona * sale del For      
}
val = atol(str); //Convierte el String en un valor numerico
return(val);
}
/*===========================================================================*/
/*======================= IDENTIFICACION DEL SISTEMA  =======================*/
/*===========================================================================*/
void identificacion(void)
{
int16 dat[45]; //Variable guarda 45 datos de la identificacion
float aux;
int i,ban=0;
LCD_PUTC("TOMANDO DATOS....");
control=R*10;
set_pwm1_duty(control); //Exita el sistema
for(i=0;i<45;i++)
{
//Lee los datos
dat[i]=read_adc(); //Leer ADC
//dat[i]=adc*5000.0/1024.0;
delay_ms(T);
}
set_pwm1_duty(0); //Desactiva el sistema
LCD_PUTC("\f");
//Muestra los datos en la pantalla del LCD utilizando la tecla A para subir
//y utilizando la tecla B para bajar, estos datos deben ser graficados (EXCEL)
//para poder montar la curva de reacción del sistema y poder determinar los
//Parametros de la Planta
i=0;
while(ban==0)
{
aux=dat[i]*5000.0/1024.0;
lcd_gotoxy(1,1);
printf(lcd_putc,"%d. %1.3f",i+1,aux/1000);
aux=dat[i+1]*5000.0/1024.0;
lcd_gotoxy(1,2);
printf(lcd_putc,"%d. %1.3f",i+2,aux/1000);
aux=dat[i+2]*5000.0/1024.0;
lcd_gotoxy(1,3);
printf(lcd_putc,"%d. %1.3f",i+3,aux/1000);
aux=dat[i+3]*5000.0/1024.0;
lcd_gotoxy(1,4);
printf(lcd_putc,"%d. %1.3f",i+4,aux/1000);
c=tecla();      //Lee el valor del teclado y espera hasta que alguna tecla se pulse
i =(c=='B' && i!=41) ? i+1:i; //Si es B incremente i
i =(c=='A' && i!=0) ? i-1:i; //Si es A decremente i
ban =(c=='*') ? 1:0;   //Si es * salga del while
}
}
/*===========================================================================*/
/*=======================    FUNCION DEL PRINCIPAL    =======================*/
/*===========================================================================*/
void main()
{
port_b_pullups (0xFF);  //Utiliza las resistencias PULL UP internas del puerto B
set_tris_c(0);
set_tris_d(0);
setup_timer_2(t2_div_by_4,249,1);   //Configuracion de Timer 2 para establecer frec. PWM a 1kHz
setup_ccp1(ccp_pwm);                //Configurar modulo CCP1 en modo PWM
set_pwm1_duty(0);                   //Dejo en cero la salida PWM
setup_adc_ports(sAN0);              //Configurar ADC (Lectura de temperatura)
setup_adc(adc_clock_internal);      //Reloj interno para la conversion analoga digital)
set_adc_channel(0);                 //Seleccionar Canal 0 para sensor de Temperatura
LCD_INIT();                         //Inicializo el LCD
LCD_PUTC("\f");                     //Limpio el LCD
while(1)
{
lcd_gotoxy(1,1);
LCD_PUTC("TOMAR DATOS PLANTA");
lcd_gotoxy(1,2);
LCD_PUTC("Escalon(0-100):");
lcd_gotoxy(1,3);
LCD_PUTC("y presione *");
lcd_gotoxy(1,4);
LCD_PUTC("SP:           ");
R=escalon(3); //Llama la funcion para digitar el escalon de exitacion
//Valida si R esta entre 0 y 100 (Esto es otra forma de usar el if - else)
R =(R > 100) ? 100:R;
//Muestra el SETPOINT en pantalla
lcd_gotoxy(1,4);
printf(lcd_putc,"SP: %3.1f",R);
delay_ms(2000);
//Aprovecho la funcion escalon para digitar el periodo de muestreo
lcd_gotoxy(1,2);
LCD_PUTC("Periodo de M(0-1000):");
lcd_gotoxy(1,3);
LCD_PUTC("y presione *");
lcd_gotoxy(1,4);
LCD_PUTC(" T:        ");
T=escalon(4);
//Muestra el periodo de muestreo en pantalla
lcd_gotoxy(1,4);
printf(lcd_putc,"T: %ld  ",T);
delay_ms(2000);
LCD_PUTC("\f");
identificacion();
opcion=0; //Regresa al menu principal
}
}
' && (++timeout< (KEYHIT_DELAY*100))) { delay_us(10); c=kbd_getc(); //Captura valor del teclado } return(c); } /*===========================================================================*/ /*============ FUNCION PARA DIGITAR ESCALÓN/SETPOINT =====================*/ /*===========================================================================*/ long escalon(int nd) { //Esta funcion captura el escalon desde el teclado, si el proceso está tomando //datos el escalon sirve para exitar el sistema, por otro lado si el sistema //está controlando, el escalo sirve para establecer el setpoint del sistema long val; int i; char str[5]; //Variable tipo String str[0]='0'; for(i=0;i<nd;i++) { c=tecla(); //Lee el valor del teclado y espera hasta que alguna tecla se pulse if(c!='*'){ //Muestra el digito presionado en el LCD lcd_gotoxy(5+i,4); lcd_putc(c); //Almacena el dato presionado en la variable String str[i]=c; } else{i=nd;} //Si se presiona * sale del For } val = atol(str); //Convierte el String en un valor numerico return(val); } /*===========================================================================*/ /*======================= IDENTIFICACION DEL SISTEMA =======================*/ /*===========================================================================*/ void identificacion(void) { int16 dat[45]; //Variable guarda 45 datos de la identificacion float aux; int i,ban=0; LCD_PUTC("TOMANDO DATOS...."); control=R*10; set_pwm1_duty(control); //Exita el sistema for(i=0;i<45;i++) { //Lee los datos dat[i]=read_adc(); //Leer ADC //dat[i]=adc*5000.0/1024.0; delay_ms(T); } set_pwm1_duty(0); //Desactiva el sistema LCD_PUTC("\f"); //Muestra los datos en la pantalla del LCD utilizando la tecla A para subir //y utilizando la tecla B para bajar, estos datos deben ser graficados (EXCEL) //para poder montar la curva de reacción del sistema y poder determinar los //Parametros de la Planta i=0; while(ban==0) { aux=dat[i]*5000.0/1024.0; lcd_gotoxy(1,1); printf(lcd_putc,"%d. %1.3f",i+1,aux/1000); aux=dat[i+1]*5000.0/1024.0; lcd_gotoxy(1,2); printf(lcd_putc,"%d. %1.3f",i+2,aux/1000); aux=dat[i+2]*5000.0/1024.0; lcd_gotoxy(1,3); printf(lcd_putc,"%d. %1.3f",i+3,aux/1000); aux=dat[i+3]*5000.0/1024.0; lcd_gotoxy(1,4); printf(lcd_putc,"%d. %1.3f",i+4,aux/1000); c=tecla(); //Lee el valor del teclado y espera hasta que alguna tecla se pulse i =(c=='B' && i!=41) ? i+1:i; //Si es B incremente i i =(c=='A' && i!=0) ? i-1:i; //Si es A decremente i ban =(c=='*') ? 1:0; //Si es * salga del while } } /*===========================================================================*/ /*======================= FUNCION DEL PRINCIPAL =======================*/ /*===========================================================================*/ void main() { port_b_pullups (0xFF); //Utiliza las resistencias PULL UP internas del puerto B set_tris_c(0); set_tris_d(0); setup_timer_2(t2_div_by_4,249,1); //Configuracion de Timer 2 para establecer frec. PWM a 1kHz setup_ccp1(ccp_pwm); //Configurar modulo CCP1 en modo PWM set_pwm1_duty(0); //Dejo en cero la salida PWM setup_adc_ports(sAN0); //Configurar ADC (Lectura de temperatura) setup_adc(adc_clock_internal); //Reloj interno para la conversion analoga digital) set_adc_channel(0); //Seleccionar Canal 0 para sensor de Temperatura LCD_INIT(); //Inicializo el LCD LCD_PUTC("\f"); //Limpio el LCD while(1) { lcd_gotoxy(1,1); LCD_PUTC("TOMAR DATOS PLANTA"); lcd_gotoxy(1,2); LCD_PUTC("Escalon(0-100):"); lcd_gotoxy(1,3); LCD_PUTC("y presione *"); lcd_gotoxy(1,4); LCD_PUTC("SP: "); R=escalon(3); //Llama la funcion para digitar el escalon de exitacion //Valida si R esta entre 0 y 100 (Esto es otra forma de usar el if - else) R =(R > 100) ? 100:R; //Muestra el SETPOINT en pantalla lcd_gotoxy(1,4); printf(lcd_putc,"SP: %3.1f",R); delay_ms(2000); //Aprovecho la funcion escalon para digitar el periodo de muestreo lcd_gotoxy(1,2); LCD_PUTC("Periodo de M(0-1000):"); lcd_gotoxy(1,3); LCD_PUTC("y presione *"); lcd_gotoxy(1,4); LCD_PUTC(" T: "); T=escalon(4); //Muestra el periodo de muestreo en pantalla lcd_gotoxy(1,4); printf(lcd_putc,"T: %ld ",T); delay_ms(2000); LCD_PUTC("\f"); identificacion(); opcion=0; //Regresa al menu principal } }

Código en Lenguaje C del Controlador PID para MOTOR-GENERADOR

#INCLUDE <16F887.h>
#DEVICE ADC=10
#USE DELAY(CLOCK=4000000)
#FUSES XT,NOPROTECT,NOWDT,NOBROWNOUT,PUT,NOLVP
#DEFINE USE_PORTB_KBD   //Por defecto el teclado se conecta al puerto D,
//como el microcontrolador que se esta usando
//no tiene puerto D se conecta al puerto B.*/
#INCLUDE <LCD420D.C>
#INCLUDE <KBD4x4.C>  //Incluir en el encabezado el driver para
//manejar el teclado telefónico MODIFICADO
#include <stdlib.h>
#include <string.h>
#use     standard_io(b) 
#define  KEYHIT_DELAY   1    //Tiempo de espera del teclado en milisegundos
#byte PORTB= 6
#byte PORTC= 7
#BYTE PORTA= 5
#BYTE PORTD= 8
int16 adc,control=0;
float R=0;
float yM=0,e=0.0,e_1=0.0,e_2=0.0,u=0.0,u_1=0.0,T=11;
float kp,ti,td,q0,q1,q2;
float k=0.8,tao=57.5,theta=30.0;
float TsMA,Wn,P1,P2;
char c;
int cont=0;
/*===========================================================================*/
/*=======================       FUNCION TECLA         =======================*/
/*===========================================================================*/
//Funcion encargada de esperar a que se presione una tecla 
char tecla(void)
{
char c;
do{ //espera hasta que se presione una tecla
c=kbd_getc(); //Captura valor del teclado
}
while(c=='\0'); 
return(c);
}
/*===========================================================================*/
/*=======================    FUNCION TECLA CON TIMER  =======================*/
/*===========================================================================*/
// Pregunta por una Tecla por un tiempo, si no hay actividad, deja de preguntar
// y deja que el PIC continue con su trabajo
char tecla_time(void) {
char c='\0';
unsigned int16 timeout;
timeout=0;
c=kbd_getc(); //Captura valor del teclado
while(c=='\0' && (++timeout< (KEYHIT_DELAY*100)))
{
delay_us(10);
c=kbd_getc(); //Captura valor del teclado
}
return(c);
}
/*===========================================================================*/
/*=======================    FUNCION DEL CONTROL PID  =======================*/
/*===========================================================================*/
void PID(void)
{
//Comienzo la ley de control
float tp;
tp= yM*100.0/5000.0; //Convierte la referencia de porcentaje a milivoltaje
e=1*(R-tp);
// Controle PID
u = u_1 + q0*e + q1*e_1 + q2*e_2; //Ley del controlador PID discreto
if (u >= 100.0)        //Saturo la accion de control 'uT' en un tope maximo y minimo
u = 100.0;
if (u <= 0.0)
u = 0.0;
control=u*10;
//Retorno a los valores reales
e_2=e_1;
e_1=e;
u_1=u;
//La accion calculada la transformo en PWM
set_pwm1_duty(control);
}
/*===========================================================================*/
/*============   FUNCION PARA DIGITAR ESCALÓN/SETPOINT  =====================*/
/*===========================================================================*/
long escalon(int nd)
{
//Esta funcion captura el escalon desde el teclado, si el proceso está tomando
//datos el escalon sirve para exitar el sistema, por otro lado si el sistema
//está controlando, el escalo sirve para establecer el setpoint del sistema
long val;
int i;
char str[5]; //Variable tipo String
str[0]='0';
for(i=0;i<nd;i++)
{
c=tecla();  //Lee el valor del teclado y espera hasta que alguna tecla se pulse
if(c!='*'){
//Muestra el digito presionado en el LCD
lcd_gotoxy(5+i,4);
lcd_putc(c);
//Almacena el dato presionado en la variable String
str[i]=c;
}
else{i=nd;} //Si se presiona * sale del For      
}
val = atol(str); //Convierte el String en un valor numerico
}
/*===========================================================================*/
/*=======================    FUNCION DEL PRINCIPAL    =======================*/
/*===========================================================================*/
void main()
{
port_b_pullups (0xFF);  //Utiliza las resistencias PULL UP internas del puerto B
set_tris_c(0);
set_tris_d(0);
setup_timer_2(t2_div_by_4,249,1);   //Configuracion de Timer 2 para establecer frec. PWM a 1kHz
setup_ccp1(ccp_pwm);                //Configurar modulo CCP1 en modo PWM
set_pwm1_duty(0);                   //Dejo en cero la salida PWM
setup_adc_ports(sAN0);              //Configurar ADC (Lectura de temperatura)
setup_adc(adc_clock_internal);      //Reloj interno para la conversion analoga digital)
set_adc_channel(0);                 //Seleccionar Canal 0 para sensor de Temperatura
SET_RTCC(246);                               //Cargo el TIMER0 con 243
SETUP_COUNTERS(RTCC_INTERNAL, RTCC_DIV_256); //Configuro el TIMER0 con  prescaler 256
ENABLE_INTERRUPTS(INT_RTCC);  //Habilito interrupcion por TIMER0
enable_interrupts(GLOBAL);    //Habilito las interrupciones a nivel global
LCD_INIT();                         //Inicializo el LCD
LCD_PUTC("\f");                     //Limpio el LCD
lcd_gotoxy(1,1);
LCD_PUTC("CONTROL PID DE MOTOR");
//*************************************************************************//
//*************  DISEÑO POR ASIGNACIÓN DE 2 POLOS REALES   ****************//
//*************************************************************************//
TsMA=5*tao;                     //Tiempo deseado en Lazo Cerrado    
Wn=3/(TsMA);               //Frecuencia natural del sistema
//Ubicación de 2 Polos reales
P1=Wn+Wn;
P2=Wn*Wn;
kp=(P1*tao-1)/k;        //Calculo de Kc
ti=(k*kp)/(P2*tao);     //Calculo de ti
//*************************************************************************//
//*****************   DISEÑO POR CANCELACIÓN DE POLOS    *******************//
//*************************************************************************//
/*
TsMA=0.75*tao;                  //Tiempo deseado en Lazo Cerrado 
kp=(tao)/(TsMA*k);      //Calculo de Kc
ti=tao;                  //Calculo de Ti (Igual a la constante de tiempo)
td=0;
*/
//*************************************************************************//
//*****************   SINTONIA POR ZIEGLER y NICHOLS    *******************//
//*************************************************************************//
/*
kp=(1.2*tao)/(k*theta);
ti=2*theta;
td=0.5*theta;
*/
//*************************************************************************//
// Calculo do controle PID digital
q0=kp*(1+T/(2*ti)+td/T);
q1=-kp*(1-T/(2*ti)+(2*td)/T);
q2=(kp*td)/T;
while(1)
{
adc=read_adc(); //Leer ADC
yM=adc*5000.0/1024.0;
//Llama la funcion del controlador PID
PID();
//Muestra Resultados en LCD cada 50 veces el periodo de muestreo
if(cont==50)
{
cont=0;
lcd_gotoxy(1,2);
printf(lcd_putc,"V: %f  E:%f",yM*100.0/5000.0,e);
lcd_gotoxy(1,3);
printf(lcd_putc,"SP: %3.1f C   ",R);
lcd_gotoxy(1,4);
printf(lcd_putc,"U: %ld   ",control);
}
//tiempo de muestreo
//delay_ms(2); 
cont=cont+1; //Incrementa contador para visualizar en el LCD
c=tecla_time();   //Lee el valor del teclado pero solo espera un tiempo determinado
if(c=='D')
{
lcd_gotoxy(1,2);
LCD_PUTC("Escalon(0-100):");
lcd_gotoxy(1,3);
LCD_PUTC("y presione *");
lcd_gotoxy(1,4);
LCD_PUTC("SP:           ");
R=escalon(3); //Llama la funcion para digitar el escalon de exitacion
//Valida si R esta entre 0 y 100 (Esto es otra forma de usar el if - else)
R =(R > 100) ? 100:R;
//Muestra el SETPOINT en pantalla
lcd_gotoxy(1,4);
printf(lcd_putc,"SP: %3.1f",R);
delay_ms(2000);
LCD_PUTC("\f");
}
}
}

Eso es todo por la entrada del dia de hoy, espero les haya gustado y hayan aprendido algo nuevo. Si te ha servido el contenido de esta entrada, de los videos y los códigos de implementación y deseas apoyar mi trabajo invitandome a un café super barato, puedes hacerlo en el siguiente link:

👉 Invitar a Sergio a un Café ☕️

Que esten muy bien, nos vemos en la siguiente entrada.

Entradas relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Comentarios (90)

Hola Sergio, primero permíteme mencionarte que tus tutoriales son increíbles, nunca ví algo tan didáctico pero con contenido profundizado como los tuyos, realmente gracias por el trabajo que haces.
Por otro lado quería consultarte, las dos lámparas bombillos que simulan la carga del sistema y que además sugieren una perturbación, dónde las conectas específicamente? Consulto ya que no lo puedo ver en el archivo y no sé si es problema de mi descarga.
Desde ya muchísimas gracias, y un saludo desde Argentina.

Responder

Hola, Sergio.
¿Pudieras explicarme, por favor, brevemente cuál es la función de los amplificadores operacionales en el diagrama del motor generador?
Es que soy nuevo en el mundo de la electrónica.
Gracias de antemano.

Responder

¿Por qué si son 45 lecturas de voltaje en el primer código, se muestran solo 40?
Gracias.

Responder

No son 40, son 45 lecturas, lo puedes observar en el excel inclusive. Allí verás las 45 lecturas hechas. Saludos.

Responder

¡Hola, Sergio!
¿Hay alguna manera de ver el diagrama de la placa que usaste en el experimento del motor generador?
Gracias.

Responder

Esa placa tiene el esquema que puedes descargar aqui, junto con una fuente de alimentación dual para los amplificadores operacionales. No tengo los diagramas de la placa dado que la placa la mandé a hacer en aquella época.

Responder

Hola.
¿Dónde puedo descargar el archivo de Proteus del motor generador?
El PID2.rar no contiene el archivo del motor generador para Proteus, sino otro diferente.
Salu2 y gracias

Responder

Edi, no hay archivo del motor generador en Proteus. Esta práctica es netamente implementación.

Responder

¡Muchas gracias!

Responder

Hola, una pregunta, cuál es el sensor y cuál es el actuador de este sistema?

Responder

El actuador es el motor donde su variable manipulada por el controlador son las revoluciones del propio motor. La variable medida o variable controlada es el voltaje generado por el Generador. Dado que genera un voltaje DC puedo leerlo directamente con el conversor ADC del PIC. Saludos.

Responder

Prodias decirnos los materiales completos que utilisaste…muchas gracias y buen video

Responder

Al comienzo del post están los circuitos de la planta para descarga Michael. Saludos!

Responder

Bro te felicitó por tu buena explicación pero una pregunta como conectas el motor al circuito para que gire ?? Espero una repuesta amigo.

Responder

Hola Luis, igual que te respondi en YouTube, el circuito está al comienzo del post. Una extremidad del motor va a tierra, la otra va al Darlington y al potenciometro (segundo circuito del word), En el primer circuito está el amplificador del generador, donde una extremidad va a tierra y la otra a la entrada del opam Vgen.

Responder

Bom dia Sergio.

Excelente projeto, parabéns.

Saudações do Brasil.

Responder

Muito obrigado Fernando, que bom que gostou do projeto. Saudações desde o Rio de Janeiro. Abs!

Responder

hola buenas tardes, una pregunta la salida digital del pic, esa va a la entrada del motor o como linealizas esa señal pulso que te arroja para conectarla a la planta (motor)

Responder

En esta aplicación se está utilizando la salida PWM del PIC, esa señal pasa por un filtro pasa bajos, como se muestra en el post, el cual transforma la señal PWM en un voltaje proporcional al ancho de pulso en un voltaje DC, el cual es inyectado posteriormente en el motor.

Responder

Hola que tal Sergio excelente proyecto,
Una pregunta me gustaria comunicarme con el ft232 a mi pc para reemplazar la lcd para realizar eso cambiaria mucho la programacion que tienes que tendria que cambiar.
Muchas gracias por tu ayuda.

Responder

Hola Miguel, solo debes colocar la comunicación serial en tu proyecto y listo. Eso lo hicimos en la entrada del PID predictor de SMITH con PIC, en ese caso usamos 2 xbee, tu reemplazarias los xbee por un modulo ft232 y un cable usb. Dale un vistazo a esa entrada en la sección del curso de microcontroladores. Saludos.

Responder

Muchas gracias Sergio por tu ayuda con la comunicación serial me ah servido mucho para otros proyectos que eh montado gracias.
Sergio un favor mas lo que sucede es que me encuentro realizando tu proyecto de motor generador ya lo tengo montado, pero cuando envió una señal al mi motor del 100% el motor que tengo como generador me da una tensión de salida de 18 Vdc eh realizado el montaje del circuito motor generador con el amplificador operacional como muestras en el diagrama, pero no logro una salida de 0 a 5V para el micro controlador y poder graficar mi funcion de transferencia ya eh utilizado varios amplificados el lm324n, lf353p, lm358 la alimentacion de ellos de -12 y +12 eh cambiado el potencionetro de 5k pero no logro la salida para el micro de 5v no me da ningún valor, como me puedes ayudar o que me aconsejas para lograr identificar mi motor y poder hacer la gráfica y así pasar a la siguiente etapa del PID
muchas gracias por tu colaboración estaré pendiente a tu respuesta

Responder

Con el circuito del Darlington puedes regular la velocidad del motor con lo cual puedes generar menos voltaje, sin embargo con el circuito del amplificador te debería dar para poder regular el voltaje de 0 a 5 v, ese circuito no tiene ningún misterio. Estas utilizando las mismas tierras???? Si no, debes hacerlo.

Responder

Sergio muchas gracias por la recomendación, te comento que ahora debo captar la señal (flanco de subida y bajada) que me viene de un circuito de cruce por cero y esta se me ocurrió hacerlo por interrupción puerto RB0 pero tengo el teclado 4×4 y activada las pulls, es posible asignar otro pin para el teclado matricial o asignar otro pin para la interrupción?.
La señal del circuito cruce por cero es debido a debo sincronizar con la red 120VAC una bomba monofásica y realizar el control por angulo fase.

Responder

La interrupción no puedes cambiarla, pero puedes colocar el teclado en el puerto D y colocar las resistencias pull up de forma física, ya que dicho puerto no posee pullup internas.

Responder

Hola que tal…Excelente tutorial, me gustaria aplicar el pid para controlar el nivel de llenado de un tanque con perturbaciones(una válvula de salida de agua), que debería modificar? aparte que sensor me recomiendas para tomar datos?.

Responder

Hola Andres, el código como tal no varía, lo que cambia sería el modelado matemático de tu proceso (función de transferencia) para poder sintonizar los parámetros del controlador. Para medir nivel talvez la mejor opción seria medir la presión al fondo del tanque y medir la altura por inferencia a través de la presión.

Responder

Una última pregunta….puedo sustituir el 2N3019 y 2N3055 por el MPSA13 o hay diferencia?
Este último, también va conectado a 12v?

Responder

No estoy seguro Daniel, debes buscar en el manual de reemplazos para ver si cumplen con la misma característica. Saludos

Responder

El LM324 el pin 4 va a positivo (+12) y el 11 va a tierra o a -12v?

Responder

Hola Daniel, el cxto es tal cual como está ahí. LM324 (+12) y GND. Para el generador el es donde debe ir a fuente dual (+12) y (-12) Saludos

Responder

Hola…
Lo que pasa es que regulo la ganancia del motor a 5v para que sea lo más qie pueda recibir el pic….Al momento de la toma de datos pongo el set point al 40% y la T en 10 ms….
Cuándo me empieza a dar los datos del muestreo empieza por ejemplo así
1- 4.95
2- 4.87
3- 4.9
4- 0.007
5- 0.009
6- aquí ya empieza todo normal
.
.
.
35+ también me marca 4.95
Se tienen que regular ambos potenciómetro o sólo el de la ganancia ( entiendo que es el de 5k)…
O con eso datos que me arroja puedo hacer mi función?

Responder

Estas usando una fuente Dual para los amplificadores operacionales? Eso ahi parece mas ruido que otra cosa, prueba filtrando tu fuente de alimentación dual, mira que los potenciometros tengan buena conexión o coloca trimmer. El cxto no es para hacer eso, sin embargo puedes intentar considerar ese ruido inicial como retardo y probar que tal te va con una FT calculada asi.

Responder

Hola, por qué el valor máximo que me arroja al momento del muestreo es de 1.18… estoy utilizando motores de 12v y setpoint de 40%

Responder

debes ajustar la ganancia del circuito que recibe el voltaje del generador. Lo que debes hacer es activar primero el motor al 100% y con el potenciometro ajustar que el voltaje de salida sea aproximadamente 5V (Conecta el multimetro a la salida antes de mandar ese voltaje al PIC) con eso garantizas que la máxima tensión generada sean 5V y no vayas a quemar tu PIC.

Responder

Ok, muchas gracias lo verificaré…y el potenciómetro de 50k para que se utiliza?

Responder

Ese regula la velocidad del motor.

Responder

Ya hice lo de regular la ganancia, pero ahora cunado pido el muestreo…los primeros tres datos me los arroja muy elevados(más que el setpoint) y de ahí en adelante también en los últimos datos igual se pasa del setpoint
Qué podría estar mal?

Tendrá mucha ganancia tu motor? Eso parece problema de ruido. No entendi si Solo son los 3 primeros datos y solo los ultimos datos que sufren ese fenomeno. Que sea mayor que tu setpoint no tiene problema ninguno, pues vos no estas controlando, estás es identificando, eso solo nos indica que el sistema tiene una ganancia mayor que uno.

Hola….cuando haces tú muestreo…el motor debe prender hasta que pones el setpoint y el periodo de muestreo???
Por qué a mí me prende enseguida que enciendo la fuente???

Responder

A la entrada del amplificador operacional que controla el motor (donde debe ir el PWM de tu pic con el filtro pasa bajos) debes asegurarte si colocandolo a GND el motor se queda detenido. (estoy considerando que estás copiando el código que hay aqui), si no se detiene el motor debes tener algún problema en esa etapa del circuito.

Responder

Hola
Por qué en los circuitos de la imágen tienes tantos capacitores, si en el archivo de word, solo aparecen 2, también hay más resistencias y componentes extras que en el archivo no hay?

Responder

Hola Daniel, es porque en el PCB además del circuito mostrado en el documento de Word, tiene montado la fuente de alimentación DUAL para los amplificadores operacionales. El circuito mostrado aqui antiguamente yo lo montaba en protoboard y hacia controles pero lo alimentaba con mis fuentes de alimentación externa. Despues de un tiempo le pasé los circuitos a una persona para que me lo montara en un PCB junto con la fuente de alimentación integrada, para simplemente conectar y desconectar el circuito. Saludos.

Responder

Hola buen día
Me podrías pasar los archivos PCB para reimprimirlos?
Por favor

Responder

Hola Daniel, no tengo los archivos del PCB.

Responder

Qué marcas de motores utilizaste?

Responder

Desconozco la marca, son motores que compre en una chatarrería. Puedes usar cualquier motor de 12 VDC o incluso si lo deseas puedes usar esos motores pequeños de Juguete de 5VDC. Saludos.

Responder

excelente proyecto…me podrías mandar una lista de los componentes eléctricos/electrónicos que utilizaste así como sus diagramas de conexión?
en mi escuela debo implementar un proyecto para controlar una variable, y este que muestras aquí me resultó interesante para realizarlo.

saludos desde México

Responder

Hola Daniel, el diagrama del circuito esta al comienzo del post, es un documento en WORD con el circuito del MOTOR-GENERADOR. Saludos.

Responder

Estarías interesado en vender tu proyecto?

Responder

Hola Daniel, en el momento NO, porque es una planta didáctica con la cual enseño teoría de Control. Saludos.

Responder

Hola!! muy bueno el proyecto! Una consulta, las lamparitas funcionan con el voltaje que genera el generador?? O están alimentadas con la fuente del motor?

Responder

Hola Carmen, Si funcionan con el voltaje que genera el motor generador. Saludos.

Responder

Por favor la descripción de los motores que usaste gracias.

Responder

Hola sergio, interesante contenido. Podrias decirme la descripción de los motores que utilizastes, por favor gracias

Responder

Adrian, usé motores de 12VDC, lo encontré en una chatarrería, pero puedes usar motores pequeños si quieres, esos de 5VDC de juguete.

Responder

sergio que tal? quisiera saber de cuanto voltage son los motores que utilizas

Responder

Jmar, son motores de 12VDC. Saludos.

Responder

Hola Sergio, excelente contenido tienes en la página, muy simple e intuitiva de usar. Felicidades.

Responder

Hola Vanessa, que bueno que te ha servido y te haya gustado la pagina. Saludos.

Responder

Hola Sergio C.
Primero, te felicito por tus tutoriales, no solamente tienes claro el procedimiento y como explicar su desarrollo, si no también tienes una capacidad de dar orden y lo mantienes en tus explicaciones, concluyo que tienes memoria fotográfica e inteligencia para su aplicación, te podría dar también más elogios. Agradezco tus tutoriales y no sabes cuanto más, pero soy un profesional de la vieja guardia ( voy a cumplir 70 años), pero sigo estudiando y leyendo acerca de mi profesión (telecom), y por eso te pido, si es posible, que si puedes, simplifiques tus pantallas, están tan saturadas de info y publicidad que es un tormento tratar de descargar algún archivo, yo uso win 7 en mis portátiles y tengo otros con win8.
No podrías simplificar algo el tema de las descargas? manteniendo tus intereses para personas como yo?
Mi otra pregunta es si puedo usar como base tus archivos, (con mención de la fuente, por supuesto), puedo instruir a mis alumnos, para el desarrollo de la tecnología PID la cual, yo creo, será la tecnología dominante en el este siglo, que será sin dudas, de los androides.

Gracias por tu atención, pero espero tu opinión.

Saludos cordiales desde Chile

Responder

Hola Juan, gracias por el comentário. La verdad es que trato de que la página sea bastante clara. Mi pregunta es Si Conseguiste descargar los archivos??? El sistema implementado en la pagina de compartir para obtener los códigos es para ayudar a difundir la página web y llegar a más personas.
Claro que puedes usar como base los archivos, están ahí justamente para ayudar a las personas a crecer a nivel profesional e intelectual, es un honor para mi que quieras usar mis archivos para enseñar a otras personas.
Cuéntame si has podido bajar los archivos después de haber visto el video de como descargarlos?? Si no, te los mando por email entonces. Saludos!!

Responder

Sergio hize este proyecto con el pic17F877A es bastante parecido al 16877, te cuento que cuando subo el código del Controlador PIC16F877A se atonta todo el sistema. no sabes por que pueda ser, Si el código es el mismo.

Responder

Hola Jhimmy ya te respondi en YouTube. Saludos.

Responder

Sergio, antes que nada un enorme saludo, excelente blog y muy buenos aportes, quisiera poder contactarme contigo por algunas dudas y asesorias, ¿podrias pasarme algun medio de contacto?

Responder

Hola Henry, en la parte superior de la página hay una sección de Contacto. Saludos.

Responder

Hola, disculpa la molestia, de casualidad podrías orientarme de como realizar el codigo PID pero en Code Composer Studio, ya que estoy utilizando Tiva C, y deseo controlar un Balancín con Helice.

Responder

Eddy yo nunca usé ese compilador, pero sigue siendo lenguaje C, por lo que el código es práticamente lo mismo. Lo único que debe cambiar son las funciones e instrucciones propias del compilador para configurar el PIC, pero la función del PID se mantendría casi que intacta. Saludos y buena suerte.

Responder

Hola Sergio muy importante tu apoyo quisiera saber si existe la posibilidad de saber si los datos que se producen pueden ser dibujados en Matlab? Gracias espero poder realizar un aporte economico en tu bloc con tu respuesta. Gracias

Responder

Hola César, claro que se puede, es más, es mucho más interesante hacerlo en MATLAB que en Excel. Por ejemplo, lo ideal es realizar una comunicación serial con el PIC para comunicarse con MATLAB y asi enviarle los datos del proceso. En matlab se procesa la grafica y se pueden hacer todos los análisis pertinentes al sistema como tal, incluso hasta podrias usar el Toolbox de identificación del propio matlab para generar tus funciones de transferencia. Saludos.

Responder

Hola Sergio, Soy nuevo en esto de los PiCS, solo quiero felicitarte y agradecer que compartas tus conocimientos con todos ! esto nos ayudara a que como pais vayamos desarrollando tecnologia propia, y es uno de los caminos para salir del tercermundismo, te reitero mis felicitaciones y agradecimiento, iré contribuyendo en tu blog en la medida de mis conocimientos y experiencias adquiridos. Saqludos

Responder

Hola Domingo, muchas gracias por el comentario y por el apoyo. me alegra que te haya gustado el blog y que te esté ayudando a aprender sobre este mundo fascinante de los microcontroladores. Te deseo el mejor de los éxitos en esta curva de aprendizaje. Un fuerte abraso.

Responder

Una pregunta. Es posible hacer un programa y que se requiere, para poder tomar lectura de sensores y que ademas te diga la fecha exacta en que fue tomada la muestra??

Responder

Hola Mario, claro que si!! puedes hacer eso con un microcontrolador. Para conseguirlo basicamente necesitaras de un reloj calendario DS1307 usando comunicación I2C, que de diga la hora y fecha y también de una memoria EEPROM externa para que vayas almacenando todos los datos de tus sensores. Si sigues todo el curso de Microcontroladores que tengo montado en la pagina, estarás en las condiciones de implementar tu proyecto. Te dejo aqui el link con todo el curso> Click AQUI. Saludos y éxitos en tu proyecto.

Responder

Sergio llevo tiempo siguiendo tu blog tan interesante. Me motivaría mucho ver un pid en un motor Brushless (como los motores que usan los drones). En la red hay vídeos pero nadie dice nada del pid con pic. Gracias

Responder

Buen proyecto, voy a tenerlo en cuenta. Saludos.

Responder

Hola Sergio
Felicitaciones por el excelente trabajo y explicación, quisiera pedirle el favor de darme unas pautas de como migrarlo su programa al pic 16F877A,es posible?, Ya que en el la ciudad donde vivo solo encontré este pic
he estado viendo todos sus vídeos y aun no puedo lograr dominarlo bien el compilador PIC C (CCS Compiler) soy nuevo en esto de microcontroladores

Responder

Solo necesitas cambiar el encabezado y agregar la libreria del 16f877a, esos dos pics son identicos
#INCLUDE <16F877a.h>

Responder

Gracias por responderme lo hare y ya te cuento

Responder

Hola Sergio:
disculpe que le moleste de nuevo, cambie el encabezado como me indico pero ahora no compila me sale este error
>>>Warning 208 “PID Contro.c” line 103(6,13):Function not void and does not return a value escalon

*** error 12 “PID Contro.c” line 14(20,24) Undefined identifier sANO
Es mismo codigo de Ud, solo lo cambie el encabezado

Responder

Es la forma de configurar el ADC, para ese PIC si no estoy mal es setup_adc_ports(AN0);

Responder

Gracias mil Sergio si ya me funciono eres un genio una vez mas gracias por tu tiempo

Hola ¿como estas?, excelente trabajo, ha sido de mucha ayuda para un proyecto que estoy realizando, tengo una pregunta ¿como puedo obtener la función de transferencia de un motorreductor que compro en el mercado ?.

Responder

Es basicamente hacer lo mismo visto en el ejemplo. Debes tener un sensor que esté midiendo tu variable de interes, aplicar un escalón, tomar los datos, graficar la respuesta y obtener la FT. Más adelate, cuando tenga algo de tiempo, comenzaré a explicar temas de identificación de sistemas. Suerte con tu proyecto.

Responder

eso de identificar sistemas estará genial, lo espero con ansias!

Responder

Hola 🙂
Como estas?
Espero que bien.
Sabes son nuevo en esto y por fin encontré a alguien que explicara bien, te felicito.
Ya baje los programas en C y el proyecto en proteus para hacer algunos ejercicios.
Pero que crees?
Cuando compilo el programa, SE QUEDA TRABADO ….. TENGO QUE ABORTARLO
Lo intenté con ambos programas y pasa lo mismo.
Compile unos programas que he hecho, y no se traba.
Que podrá ser?
GRACIAS…

Responder

Hola Oscar. no entendi muy bien tu pregunta. El compilador se esta quedando trabado cuando compilas mis códigos? No se a que pueda deberse. Intenta ejecutar el compilador como administrador o utilizar otro equipo para ir descartando problemas. Pero una excelente noticia es que SI compilan tus códigos y el objetivo del blog es dar una inducción y que realmente uds hagan sus propios códigos para que realmente aprendan. Saludos y muchos éxitos en tus proyectos.

Responder

Sergio excelente proyecto mas aun tu excelente explicación la verdad no savia como sacar los datos iniciales de una proceso físico , gracias.

en manera de lo posible me gustaría me mandaras el plano del tarjeta que utilizas, lo pienso realizar físico.

de antemano muchas gracias.

Att: emerson palacio
correo: [email protected]

Responder

Emerson ahi en el Blog esta el plano de la tarjeta para que la reproduzcas.

Responder

a si sergio es el que esta en el documento en word, que pena parcero gracia por su pronta respuesta.

Responder