domingo, 11 de noviembre de 2012

Progreso 01 - 05 Nov ( Mejorando la dirección)


Poco pero rompe coco!


Un fin de semana con puente abordo, la verdad he disminuido el tiempo dedicado a este proyecto, por dedicarle más tiempo a mi familia, como he comentado anteriormente y gracias a que siento que logrado nivelarme en mi curva de aprendizaje, actualmente tengo todos los aspectos de este proyecto cubierto y solo me resta afinarlos antes de ensamblarlo... ya saben..."El todo es la suma de sus partes"


"Halloween" 31/10/2012

Fuerte Sn Felipe de barajas - Cartagena de Indias 03/11/12

Ya que suele gustarme ir por el camino difícil  y más cuando consiste en torturar mis neuronas, me puse a investigar como hacer funcionar la transmisión con aquel servo motor rudimentario, me imagine como hacerlo funcionar, pero no tenía del todo claro como implementarlo en el código... buscando y búscando encontré un par vídeos en youtube de servo casero, y era como me habia imaginado, pero no mostraba el trasfondo (como retroalimentar constantemente la lectura del potenciometro para que no pasarme de los limites) los dejo a continuación (mi meta es llegar a este nivel de precisión..ya es algo personal)





Como soy egocéntrico no  puedo aceptar que algo me quede grande, decidí averiguar la base de esto, después de googlear un montón, encontré el método PID, metodología de control de sistemas de Ingeniería  la cual se aplica a variados sistemas y es básicamente  modular constantemente una variable para para obtener el resultado deseado, de acuerdo a la desviación presentada (error), un ejemplo práctico es cuando estas conduciendo un auto, y quieres mantener una velocidad estable, estas viendo el velocímetro (tu feedback) y de acuerdo a si estas por encima o por debajo, aprietas o sueltas el acelerador, que tanto lo sueltas o aprietas, dependerá de que tan alejado o pasado estés de la velocidad deseada.

PID viene de proporcional, derivativo e integral, son las tres funciones matemáticas aplicadas al error de tu sistema, en términos sencillos:

y(salida) =  error*Kp + ( §error)*Ki + (error - error anterior)*kd

donde:

 error = (valor deseado - valor obtenido)

y Kp, Ki, Kd, son constantes del sistema, estas se pueden obtener definiendo el algoritmo de tu sistema, en donde se relacionan matemáticamente tu entrada con tu salida. este modelado se puede realizar con herramientas informáticas como Labview o Matlab/simulink..lastimosamente no cuento con estas herramientas por el momento, y como no requiero tanta exactitud por el momento trate de hacerlo manualmente, para esto hay unas técnicas de tunning (PID tunning) basadas en el ensayo y error.


Para nuestro caso:


El potenciometro es nuestro feedback (valor de salida del sistema y de entrada para nuestra función), vamos a saber donde esta (ángulo del motor) pero como haces efectivo tu posicionamiento?...pues con el PID aplicado a la velocidad (salida de la función y entrada de nuestro sistema) variaremos la velocidad usando PWM( modulación del ancho del pulso).

Espero haber sido claro en este punto, hay mucha literatura del tema, no siempre tan clara, la mejor esta en ingles.

Después de un par de horas de prueba y error logre unos valores, escribí el sketch y lo probé  me parece que voy por el buen camino, estoy más que complacido con lo logrado, para la aplicación la precisión es suficiente (pero lo mejorare en la próxima sesión de trabajo)

Este es el esquema de conexionado:

utilice un par de botones para indicar el sentido de giro:





