Saltar al contenido

Adquisición de Datos e Identificación de un Horno con PIC

Hola controleros y controleras, en el día de hoy vamos a tomar un horno eléctrico, vamos a sensar su temperatura con una termocupla tipo K y un microcontrolador PIC, haremos una adquisición de datos a través de MATLAB comunicando inhalámbricamente el PIC con el computador por Radiofrecuencia usando los modulos XBEE y por último haremos la identificación del sistema para obtener la función de transferencia del horno eléctrico.

Antes de comenzar con la explicación detallada y antes de mostrarte los códigos Gratuitos, te invito a que veas el 👉 curso de microcontroladores PIC Gratuito del sitio web.

Proceso: Horno Eléctrico

Antes que nada, vamos a entender que el proceso que vamos a tratar aquí, será un horno eléctrico, de esos convencionales que podremos encontrar en casa.

25. Monitoreo de Temperatura en un Horno Eléctrico

Este POST es la Segunda parte de la entrada pasada, donde EXPLICAMOS el funcionamiento del HORNO, junto con su circuito de POTENCIA y junto con la lectura, comunicación y graficación de la temperatura en el computador.

Por eso, para que puedas ENTENDER este post, será necesário que leas el post anterior, te dejo el link a continuación.

Mira como 👉 Monitorear la temperatura de un Horno usando un PIC.

Esquema del Circuito de Adquisición de Datos

A continuación te muestro el esquema del circuito que vamos a usar para tomar los datos del horno, que es exactamente el mismo circuito de la entrada anterior. NOTA: El circuito es meramente ilustrativo en Proteus, la simulación de este circuito no es funcional en proteus.

Adquisición de Datos

La adquisición de datos del horno se hará a traves de Matlab, tomando los datos de temperatura sensados por el microcontrolador PIC cada 1 segundo.

Los datos obtenidos de este proceso, junto con el código de adquisición de datos estarán disponibles al final de este post.

La respuesta obtenida en lazo abierto, del sistema, despues de hacer un estímulo con un escalón de 110C, fue la siguiente.

Datos de temperatura del horno

Como podemos observar, el sistema presenta un comportamiento parecido a un sistema de primer orden con retardo. Adicionalmente dado que la temperatura dió por encima del escalón podemos intuir que la ganancia estática del sistema es mayor que 1, por lo tanto es un sistema amplificador.

Tratamiento de los datos del Horno

Una vez tenemos la dinámica del horno en datos, procedemos a hacer un recorte de los datos, para tomar únicamente los datos que están dentro del escalón del 110 y adicionalmente haremos una traslación de los datos hacia el origen, para trabajar en algo que se conoce como la variable desvio.

El código para hacer este tratamiento, también está disponible al final de este post.

Datos de temperatura del Horno recortados y transladados

Identificación el Sistema

Para obtener la función de transferencia del sistema, utilizaremos el toolboz de System Identification del MATLAB

Primero importamos los datos transladados y recortados, que se obtienen despues de ejecutar el código.

Luego procedemos a realizar la estimación del proceso a través de una función de transferencia. Para este caso se optó por obtener una función de transferencia de primer orden con retardo (1 polo y delay). Se dá estimar y se obtienen los parametros mostrados en el paso 4 de la siguiente figura.

Según la estimación del proceso, nuestra función de transferencia para el horno es:

G(s)=\dfrac{2.3553}{370s+1}e^{-30s}

Control del Proceso

En la próxima entrada veremos como realizar un control PI dentro de una estructura de Predictor de Smith para este proceso, sin embargo, si deseas aprender a crear tus propios controladores en la vida real, te invito a realizar mis cursos de control en sistemas embebidos, basta con seleccionar el curso con el dispositivo embebido de tu preferencia (PIC o Arduino):

  • Curso de Sistemas de Control en Dispositivos Microcontrolados en UDEMY (PIC y ARDUINO)
  • Certificado de Aprobación una vez finalices el Curso
  • DESCUENTO si accedes directamente con los siguientes botones de acceso.
  • NOTA: Si buscas el curso directamente en UDEMY o si lo adquieres en otra plataforma distintas a las mostradas anteriormente NO OBTENDRÁS NINGUN DESCUENTO sobre el valor final del Curso.

Códigos de Implementación

A continuación te dejo todos los códigos para que puedas reproduzir esta práctica. Sabes que para acceder a ellos, solo basta con compartir la información de este post, para que más personas tengan conocimiento de esta información.

Código del PIC C Compiler

Para descargar la librería del MAX6675 deberás hacerlo desde el post anterior: 👉 

#include <18F4550.h>
#device ADC=10

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

#use delay(crystal=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

#define TC_CLK     PIN_B1  
#define TC_CS      PIN_C0 
#define TC_DATA    PIN_B0



#include "max6675.c"
#include <stdlib.h>
#include <string.h>

long deg=0;

