miércoles, 30 de noviembre de 2016

Robot Velocista QTR8A (Parte III - Programacion del Robot)

Programación del Robot


Algoritmo PID

Este sera el encargado de regular el comportamienito del robot y corregir su marcha en el recorrido de la pista, recibe datos entrada (sensores) , las procesa, (PID) y envia la señal de correccion hacia los motores (salida de control) y nuevamente repite el proceso coparando la salida con la entrada (retroalimentacion) sin entrar en mas teoría se puede resumir de manera esquematica este controlador
  • Entrada de mando: Vendría a ser el punto de referencia en donde queremos fijar al robot "Set point", nuestro objetivo es que el robot no se salga de la linea, por lo tanto lo deseado es que siempre se mantenga centrado en el medio, como se vio anteriormente el centro de los sensores arrojaba un valor de posición relativa de 3500, este sera nuestra referencia o "set point" (donde queremos que el robot se mantenga siempre.
  • Controlador :  En este caso el controlador es el encargado de corregir y mantener en marcha al robot, su objetivo es que no se salga del punto de referencia o que almenos logre tenerlo dentro de los rangos permitidos. lo ideal es que mantenga al robot fijado en el centro, pero en la realidad ocurrirá que el mundo externo provoque muchas  perturbaciones haciendo que el robot oscile o se salga del punto de referencia por lo que tendrá que corregir continuamente la marcha. Si este controlador es el "PID"... Que para nuestro caso sera un algoritmo programado en arduino.
  • Planta: La planta esta relacionada con las condiciones físicas del robot, peso, longitud, traccion de los motores, velocidad, rozamiento, inercia, etc.  Como se ve el diagrama de bloques, el controlador modifica el comportamiento de la planta, osea el comportamiento del robot.
  • Salida o señal de control: Es la respuesta producida por el control aplicado en el robot, en este caso la salida  de control se envia al driver de motor y luego a los motores para que puedan corregir la marcha constantemente. la medición de esta salida es jutamente la señal es la posicion actual del robot medido .
  • Realimentacion: Esta compuesta de la adquisición de datos, osea la de los sensores del robot, que va leer la posición relativa actual del robot la procesa y manda nuevamente a comparararse con la referencia que es el "set point"  , esta comparación traerá un resultado llamado error que nuevamente es entregado al controlador para que pueda procesarla y enviar una señal de correccion, la realimentacion es la comparación de la salida con respecto a la entrada, 
Todo esto en gran parte sera el algoritmo de control del robot: Se que es muy abstracto todo lo que concierne con PID, pero con la practica algunos de estos conceptos estaran claros.

En este post ya tramos acerca de cada una de las acciones del PID,  de las constantes y el procedimiento para sintonizar, por lo que ya no seré tan redundante explicando nuevamente. : http://aprendiendofacilelectronica.blogspot.pe/2014/12/robot-velocista-de-competencia_4.html


Circuito del Robot Velocista


Programa Completo

/////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////

#include <QTRSensors.h>

  //entradas
#define btn1      0
#define btn2      1
  //salidas
#define led1      13

#define led_on    9   //~
#define mi1       3
#define mi2       4
#define pwmi      6   //~
#define md1       8
#define md2       7
#define pwmd      5   //~
  

#define NUM_SENSORS             8  // number of sensors used
#define NUM_SAMPLES_PER_SENSOR  1 // average 4 analog samples per sensor reading
#define EMITTER_PIN             9   // emitter is controlled by digital pin 2

QTRSensorsAnalog qtra((unsigned char[]) {7, 6, 5, 4, 3, 2,1,0},NUM_SENSORS, NUM_SAMPLES_PER_SENSOR, EMITTER_PIN);
unsigned int sensorValues[NUM_SENSORS];
int proporcional=0;
int derivativo=0;
int integral=0;
int salida_pwm=0;
int proporcional_pasado=0;
int position=0;

////////////////////Parametros PID/////////////////////////////////
int velocidad=120;
//float KP=0.15, KD=2.2, KI=0.006; //reaccion rapida
float KP=0.01, KD=0.15 , KI=0.0001; //reaccion rapida
///////////////////////////////////////////////////////

/////////////////parametros de sensado/////////////////////////////
int linea=0; //0 linea negra, 1 para linea blanca
int flanco_color=  0 ;
int en_linea=  500 ;
int ruido= 30;
/////////////////////////////////////////////////////////
int boton1=7;
int boton2=7;

void setup()
{
    pinMode(led1,OUTPUT);
    pinMode(led_on,OUTPUT);
    pinMode(mi1,OUTPUT);
    pinMode(mi2,OUTPUT);
    pinMode(pwmi,OUTPUT);
    pinMode(md1,OUTPUT);
    pinMode(md2,OUTPUT);
    pinMode(pwmd,OUTPUT);

digitalWrite(led1,HIGH);
delay(200);
digitalWrite(led1,LOW);
delay(200);

digitalWrite(led1, HIGH);    // turn on Arduino's LED to indicate we are in calibration mode
  for (int i = 0; i < 200; i++)  // make the calibration take about 10 seconds
  {
    qtra.calibrate();       // reads all sensors 10 times at 2.5 ms per six sensors (i.e. ~25 ms per call)
  }
  digitalWrite(led1, LOW);     // turn off Arduino's LED to indicate we are through with calibration
 //Serial.begin(115200);
   //Serial.println();

   while(true)
   {
      botones();
      if(boton2==0) 
      {
        delay(20);
        digitalWrite(led1,HIGH);
        delay(100);
        digitalWrite(led1,LOW);
        delay(100);
        break;
      }
   }
  
Serial.begin(115200);
//bt.println("Hello, world?");

}

void loop()
{
  pid(1,velocidad,KP,KI,KD);
  frenos_contorno(600);

 Serial.println(position);
 delay(2);
}

void pid(int linea, int velocidad, float Kp, float Ki, float Kd)
{
   
   position = qtra.readLine(sensorValues,QTR_EMITTERS_ON, linea, flanco_color, en_linea, ruido);
  //0 linea negra, 1 para linea blanca
  
      //  Serial.println(position);
  proporcional = (position) - 3500; // set point es 3500, asi obtenemos el error
  integral=integral + proporcional_pasado; //obteniendo integral
  derivativo = (proporcional - proporcional_pasado); //obteniedo el derivativo
  int ITerm=integral*KI;
  if(ITerm>=255) ITerm=255;
  if(ITerm<=-255) ITerm=-255;
  
  salida_pwm =( proporcional * KP ) + ( derivativo * KD )+(ITerm);
  
  if (  salida_pwm >velocidad )  salida_pwm = velocidad; //limitamos la salida de pwm
  if ( salida_pwm  <-velocidad )  salida_pwm = -velocidad;
  
  if (salida_pwm < 0)
 {
    int der=velocidad-salida_pwm; //(+)
    int izq=velocidad+salida_pwm;  //(-)
    if(der>=255)der=255;
    if(izq<=0)izq=0;
    motores(izq, der);
 }
 if (salida_pwm >0)
 {
  int der=velocidad-salida_pwm; //(-)
  int izq=velocidad+salida_pwm; //(+)
  
  if(izq >= 255) izq=255;
  if(der <= 0) der=0;
  motores(izq ,der );
 }

 proporcional_pasado = proporcional;  
}


void frenos_contorno(int flanco_comparacion)
{
    if (position <=10) //si se salio por la parte derecha de la linea
    {
      while(true)
      { 
        digitalWrite(led1,HIGH);
        motores(-125,60);
        qtra.read(sensorValues); //lectura en bruto de sensor
        if ( sensorValues[0]<flanco_comparacion || sensorValues[1]<flanco_comparacion || sensorValues[2]<flanco_comparacion || sensorValues[3]<flanco_comparacion || sensorValues[4]<flanco_comparacion || sensorValues[5]<flanco_comparacion || sensorValues[6]<flanco_comparacion || sensorValues[7]<flanco_comparacion)
        {
          break;
        }
        
      }
    }

    if (position>=6990) //si se salio por la parte izquierda de la linea
    {
      while(true)
      {
        digitalWrite(led1,HIGH);
        motores(60,-125); 
        qtra.read(sensorValues);
        if (sensorValues[7]<flanco_comparacion || sensorValues[6]<flanco_comparacion|| sensorValues[5]<flanco_comparacion || sensorValues[4]<flanco_comparacion || sensorValues[3]<flanco_comparacion || sensorValues[2]<flanco_comparacion || sensorValues[1]<flanco_comparacion|| sensorValues[0]<flanco_comparacion)
        {
          break;
        }
      }
  }
  digitalWrite(led1,LOW);
}


void motores(int motor_izq, int motor_der)
{
  if ( motor_izq >= 0 )  
  {
    digitalWrite(mi1,LOW);
    digitalWrite(mi2,HIGH); 
    analogWrite(pwmi,motor_izq); 
  }
  else
  {
    digitalWrite(mi1,HIGH); 
    digitalWrite(mi2,LOW);
    motor_izq = motor_izq*(-1); 
    analogWrite(pwmi,motor_izq);
  }

  if ( motor_der >= 0 ) //motor derecho
  {
    digitalWrite(md1,LOW);
    digitalWrite(md2,HIGH);
    analogWrite(pwmd,motor_der);
  }
  else
  {
    digitalWrite(md1,HIGH);
    digitalWrite(md2,LOW);
    motor_der= motor_der*(-1);
    analogWrite(pwmd,motor_der);
  }
}

void botones()
{
    boton1=digitalRead(btn2);
    boton2=digitalRead(btn1); ///boton izquierdo, derecho
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Nota: este programa esta utilizando la libreria modificada de este post Modificacion de libreria QTR, si estas usando la libreria sin modificar, que de hecho no funcionara con este codigo tendrás que descargarlo desde este link: https://mega.nz/#!CkMkiZhA!FMK4eJQVmOGZK9GZzfqSKRgEPOijTSkMmbNDUwbf5C0 en instalarlo nuevamente. 

Instalacion de Libreria QTR SENSORS:


Esquematicos de FK-BOT:

Ya que me estuvieron pidiendo esquemáticos por mucho tiempo, pues aqui las libero.
 He pasado muy buenos días diseñando este robot, que fue considerado en su momento como el más rapido, ya ha pasado los años y cumplio su mision ...

La mejor forma de agradecerme es que le des clic a los anuncios de la parte superior del blog (cosa que no te costara nada hacerlo) , asi me ayudaras mucho! Saludos amigos robotero!!!  😊😎🙌



Cifrado: !tBRwDXi3MO-D9U3xMqgBTw

Driver Sparkfun-Compatible(rojo): https://mega.nz/#F!Ok1jULzb!DFAwhpyvyMLxdrc3C_xedw
Cifrado: !DFAwhpyvyMLxdrc3C_xedw


PRUEBAS FINALES: 





Post Anterior  << Manejando sensores QTR8A y Driver

martes, 29 de noviembre de 2016

Robot Velocista QTR8A (Parte II - Manejando Sensores y Motores)

 Manejando Sensores QTR8A


1. Manejando Sensor QTR8A con la libreria

Uso de librería Qtr8a en Arduino:


  • https://www.pololu.com/product/960/resources (mayor información)
  • Descargar la librería desde aquí : https://mega.nz/#F!78FVmD7Q!auGJgTr0Muo9qkNtl9CuLA
  • Una vez descargado instalar la librería de modo convencional en arduino: Copiar y pegar en la carpeta “librerías” de la carpeta donde esta instalado arduino.
  • Generalmente en esta dirección esta instalada C:\Program Files (x86)\Arduino\libraries
Descargar, descomprimir y copiar .

Ubicar la dirección donde se instalo arduino y buscar la carpeta libraries, y pergar la libreria QTRSensors.


La conexión sera la siguiente: 



  • La librería contiene un ejemplo básico de uso de los sensores
  • “QTRAExample”, abrirla y experimentar…


Configurando pines para uso de sensores Qtr8a :

Como estamos usando la regleta que trae 8 sensores, entonces debemos configurarlo para usar los 8 sensores, ya que por defecto esta configurado para usar 6, en esta imagen se muestra como configurarlo correctamente de acuerdo a las conexiones que se tienen en arduino de la imagen previa.


El código completo :
/////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <QTRSensors.h>

#define NUM_SENSORS             8  // number of sensors used
#define NUM_SAMPLES_PER_SENSOR  4  // average 4 analog samples per sensor reading
#define EMITTER_PIN             9  // emitter is controlled by digital pin 2

// sensors 0 through 5 are connected to analog inputs 0 through 5, respectively
QTRSensorsAnalog qtra((unsigned char[]) {7, 6, 5, 4, 3, 2, 1, 0}, 
  NUM_SENSORS, NUM_SAMPLES_PER_SENSOR, EMITTER_PIN);
unsigned int sensorValues[NUM_SENSORS];


void setup()
{
  delay(500);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);    // turn on Arduino's LED to indicate we are in calibration mode
  for (int i = 0; i < 400; i++)  // make the calibration take about 10 seconds
  {
    qtra.calibrate();       // reads all sensors 10 times at 2.5 ms per six sensors (i.e. ~25 ms per call)
  }
  digitalWrite(13, LOW);     // turn off Arduino's LED to indicate we are through with calibration

  // print the calibration minimum values measured when emitters were on
  Serial.begin(9600);
  for (int i = 0; i < NUM_SENSORS; i++)
  {
    Serial.print(qtra.calibratedMinimumOn[i]);
    Serial.print(' ');
  }
  Serial.println();
  
  // print the calibration maximum values measured when emitters were on
  for (int i = 0; i < NUM_SENSORS; i++)
  {
    Serial.print(qtra.calibratedMaximumOn[i]);
    Serial.print(' ');
  }
  Serial.println();
  Serial.println();
  delay(1000);
}


void loop()
{
  unsigned int position = qtra.readLine(sensorValues);
  
  // print the sensor values as numbers from 0 to 1000, where 0 means maximum reflectance and
  // 1000 means minimum reflectance, followed by the line position
  for (unsigned char i = 0; i < NUM_SENSORS; i++)
  {
    Serial.print(sensorValues[i]);
    Serial.print('\t');
  }
  //Serial.println(); // uncomment this line if you are using raw values
  Serial.println(position); // comment this line out if you are using raw values
  
  delay(50);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



Calibración

  • Previamente, para poder utilizar los sensores es necesario hacer una rutina de calibración, esto  durante algunos segundos. esto hace que la librería procese los datos de sensado, y muestre valores correctos.
  • En el proceso de calibración es necesario pasar repetidas veces los sensores sobre la línea negra y luego sobre la superficie blanca si levantar los sensores.
  • Se recomienda hacer la calibración de manera a una distancia constante sobre la superficie.
Lo que hace este código ejemplo es hacer uso de la librería QTRSensors ,se  obtienen los datos  de los sensores, que son las 8 primeras columnas. La 9na columna son los datos de posición relativa del sensor que vas desde 0 hasta 7000, en donde el centro se encuentra en 3500 a este valor le llamaremos set point. Este valore nos sera util para utilizar el algoritmo PID que controlara al Robot. Ademas se puede notar que cuando los sensores estan posicionados en la linea negra, los valores de sensado unitario incrementan alrededor de 800 a 1000 y cuando están sobre superficie blanca los valores son 0. Para visualizar estos datos se tiene que Abrir el monitor serie de Arduino.

 funciones de la librería Qtr8a

  • qtra.calibrate();  
                   Primera función a ser llamada, antes de usar los sensores, hace calibración de sensores                       (debe usarse un tiempo adecuado)
  • qtra.read(sensorValues);
                    Hace lectura de cada sensor y los guarda en matriz “sensorValues[ ];”
                    Rango de lectura de cada sensor : 0 a 1000.
  • int position = qtra.readLine(sensorValues);
                     Esta función devolverá la posición de sensores (necesario  PID)


2. Manejando Motores 

La conexión es la siguiente:

Ya hice un post para manejar este tipo de driver con arduino pueden verlo aca:  http://aprendiendofacilelectronica.blogspot.pe/2016/11/control-de-motores-dc-con-modulo-driver.html

Simplemente lo que haremos aca es utilizar otros pines con arduino  definiendolos nuevamente y listo, el programa de control de motores para el velocista  esta aqui:

///////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define mi1        3
#define mi2        4
#define pwmi       6
#define md1        8
#define md2        7
#define pwmd       5

void setup() 
{
  pinMode(mi1,OUTPUT);
  pinMode(mi2,OUTPUT);
  pinMode(md1,OUTPUT);
  pinMode(md2,OUTPUT);
}

void loop()
{
  motores(100,100);
}

void motores(int motor_izq, int motor_der)
{
  if( motor_izq >=0)
    {
      digitalWrite (mi1,HIGH);
      digitalWrite (mi2,LOW);
      analogWrite (pwmi,motor_izq);
    }
  else
    {
      digitalWrite(mi1,LOW);
      digitalWrite(mi2,HIGH);
      motor_izq = motor_izq*(-1);
      analogWrite(pwmi,motor_izq); 
    }
  if(motor_der>=0)
    {
      digitalWrite(md1,HIGH);
      digitalWrite(md2,LOW);
      analogWrite(pwmd,motor_der);
  }
  else
     {
      digitalWrite(md1,LOW);
      digitalWrite(md2,HIGH);
      motor_der=motor_der*(-1);
      analogWrite(pwmd,motor_der);    
     }
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////









Anterior post << Materiales
Siguiente post >> Programacion PID Robot

martes, 15 de noviembre de 2016

Sensor GP2Y0D340K y Arduino

Sensor GP2Y0D340K y Arduino

El sensor GP2Y0D340K o mas conocido como Sharp340k es un sensor de distancia IRED, que posee un procesador de señal integrado, lo cual facilita enormemente ya que a su salida dara un valor digital "0" o "LOW" si hay un obstáculo y "1" o "HIGH" si no encuentra obstáculo alguno. Su pequeño tamaño lo hace ideal para aplicaciones como detección de obstáculos, sensor de proximidad, y porsupuesto para aplicaciones de robotica, como los robots minisumos.
Estas son algunas de sus características a destacar:


  • Salida de tipo digital.
  • Distancia máxima de detección 40.00 cm.
  • Consumo tipico de 31 mA.
  • Velocidad de respuesta de 8 ms.
  • Tamaño  de 15 x 9.6 x 8.7 mm.
  • Voltaje de funcionamiento de 4.5 a 5.5V.
Esquema en Bloques:


Modo de Conexión:









Código Ejemplo:

Este ejemplo hace una lectura del pin donde esta el sensor y si detecta algo, imprimirá en pantalla y a la vez encenderá el led del pin 13.


#define sensor 9  // lectura en pin D9 
#define led    13 // D13

int lectura;
void setup() {
  pinMode(sensor, INPUT);
  pinMode(led,OUTPUT);
  Serial.begin(9600);
}
void loop() {
  lectura=digitalRead(sensor);
  if(lectura==0)
  {
    digitalWrite(led,HIGH);
    Serial.println("Obstaculo");
  }
  else{
    digitalWrite(led,LOW);
    Serial.println("No obstaculo");
  }




viernes, 4 de noviembre de 2016

Driver TB6612fNG y ARDUINO (Control de Motores DC + programa)

  Driver TB6612fNG y  ARDUINO

 (Pololu, Sparkfun Breakout)



El Modulo driver Tb6612fng cuenta con las siguientes características:

  • Puente H doble de tecnología LD MOS (2 canales para manejar 2 motores DC)
  • Voltaje máximo de entrada de hasta 15V.
  • Corriente de trabajo tipico de 1.2 A por canal y 3A pico por un lapso de 10 milisegundos
  • 2 entradas para PWM con una frecuencia máxima de hasta 100KHz
Estas características ademas de ser muy pequeño (2.0x2.0 cm como máximo ) y de ser altamente eficiente a comparación  al modulo L298N que esta basado en tecnologia bjt (no muy eficiente por lo que las baterías se agotan demasiado rapido), lo hacen un modulo driver muy versatil para distintos proyectos en donde se tenga hacer uso de motores DC, y en especial en robotica donde se le puede sacar bastante provecho usandolos con micromotores Pololu.

En este apartado explicare a como usarlos correctamente y conectarlos a la placa Arduino en donde describire  un codigo  que es altamente eficiente en el control de los motores (velocidad y dirección): Pero antes de ello tenemos que saber que en el mercado existen varios fabricantes de estos módulos usando el chip TB6612FNG y que sus patillajes no son necesariamente los mismos, por el contrario tienen diferente dispocicion de pines, pero el funcionamiento sigue siendo el mismo. Debemos verificar cual es el que vamos a usar, a continuación explico algunas características de estos:

TB6612FNG Pololu


Este modulo es fabricado por Pololu, cuenta con un transistor mosfet que evita que al conectar de manera inversa no se queme o que cuando reciba una corriente inversa  que puede ser muy perjudicial no lo dañe permanentemente. También cuenta con algunos condensadores filtros que atenúan el ruido producido por los motores DC. Tienen un tamaño de 1.5 x2.0 cm. 
Estos Módulos son generalmente un poco mas costosos que los que fabrica Sparkfun o compatibles. se conecta de esta Forma:


TB6612FNG Sparkfun Breakout y compatibles chinos

Estos módulos son fabricados por sparkfun y también por varios fabricantes chinos, No cuenta con un circuito proteccion de corriente inversa, por lo que se debe tener cuidado al conectar las polaridades de la batería de forma correcta (es recomendado poner un diodo en la alimentacion). Cuenta con  capacitores filtros que atenúan el ruido eléctrico producido por los motores.
Son mucho mas baratos  a comparación de los módulos de Pololu, varios fabricantes chinos lo comercializan a muy bajo costo por lo que si se te quema no te perjudicara económicamente. Tienen una medida de 2 . 0 x 2.0 cm. La forma de conectarlo correctamente es la Siguiente:


Código en Arduino Para manejar motores DC:

Este código Funciona de la siguiente manera: 
  • Podemos controlar velocidad y dirección de cada motor independiente del otro para esto creamos una función que recibe 2 parámetros numéricos el primero es para el motor izquierdo el segundo para el motor derecho : " void   motores(int izq , int der) "
  • Para controlar la velocidad solo basta variar el valor de los parámetros desde 0 a 255, que justamente es el pwm del arduino. Ejemplo motores(150,150);
  • Si queremos que gire en sentido inverso  los motores, pues simplemente colocamos un valor negativo desde -1 hasta -255,  la función se encargara de dar la dirección y velocidad. Ejemplo: motores(-150,-150);
  • Si queremos parar pues damos motores(0,0); 

//Se definen los pines a usar del arduino

#define pwm_i 9 //~
#define izq_1 4
#define izq_2 5

#define pwm_d 10 //~
#define der_1 6
#define der_2 7

void setup() {
  delay(1000);
pinMode(izq_1,OUTPUT);
pinMode(izq_2,OUTPUT);
pinMode(der_1,OUTPUT);
pinMode(der_2,OUTPUT);
}

void loop() {
  motores(150,150);
}

void motores(int izq, int der)
{
  if(izq>=0)
  {
    digitalWrite(izq_1,HIGH);
    digitalWrite(izq_2,LOW);
    analogWrite(pwm_i,izq);
  }
  if(izq<0)
  {
    digitalWrite(izq_1,LOW);
    digitalWrite(izq_2,HIGH);
    izq=izq*-1;
    analogWrite(pwm_i,izq);
  }

  if(der>=0)
  {
    digitalWrite(der_1,HIGH);
    digitalWrite(der_2,LOW);
    analogWrite(pwm_d,der);
  }
  if(der<0)
  {
    digitalWrite(der_1,LOW);
    digitalWrite(der_2,HIGH);
    der=der*-1;
    analogWrite(pwm_d,der);
  }
}