CONTROL PID-Ziegler-Nichols

Buenas, estoy intentando crear balansin con dos motores ,uno en cada extremo.que estan conectados al arduino uno.
mi problema es que no he podido encontar las constantis P,I,D,PARA que se quede en balancin el el punto deceado.
me encontre con este metodo, que da una aproximacion de como encontrar las constantes, y luego poder afinarlas.
pero desarfortunadamente,algo estoy faciendo mal , poq no funca.
les cuento un poquito del macanismo de Ziegler-Nichols.
ante que nada estoy simulando el control pid,un simulador que me encontre para processing. en la cual
me tira los dotos en un archivo txt, y los dibujo con un programa dibuja funciones.(MatemáticasIES Antonio Menárguez Costa: abril 2011), es copiar los datos del archivo txt y pegar en el programa.

metodo de Ziegler-Nichols

Eliminar la acción integral y derivativa. Establecer el tiempo integral (Ti) a 999 o su mayor valor y establecer el controlador derivativo (Td) a cero.
Crear una pequeña perturbación en el circuito, cambiando el punto de ajuste. Ajuste el aumento proporcional, y / o disminución de la ganancia hasta que las oscilaciones tienen una amplitud constante.
Registre el valor de la ganancia (Ku) y periodo de oscilación (Pu).


Table 1. Closed-Loop Calculations of Kc, Ti, Td

y se llega a una grafica como esta

aqui le dejo mi codigo q lo he modicado del autor un poquito.
deben esperar hasta q salga soo el programa y le s garba los datos en el archivo txt

 * Contol PID    -  Para  PROCESSING - NO sirve para ARDUINO
 * 
 * Prueba Bucle Control en funcion  
 *      P = Proporcional Error
 *      I = Integral del Error
 *      D = Derivada del Error
 * Recordar en PROCESSING las "y" son hacia ABAJO (por eso parecen los signos al reves)
 *
 * Desarrollado por TUTO2002   -   tuto2002@gmail.com
 * Software de libre distribucion
 */
 int int2=0;
 int c=0;
PrintWriter OUTPUT; 
float time=0;
int[] altura;
float[] a;
float[] b;
int objetivo = 200;  // En los graficos es (height-objetivo)
float posicion ;
float posicionAnt ;
int posiInicial = 275;
//   Constantes PID
float factorP =0.84;;
float factorI =0.004;
float factorD =  -4.5;


boolean pantallaLlena = false;
boolean inicio = true;
int n=1;  // para la primera pantalla

int error=0;  // Diferencia entre el Objetivo y nuestra Posicion
float integralError =0;   // Suma de Errores = Integral

int tiempo =1;  // En los calculos no afecta lo incluyo para entender las formulas
float  fuerza = 0;  // Es la diferencia entre la Fuerza Total y el Peso
float masa = 600;   // Un parametro para convertir Fuerzas en Aceleraciones - Equivale a la INERCIA
float aceleracion = 0 ;  // Lo suponemos que esta en equilibrio y queremos que suba al Objetivo
float velocidad = 0;

PFont body;  // Para Escribir en Pantalla

void setup() 
{
  size(500, 500);   // Tamaño de la Pantalla Grafica

  body = loadFont("ArialNarrow-48.vlw");
  textFont(body);
  
  altura = new int[width];
  a = new float[2000];
  b = new float[2000];
  altura[0] = posiInicial;
  posicion = posiInicial;
//OUTPUT = createWriter("exportedPoints.txt");
  ;
}



