Diferencia entre revisiones de «Robot sigue líneas con Arduino»

De Jose Castillo Aliaga
Ir a la navegación Ir a la búsqueda
Línea 66: Línea 66:
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.  
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:
La biblioteca funciona tanto para el QTR-8RC como el QTR-8A, pero cambia la manera de configurarlo:
<syntaxhighlight lang="c" style="font-family:monospace; font-size:0.8em;">
<syntaxhighlight lang="c" style="font-family:monospace; font-size:0.8em;">
// Crear un objeto para 4 sensores en los pines digitales 0,9
// Crear un objeto para 8 sensores en los pines digitales 2,4,5,6,7,10 y en los analogicos A4 A5
// y en los analógicos 1 y 3 (haciendo de digital)
  QTRSensors qtr;
QTRSensorsRC​ qtrrc​((​unsigned​​char​[])​​{​0​,​​9​,​​15​,​​17​},​​4​);
  qtr.setTypeRC();
</syntaxhighlight>
  qtr.setSensorPins((const uint8_t[]){19,18,2,4,5,6,7,10}, 8);
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:
  qtr.setEmitterPin(16);
<syntaxhighlight lang="c" style="font-family:monospace; font-size:0.8em;">
QTRSensorsRC​ qtrrc​((​unsigned​​char​[])​​{​2​,​​4​,​​5​,​​6​},​​4​);
</syntaxhighlight>
O si lo quisieramos para los 8 sensores:
<syntaxhighlight lang="c" style="font-family:monospace; font-size:0.8em;">
QTRSensorsRC​ qtrrc​((​unsigned​​char​[])​​{​2​,​​4​,​​5​,​​6​,7,10,15,17},​​8​);
</syntaxhighlight>
</syntaxhighlight>


Línea 85: Línea 79:
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:
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:
<syntaxhighlight lang="c" style="font-family:monospace; font-size:0.8em;">
<syntaxhighlight lang="c" style="font-family:monospace; font-size:0.8em;">
#include <QTRSensors.h>
QTRSensors qtr;
void setup()
void setup()
{
{
  // Optional: wait for some input from the user, such as a button press.
  pinMode(A3, OUTPUT);  // LED para indicar que está calibrando
   // Initialize the sensors.
  // In this example we have three sensors on pins A0 - A2.
   // configure the sensors
   qtr.setTypeRC(); // or setTypeAnalog()
   qtr.setTypeRC();
   qtr.setSensorPins((const uint8_t[]){A0, A1, A2}, 3);
   qtr.setSensorPins((const uint8_t[]){19,18,2,4,5,6,7,10}, SensorCount);
   // Optional: change parameters like RC timeout, set an emitter control pin...
   qtr.setEmitterPin(16);
   // Then start the calibration phase and move the sensors over both reflectance
 
   // extremes they will encounter in your application. This calibration should
  delay(500);
   // take about 5 seconds (250 iterations * 20 ms per iteration).
   //pinMode(A3, OUTPUT);
   //
   digitalWrite(A3, HIGH); // turn on Arduino's LED to indicate we are in calibration mode
   // Passing a QTRReadMode to calibrate() is optional; it should match the mode
 
  // you plan to use when reading the sensors.
   // 2.5 ms RC read timeout (default) * 10 reads per calibrate() call
   for (uint8_t i = 0; i < 250; i++)
   // = ~25 ms per calibrate() call.
   // Call calibrate() 400 times to make calibration take about 10 seconds.
   for (uint16_t i = 0; i < 400; i++)
   {
   {
     qtr.calibrate();
     qtr.calibrate();
    delay(20);
   }
   }
   // Optional: signal that the calibration phase is now over and wait for
  digitalWrite(A3, LOW); // turn off Arduino's LED to indicate we are through with calibration
   // further input from the user, such as a button press.
 
   // print the calibration minimum values measured when emitters were on
  Serial.begin(9600);
  for (uint8_t i = 0; i < SensorCount; i++)
  {
    Serial.print(qtr.calibrationOn.minimum[i]);
    Serial.print(' ');
  }
  Serial.println();
 
   // print the calibration maximum values measured when emitters were on
  for (uint8_t i = 0; i < SensorCount; i++)
  {
    Serial.print(qtr.calibrationOn.maximum[i]);
    Serial.print(' ');
  }
  Serial.println();
  Serial.println();
  delay(1000);
}
}
</syntaxhighlight>
</syntaxhighlight>
Línea 118: Línea 129:
<syntaxhighlight lang="c" style="font-family:monospace; font-size:0.8em;">
<syntaxhighlight lang="c" style="font-family:monospace; font-size:0.8em;">
#include <QTRSensors.h>
#include <QTRSensors.h>
#define NUM_SENSORS  8    // numero de sensores usados
 
#define TIMEOUT      2500  // esperar 2.5 ms para tener una respuesta del sensado
// This example is designed for use with eight RC QTR sensors. These
#define EMITTER_PIN  6    // este pin controla el led on del los sensores (enciende y apaga)
// reflectance sensors should be connected to digital pins 3 to 10. The
 
