Hola.
Te "pego" el algoritmo para el PID que estoy usando yo para el control de velocidad de un motor.
Tienes que tener en cuenta que:
1.- referencia -> indica la consigna que quieres que alcance
2.- real -> lo que midas del sensor
Codigo:
int16 duty_PWM2=400; // Variable para modificar el "duty cycle" del PWM2.
float Kp_vel,Ki_vel,Kd_vel; // Constantes del controlador PID.
float referencia=0,real; // Consigna de referencia y real del eje a controlar.
float error=0,serror=0,errant=0,outctrl; // Variables para algoritmo PID.
El tiempo de muestreo lo tendras que programar usando un timer, ojo que no puedes usar el timer2 que lo usa el modulo PWM.
Yo fijo el timer a 10ms y utilizo una variable para hacer periodos de muestreo multiplos de 10ms. Para un calefactor necesitaras tiempos mayores.
Codigo:
errant=error; // Guardamos error de iteracion anterior, usado en parte D.
error=referencia-real; // Error actual.
serror+=error; // Error acumulativo.
if(serror>MAX_serror) serror=MAX_serror; // Al ser acumulativo puede desbordarse, asi le imponemos
if(serror<-MAX_serror) serror=-MAX_serror; // un maximo.
outctrl=Kp_vel*error+Ki_vel*serror+Kd_vel*(error-errant); // Señal de control, duty cycle para PWM.
if(outctrl>MAX_duty) outctrl=MAX_duty; // Debe tener como maximo 100% duty cycle, calculado sobre base
if(outctrl<-MAX_duty) outctrl=-MAX_duty; // de tiempos del modulo PWM.
duty_PWM2=abs(outctrl);
set_pwm2_duty(duty_PWM2); // Cargamos en modulo PWM el valor absoluto de la señal de control obtenida.
Espero te sirva.
Salu2
Wenas.
No puedo poner el programa entero, que son unas 900 lineas y mazo de funciones. Pero dime que te interesa saber y te posteo esa parte y te explico como lo hago.
El programa realiza un control de velocidad para un motor DC, recibiendo ordenes desde un PC el cual grafica los resultados. Los parametros del PID se leen inicialmente de la EEPROM del PIC, y tb se pueden cambiar desde el PC. Como encoder uso un raton de PC, comunicacion PIC-Raton mediante protocolo PS2.
Te pongo la rutina de atencion para el timer1:
Codigo:
// -----------------------------------------------------------------------------
// Rutina de atencion a la interrupcion por desbordamiento del timer1.
// El timer1 tendrá un valor fijo de tiempo (10ms), y en funcion del valor de Ts tendremos
// el tiempo de muestreo (multiplo de 10ms).
// Ts inicial = 4 -> Tiempo de muestreo = 40ms
// -----------------------------------------------------------------------------
#int_TIMER1 // Indica que la siguiente funcion es de atencion a interrupcion del timer1.
void TIMER1_PID() {
set_timer1(0xD8EF); // Contador ascendente, interrupcion al pasar de FFFF a 0000.
// La interrupcion saltara cada 15ms (FFFF-C567).
// 10ms (FFFF-D8EF).
// 45ms (FFFF-5037).
// 60ms (FFFF-159F).
// Cuando contador valga Ts, se ejecutara el control
contador_Ts++;
/////////////////////////////////////
if(contador_Ts>=Ts){
contador_Ts=0;
// Pedimos datos al raton. Almacenados en byte1, byte2 y byte3.
lee_raton();
// Indicamos nuevo dato listo para enviar a HOST.
nueva_lectura=true;
// Indica fallo en lectura del raton.
if(err_leyend_raton) output_high(PIN_A5);
PID_ejeX(); // LLamada a subrrutina de control PID.
}
//////////////////////////////////////
#asm
bcf PIR1,0 // Incluido por problemas del copilador empleado, falla si no se incluyen
retfie // reentrando en la interrupcion (problemas al leer raton).
#endasm
}
PID_ejeX() es la subrrutina que puse en el primer mensaje, la que realiza el control PID.
Espero opiniones.
>Salu2<