Autor Tema: PID para dos motores con pic16f877a  (Leído 4453 veces)

0 Usuarios y 2 Visitantes están viendo este tema.

Desconectado gera

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2188
PID para dos motores con pic16f877a
« en: 11 de Diciembre de 2009, 20:47:42 »
Hola amigos!! Q tal?
Necesito controlar dos motores de CC. Para lo cual tengo q generar dos señales PWM, y leer dos encoders de cuadratura. Queria saber cual seria la mejor forma de hacer esto.
Para generar la señal PWM podria usar los dos modulos CCP q trae el pic, pero no se me ocurre como puedo leer los dos encoders. Creo q lo mejor es medir el periodo entre un flanco ascendente y el proximo, usando alguna interrupcion por cambio de RB4-7 en combinacion con algun timer. Pero me parece q se puede complicar para identificar el flanco y de que encoder proviene.
Otra q se me ocurre es usar el CCP en modo captura y un timer para leer el encoder, y generar el PWM por software con otro timer.
Que se les ocurre a ustedes??
Saludos y gracias!!

"conozco dos cosas infinitas: el universo y la estupidez humana. Y no estoy muy seguro del primero." A.Einstein

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: PID para dos motores con pic16f877a
« Respuesta #1 en: 12 de Diciembre de 2009, 02:39:35 »
¿Tienes dos interrupciones externas en ese micro?
Lo ideal es configurarla para que salte en flanco ascendente o descendente, es indiferente, y cuando salta la interrupción lees el otro canal del encoder en un pin cualquiera, para saber si está girando en un sentido o en el otro.
Un timer corriendo en paralelo te dará la medida de la velocidad.

Desconectado Algec

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 974
Re: PID para dos motores con pic16f877a
« Respuesta #2 en: 12 de Diciembre de 2009, 06:33:43 »
Mira mi post en la parte de codigo C para pics, tengo dudas pero lo que subi funciona de momento parace que bien, te puede servir
Ademas me podrias ayudar, de momento no tengo suerte

http://www.todopic.com.ar/foros/index.php?topic=28698.0
çya me diras

Desconectado gera

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2188
Re: PID para dos motores con pic16f877a
« Respuesta #3 en: 12 de Diciembre de 2009, 09:09:56 »
Manolo, es exactamente lo q hago. Pero si uso la interrupcion por flanco, me quedo sin modulo CCP para el pwm (necesito 2 pwm).
Esto es lo que tengo hasta ahora:

Código: C
  1. #include <16f877a.h>
  2. #fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
  3. #use delay(clock=4000000)
  4. #use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,parity=N,bits=8,stop=1)
  5.  
  6. unsigned long int contador=0, T=0;
  7. int flag=0;
  8. float f=0;
  9.  
  10. #INT_CCP1
  11. void handle_ccp1_int()
  12. {
  13.    T = contador; //periodo=cantidad de interrupciones
  14.   contador = 0;
  15.    f = 1000.0 / (float)T; //frecuencia=1/Tms
  16.  
  17.    if(!input(PIN_D0))  //leemos el otro canal para saber la direccion
  18.      f*=-1.0;
  19.    
  20.    set_timer1(64543);
  21.    flag=1;
  22. }
  23.  
  24. #INT_TIMER1
  25. void handle_timer1_int()
  26. {
  27.    contador++;
  28.    set_timer1(64543); //interrumpe cada 1ms
  29. }
  30.  
  31. void main()
  32. {
  33.    set_tris_d(0x01);
  34.    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
  35.    setup_ccp1(CCP_CAPTURE_RE);
  36.    enable_interrupts(INT_CCP1);
  37.    enable_interrupts(INT_TIMER1);
  38.    enable_interrupts(GLOBAL);
  39.    
  40.    set_timer1(64543);
  41.    
  42.    while(TRUE)
  43.    {
  44.       if(flag)
  45.       {
  46.          flag=0;
  47.          printf("T=%ldms f=%fHz  \r\n",T,f);
  48.       }
  49.    }
  50. }

Funciona a la perfeccion, asiq pense en usar el otro modulo CCP para leer el segundo encoder, y generar el pwm por software. Salvo q encuentre otra forma de leer los encoders sin usar el modulo CCP.

Algec, ahi vi tu codigo, pero no resuelve mi problema. Si hago funcionar lo mio veo de darte una mano :wink:

Gracias por su ayuda muchachos, saludos!
« Última modificación: 12 de Diciembre de 2009, 09:12:44 por gera »

"conozco dos cosas infinitas: el universo y la estupidez humana. Y no estoy muy seguro del primero." A.Einstein