// sensors' emitter control pin (CTRL or LEDON) can optionally be connected to
//aqui se pone el numero de los pines conectados a los sensores
// digital pin 2, or you can leave it disconnected and remove the call to
// Estos son: A5 A4 A3 A2 A1 A0 11 12
// setEmitterPin().
// Se han conectado en el sensor del 8 al 1
//
QTRSensorsRC qtrrc((unsigned char[]) {19, 18, 17, 16, 15, 14, 11, 12},
// The setup phase of this example calibrates the sensors for ten seconds and
  NUM_SENSORS, TIMEOUT, EMITTER_PIN);  
// turns on the Arduino's LED (usually on pin 13) while calibration is going
unsigned int sensorValues[NUM_SENSORS];
// on. During this phase, you should expose each reflectance sensor to 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.
//
// 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 1000 (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.
 
QTRSensors qtr;
 
const uint8_t SensorCount = 8;
uint16_t sensorValues[SensorCount];
 
void setup()
void setup()
{
{
    //Setup Channel A
  pinMode(12, OUTPUT); //Initiates Motor Channel A pin
  pinMode(9, OUTPUT); //Initiates Brake Channel A pin
  //Setup Channel B
  pinMode(13, OUTPUT); //Initiates Motor Channel A pin
  pinMode(8, OUTPUT);  //Initiates Brake Channel A pin
  pinMode(A3, OUTPUT);
 
  // configure the sensors
  qtr.setTypeRC();
  qtr.setSensorPins((const uint8_t[]){19,18,2,4,5,6,7,10}, SensorCount);
  qtr.setEmitterPin(16);
   delay(500);
   delay(500);
   pinMode(13, OUTPUT);      
   //pinMode(A3, OUTPUT);
   digitalWrite(13, HIGH);   //este led encendido indica que comienza la calibracion
   digitalWrite(A3, HIGH); // turn on Arduino's LED to indicate we are in calibration mode
   for (int i = 0; i < 200; i++) // la calibracion se lleva a cabo por 5 segundos
 
  // 2.5 ms RC read timeout (default) * 10 reads per calibrate() call
  // = ~25 ms per calibrate() call.
  // Call calibrate() 400 times to make calibration take about 10 seconds.
   for (uint16_t i = 0; i < 400; i++)
   {
   {
     qtrrc.calibrate();       // funcion para calibrar los sensores
     qtr.calibrate();
   }
   }
   digitalWrite(13, LOW);     // se paga el led para que indique que termino la calibracion
   digitalWrite(A3, LOW); // turn off Arduino's LED to indicate we are through with calibration
 
 
   // imprime la calibracion minima de los sensores
   // print the calibration minimum values measured when emitters were on
   Serial.begin(9600);
   Serial.begin(9600);
   for (int i = 0; i < NUM_SENSORS; i++)
   for (uint8_t i = 0; i < SensorCount; i++)
   {
   {
     Serial.print(qtrrc.calibratedMinimumOn[i]);
     Serial.print(qtr.calibrationOn.minimum[i]);
     Serial.print(' ');
     Serial.print(' ');
   }
   }
   Serial.println();
   Serial.println();
   
 
   // imprime la calibracion maxima de los sensores
   // print the calibration maximum values measured when emitters were on
   for (int i = 0; i < NUM_SENSORS; i++)
   for (uint8_t i = 0; i < SensorCount; i++)
   {
   {
     Serial.print(qtrrc.calibratedMaximumOn[i]);
     Serial.print(qtr.calibrationOn.maximum[i]);
     Serial.print(' ');
     Serial.print(' ');
   }
   }
Línea 159: Línea 212:
   delay(1000);
   delay(1000);
}
}
 
 
void loop()
void loop()
{
{
   // read calibrated sensor values and obtain a measure of the line position from 0 to 5000
   // read calibrated sensor values and obtain a measure of the line position
  // To get raw sensor values, call:
  // from 0 to 5000 (for a white line, use readLineWhite() instead)
  //  qtrrc.read(sensorValues); instead of unsigned int position = qtrrc.readLine(sensorValues);
   uint16_t position = qtr.readLineBlack(sensorValues);
   unsigned int position = qtrrc.readLine(sensorValues);
 
 
   // print the sensor values as numbers from 0 to 1000, where 0 means maximum
   // print the sensor values as numbers from 0 to 1000, where 0 means maximum reflectance and
   // reflectance and 1000 means minimum reflectance, followed by the line
   // 1000 means minimum reflectance, followed by the line position
  // position
   for (unsigned char i = 0; i < NUM_SENSORS; i++)
   for (uint8_t i = 0; i < SensorCount; i++)
   {
   {
     Serial.print(sensorValues[i]);
     Serial.print(sensorValues[i]);
     Serial.print('\t');
     Serial.print('\t');
   }
   }
  //Serial.println(); // uncomment this line if you are using raw values
   Serial.println(position);
   Serial.println(position); // comment this line out if you are using raw values
 
   
   delay(250);
   delay(50);
}
}
</syntaxhighlight>
</syntaxhighlight>

