domingo, 19 de abril de 2015

MODIFICACION LIBRERIA "QTR SENSORS" PARA MEJOR SENSADO - Parte II

Modificacion de código del Robot Velocista (Mejorado para cualquier pista de competencia)



Para esta ocasión  vamos a modificar el algoritmo de un velocista para que funcione en cualquier linea, pista, terreno, etc.  Ya que hemos visto en el post anterior la utilizacion de la libreria que modifique para los sensores qtr y si  llegaron a probarlos, supongo que ya habrán sacado sus propias conclusiones acerca de como afectan los valores de los parámetros que agregue a la función. Entonces ahora si estamos listos para lo bueno!

En este post esplique el funcionamiento de un "algoritmo pid para un robot velocista", y ademas puese un ejemplo de la utilizacion del programa de un velocista de competencia:
Robot Velocista de competencia: Algoritmo Pid - Programacion Robot velocista

Con las modificaciones respectivas el velocista esta listo para competir en cualquier pista y ya nunca mas tendremos el problema de que no sense bien el robot, este codio es robusto  y  lo he probado con el robot en anbientes donde hay mucha luz de sol , y  el robot anda de maravilla, claro nunca esta de mas tratar de cubrir los sensores para que la interferencia de la luz no afecte.

El codigo final es este:


#include <QTRSensors.h>
/////////////////////////////////////////////////////////////////////////////////////
//*************  Programa realizado por MARKO A. CABALLERO MORENO***************   //
// Solo para fines educativos   //
//   robot velocista mini FK BOT  V 2.0                                            //
// micro motores pololu MP 10:1, sensores qtr 8rc, driver drv8833, arduino nano    //
//                                                      
// ACTUALIZADO 22/4/2015          //  
/////////////////////////////////////////////////////////////////////////////////////

#define NUM_SENSORS   8  //numero de sensores usados
#define TIMEOUT       2500  // tiempo de espera para dar resultado en uS
#define EMITTER_PIN   6    //pin led on
///////////////pines arduino a utilizar/////////////////////
#define led1          13 
#define led2          4  
#define mot_i         7
#define mot_d         8
#define sensores      6
#define boton_1       2  //pin para boton
#define pin_pwm_i     9
#define pin_pwm_d     10

QTRSensorsRC qtrrc((unsigned char[]) {19, 18, 17, 16,15,14,11,12}
,NUM_SENSORS, TIMEOUT, EMITTER_PIN);

//variables para almacenar valores de sensores y posicion
unsigned int sensorValues[NUM_SENSORS];
unsigned int position=0;

/// variables para el pid
int  derivativo=0, proporcional=0, integral=0; //parametros
int  salida_pwm=0, proporcional_pasado=0;


//_______AQUI CAMBIEREMOS LOS PARAMETROS DE NUESTRO ROBOT_________________
int velocidad=70; //variable para la velocidad, el maximo es 255
float Kp=0.18;
float Kd=2;
float Ki=0.01;  //constantes
//variables para el control del sensado
int linea=0;                //  0 para lineas negra, 1 para lineas blancas
int flanco_color =0;      // aumenta o disminuye el valor del sensado
int en_linea=500;         //valor al que considerara si el sensor esta en linea o no
int ruido=  50;          //valor al cual el valor del sensor es considerado como ruido
//________________________________________________________________________________

void setup()
{
  delay(800);
 pinMode(mot_i, OUTPUT);//pin de direccion motor izquierdo
 pinMode(mot_d, OUTPUT);//pin de direccion motor derecho
 pinMode(led1, OUTPUT); //led1
 pinMode(led2, OUTPUT); //led2
        pinMode(boton_1, INPUT); //boton 1 como pull up
        
        for (int i = 0; i < 50; i++)  //calibracion durante 2.5 segundos,
 {                                 //para calibrar es necesario colocar los sensores sobre la superficie negra y luego 
  digitalWrite(led1, HIGH);  //la blanca
                delay(20);
  qtrrc.calibrate();    //funcion para calibrar sensores   
  digitalWrite(led1, LOW);  
                delay(20);
 }
        digitalWrite(led1, LOW); //apagar sensores para indicar fin 
                                  //de calibracion 
        delay(400); 
        digitalWrite(led2,HIGH); //encender led 2 para indicar la
                                 // espera  de pulsacion de boton
       
        while(true)
        {
          int x=digitalRead(boton_1); //leemos y guardamos el valor
                                      // del boton en variable x
                                      delay(100);
          if(x==0) //si se presiona boton 
          {
             digitalWrite(led2,LOW); //indicamos que se presiono boton
             digitalWrite(led1,HIGH); //encendiendo led 1
             delay(100);
             break; //saltamos hacia el bucle principal
          }
        }
}       



