CONTROL DE LA VELOCIDAD DE UN MOTOR DC CON ENCODER

10,056 views
9,582 views

Published on

Published in: Education
1 Comment
2 Likes
Statistics
Notes
No Downloads
Views
Total views
10,056
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
293
Comments
1
Likes
2
Embeds 0
No embeds

No notes for slide

CONTROL DE LA VELOCIDAD DE UN MOTOR DC CON ENCODER

  1. 1. CONTROL  DE LA VELOCIDAD DE UN MOTOR DC CON ENCODER    FUNCIONAMIENTO:  Primero se introduce las RPM deseadas utilizando un potenciómetro, cuya salida se ingresa al  conversor análogo digital en la pata RA0.   A través de la INTRB0 se cuentan los pulsos generados por el encoder (estos pulsos han sido  duplicados previamente por un XOR).   La interrupción por TMR1 nos permite tener un tiempo de muestreo de 100ms. Tomando en  cuenta dicho tiempo y el número de pulsos, podemos calcular las RPM reales y el error.  Los factores proporcionales de los u (k proporcional, k derivativo y k integrador)  los hemos  hallado experimentalmente, probando directamente en el motor y variándolos  según se  reduzca el error.    Dado que u puede ser negativo, hemos visto necesario permitir un cambio en el sentido de  giro para que el motor se estabilice más rápidamente; de lo contrario, o se demora mucho o  nunca se estabiliza. También,  hemos limitado tanto el u integrador como el total entre 0 y 255  para no llegar a errores infinitos y poder introducir el u en el PWM (MIKRO solo acepta un duty  time entre 0 y 255).     Finalmente, el proceso se repite indefinidamente haciendo el valor de RPM ingresado igual al  valor de RPM del motor.  Diagrama de bloques      potencio metro   (RPM)     Control  PID  Generación de  PWM  Puente H  Motor dc               Int  TIMER1  Int  RBO      PIC 16F877A  XOR  encoder 
  2. 2. DIFICULATADES   Y ALTERNATIVAS DE SOLUCION  Introducción de la referencia  Inicialmente,  quisimos introducir la referencia de RPM por teclado, se hizo el código y se  simulo exitosamente  en Proteus, pero la implementación de teclado en el entrenador de PIC’s   falló. Intentamos modificar la librería del teclado para realizar un polling de 0’s, pero el  MIKROC no permite modificar librerías. Luego, intentamos crear nuestro propio programa de  exploración de teclado, el problema fue que este entraba en conflicto con los TMRs, por lo que  desistimos de usar teclado.  Nuestra segunda opción fue emplear la comunicación asíncrona (UART) del MIKROC. Al  momento de probar el circuito real, la comunicación reseteaba en cada intento la  computadora. Solo se podía probar por poco menos de un minuto, por lo que tuvimos que  descartar esa opción.   Para simplificar el código, esperando eliminar posibles problemas, decidimos introducir las  RPM por un potenciómetro conectado al ADC. De esa manera pudimos introducir  exitosamente la referencia e iniciar el programa.  Control  Los  problemas principales fueron: La poca precisión de la lectura de las RPM, la falta de  información técnica del motor para hallar los k, y el error elevado en estado estacionario.  Para aumentar la precisión, utilizamos un XOR conectado a ambos canales del encoder para  duplicar los pulsos.  Las k, las tuvimos que encontrar por prueba y error. Utilizamos valores pequeños, alrededor de  1 y fuimos bajando hasta tener un error estable.  A pesar de lo anterior, el error seguía siendo inaceptable. La solución a la que llegamos fue el  de cambiar el control PD inicial por un control PID. De esta manera, llevamos el error  estacionario a cero.                  
  3. 3. CODIGO EN MIKROC  unsigned short kp, RPMi1, RPMi2, RPMi3, RPMi4, ANencd;  unsigned int RPMi=500;  unsigned short cnd;  unsigned short cnt;  unsigned short x;  unsigned short e=0;  unsigned int AN;  float errora=0;  float derror=0;  float u=0;  float up=0;  float ud=0;  float ui=0;  long int contador=0;  int delay=0;  //unsigned short kp = 2;  //unsigned short kd = 3;  float error=0;  float ierror=0;  char txte[14];  char txtu[14];  char txt[7];  unsigned int Pencd;  unsigned long int fencd;  float RPMr;  float RPMm = 1600;                     // valor maximo de las revoluciones por minuto 
  4. 4. float RPM;  float duty1;                               // recibe un valor decimal  unsigned short duty;                       // lo convierte en entero    // LCD module connections  sbit LCD_RS at RD1_bit;  sbit LCD_EN at RD3_bit;  sbit LCD_D4 at RD4_bit;  sbit LCD_D5 at RD5_bit;  sbit LCD_D6 at RD6_bit;  sbit LCD_D7 at RD7_bit;    sbit LCD_RS_Direction at TRISD1_bit;  sbit LCD_EN_Direction at TRISD3_bit;  sbit LCD_D4_Direction at TRISD4_bit;  sbit LCD_D5_Direction at TRISD5_bit;  sbit LCD_D6_Direction at TRISD6_bit;  sbit LCD_D7_Direction at TRISD7_bit;  // End LCD module connections    interrupt(){   if(INTCON.INTF==1){                       // int por RB0   contador++;   INTCON.INTF=0;   }   if(PIR1.TMR1IF==1){    T1CON.TMR1ON=0; 
  5. 5.   TMR1H=0x0B;                         //100ms    TMR1L=0xDB;    T1CON.TMR1ON=1;    fencd=contador/10;                       // frecuencia del encoder en kHz    RPMr = 1.5*contador;                      // RPM reales segun encoder    contador=0;    AN=ADC_Read(0);    RPMi=(AN*RPMm)/1023;    errora=error;    error= RPMi+‐1*RPMr;                     // calcula el error cada 10ms(tiempo de muestreo)    derror=(error+‐1*errora)/0.1;    ierror=ierror+0.05*(error+errora);    up=0.2*error;    ud=0.02*derror;    ui=1*ierror;    if(ui>=255) ui=255;    u=up+ud+ui;    if(u>=0){    PORTB.F1=1;    PORTB.F2=0;    }    else{    PORTB.F1=0;    PORTB.F2=1;    u=‐u;    }    if(u>=255) u=255; 
  6. 6.   PWM1_Start();                             // enciende el PWM    duty=u;    PWM1_Set_Duty(duty);                     // establece el duty    PIR1.TMR1IF=0;    }    }      Port_init() {                                // inicializa puertos  TRISC.F2=0;                                  // Port C salida  PORTC.F2=0;                                  // PWM es inicialmente cero  TRISA.F0=1;                                  // Entrada ADC para la realimentación  PORTB=0;  TRISB=1;  ADCON1 = 142;                                // Configure AN0 pin as analog  PORTD=0x00;  TRISD=0b00000101;  }    Inte_init(){  INTCON.GIE=1;  INTCON.PEIE=1;  OPTION_REG=0X87;  TMR1H=0x0B;                         //100ms  TMR1L=0xDB;  T1CON=0b00100001;  INTCON.INTE=1;                               //habilita la int por RB0 
  7. 7. PIE1.TMR1IE=1;    }      void main() {    cnt = 0;                                 // Reset counter    cnd = 1;    Port_init();    Lcd_Init();                              // Initialize Lcd    Lcd_Cmd(_LCD_CLEAR);                     // Clear display    Lcd_Cmd(_LCD_CURSOR_OFF);                // Cursor off    PWM1_Init(5000);                         // inicializa el PWM y establece una frecuencia de 5kHz    ADC_Init();    Inte_init();    error=0;    while(1) {       Lcd_out(1, 1, "RPMref= ");       IntToStr(RPMi, txt);       Lcd_Out_Cp(txt);                        // introduce el valor de RPM en el uC       Delay_ms(10);       Lcd_Out(2, 1, "RPMreal= ");       FloatToStr(RPMr, txte);       Lcd_Out_Cp(txte);                    // imprime los millares                        // Muestra las RPM en el  LCD       Lcd_Out_Cp("         ");    }  } 
  8. 8. CIRCUITO EN PROTEUS     

×