Robot sigue líneas con Arduino
Este artículo trata sobre la construcción y programación de un robot que sigue líneas con Arduino y un sensor de infrarojos.
Construcción del Robot
Materiales
El chasis que verás en las fotos es específico, creado a medida por la empresa What's Next? para el proyecto [Robots Boost Skills]. El resto de componentes son genéricos y se pueden comprar Arduinos oficiales, What's Next Yellow o cualquier clon compatible.
Esta es la lista de materiales:
- Chasis que permita 2 ruedas con motor DC analógicos y una rueda delantera.
- 2 Motores DC analógicos con reducción y ruedas.
- Arduino Uno o equivalente.
- 1 Sensor Pololu QTR-8A o QTR-8RC
- Arduino Motor Shield o alguno que tenga el mismo Chip L298
- Baterías, entre 9V y 12V
Construcción del Chasis
En el caso del robot del ejemplo, el chasis tiene todos los elementos necesarios. Si lo tienes que construir, aquí tienes algunos consejos:
- Se recomienda cuidar el centro de gravedad de robot para que no plante rueda y tenga la adherencia necesaria. Por ejemplo, las baterías deberían estar entre las ruedas motrices y la rueda delantera.
- La distancia al suelo del sensor infrarojo es muy importante, ha de estar muy cerca, pero no rozar.
- Hay que dejar espacio para los cables y para poder modificar las conexiones sin necesidad de desmontar todo el robot.
El sensor
En nuestro caso, el sensor QTR-8[A-RC] es un conjunto de 8 emisores y sensores infrarrojos en un mismo circuito. Esto permite una gran precisión ,ya que tienes 8 lecturas cada vez. Estos sensores tienen una distancia recomendada de 3mm y un máximo de 6mm para el QTR-A y 9.5mm para el QTR-8RC.
La salida de los dos sensores es diferente, (analógica o digital), por lo que es importante distinguirlos y decidir cual vamos a usar. En nuestro caso, tenemos el QRT-8RC, por lo que, a partir de aquí, todo el manual se basa en este.
Puesto que vamos a usar 5V para alimentarlo, no es necesario unir los pines de 3.3V Bypass
Podemos conectar el pin LEDON que permite indicar con HIGH, LOW o PWM el estado de los LEDs. Si los apagamos, podemos consumir menos energía cuando no está leyendo.
El QTR8-RC mide la reflectancia con el tiempo entre un estado HIGH y uno LOW.
La lectura típica en el QTR8-RC es la siguiente:
- Encender los LEDs (opcional)
- Poner la linea I/O a una salida y ponerla en HIGH.
- Dejar al menos 10 μs al sensor para que arranque.
- Poner la I/O a Input
- Medir el tiempo que tarda el voltaje en caer esperando a la I/O a que vuelva a LOW.
- Apagar los LEDs (opcional)
Estos pasos se pueden hacer en varias líneas I/O al mismo tiempo. Con mucha reflectividad, el tiempo de bajada a LOW debe ser mínimo. Con poca (superficie negra) el tiempo debe mayor. Se recomienda usar el LEDON para no gastar batería hasta en un 90% del tiempo para lecturas a baja frecuencia, unos (100Hz).
Si se necesitan lecturas a mucha frecuencia, se recomienda que el sensor esté muy cerca del suelo, recomendado 3,5 mm i máximo 9 mm.
Cuanto más lejos peor lecturas y cuanta más luz ambiental peor. Si es necesario, bloquearemos la luz ambiental con cinta aislante o similar.
De esta manera, el esquema de conexiones del robot queda de la siguiente manera:
Programación del robot
Leyendo del sensor
Para que funcione, necesitamos la biblioteca correspondiente. En los últimos Arduino IDE es tan simple como ir al gestor de Bibliotecas y importar la QTRSensors.
La biblioteca funciona tanto para el QTR-8RC como el QTR-8A, pero el constructor es el que cambia:
// Crear un objeto para 4 sensores en los pines digitales 0,9
// y en los analógicos 1 y 3 (haciendo de digital)
QTRSensorsRC qtrrc((unsignedchar[]){0,9,15,17},4);
Este es el ejemplo que siguen en la web oficial, pero nosotros podemos usar los pines que necesitemos. Como quedan libres los pines digitales 2,4,5,6,7 y 10, podemos hacer un constructor para 4 sensores como el siguiente:
QTRSensorsRC qtrrc((unsignedchar[]){2,4,5,6},4);
O si lo quisieramos para los 8 sensores:
QTRSensorsRC qtrrc((unsignedchar[]){2,4,5,6,7,10,15,17},8);
Calibrar los sensores es lo primero que debería hacer el robot. Así, en la rutina de inicialización (setup), se recomienda lanzar este código:
#include <QTRSensors.h>
// create an object for your type of sensor (RC)
// in this example we have three sensors on analog inputs 0 - 2, a.k.a. digital pins 14 -16
QTRSensorsRC qtr((char[]){14,15,16},3);
void setup()
{
// optional: wait for some input from the user, such as a button press
// then start calibration phase and move the sensors over both
// reflectance extremes they will encounter in your application:
int i;
for(i =0; i <250; i++)// make the calibration take about 5 seconds
{
qtr.calibrate();
delay(20);
}
// optional: signal that the calibration phase is now over and wait for further
// input from the user, such as a button press
}
Para leer del sensor, se recomienda usar la función readCalibrated() o read(). Con readCalibrated(), los valores obtenidos serán entre 0 (blanco) y 1000 (negro).
Para la detección de líneas, se usar la función readLine() a la que se puede decir si la línea es blanca o negra. El resultado de esta función es 0 si la línea está dentro o fuera de sensor 0 y 1000*(N-1) para cada sensor. Los valores para 8 sensores pueden ser, por tanto, 0, 1000, 2000 ... 8000 dependiendo de la posición de la línea. Código para analizar los valores que obtiene el sensor con los 8 sensores:
#include <QTRSensors.h>
#define NUM_SENSORS 8 // numero de sensores usados
#define TIMEOUT 2500 // esperar 2.5 ms para tener una respuesta del sensado
#define EMITTER_PIN 6 // este pin controla el led on del los sensores (enciende y apaga)
//aqui se pone el numero de los pines conectados a los sensores
// Estos son: A5 A4 A3 A2 A1 A0 11 12
// Se han conectado en el sensor del 8 al 1
QTRSensorsRC qtrrc((unsigned char[]) {19, 18, 17, 16, 15, 14, 11, 12},
NUM_SENSORS, TIMEOUT, EMITTER_PIN);
unsigned int sensorValues[NUM_SENSORS];
void setup()
{
delay(500);
pinMode(13, OUTPUT);
digitalWrite(13, HIGH); //este led encendido indica que comienza la calibracion
for (int i = 0; i < 200; i++) // la calibracion se lleva a cabo por 5 segundos
{
qtrrc.calibrate(); // funcion para calibrar los sensores
}
digitalWrite(13, LOW); // se paga el led para que indique que termino la calibracion
// imprime la calibracion minima de los sensores
Serial.begin(9600);
for (int i = 0; i < NUM_SENSORS; i++)
{
Serial.print(qtrrc.calibratedMinimumOn[i]);
Serial.print(' ');
}
Serial.println();
// imprime la calibracion maxima de los sensores
for (int 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
// To get raw sensor values, call:
// qtrrc.read(sensorValues); instead of unsigned int position = qtrrc.readLine(sensorValues);
unsigned int position = qtrrc.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);
}
Ejemplo del manual oficial del sensor para un sigue líneas simple con 3 sensores:
void loop()
{
unsigned int sensors[3];
// get calibrated sensor values returned in the sensors array,
// along with the line position.
// position will range from 0 to 2000,
// with 1000 corresponding to the line over the middle sensor.
int position = qtr.readLine(sensors);
// if all three sensors see very low reflectance,
// take some appropriate action for this situation.
if (sensors[0] > 750 && sensors[1] > 750 && sensors[2] > 750)
{
// do something.
// Maybe this means we're at the edge of a course or about to fall off
// a table, in which case, we might want to stop moving, back up, and turn around.
return;
}
// compute our "error" from the line position.
// We will make it so that the error is zero
// when the middle sensor is over the line,
// because this is our goal. Error will range from
// -1000 to +1000.
// If we have sensor 0 on the left and sensor 2 on the right, a reading of
// -1000 means that we see the line on the left
// and a reading of +1000 means we see the
// line on the right.
int error = position - 1000;
int leftMotorSpeed = 100;
int rightMotorSpeed = 100;
if (error < -500) // the line is on the left
leftMotorSpeed = 0; // turn left
if (error > 500) // the line is on the right
rightMotorSpeed = 0; // turn right
// set motor speeds using the two motor speed variables above
}
- (Obsoleto) Manual de la biblioteca del sensor Referencia de la biblioteca
- (Versión 4.) Manual Referencia
- Tutorial en castellano