Revisión del 18:39 9 abr 2019

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

Fotos

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.

Esquemapololu.png

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:

  1. Encender los LEDs (opcional)
  2. Poner la linea I/O a una salida y ponerla en HIGH.
  3. Dejar al menos 10 μs al sensor para que arranque.
  4. Poner la I/O a Input
  5. Medir el tiempo que tarda el voltaje en caer esperando a la I/O a que vuelva a LOW.
  6. 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.

Si necesitamos saber si funcionan los LEDs, podemos usar la cámara del móvil, que capta la luz infraroja.

De esta manera, el esquema de conexiones del robot queda de la siguiente manera:

Sensors qtr-8rc.png

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 cambia la manera de configurarlo:

// Crear un objeto para 8 sensores en los pines digitales 2,4,5,6,7,10 y en los analogicos A4 A5 
  QTRSensors qtr;
  qtr.setTypeRC();
  qtr.setSensorPins((const uint8_t[]){19,18,2,4,5,6,7,10}, 8);
  qtr.setEmitterPin(16);
Para aprender a usarlo, se recomienda ir a los ejemplos de Arduino IDE específicos de los sensores QTR.

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:

void setup()
{
   pinMode(A3, OUTPUT);  // LED para indicar que está calibrando
 
  // configure the sensors
  qtr.setTypeRC();
  qtr.setSensorPins((const uint8_t[]){19,18,2,4,5,6,7,10}, SensorCount);
  qtr.setEmitterPin(16);

  delay(500);
  //pinMode(A3, OUTPUT);
  digitalWrite(A3, HIGH); // turn on Arduino's LED to indicate we are in calibration mode

  // 2.5 ms RC read timeout (default) * 10 reads per calibrate() call
  // = ~25 ms per calibrate() call.
  // Call calibrate() 400 times to make calibration take about 10 seconds.
  for (uint16_t i = 0; i < 400; i++)
  {
    qtr.calibrate();
  }
  digitalWrite(A3, 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 (uint8_t i = 0; i < SensorCount; i++)
  {
    Serial.print(qtr.calibrationOn.minimum[i]);
    Serial.print(' ');
  }
  Serial.println();

  // print the calibration maximum values measured when emitters were on
  for (uint8_t i = 0; i < SensorCount; i++)
  {
    Serial.print(qtr.calibrationOn.maximum[i]);
    Serial.print(' ');
  }
  Serial.println();
  Serial.println();
  delay(1000);
}


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>

// This example is designed for use with eight RC QTR sensors. These
// reflectance sensors should be connected to digital pins 3 to 10. The
// sensors' emitter control pin (CTRL or LEDON) can optionally be connected to
// digital pin 2, or you can leave it disconnected and remove the call to
// setEmitterPin().
//
// The setup phase of this example calibrates the sensors for ten seconds and
// turns on the Arduino's LED (usually on pin 13) while calibration is going
// on. During this phase, you should expose each reflectance sensor to 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.
//
// 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 1000 (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.

QTRSensors qtr;

const uint8_t SensorCount = 8;
uint16_t sensorValues[SensorCount];

void setup()
{

    //Setup Channel A
  pinMode(12, OUTPUT); //Initiates Motor Channel A pin
  pinMode(9, OUTPUT); //Initiates Brake Channel A pin
  //Setup Channel B
  pinMode(13, OUTPUT); //Initiates Motor Channel A pin
  pinMode(8, OUTPUT);  //Initiates Brake Channel A pin

   pinMode(A3, OUTPUT); 


  
  // configure the sensors
  qtr.setTypeRC();
  qtr.setSensorPins((const uint8_t[]){19,18,2,4,5,6,7,10}, SensorCount);
  qtr.setEmitterPin(16);

  delay(500);
  //pinMode(A3, OUTPUT);
  digitalWrite(A3, HIGH); // turn on Arduino's LED to indicate we are in calibration mode

  // 2.5 ms RC read timeout (default) * 10 reads per calibrate() call
  // = ~25 ms per calibrate() call.
  // Call calibrate() 400 times to make calibration take about 10 seconds.
  for (uint16_t i = 0; i < 400; i++)
  {
    qtr.calibrate();
  }
  digitalWrite(A3, 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 (uint8_t i = 0; i < SensorCount; i++)
  {
    Serial.print(qtr.calibrationOn.minimum[i]);
    Serial.print(' ');
  }
  Serial.println();

  // print the calibration maximum values measured when emitters were on
  for (uint8_t i = 0; i < SensorCount; i++)
  {
    Serial.print(qtr.calibrationOn.maximum[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 (for a white line, use readLineWhite() instead)
  uint16_t position = qtr.readLineBlack(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 (uint8_t i = 0; i < SensorCount; i++)
  {
    Serial.print(sensorValues[i]);
    Serial.print('\t');
  }
  Serial.println(position);

  delay(250);
}

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
}