void draw(){

  background(255);
  time=millis();
println("TIME="+time/1000);
  time=time/1000;
  OUTPUT = createWriter("exportedPoints.txt");

  // como la funcion delay() no funciona Lo RELENTIZO con estos calculos que no sirven para nada
  for(long q = 1; q<200000; q++) { 
    float nada = sqrt (q ); 
    float cada = sqrt (nada ); 
  }

  if (inicio == true){   // Inicializo los datos
    altura = new int[width];
    for(int i=1; i<width; i++) {  // Para que NO salgan en pantalla los ceros
      altura[i-1] = -10; 
    }
    altura[0] = posiInicial;
    posicion = posiInicial;
    posicionAnt = posiInicial;
    velocidad =0;
    inicio = false;
  }

  //  CALCULOS

  posicion = posicionAnt - (velocidad * tiempo);  // Recordar coordenadas hacia ABAJO
  posicionAnt = posicion;
  error =  int(posicion )- objetivo;
  integralError = integralError +error;  //  INTEGRAR es Sumar 
  // La DERIVADA del Error(espacio) es la VELOCIDAD
  fuerza =  error *factorP + integralError* factorI+ velocidad*factorD; // formula de autor 
  //sacar el comen a mi foemula para probar los constantes ya obtenidas y 
 // pasarlas al programa q dibuja 
 // fuerza =  factorP*(error+(time/factorI)*integralError+(factorD/time)*velocidad  )+posiccion; formula mia-
  aceleracion =fuerza / masa;
  velocidad = velocidad + aceleracion*tiempo;  // para el proximo ciclo
c+=1;
 a[c]=fuerza;
 b[c]=time;
 if(c>=600){
   int2=1;
 }

 //println(time);
// println("  "+fuerza);
  
  
  if(int2==1){
       for(int i2=0;i2<c;i2++){
           
         
         
     OUTPUT.print(b[i2]);println("time="+time);
     OUTPUT.println("  "+a[i2]);
 }
   
    
  OUTPUT.flush();
 OUTPUT.close();
 delay(2000);
 exit();
     }
  

 if (pantallaLlena == false){    // Hasta que no se llene la Matriz no desplazo los valores
    altura[n] = int(posicion); 
    n +=1;
    
   // int i2=+i;
    
    if (n == (width-1)){
      pantallaLlena = true;
    } 
  }
    if (pantallaLlena == true){  // Desplazo a la Izquierda los valores de la Matriz
    for(int i=1; i<width; i++) { 
      altura[i-1] = altura[i]; 
    }
    // Añado el nuevo valor al Final de la Matriz
    altura[width-1] = int(posicion); 
   
    
     
  } 
 

  fill(123);
  textFont(body,30);
  textAlign(CENTER, CENTER);
  fill(204,102,0);
  text ( "Control PID", width/2, 50);
  stroke(0,102,0);
  fill(0,102,0);
  textFont(body,15);
  textAlign(LEFT, CENTER);
  text ( "Objetivo", 10, objetivo-20);
  text ( (height -objetivo), 70, objetivo-20);
  strokeWeight(2);   
  line ( 0,objetivo, width, objetivo);
  textAlign(LEFT, CENTER);
  fill(0,0,160);

  textFont(body,30);
  for(int i=0; i<width; i++) {
   text ( ".", i, altura[i]);
   
    

  }


  
  textFont(body,20);
  textAlign(LEFT, CENTER);
  fill(0,0,160);
  text ( "Fuerza", 10, 400);
  text ( int(fuerza), 90, 400);
  text ( "Velocidad", 200, 400);
  text (  velocidad, 300, 400);
  text ( "Altura", 380, 400);
  text ( int(height-posicion), 450, 400);
  rectMode(CENTER);
  if (fuerza >0){
    fill(0,0,153);  // Cuadro en AZUL = Fuerza POSITIVA = F. TOTAL Mayor que el Peso
  }
  else {
    fill(153,0,0);  // Cuadro en ROJO = Fuerza NEGATIVA= F. TOTAL Menor que el Peso
  } 
  rect(140, 400, 20, 20);

  textFont(body,25);
  textAlign(LEFT, CENTER);
  fill(0,102,153);
  text ( "kP", 50, 450);
  text ( factorP , 90, 450);
  text ( "kI", 200, 450);
  text ( factorI , 240, 450);
  text ( "kD", 350, 450);
  text ( factorD , 390, 450);
  

}

aqui les dejo de donde saque el metodo

https://controls.engin.umich.edu/wiki/index.php/PIDTuningClassical#Ziegler-Nichols_Method

Un código un poco duro de entender bien para mí. No sabía que existiera un método empírico para calcular un PID.

Probablemente es una cosa muy tonta pero no sé si habrás tenido en cuenta que los parámetros que se obtienen con Ziegler-Nichols no se corresponden con Kp, Ki y Kd que se introducen en un PID.

Por otro lado no sé la fiabilidad que puede tener ese código que modeliza el balancín y entiendo que implementa un PID, ¿no? Ese código, ¿también simula la perturbación que hay que producir?

¿No has probado a aplicar el método Ziegler-Nichols sobre el sistema real montado?

Un código un poco duro de entender bien para mí. No sabía que existiera un método empírico para calcular un PID.

