MANUAL PROGRAMACIÓN v 4.0
01/2012
3.- Sensores QTR-RC de Pololu. 3.1.- SU FUNCIONAMIENTO
Los sensores de reflexión IR, son dispositivos electrónicos que incorporan un emisor de IR y un fototransistor en el mismo encapsulado. Al encontrarse el emisor y el receptor en el mismo plano su funcionamiento consiste en la emisión de luz infrarroja mediante el diodo emisor y la detección por parte del fototransistor de la parte de la luz IR que es reflejada en una superficie. El circuito que utilizamos para el control del sensor IR es el de la figura, donde el colector del elemento fototransistor del circuito integrado U4 es conectado a través de un condensador de 10 nF al positivo Vcc y mediante una R de 220Ω a un pin de ARDUINO, colocando el emisor a masa. Por otro lado el diodo emisor de IR es polarizado en directa mediante una R 220Ω.
El circuito basa su funcionamiento en las tensiones umbrales de los diferentes estados a la entrada digital de un puerto, dependiendo del nivel de tensión que tengamos en una entrada, se considerará un ‘1’ o un ‘0’ lógico. En la tabla de las características eléctricas del AVR podemos encontrar estos valores VILmin ,VILmax , VIHmin y VIHmax. Si partimos del instante t0 en el que el condensador C1 se encuentra cargado, tendremos un nivel H en la entrada del AVR
21
MANUAL PROGRAMACIÓN v 4.0
01/2012
Transcurrido un tiempo t1, el condensador se irá descargado a través del transistor hasta alcanzar la tensión en el colector el valor de VILmax. Al alcanzar la entrada del AVR ese valor, hará que pase a considerarse un nivel L. El tiempo que tarde en alcanzarse esa tensión en el colector del transistor, dependerá de lo rápido que se descargue el condensador a través del transistor. Podemos decir que el transistor regula el tiempo de descarga del condensador. Para hacer más o menos conductor al transistor debemos aplicarle más radiación IR a la base o menos. Para aplicarle más o menor radiación IR a la base, al tratarse de un dispositivo que detecta la radiación reflejada en una superficie, deberemos hacer que esa superficie sea más o menos reflectante, es decir, más oscura o clara (NEGRO, BLANCO). Tiempos cortos de descarga implicaría superficies reflectantes claras, tiempos largos de descarga implicaría superficies oscuras.
Para que el circuito funcione, el condensador debe ser cargado inicialmente desde el pin del puerto del microcontrolador al que está conectado, esto obliga al programador a configurar el pin del puerto como salida y sacar un estado alto H por ese pin, un tiempo determinado, de ese modo el condensador C se cargará. Ese tiempo es 5RC, es decir aproximadamente: 5RC= 5*220 *10*10-9 = 11 µs. Esta carga la mantendrá de forma temporal. Si ahora configuramos el pin del puerto como entrada, el AVR leerá un estado H mientras la tensión en el colector del transistor esté por encima de VLmax, cuando la tensión en el colector disminuya por debajo de VLmax, pasará a leer un nivel bajo L. El tiempo que tarde el condensador en descargarse dependerá de la corriente de base, es decir, de la cantidad de radiación infrarroja (IR) que llegue a la base del fototransistor. Si la reflexión se produce sobre blanco será muy corto (imagen derecha) y si se produce sobre una superficie negra (imagen izquierda) tardará más tiempo en descargarse el condensador.
22
MANUAL PROGRAMACIÓN v 4.0
01/2012
En la imagen del osciloscopio, se observa que el voltaje del condensador (trazo amarillo) en el colector de transistor y el valor considerado a la entrada del pin del puerto (trazo azul). La cantidad de corriente que fluye a través del fototransistor depende del nivel de luz reflejada, de modo que cuando el robot está en una superficie blanca brillante, el valor 0 se devuelve con mucha más rapidez que cuando está sobre una superficie de color negro.
3.2.- SU PROGRAMACIÓN Una vez conocido el comportamiento del circuito y sabiendo que el robot incorpora 6 circuitos como estos conectados a los pines 2,4,3,7,8 y 11 de ARDUINO, podemos traducir en seudocódigo la tarea que debe realizar nuestra función para leer el estado en el que se encuentran los 6 sensores de reflexión IR. .
.- 1º LAS LINEAS DE E/S (pines 2,4,3,7,8 y 11)PROGRAMADAS COMO SALIDA .- 2º Colocar a 1 las salidas pines 2,4,3,7,8 y 11. .- 3º Cargar los C durante 25 µs para cuando C= .- 4º Desactivar r de pull-up del pin y .- 5º colocar las líneas como entrada .- 6º Esperar a leer un 0. No nos asustemos, no necesitamos crear las funciones para calibrar y leer los sensores. Utilizaremos la librería que ha desarrollado Pololu para su manejo en ARDUINO. En el siguiente enlace encontraremos la información de cómo instalarla y en este otro enlace cómo utilizarla. En ambos enlaces y en un perfecto inglés, nos explica todo lo que necesitamos saber para usar el array de sensores en ARDUINO. Para facilitaros de comprender cómo debemos instalar y usar la librería aquí os dejo una rápida traducción del contenido de los enlaces anteriores: 3.2.1 INSTALACIÓN DE LA LIBRERÍA Descargar el archivo de GitHub, descomprimirlo, y copiar la carpeta "QTRSensors" en el directorio arduino-1.0/libraries.
23
MANUAL PROGRAMACIÓN v 4.0
01/2012
Ahora deberemos ser capaces de utilizar las librerías en nuestros programas, para ello seleccionaremos Sketch> Import Library> QTRSensors del entorno de programación de la placa de Arduino IDE (o simplemente escribir # include en la parte superior de nuestro programa). Tener en cuenta que es posible que tengamos que reiniciar el Arduino IDE para poder ver la librería recién instalada. Una vez hecho esto, ya podemos crear un objeto para nuestro sensor QTR-RC: // create an object for three QTR-xA sensors on analog inputs 0, 2, and 6 QTRSensorsAnalog qtra((unsigned char[]) {0, 2, 6}, 3); // create an object for four QTR-xRC sensors on digital pins 0 and 9, and on analog // inputs 1 and 3 (which are being used as digital inputs 15 and 17 in this case) QTRSensorsRC qtrrc((unsigned char[]) {0, 9, 15, 17}, 4);
Esta librería sirve tanto para los sensores analógicos QTR-xA, como para los digitales QTR-XRC, proporcionando una interfaz común para ambos sensores. La única diferencia externa está en los constructores, como se puede ver en el ejemplo de código anterior. El primer argumento para el constructor QTRSensorsAnalog es una matriz de pines de entrada analógica (0 - 7), mientras que el primer argumento del constructor de QTRSensorsRC es una matriz de pines digitales (0 - 19). Nótese que las entradas analógicas 0 a 5 se puede utilizar como pines digitales 14 - 19. La otra diferencia está en el tiempo que tarda en leer los valores de los sensores. Los sensores de QTR-XRC se pueden leer en paralelo, cada uno requiere un tiempo de hasta 3 ms. Los sensores QTR-XA utilizar el convertidor analógico-digital (ADC) y por lo tanto deben ser leídos secuencialmente. Dos ejemplos de utilización están a nuestra disposición, uno para los sensores analógicos QTR-XA y otro para los digitales QTR-XRC. Para ver estos ejemplos, abrir el IDE de Arduino e ir a: Archivo> Ejemplos> QTRSensors y seleccione QTRAExample o QTRRCExample. 3.2.1 GUIA DE REFERENCIA DE LOS COMANDOS Para los sensores analógicos QTR-XA, crearemos una instancia de un objeto QTRSensorsAnalog, y para los digitales QTR-XRC una instancia de un objeto QTRSensorsRC. Además de los constructores, estos dos objetos proporcionan los mismos métodos para la lectura de los valores de los sensores. La librería permite el acceso tanto a los valores de los sensores en bruto, como a las funciones de alto nivel, incluyendo la calibración y el rastreo de la línea. La biblioteca define un objeto para cada uno de los dos tipos de sensores QTR, la clase QTRSensorsAnalog a de ser utilizada con QTR-XA y la clase QTRSensorsRC a de ser utilizada con QTR-XRC. Esta biblioteca se ocupa de las diferencias internas entre los sensores QTR-xA y QTR-XRC, proporcionando una interfaz común para ambos sensores. La única diferencia externa es en los constructores. Deberemos crear una instancia QTRSensorsAnalog o QTRSensorsRC, antes de poder utilizar los sensores. Esto nos permite controlar varios array de sensores de forma independiente como objetos separados QTRSensors. Internamente, esta biblioteca utiliza todas las funciones estándar de Arduino como micros () para la sincronización y analogRead () o digitalRead () para obtener los valores de los
24
MANUAL PROGRAMACIÓN v 4.0
01/2012
sensores, por lo que debería funcionar en todos los Arduinos sin entrar en conflicto con otras librerías.
void read(unsigned int *sensorValues, unsigned char readMode = QTR_EMITTERS_ON) Lee los valores de los sensores en bruto en una matriz. Debe haber tanto espacio para almacenar los valores como sensores se especifiquen en el constructor. Los valores devueltos son una medida de la reflectancia en unidades que dependen del tipo de sensor utilizado, los valores más altos corresponden a baja reflectancia (una superficie de color negro o un hueco). QTR-XA sensores devolverá un valor en bruto entre 0 y 1023. Mienras que los sensores QTR-XRC devolverá un valor en bruto entre el 0 y el argumento de tiempo de espera (en unidades de microsegundos), especificado en el constructor (que por defecto es 2000). Las funciones que se leen los valores de los sensores llevan todas un argumento readMode, que especifica el tipo de lectura que se llevará a cabo. Se definen varias opciones para readMode: .- QTR_EMITTERS_OFF especifica que la lectura debe hacerse sin necesidad de encender el infrarrojo (IR) emisores, en cuyo caso la lectura representa niveles de luz ambiente cerca del sensor; .- QTR_EMITTERS_ON especifica que los emisores debe ser activado para la lectura, que los resultados en una medida de la reflectancia, y .- QTR_EMITTERS_ON_AND_OFF especifica que una lectura debe hacerse tanto en el estado encendido y apagado. Los valores devueltos cuando la opción se utiliza QTR_EMITTERS_ON_AND_OFF vendrán dados por on + max- off, donde on es la lectura con los emisores activados, off es la lectura con los emisores desactivados, y el máx es la lectura máxima del sensor. Esta opción puede reducir las interferencias de la luz ambiente. Tenga en cuenta que el control del emisor sólo funcionará si se especifica un pin emisor válido en el constructor.
Ejemplo: 1 2
unsigned int sensor_values[8]; sensors.read(sensor_values);
void emittersOn() Encender el LED de infrarrojos.
void emittersOff() Apaga el led de infrarrojos.
void calibrate(unsigned char readMode = QTR_EMITTERS_ON) Lee los sensores para su calibración. Los valores de los sensores no se devuelven. Los valores máximos y mínimos encontrados durante el tiempo de calibración, se almacenan internamente y son utilizados para el método readCalibrated (). Podemos acceder a los valores de calibración (los valores en bruto máximo y min de los sensores) a través de los métodos públicos calibratedMinimumOn, calibratedMaximumOn, calibratedMinimumOff y calibratedMaximumOff. Tenga en cuenta que estos indicadores apuntan a las matrices de
25
MANUAL PROGRAMACIÓN v 4.0
01/2012
de longitud numSensors, especificada en el constructor, y que sólo se asignarán después de llamar al método calibrate().
void readCalibrated(unsigned int *sensorValues, unsigned char readMode = QTR_EMITTERS_ON) Lecturas de los sensores calibrados correspondientes a un valor entre 0 y 1000, donde 0 corresponde a una lectura que es menor o igual al valor mínimo leído por calibrate() y 1000 corresponde a una lectura que es mayor o igual que al valor máximo. Los valores de calibración se almacenan por separado para cada sensor, por lo que las diferencias en los sensores se registran de forma automática.
unsigned int readLine(unsigned int *sensorValues, unsigned char readMode = QTR_EMITTERS_ON, unsigned char whiteLine = 0) Funciona de la misma forma que readCalibrate(), pero con una característica distinta diseñada específicamente para seguir la línea: esta función devuelve una posición estimada de la línea. La estimación se realiza mediante un promedio ponderado de los índices de los sensores, multiplicado por 1000, por lo que un valor de retorno de 0 indica que la línea está directamente debajo del sensor 0, un valor de retorno de 1000 indica que la línea está directamente debajo del sensor 1, 2000 indica que está por debajo del sensor de 2,etc… los valores intermedios, indican que la línea se encuentra entre dos sensores. La fórmula es: 0*value0 + 1000*value1 + 2000*value2 + ... value0 + value1 + value2 + ... Mientras los sensores no estén demasiado separados respecto de la línea, este valor que retorna está diseñado para ser monótono, lo que hace ideal para uso en el control PID en bucle cerrado. Además, este método recuerda donde se vio por última vez a la línea, así que si alguna vez perdemos la línea a la izquierda o a la derecha, su valor nos indicará donde se encuentra la línea. Vistas algunas de los métodos que se encargan de los sensores, haremos uso del array de sensores que tenemos montados en la parte delantera de nuestro ROBOT para conseguir que nos represente en pantalla el estado de los sensores al recorrer la línea con los motores parados. Aconsejo que no se acometan tareas más complicadas, sin antes comprobar que no hay ningún sensor que falle. Si alguno de los sensores falla recomiendo que se averigüe el fallo, siempre suele provenir de malos contactos o rotura de alguno de los sensores. Para comprobar que todos los sensores están alimentados correctamente es conveniente observar a través de la óptica de una cámara de un móvil que se iluminan todos los diodos LED de IR. Para comprobar que el ROBOT es capaz de leer la línea de forma segura, recomiendo cargar el programa que podemos encontra en la librería y que se llama QTRRCExample.ino en el robot y comprobar la lectura de los sensores. Para leer la línea nos valdremos de la función readLine() que hemos visto antes. El valor que retorna la función es el valor en decimal comprendido entre 0 y 5000 que nos indica que sensor está sobre la línea. #include // This example is designed for use with eight QTR-1RC sensors or the eight sensors of a // QTR-8RC module. These reflectance sensors should be connected to digital inputs 3 to 10.
26
MANUAL PROGRAMACIÓN v 4.0
01/2012
// The emitter control pin can optionally be connected to digital pin 2, or you can leave // it disconnected and change the EMITTER_PIN #define below from QTR_NO_EMITTER_PIN.
2
// The setup phase of this example calibrates the sensor for ten seconds and turns on // the pin 13 LED while calibration is going on. During this phase, you should expose each // reflectance sensor ot the lightest and darkest readings they will encounter. For // example, if you are making a line follower, you should slide the sensors across the // line during the calibration phase so that each sensor can get a reading of how dark the // line is and how light the ground is. Improper calibration will result in poor readings. // If you want to skip the calibration phase, you can get the raw sensor readings // (pulse times from 0 to 2500 us) by calling qtra.read(sensorValues) instead of // qtra.readLine(sensorValues). // The main loop of the example reads the calibrated sensor values and uses them to // estimate the position of a line. You can test this by taping a piece of 3/4" black // electrical tape to a piece of white paper and sliding the sensor across it. It // prints the sensor values to the serial monitor as numbers from 0 (maximum reflectance) // to 9 (minimum reflectance) followed by the estimated location of the line as a number // from 0 to 5000. 1000 means the line is directly under sensor 1, 2000 means directly // under sensor 2, etc. 0 means the line is directly under sensor 0 or was last seen by // sensor 0 before being lost. 5000 means the line is directly under sensor 5 or was // last seen by sensor 5 before being lost.
#define NUM_SENSORS 8 // number of sensors used #define TIMEOUT 2500 // waits for 2500 us for sensor outputs to go low #define EMITTER_PIN 2 // emitter is controlled by digital pin 2 // sensors 0 through 7 are connected to digital pins 3 through 10, respectively QTRSensorsRC qtrrc((unsigned char[]) {3, 4, 5, 6, 7, 8, 9, 10}, NUM_SENSORS, TIMEOUT, EMITTER_PIN); unsigned int sensorValues[NUM_SENSORS];
void setup() { delay(500); int i; pinMode(13, OUTPUT); digitalWrite(13, HIGH); // turn on LED to indicate we are in calibration mode for (i = 0; i < 400; i++) // make the calibration take about 10 seconds { qtrrc.calibrate(); // reads all sensors 10 times at 2500 us per read (i.e. ~25 ms per call) } digitalWrite(13, LOW); // turn off LED to indicate we are through with calibration // print the calibration minimum values measured when emitters were on Serial.begin(9600); for (i = 0; i < NUM_SENSORS; i++) { Serial.print(qtrrc.calibratedMinimumOn[i]); Serial.print(' '); } Serial.println();
27
to
MANUAL PROGRAMACIÓN v 4.0
01/2012
// print the calibration maximum values measured when emitters were on for (i = 0; i < NUM_SENSORS; i++) { Serial.print(qtrrc.calibratedMaximumOn[i]); Serial.print(' '); } Serial.println(); Serial.println(); delay(1000); }
void loop() { // read calibrated sensor values and obtain a measure of the line position // from 0 to 5000, where 0 means directly under sensor 0 or the line was lost // past sensor 0, 1000 means directly under sensor 1, 200 means directly under sensor 2, etc. // Note: the values returned will be incorrect if the sensors have not been properly // calibrated during the calibration phase. To get raw sensor values, call: // qtra.read(sensorValues); unsigned int position = qtrrc.readLine(sensorValues); //qtrrc.read(sensorValues); // print the sensor values as numbers from 0 to 9, where 0 means maximum reflectance and // 9 means minimum reflectance, followed by the line position unsigned char i; for (i = 0; i < NUM_SENSORS; i++) { Serial.print(sensorValues[i] * 10 / 1001); Serial.print(' '); } Serial.print(" "); Serial.println(position); delay(250); }
28