"AÑO DE LA UNIVERSALIZACIÓN DE LA
SALUD"
UNIVERSIDAD NACIONAL DE PIURA
FACULTAD DE CIENCIAS
INGENIERIA ELECTRONICA Y TELECOMUNICACIONES
ESCUELA :
ING. ELECTRÓNICA Y
TELECOMUNICACIONES
CURSO :
MICROCONTROLADORES II
PROYECTO :
ROBOT VELOCISTA
PROFESOR :
ING. PERCY CASAS
ALUMNOS :
PRIETO PACHERRES MIRTHA
LUCERO
PALACIOS ÑAUPA DANIEL
GARCIA GUERRERO JOSE
VIERA NAVARRO EINER
INTRODUCCIÓN
Tanto a nivel nacional como a nivel internacional existe una gran cantidad de
competiciones en las que el objetivo principal es que uno o varios robots
autónomos realicen una determinada tarea tratando de conseguir un mejor
resultado en términos de tiempo u objetivos alcanzados que el resto de
participantes, o enfrentándose literalmente a ellos.
La mayoría de estas competiciones están destinadas a estudiantes
(principalmente de ingeniería, pero cada vez más también a alumnos más
jóvenes en institutos) y tienen asociada una finalidad educativa importante ya
que implican una aplicación práctica de los conocimientos adquiridos en
materias como electrónica, robótica, regulación automática y programación.
Además, permiten desarrollar capacidades de trabajo en equipo y plantean un
reto importante al enfrentar a los participantes a problemas reales que han de
resolver de manera ingenieril.
ROBOT VELOCISTA
La competición de velocistas guarda bastante relación con la de los seguidores
de línea puesto que también se trata de seguir un circuito marcado con líneas
negras sobre un fondo blanco, pero mientras a los robots rastreadores se les
exige que sean capaces de seguir un camino complicado, lleno de curvas y
bifurcaciones, lo que se espera de los robots velocistas es que, como su propio
nombre indica, sean capaces de desarrollar altas velocidades sobre el circuito.
Siguiendo esta filosofía la forma de los circuitos es mucho más sencilla,
reduciéndose en algunos casos a un simple ovalo.
Generalmente las eliminatorias de robots velocistas se corren uno contra uno.
Lo habitual es que primero se realice una clasificatoria por tiempos para, a
continuación, ir eliminando participantes por eliminatorias en las que un robot se
medirá a otro. Estas carreras se realizan haciendo salir a cada robot desde
puntos opuestos del circuito, terminando la misma cuando uno de ellos alcance
al otro o tras un número determinado de vueltas, ganando el robot que haya
sido capaz de acercarse más a su contrincante.
MATERIALES USADOS
a) SENSORES QTR 8RC
Básicamente estos sensores utilizan pines digitales, también se pueden utilizar
en pines analógicos, pero previamente configurados como digitales. Es por ello
que estos sensores son muy versátiles y tienen mayor distancia de sensado a
comparación de los analógicos. La forma de funcionamiento de estos sensores
es a base de la carga y descarga de los condensadores que está en serie con
los fototransistores, cuando este en una superficie blanca el capacitor tendera a
no retener carga por lo tanto la salida será de 0 volts, pero, por el contrario, si
se encuentra en una superficie oscura, el foto-transistor no se saturará, de esta
forma el capacitor retendrá carga, produciendo un voltaje positivo. Previamente
se tiene que configurar los pines como salida, mandando un pulso de unos
cuantos microsegundos, luego configurando como entrada los pines haciendo
una lectura; esto continuamente en un bucle.
Es así como se puede saber si se está en blanco o negro. Pero estos sensores
ya cuentan con una librería en arduino que hace todo este procedimiento de
forma automática, solo tendremos que declarar los pines que utilizaremos y
haremos los llamados a las respectivas funciones de calibrados, funciones de
lectura de sensores y lecturas de posición, que es justamente la que
utilizaremos para el robot velocista.
b) Arduino Nano
En teoría se puede utilizar cualquier arduino, pero lo recomendable para un
robot velocista (que por lo general son muy livianos) es utilizar un arduino nano
o mini pro. Nosotros utilizamos el arduino nano ya que nos permitía cargar el
programa directamente desde el USB.
Utilizamos los pines analógicos del arduino para las lecturas de los sensores, ya
que estos no cuentan con módulos extras como el que traen los pines digitales
que son, PWM, de interrupción, de comunicación serial, etc.
c) MOTOR POLOLUO
Este es elemento principal y crítico que determinará las características del robot
velocista, ya que básicamente dependerá de qué tipo de reducción, consumo y
torque que poseerá. Por lo general se utilizan los " high power" o "HP" con
reducciones de 10:1 y 30:1. La reducción es el tipo de engranaje que poseerá el
motor para reducir la velocidad del motor, y convertirla en torque, o lo
vulgarmente decimos "fuerza" es decir, un motor de reducción 10:1 utilizara
engranajes que reducirán 10 vueltas del motor en un 1 produciendo un torque
relativamente mayor, por ejemplo: un motor de reducción 10:1
tendrá mucha más velocidad que un motor 30:1, pero este poseerá menor
torque que el motor 30:1.
Dado que nuestro robot que salió un poco pesado, utilizamos los motores 30:1.
d) Driver del Motor
Para el driver de nuestros motores, usamos un circuito L293D. El L293D es un
controlador de motor típico o conductor del motor de IC que se utiliza para
conducir DC en cualquier dirección. Posee 16 pines que puede controlar un
conjunto de dos motores de corriente continua de forma simultánea en
cualquier dirección.
Este circuito se basa en el concepto de puente en H. El puente H es un circuito
que permite que la alta tensión se recorra en cualquier dirección.
En un solo integrado L293D hay dos circuitos puente H dentro de la misma que
puede girar dos motores de corriente continua de forma independiente.
Los motores se hacen girar sobre la base de las entradas las cuales pueden
ser de entrada como 1 o 0 lógico.
e) LLANTAS RW2
Estas llantitas se acoplan bien a los micro motores utilizado para este proyecto
f) Baterías
g) Capacitores
Uno de estos factores que puede afectar a nuestro robot es el ruido eléctrico.
Este es el principal factor que afecta a la mayoría de artefactos electrónicos en
especial a los microcontroladores, y arduino no se salva de esto. El ruido
eléctrico es generalmente inducido por los motores, haciendo que haya un mal
funcionamiento del microcontrolador (reinicios, hace cosas extrañas, apagado
intempestivo, y en el peor de los casos quemado del chip).
Para evitar el ruido eléctrico, utilizamos dos condensadores cerámicos 104 (0.01
uf).
PROGRAMACION
#include <QTRSensors.h> // es siempre necesario la inclusión de la librería de
los qtr8rc
Lo primero que hay que reconocer son los define:
#define NUM_SENSORS 8 // aquí definimos cuantos sensores estamos
utilizando, en este caso 8
#define TIMEOUT 2500 //este será el tiempo que esperaremos para que se
de los resultados de lectura de los sensores.
El tiempo optimo esta entre los 1500 us a 2500 us.
#define EMITTER_PIN 2 // este es el pin del "led ON" es necesario
especificar en qué pin se utilizará
Se utilizará en este caso, el 2
*Objeto para sensor QTR 8RC:
Aquí van los pines a utilizar para las lecturas
QTRSensorsRC qtrrc((unsigned char[]) {3, 4, 5, 6, 7, 8,
9, 10}, NUM_SENSORS, TIMEOUT, EMITTER_PIN);
Lo que hay que especificar aquí son los pines de lectura que utilizaremos del
arduino para cada sensor, se pueden utilizar pines del 0 hasta el 19(del 14 al
19 son los analógicos q
los podemos también utilizar como digitales). Para el caso de utilizar los pines
analógicos comenzaría desde el 14 hasta el 19.
unsigned int sensorValues[NUM_SENSORS]; // es necesario la creación de un
array, esto para la almacenarían de los valores de reluctancia de los
sensores
Funciones Importantes:
qtrrc.calibrate();
Calibración de sensores es necesario antes de utilizar los sensores, esta función
no devuelve valor alguno
qtrrc.readLine(sensorValues, QTR_EMITTERS_ON, 0);
Realiza la lectura de los sensores, y devuelve el valor de posición estimada de
los sensores, la estimación se hace con un promedio ponderado de cada
sensor. El tercer parámetro es para indicar si se requiere leer una superficie
blanca con una línea negra, este valor será de "0". Si se quiere leer una
superficie negra con una línea blanca, se tiene que cambiar el valor a "1".
qtrrc.read(sensorValues);
Realiza lecturas en bruto de cada sensor, para obtener estos valores es
necesario leer el índice de array donde se guarda los valores de cada sensor.
Por ejemplo, si queremos saber el valor de reflactancia que tiene el sensor
numero 1 tenemos que crear una variable y asignar el valor del array que
contiene el valor del sensor:
int sensor_1=sensorValues[0];
PROGAMACIÓN DE NUESTRO ARDUINO
El PID (control proporcional, integral y derivativo) es un mecanismo de control
por realimentación que calcula la desviación o error entre un valor medido y el
valor que se quiere obtener (set point, target position o punto de consigna),
para aplicar una acción correctora que ajuste el proceso.
En el caso del robot velocista, el controlador PID, (que es una rutina basada
matemáticamente), procesara los datos del sensor, y lo utiliza para controlar la
dirección (velocidad de cada motor), para de esta forma mantenerlo en curso.
Error: Llamamos a la diferencia entre la posición objetivo y la posición medida
del error. (que tan lejos del punto de consigna se encuentra el sensor, en
nuestro caso el objetivo es tener los sensores centrados)
Target Position: Cuando el error es 0 (cero). En el caso del robot velocista, la
idea es siempre mantenerlo en la línea, o lo que es el caso de los sensores,
mantenerlo centrado y así no se llegue a salir de la línea
PARAMETROS:
Proporcional: Es la respuesta al error que se tiene que entregar de manera
inmediata, es decir, si nos encontramos en el centro de la línea, los motores,
tendrán en respuesta una velocidad de igual valor, si nos alejamos del
centro, uno de los motores reducirá su velocidad y el otro aumentara.
Proporcional=(posición) - punto_consigna
Integral: La integral es la sumatoria de los errores acumulados, tiene como
propósito el disminuir y eliminar el error en estado estacionario provocado
por el modo proporcional, en otras palabras, si el robot velocista se
encuentra mucho tiempo alejado del centro (ocurre muchas veces cuando
se encuentra en curvas), la acción integral se ira acumulando e ira
disminuyendo el error hasta llegar al punto de consigna
Integral=Integral + proporcional_pasado
Derivativo: Es la derivada del error, su función es mantener el error al
mínimo, corrigiéndolo proporcionalmente con la misma velocidad que se
produce, de esta manera evita que el error se incremente, en otra palabra,
anticipara la acción evitando así las oscilaciones excesivas.
Derivativo=proporcional-proporcional_pasado
CONSTANTES
Factor (Kp): Es un valor constante utilizado para aumentar o reducir el
impacto de Proporcional. Si el valor es excesivo, el robot tendera responder
inestablemente, oscilando excesivamente. Si el valor es muy pequeño, el
robot responderá muy lentamente, tendiendo a salirse de las curvas
Factor (Ki): Es un valor constante utilizado para aumentar o reducir el
impacto de la Integral, El valor excesivo de este provocara oscilaciones
excesivas, Un valor demasiado bajo no causara impacto alguno.
Factor (Kd): Es un valor constante utilizado para aumentar o reducir el
impacto de la Derivada. Un valor excesivo provocara una sobre
amortiguación. provocando inestabilidad.
Salida_pwm = (proporcional * Kp) + (derivativo * Kd) + (integral*Ki);
PROGRAMACIÓN DEL VELOCISTA
#include <QTRSensors.h>
#define NUM_SENSORS 8 //numero de sensores usados
#define TIMEOUT 2000 // 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;
// PARAMETROS DE NUESTRO ROBOT
int velocidad=120; //variable para la velocidad, el maximo es 255 float Kp=0.18, Kd=100,
Ki=100; //constantes
//variable para escoger el tipo de linea
int linea=0; // 0 para lineas negra, 1 para lineas blancas
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 < 40; 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(0, 120, 0.18, 4, 0.001);
pid(linea,velocidad,Kp,Ki,Kd); //funcion para algoritmo pid
//(tipo,flanco de comparacion)
//frenos_contorno(0,700);
frenos_contorno(linea,700); //funcion para frenado en curvas tipo
//0 para lineas negras, tipo 1 para lineas blancas
//flanco de comparación va desde 0 hasta 1000 , esto para ver
//si está en negro o blanco
}
////////funciones para el control del robot////
void pid(int linea, int velocidad, float Kp, float Ki, float Kd)
{
position = qtrrc.readLine(sensorValues, QTR_EMITTERS_ON, linea); //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; //limitar la integral ( evitar errores)
if (integral<-1000) integral=-1000;
salida_pwm =( proporcional * Kp ) + ( derivativo * Kd )+(integral*Ki);
if ( salida_pwm > velocidad ) salida_pwm = velocidad; //limitar 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;
}
}
}
}