void loop()
{

                    
  pid(linea, velocidad, Kp, Ki, Kd, flanco_color, en_linea, ruido); //funcion para algoritmo pid(modificado )
    //(tipo_linea,velocidad,kp,ki,kd,flanco_color,en_linea,ruido)

         
  frenos_contorno(linea,700); //funcion para frenado en curvas tipo 
                  //flanco de comparación va desde 0 hasta 1000 , esto para ver 
                 //si esta en negro o blanco
}


////////funciones para el control del robot////

//aqui esta modificado la funcion del pid para que reciba los nuevos parametros  para la libreria modificada
 void pid(int linea, int velocidad, float Kp, float Ki, float Kd,int flanco_color, int en_linea,int ruido)
{
  position = qtrrc.readLine(sensorValues, QTR_EMITTERS_ON, linea,flanco_color, en_linea, ruido ); //0 para linea 
                                                //negra, 1 para linea blanca
  proporcional = (position) - 3500; // set point es 3500, asi obtenemos el error
  integral=integral + proporcional_pasado; //obteniendo integral
  derivativo = (proporcional - proporcional_pasado); //obteniedo el derivativo
  if (integral>1000) integral=1000; //limitamos la integral para no causar problemas
  if (integral<-1000) integral=-1000;
  salida_pwm =( proporcional * Kp ) + ( derivativo * Kd )+(integral*Ki);
  
  if (  salida_pwm > velocidad )  salida_pwm = velocidad; //limitamos la salida de pwm
  if ( salida_pwm < -velocidad )  salida_pwm = -velocidad;
  
  if (salida_pwm < 0)
 {
  motores(velocidad+salida_pwm, velocidad);
 }
 if (salida_pwm >0)
 {
  motores(velocidad, velocidad-salida_pwm);
 }

 proporcional_pasado = proporcional;  
}

void motores(int motor_izq, int motor_der)
{
  
  if ( motor_izq >= 0 )  //motor izquierdo
 {
  digitalWrite(mot_i,HIGH); // con high avanza
  analogWrite(pin_pwm_i,255-motor_izq); //se controla de manera
                                                 //inversa para mayor control
 }
 else
 {
  digitalWrite(mot_i,LOW); //con low retrocede
  motor_izq = motor_izq*(-1); //cambio de signo
  analogWrite(pin_pwm_i,motor_izq); 
 }


  if ( motor_der >= 0 ) //motor derecho
 {
  digitalWrite(mot_d,HIGH);
  analogWrite(pin_pwm_d,255-motor_der);
 }
 else
 {
  digitalWrite(mot_d,LOW);
  motor_der= motor_der*(-1);
  analogWrite(pin_pwm_d,motor_der);
 }

  
}

void frenos_contorno(int tipo,int flanco_comparacion)
{
  
if(tipo==0)
{
  if (position<=500) //si se salio por la parte derecha de la linea
 {
  motores(-80,90); //debido a la inercia, el motor 
                                  //tendera a seguri girando
                                  //por eso le damos para atras , para que frene
                                 // lo mas rapido posible 
  while(true)  
  {
   qtrrc.read(sensorValues); //lectura en bruto de sensor   
if ( sensorValues[0]>flanco_comparacion || sensorValues[1]>flanco_comparacion ) 
//asegurar que esta en linea
   {
    break;
   } 
  }
 }

 if (position>=6500) //si se salio por la parte izquierda de la linea
 { 
  motores(90,-80);
  while(true)
  {
   qtrrc.read(sensorValues);
if (sensorValues[7]>flanco_comparacion || sensorValues[6]>flanco_comparacion )
   {
    break;
   }  
  }
 }
}

//*******
if(tipo==1) //para linea blanca con fondo negro
{
  if (position<=500) //si se salio por la parte derecha de la linea
 {
  motores(-80,90); //debido a la inercia, el motor 
                                  //tendera a seguri girando
                                  //por eso le damos para atras , 
                                  //para que frene lo mas rapido posible 
  while(true)  
  {
   qtrrc.read(sensorValues); //lectura en bruto de sensor
if ( sensorValues[0]<flanco_comparacion || sensorValues[1]<flanco_comparacion )
//asegurar que esta en linea
   {
    break;
   }
   
  }
 }

 if (position>=6500) //si se salio por la parte izquierda de la linea
 { 
  motores(90,-80);
  while(true)
  {
   qtrrc.read(sensorValues);
  if (sensorValues[7]<flanco_comparacion || sensorValues[6]<flanco_comparacion)
   {
    break;
   }  
  }
 }
}

}



viernes, 3 de abril de 2015

MODIFICACION LIBRERIA "QTR SENSORS" PARA MEJOR SENSADO - Parte I

Modificacion de librería"QTR SENSORS" para un mejor sensado

En este post  voy a presentar algunas de las modificaciones que hice al a librería "QTRSensors" para  el uso con los sensores "qtr 8rc" y "qtr 8a"  para lecturas en  linea blanca. 