short timeout_error;
char car[10];

char timed_getc() { 
   long timeout;
   
   timeout_error=FALSE; 
   timeout=0; 
   
   while(!kbhit()&&(++timeout<50000)) // 1/2 second 
      delay_ms(100); 

   if(kbhit()) 
      return(getc()); 
   else { 
      timeout_error=TRUE; 
      return(0); 
   } 
}

//Define la interrupción por recepción Serial
#int_RDA
void RDA_isr()
{
 int i=0,ini=0,fin=0;
 char dat[5];
 char degC[5];
 long duty;
 
 // Almacena 10 datos leidos del serial
  for(i=0;i<5;i++){
     dat[i]=getc();
     putc(dat[i]);
    }



//Busco el valor del escalon en los datos recibidos
for(i=0;i<5;i++){
  if(dat[i]=='S'){
    ini=i+1;
    i=10;
  }
 }
 for(i=ini;i<5;i++){
  if(dat[i]=='
){
    fin=i-1;
    i=10;
  }
 }
 if(ini!=0 && fin!=0){
    // salvo en degC el caracter con el escalon
    for(i=ini;i<=fin;i++){
     degC[i-ini]=dat[i];
    }
    
     deg = atol(degC); //Convierte el String en un valor numerico
     
     // valida que el escalón esté ente 0 y 300 grados celcius
     
     if(deg>600)
         deg=600;
     if(deg<0)
         deg=0;
    
        duty=deg*10/6;
    set_pwm1_duty(duty);      // set PWM del PIC
 }
}
//! 

void main() 
{ 
   
   char msg[32]; 
   delay_ms(50);      //allow oscillator to stabilise 
   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
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);

   while(1){ 
      delay_ms(1000); 
      //sprintf(msg,"%3.2f%cC\r\n",do_everything(),0xB0); 
      sprintf(msg,"I%3.2fFI%3.2fFI%3.2fF",do_everything(),do_everything(),do_everything()); 
      printf("%s",msg); 
   } 
} 

Código en MATLAB

Si lo deseas puedes descargar la lista de datos que se obtuvo en ente proceso. CLICK AQUI PARA DESCARGAR

Para poder ver estos datos, debes digitar en MATLAB:

plot(tiempo,escalon,tiempo,salida)

Código del Tratamiento de Datos

%Programa de Identificacion
load('Ident1.mat')
plot(tiempo,escalon,tiempo,salida);

%Renombra variables
us=escalon;
ys=salida;
ts=tiempo;

b=110; % Escalon donde se hizo lA IDENTIFICACION

%Busca el momento exacto donde se insertó el escalón
 i=1;
while(us(i)<b)
    i=i+1;
end
x1=i;
while(us(i)==b)
    i=i+1;
end
x2=i-1;

%Recortar datos hasta el origen
ur=us(x1:x2);
yr=ys(x1:x2);

tr=ts(x1:x2);
%transladar los datos

ut=ur-us(1);
yt=yr-yr(2);

tt=tr-tr(1);

%Graficar escalon Trasladado
figure(2)
plot(tt,ut,tt,yt,'linewidth',3),grid
title('Datos recortados y transladados')
xlabel('Tiempo (s)')
ylabel('Temperatura (C)')

Código de la Interfaz Gráfica para Adquisición de Datos

%% Ejemplo Monitoreo de señales en tiempo Real
function varargout=monitoreo(varargin)
parar=false;
fclose('all')
global tiempo salida escalon y
fig(1)=figure('name','Monitor','menubar','none','position',[200 200 800 700],'color',[0.9 0.6 0.3])
movegui(fig(1),'center');
axe(1)=axes('parent',fig(1),'units','pixels','position',[60 80 600 550],'xlim',[0 40],'ylim',[0 200],'xgrid','on','ygrid','on')
set(get(axe(1),'XLabel'),'String','Tiempo (Seg)')
set(get(axe(1),'YLabel'),'String','Temperatura (°C)')

lin(1)=line('parent',axe(1),'xdata',[],'ydata',[],'Color','r','LineWidth',2.5);
lin(2)=line('parent',axe(1),'xdata',[],'ydata',[],'Color','k','LineWidth',2);


bot(1)=uicontrol('parent',fig(1),'style','pushbutton','string','Detener','position',[680 50 100 50],'callback',@stop,'fontsize',11)
bot(2)=uicontrol('parent',fig(1),'style','pushbutton','string','Enviar','position',[680 200 100 50],'callback',@enviar,'fontsize',11)

txbx(1)=uicontrol('parent',fig(1),'style','tex','string','Temp','position',[680 100 100 50],'fontsize',11)
txbx(2)=uicontrol('parent',fig(1),'style','edit','string','000','position',[680 250 100 50],'fontsize',11)



%% Funcion Pare
    function varargout=stop(hObject,evendata)
        parar=true;
        fclose(SerialP);
        delete(SerialP);
        clear SerialP;
        
    end