El sketch


 int D = 6 ;  
 int I = 5 ;  
 int LED = 13 ;  
 boolean state1 = 0;  
 boolean state2 = 0;  
 int currenPosition;  
 int der = 7;//cable amarillo  
 int izq = 9;//cable negro  
 int enable = 3;  
 float Kp = 0.2;  
 float Ki = 0.05;  
 float Kd = 1.75;  
 int setpointDer = 70;   
 int setpointIzq = 170;  
 int setpointCenter = 120;  
 float speedVal = 70;  
 float error = 0;  
 float lastError = 0;  
 float sumError = 0;  
 void setup(){  
  pinMode(D, INPUT);  
  pinMode(I, INPUT);  
  pinMode(LED, OUTPUT);  
  Serial.begin(9600);  
  Serial.println ("Setup");  
 }  
 void loop(){  
  currenPosition = analogRead(A5);  
  currenPosition = map(currenPosition,0,1023,0,255);  
  state1 = digitalRead(I);  
  state2 = digitalRead(D);  
  //Serial.print ("currenpos ");  
  //Serial.println(currenPosition);  
  if(state1 == HIGH){  
   if (currenPosition > 100){  
     error = currenPosition - setpointDer;  
     speedSetup();  
     analogWrite(enable, speedVal);  
     digitalWrite(izq,HIGH);  
     digitalWrite(der,LOW);  
               }  
    else { analogWrite(enable, 0);}  
   Serial.print("IZQUIERDA");  
   Serial.print ("currenpos ");  
   Serial.print(currenPosition);  
   Serial.print ("speed ");  
   Serial.print(speedVal);  
   Serial.print ("error ");  
   Serial.println(error);  
    }  
  if(state2 == HIGH){  
     if (currenPosition < 230){  
     error = setpointIzq - currenPosition;  
     speedSetup();  
     analogWrite(enable, speedVal);  
     digitalWrite(der,HIGH);  
     digitalWrite(izq,LOW);  
               }  
    else { analogWrite(enable, 0);}  
   Serial.print("DERECHA");  
   Serial.print ("currenpos ");  
   Serial.print(currenPosition);  
   Serial.print ("speed ");  
   Serial.print(speedVal);  
   Serial.print ("error ");  
   Serial.println(error);  
  }  
  if (state1 == 0 && state2 == 0) {  
   if ( currenPosition < setpointCenter ){  
     error = setpointCenter - currenPosition;  
     speedSetup();  
     analogWrite(enable, speedVal);  
     digitalWrite(der,HIGH);  
     digitalWrite(izq,LOW);  
     }  
   else if ( currenPosition > setpointCenter){  
     error = currenPosition - setpointCenter;  
     speedSetup();  
     analogWrite(enable, speedVal);  
     digitalWrite(izq,HIGH);  
     digitalWrite(der,LOW); }  
   digitalWrite(LED, HIGH);  
   Serial.print("DERECHA");  
   Serial.print ("currenpos ");  
   Serial.print(currenPosition);  
   Serial.print ("speed ");  
   Serial.print(speedVal);  
   Serial.print ("error ");  
   Serial.println(error);  
   delay(200);  
  }  
  else   
  {digitalWrite(LED, LOW);}  
  }  
 void speedSetup(){  
  float lastError = 0;  
  float sumError = 0;  
  speedVal = Kp*error;  
  speedVal += Kd*(error - lastError);  
  speedVal += Ki*sumError ;  
  lastError = error ;  
  sumError += error ;  
   if (speedVal > 255){  
    speedVal = 255; }  
   else if(speedVal < 40){  
    speedVal = 0;}   
 }  

Video del funcionamiento:





conclusiones y acciones correctivas:


  • El método PID es una excelente herramienta, algo complicada de realizar de manera manual, pero los resultados son asombrosos, utilizado ampliamente en diferentes proyectos de robotica como los quadcopters (para lograr equidad entre las velocidades de los rotores) péndulo invertido y robots auto-balanceantes. seguiré trabajando hasta mejorar la implementación.
  • una vez probado el funcionamiento del sistema, al querer aplicar el sistema inalámbrico y modificar el sketch, por algún error el motor siguió andando más allá del límite establecido quedando trabado al final del giro del potenciometro, quedando trabado y trayendo como consecuencia aumento del amperaje del motor y daño del integrado L293D. ya que no es la primera vez y me parecen muy susceptibles estos integrados, utilizare el L298n que soporte con 2A (hasta 3A en picos) por canal (4en total, 2 puentes H, osea 2 motores)
  • Me llama la atención el uso de Matlab para sacar las constantes, aunque ví el programa durante el curso de sistemas de control en la U, no fue el fuerte de nuestra institución y debo repasar su uso.  Ya tengo el ubicado el software, falta aprender a conectar el Arduino y estudiar el uso de simulink.
  • El Sketch que realice sigue mejorando ya es capaz de regresar a la posición cero de mi dirección quiero aumentar la precisión u sospecho de un pequeño error en el algoritmo.