En la libreria  QTRSensors se tiene la opcion de cambiar el tipo de linea que queramos sensar, cambiando desde la funcion de lectura de linea o mejor dicho:
qtrrc.readLine(sensorValues, QTR_EMITTERS_ON, 0);

En las indicaciones nos dice que si queremos sensar lineas blancas, entonces debemos colocar en el ultimo parámetro de la funcion un "1" en ves del 0 que esta por defecto para las  lineas negras. 

Hasta aqui todo esta bien, pues solo hay que cambiar un parametro y listo, deberia funcionar bien para lineas blancas. Pero aqui viene  lo  frustrante del caso, o almenos ocurrió en el mio:

Yo utilizaba los sensores "qtr-8rc" en un robot velocista que debia competir para  una pista  que estaba impresa  en un baner que tenia lineas blancas y el fondo era negro, y me di con la sorpresa que el robot no seguía las lineas. tras varios test que hacia al robot y cuestionamientos, chekar infinidad de veces la programación , no llegaba a ver cual era la razón por la que no funcionaba bien el robot. 
Me puse  a indagar en internet y foros acerca del tema pero, nadie daba con la respuesta, Asi que me llene de valor y  decidí a  resolver este misterio.  Busque los datasheets de cada componente, estudie  a profundidad el esquema electronico del arreglo de los sensores, y no encontre  nada de malo, por lo que la unica solucion podria hallarse en el algoritmo de sensado de la libreria, asique no me quedo de otra que tratar de entender a la libria QTRsensors  para buscar la solucion.
Pues, asi fue, le dedique su  tiempo a eso y logre entender el funcionamiento de la libreria y puedo decir  que encontre la solucion :D.  Ahora les explicare:


MODIFICACION DE LA FUNCION DE LECTURA DE LINEA
Puedes descargar la libreria modificada:" https://mega.nz/#!CkMkiZhA!FMK4eJQVmOGZK9GZzfqSKRgEPOijTSkMmbNDUwbf5C0"

La instalacion es como cualquier otra libreria convencional de arduino, por lo que eso pasos los ignorare, o sino puedes guiarte del post donde hablo de eso : Utilizando la libreria QTR SENSORS


Como veran ahora en la modificacion que hice aparecen  3 nuevos parámetros: flanco_color, en_linea, ruido.

         qtrrc.readLine(sensorValues, QTR_EMITTERS_ON, 1, flanco_color, en_linea, ruido);

flanco_color: Este parametro sirve para aumentar  o disminuir valores de lectura. Como sabemos cada  sensor lee valores desde 0 ( mínima reflactancia) hasta 1000 (maxima reflactancia). pero    segun los testeos que hice, no se llega a obtener un valor adecuado, por eso  cree una variable que aumentara o disminuyera esos valores forzosamente para asi obtener valores decentes que sean medibles. el valor por defecto es 0

en_linea: Con este parámetro podemos variar la forma en que la libreria  tomara los valores de los sensores y los considerara "si esta o no en una linea", luego la libreria tomara los valores de cada sensor y los  promediara para asi obtener un valor de posicion con respecto a esa linea. su valor por defecto es de 200.

ruido: Con este parametro se podra variar  desde que valores  de reflactancia es  considerados como ruido, el valor por defecto es de 50.


EN ACCION!

Unos valores que probe en linea blanca  que funcionan, y podria decir que hasta mejor que antes,  son estos :

             position = qtrrc.readLine(sensorValues,QTR_EMITTERS_ON, 1 , 0 , 400 , 30);
             position = qtrrc.readLine(sensorValues,QTR_EMITTERS_ON, 1 , 500 , 400 , 50);
             position = qtrrc.readLine(sensorValues,QTR_EMITTERS_ON, 1 , 500 , 500 , 50);
             position = qtrrc.readLine(sensorValues,QTR_EMITTERS_ON, 1 , 300 , 500 , 100);

Valores para linea negra:
 position = qtrrc.readLine(sensorValues,QTR_EMITTERS_ON, 0 , 0 , 400 , 30);
position = qtrrc.readLine(sensorValues,QTR_EMITTERS_ON, 0 , 0 , 300 , 50);
position = qtrrc.readLine(sensorValues,QTR_EMITTERS_ON, 0 , -200 , 200 , 100);

pueden  probar con estos  valores, y  ver que tal les va. Cada valor dependera del tipo de superficie, por lo que los resultados variaran, asi que si no te resulta estos valores trata de buscar tus valores adecuados testeando los con el ejemplo y te sacas la duda de como funcionan en verdad cada paramtro ;) :

Nota: esta modificacion es valida tambien para sensores QTRA (todavia no he  probado en estos sensores , pero en teoria deberian funcionar, si lo pruban porfavor aganmelo saber si les funciono o no  para seguir mejorandolo :D). Si lo quieres utilizar para estos sensores solo debes  escoger el ejemplo que dice QTRAExample y cambia lo mismo como lo indicado arriba.