%% Funcion enviar
    function varargout=enviar(hObject,evendata)
        deg1=get(txbx(2),'string');
        deg=["S"+deg1+"$"];
        fwrite(SerialP,deg,'uchar');
    end
    %% funcion Graficar
   % function varargout=grafique(hObject,evendata)
        tiempo=[0];
        salida=[0];
        escalon=[0];
        deg1="0";
   
        dt=1;
        limx=[0 40];
        limy=[0 200];
        set(axe(1),'xlim',limx,'ylim',limy);
        
        
    %% Configura el Puerto Serial
    
    SerialP=serial('COM8');
    set(SerialP,'Baudrate',9600); % se configura la velocidad a 9600 Baudios
    set(SerialP,'StopBits',1); % se configura bit de parada a uno
    set(SerialP,'DataBits',8); % se configura que el dato es de 8 bits, debe estar entre 5 y 8
    set(SerialP,'Parity','none'); % se configura sin paridad

    fopen(SerialP);
              
     %% Grafico
     k=5;nit = 10000;
        while(~parar)

            % Lectura del Dato por Puerto Serial
            variable= (fread(SerialP,20,'uchar'));
            ini=find(variable==73); %Busca el retorno de carro (Primer dato)
            ini=ini(1)+1;
            fin=find(variable==70); %Busca operador grados (ultimo dato)
            fin= fin(find(fin>ini))-1;
            fin=fin(1);
            tempC=char(variable(ini:fin))';
            temp=str2num(tempC);
            
            set(txbx(1),'string',tempC);
            %Actualiza las variables del grafico
           
             tiempo=[tiempo tiempo(end)+dt];
             salida=[salida temp];
             escalon=[escalon str2num(deg1)];
             set(lin(1),'xdata',tiempo,'ydata',salida);
             set(lin(2),'xdata',tiempo,'ydata',escalon);
             pause(dt); %% espera 0.1 seg para cada interación
             if tiempo(end)>=limx % actualizo grafica cuando llega a su limite en tiempo real
             limx=[0 limx(2)+40];
             set(axe(1),'xlim',limx);
             end
             
             if salida(end)>=limy % actualizo grafica cuando llega a su limite en tiempo real
             limy=[0 limy(2)+30];
             set(axe(1),'ylim',limy); 
             end
             
             k=k+1;
             if(k==nit)
                 parar=true;
             end
        end
        parar=false;
        
end

Perfecto Controleros y Controleras, con esto llegamos al final de nuestra páctica del día de hoy.

Recuerda que si deseas apoyar mi trabajo, puedes invitarme a un café y seguirme ayudando a mantener los servidores de este sitio web, es muy barato el café y contribuyes con el tiempo y esfuerzo invertidos en las clases elaboradas en el canal y pagina web: 👉Invitar a un Café a Sergio ☕️

Espero que esten muy bien y nos vemos en la próxima.

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 (6)

Buen día, gracias por esta excelente pagina. Espero se encuentre bien en estos tiempos de cuarentena.
Estoy haciendo un prototipo de invernadero y le quiero hacer un control de temperatura a través de una salida PWM de arduino para que éste encienda un bombillo incandescente a determinada temperatura y se mantenga, pero tengo una duda, espero me la pueda solucionar.
En el vídeo muestra un escalón de 110, pero este valor que viene siendo? temperatura, voltaje, constante …
Para mi proyecto necesito también un un escalón pero no entiendo bien este valor.
Gracias.

Responder

Hola Dilber, ese 110 es un escalón de temperatura. En el código del PIC se estableció si no estoy mal 300 grados máximos, o sea que aplicando el PWM al 100% equivalia a un escalón de 300. Tu puedes determinar ese valor colocando el PWM en 100% y viendo cual sería tu máxima temperatura con el bombillo. Despues puedes identificar tu proceso, para eso escoge un escalón que haga que tu temperatura suba más o menos al punto donde la deseas controlar en tu proceso, por ejemplo en 30 grados. No importa si el escalón es muy grande o muy pequeño, si consigues que tu temperatura este cerca de esa temperatura, es un buen punto para identificar tu sistema.

Responder

como puedo meter la ecuación de la función de transferencia que nos da el horno en matlab? necesito hacer otros estudios y no se como poner esa «e» a la -30s

Responder

Seria:
G=tf(2.3553,[370 1])
G.iodelay=30

Responder

Hola. Cómo hago para meter esta función de transferencia con retardo en Simulink?
Lo que he podido ver en los bloques FT de Simulink es que solo se pueden introducir coeficientes de los polinomios de s del numerador y del denominador de la función

Responder

Para poner el retardo en Simulink debes poner en serie otro bloque llamado «Transport Delay» y allí le configuras el 30 correspondiente al retardo de este sistema. Saludos.

Responder