CItando al autor; Para poder entender mejor este lió, he preparado un Programa en el que se “simula”:

Un OVNI que solo se puede mover Arriba y Abajo

Inicialmente está “equilibrado” y queremos subirlo a una altura “objetivo” de 300

Con un “Bucle de Control PID” calculamos la fuerza adicional (Fuerza Total – Peso) que tenemos que aplicarle para llegar y mantenerse en el objetivo, tomando como base el “error” (objetivo – posición actual).

osea toma como variables la fuerza , la masa del objeto, la velocidad, eñ objetivo, y posicion actual:

Probablemente es una cosa muy tonta pero no sé si habrás tenido en cuenta que los parámetros que se obtienen con Ziegler-Nichols no se corresponden con Kp, Ki y Kd que se introducen en un PID.

si queres dejarla como estas acostubrado a la ecuacion del control pid , reeamplaza

¿No has probado a aplicar el método Ziegler-Nichols sobre el sistema real montado?

no, solo intente afinar al alzar los terminos pid

Alguna idea?, no puedo encontrar la soluccion, he probado de diferentes maneras, ni modo de hacerlo funcionar.

Hombre yo las mejores respuestas pids las obtuve en la carrera metiendo valores a voleo (pongo un poquito aqui quito otro poquito de alli). Si tienes el hardware montado metele valores hasta que responda como te guasta. Metodo empírico 100% XD

es que no me gusta el azar. :D $)

=( =( =( =( =( =( =( =( =( =( =( =( =( =( =( =( =( =( =( =( =( =(
=( =( =( =( =( =( =( =( =( =( =( =( =( =( =( =( =( =( =( =(
=( =( =( =( =( =( =( =( =( =( =( =( =( =( =( =( =(
=( =( =( =( =( =( =( =( =( =( =( =( =( =(
=( =( =( =( =( =( =( =( =( =( =(
=( =( =( =( =( =( =(
=( =( =( =(
=( 8)

=( =( =( =(

La verdad que tienes muchísima bibliografía de ajuste de PID. Si vas a usar método empírico de ajuste, yo lo primero que me haría es un "visor" gráfico a "tiempo real" para poder ver la salida de tu sistema. Para ello usaría KST ó Stamplot. Te pongo un par de links de cosas que escribí que creo que te pueden servir: http://real2electronics.blogspot.com/2011/07/maqueta-de-control-pid-con-arduino.html http://real2electronics.blogspot.com/2011/09/arduino-adc-muestreo-alta-velocidad.html

Para empezar con el "tuning" tienes que saber que influye cada término, por ejemplo Kp se usar para decrecer el tiempo de subida, Kd se usa para reducir el overshoot + tiempo de establecimiento y el Ki para eliminar el error permanente (a grandes rasgos, sin entrar en detalles de estabilidad y demás).

Puedes ver en este link algunos métodos => https://controls.engin.umich.edu/wiki/index.php/PIDTuningClassical#Ziegler-Nichols_Method

Un método empírico rápido para empezar: es proveer una señal escalón a la entrada, con todas las ganancias a cero. Entonces vas subiendo la ganancia proporcional hasta que el sistema empieza a oscilar. En ese momento de oscilación, la reduces hasta que desaparezca, y de ese punto, vuelves a reducir otro 20%. Incrementas la parte derivativa para mejorar la respuesta temporal y estabilidad. Luego por último, aumentas la parte integral hasta que vuelvas el sistema inestable, y en en ese momento lo reduces ligéramente.

Por cierto, puede que no puedas ajustar tu sistema usando las reglas de sintonización de Ziegler-Nichols (por ejemplo en sistemas que tienen integradores). Esto lo verás si al aplicar un escalón en lazo abierto, la respuesta no exhibe una forma de "S".

Por otro lado, yo no utilizaría el algoritmo tal cual usando la fórmula de un PID. Puedes hacerte cosillas un poco más avanzadas, como por ejemplo una tabla con ganancias proporcionales que varían según el error (por ejemplo, cuanto más lejos estás de tu setpoint, puede ser mayor y se va reduciendo al acercarte). Para el control integral, pondría que si el error no esta dentro de una ventana, no lo uses para evitar "saturarlo" (windup), etc.

Saludos

Igor R.

muchas gracias por la info, veremos que sale de todo esto,saludos!!