Desconectado Algec

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 974
Re: PID para dos motores con pic16f877a
« Respuesta #4 en: 12 de Diciembre de 2009, 11:11:30 »
EN mi codigo hay una parte no habilitada que puedes usar para medir la velocidad , la interrupcion de tiempo, si te fijas bien, hay unas notas para sacar la velocidad en el lcd, pero estan inhabilitadas como comentarios en el codigo
La rutina del encoder por interrupcion de flanco esta tambien hecha y funciona bien porque la uso en mi fresadora para ver las psoiciones de los ejes con exactitud con unos encoders. Precisamente con un 16F877 pero como uso tres encoders lo hago por tiempo no por flanco.
En el codigo del servo esta por flanco tanto el encoder como los pulsos de psoicionamiento.
Querria ver tu PID a ver. Gracias

Desconectado gera

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2188
Re: PID para dos motores con pic16f877a
« Respuesta #5 en: 12 de Diciembre de 2009, 19:14:24 »
No entendi bien como decis q lees el encoder. Vos decis q te fijas cuantos pulsos vienen en un determinado tiempo? Lo q hago yo es medir el tiempo entre un pulso y el otro porq asi es menor el error, ya q la frecuencia de la señal es muy baja.
El pid todavia no lo tengo armado, tengo q resolver esta cuestion primero. Cuando lo tenga listo te lo muestro ;)
saludos!!

"conozco dos cosas infinitas: el universo y la estupidez humana. Y no estoy muy seguro del primero." A.Einstein

Desconectado Algec

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 974
Re: PID para dos motores con pic16f877a
« Respuesta #6 en: 12 de Diciembre de 2009, 21:28:23 »
Lo que digo del encoder es que se puede hacer de dos formas, la primera generando una interrupcion por cambio de estado de un pin, normalmente esta implementado en RB3 a Rb7 en los pics.
La otra es vigilar el estado de los pines cada x tiempo con una interrupcion por rebose de contador.
La primera es mas eficaz, pero la segunda la uso por tener que vigilar 3 encoders, que son los que usa mi aplicacion y no tener pines bastantes que generen interrupcion por cambio de estado.
 

Desconectado gera

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2188
Re: PID para dos motores con pic16f877a
« Respuesta #7 en: 13 de Diciembre de 2009, 15:56:15 »
Buenas!! creo q ya tengo solucionado el problema jeje. Lo q hice fue utilizar la interrupcion por cambio de estado de los pines R4-R7 como dice Algec.
Cada vez q cae la interrupcion, me fijo q pin la genero, y reviso cuantos desbordamientos hubo del timer. De ese modo puedo saber la velocidad de ambos encoders, para saber la direccion reviso el otro canal de cada encoder y listo :D
Ahora tengo libres los modulos CCP para generar la señal q va a mover los motores. Les dejo el codigo como va hasta ahora.

Código: C
  1. #include <16f877a.h>
  2. #fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
  3. #use delay(clock=4000000)
  4. #use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,parity=N,bits=8,stop=1)
  5.  
  6. #define LOAD      64543   //precarga timer1, int cada 1ms
  7. #define ENCODERL  PIN_B4
  8. #define DIRL          PIN_B2
  9. #define ENCODERR  PIN_B5
  10. #define DIRR          PIN_B3
  11.  
  12. unsigned long countL=0, countR=0;
  13. int flag=0;
  14. float freqL=0, freqR=0;
  15.  
  16. #INT_RB
  17. void handle_rb_int()
  18. {
  19.    if(input(ENCODERL))
  20.    {
  21.       freqL = 1000.0 / (float)countL;
  22.       countL=0;
  23.      
  24.       if(!input(DIRL))
  25.          freqL*=-1.0;
  26.          
  27.       flag=1;
  28.    }
  29.    
  30.    if(input(ENCODERR))
  31.    {
  32.       freqR = 1000.0 / (float)countR;
  33.       countR=0;
  34.      
  35.       if(!input(DIRR))
  36.          freqR*=-1.0;
  37.      
  38.       flag=1;
  39.    }
  40. }
  41.  
  42. #INT_TIMER1
  43. void handle_timer1_int()
  44. {
  45.    if(countR < 0xFFFF)
  46.       countR++;
  47.      
  48.    if(countL < 0xFFFF)
  49.       countL++;
  50.  
  51.    set_timer1(LOAD);
  52. }
  53.  
  54. void main()
  55. {
  56.    set_tris_b(0x3C);  //B5 B4 B3 B2 entradas
  57.    
  58.    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
  59.    enable_interrupts(INT_RB);
  60.    enable_interrupts(INT_TIMER1);
  61.    enable_interrupts(GLOBAL);
  62.    
  63.    set_timer1(LOAD);
  64.    
  65.    while(TRUE)
  66.    {
  67.       if(flag)
  68.       {
  69.          flag=0;
  70.          printf("R: %f   L: %f  \r\n",freqR,freqL);
  71.       }
  72.    }
  73. }

Saludos y gracias!

"conozco dos cosas infinitas: el universo y la estupidez humana. Y no estoy muy seguro del primero." A.Einstein


 

anything