Robot Seguidor de linea Negra

Muy buenas,

Estoy montando un robot seguidor de linea negra con:

Chasis con 4 motores de 6v
Arduino Uno
Shield L293D
4 Sensores

codido:

/*
 * SEGUIDOR DE LINEA NEGRA
 * 0 = NEGRO = LOW
 * 1 = BLANCO = HIGH
 */
#include <AFMotor.h>

int s3DE = A2;  // sensor Derecha Externo al pin A2.
int s1D = A5;   // sensor Derecha al pin A5.
int s2I = A4;   // sensor Izquierda al pin A4.
int s4IE = A3;  // sensor Izquierda Externo al pin A3.

int sensorValor_s3DE;  // guardamos el valor del sensor de la DERECHA EXTERNO. 
int sensorValor_s1D;   // guardamos el valor del sensor de la DERECHA.
int sensorValor_s2I;   // guardamos el valor del sensor de la IZQUIERDA.
int sensorValor_s4IE;  // guardamos el valor del sensor de la IZQUIERDA EXTERNO.

AF_DCMotor m1DD(1);  // motor Derecha Delante.
AF_DCMotor m2DI(2);  // motor Derecha Izquierda.
AF_DCMotor m3AI(3);  // motor Atras Izquierda.
AF_DCMotor m4AD(4);  // motor Atras Derecha.

void setup() {
   
  Serial.begin(9600);  // abrimos el monitor serial
  
  pinMode(s3DE, INPUT);  // declaramos sensor #3 como entrada
  pinMode(s1D, INPUT);   // declaramos sensor #1 como entrada
  pinMode(s2I, INPUT);   // declaramos sensor #2 como entrada  
  pinMode(s4IE, INPUT);  // declaramos sensor #4 como entrada
  
  m1DD.setSpeed (100);  // Configura velocidad a 100 (de 0 a 255).
  m2DI.setSpeed (100);
  m3AI.setSpeed (100);
  m4AD.setSpeed (100);
}

void loop() {

  int sensorValor_s3DE = digitalRead(A2);  // Recogemos los valores y los enviamos al monitor serial
  Serial.print("  Derecha Exterior = ");
  Serial.println( sensorValor_s3DE);
  
  int sensorValor_s1D = digitalRead(A5);
  Serial.print("           Derecha = ");
  Serial.println( sensorValor_s1D);
  
  int sensorValor_s2I = digitalRead(A4);
  Serial.print("         Izquierda = ");
  Serial.println( sensorValor_s2I);
  
  int sensorValor_s4IE = digitalRead(A3);  // aqui tenia que me daba el valor invertido
   if (sensorValor_s4IE == 0)              // es un sensor de otra marca y para no liarme lo he cambiado.
    {
      sensorValor_s4IE = 1;      
    }
    else
    {
      sensorValor_s4IE = 0;
    }
  Serial.print("Izquierda Exterior = ");
  Serial.println( sensorValor_s4IE);
  Serial.println("--------------------------------");
  
  if (digitalRead(s1D) == HIGH && digitalRead(s2I) == HIGH && digitalRead(s1D) == HIGH && digitalRead(s1D) == HIGH)
    {
      m1DD.run(RELEASE);   // si todos estan leen 1 = Blanco estan parados
      m2DI.run(RELEASE); 
      m3AI.run(RELEASE);
      m4AD.run(RELEASE); 
     
    }

  if (digitalRead(s1D) == HIGH && digitalRead(s2I) == LOW)
    {
      m1DD.run(FORWARD);     // si sensor derecha 1 = blanco y el sensor izquierdo 0 = negro
      m2DI.run(BACKWARD);    // entonces giramos a la izquierda.
      m3AI.run(BACKWARD);
      m4AD.run(FORWARD); 
    }

  if (digitalRead(s1D) == LOW && digitalRead(s2I) == HIGH)
    {
      m1DD.run(BACKWARD);  // si el sensor dercha 0 = negro y el sensor izquierda 1 = blanco
      m2DI.run(FORWARD);   // entonces giramos a la derecha
      m3AI.run(FORWARD);
      m4AD.run(BACKWARD); 
    }

  if (digitalRead(s1D) == LOW && digitalRead(s2I) == LOW)
    {
      m1DD.run(FORWARD);   // si los dos sensores derecha y izquierda 0 = negro
      m2DI.run(FORWARD);   // entonces avanzamos
      m3AI.run(FORWARD);
      m4AD.run(FORWARD); 
    }

  if (digitalRead(s3DE) == HIGH && digitalRead(s1D) == HIGH && digitalRead(s2I) == LOW && digitalRead(s4IE) == HIGH)
    {
      m1DD.run(FORWARD);    // si solo sensor izquierda es 0 = negro 
      m2DI.run(BACKWARD);   // entonces giramos a la izquierda
      m3AI.run(BACKWARD);
      m4AD.run(FORWARD);
    }

  if (digitalRead(s3DE) == LOW && digitalRead(s1D) == LOW && digitalRead(s2I) == HIGH && digitalRead(s4IE) == HIGH)
    {
      m1DD.run(BACKWARD);   // si los sensores de la izquierda 1 = blanco
      m2DI.run(FORWARD);    // entonces giramos a la derecha
      m3AI.run(FORWARD);
      m4AD.run(BACKWARD);
    }    

  if (digitalRead(s3DE) == LOW && digitalRead(s1D) == HIGH && digitalRead(s2I) == HIGH && digitalRead(s4IE) == HIGH)
    {
      m1DD.run(BACKWARD);
      m2DI.run(FORWARD);   // entonces giramos a la derecha
      m3AI.run(FORWARD);
      m4AD.run(BACKWARD);
    }

  if (digitalRead(s3DE) == HIGH && digitalRead(s1D) == HIGH && digitalRead(s2I) == HIGH && digitalRead(s4IE) == LOW)
    {
      m1DD.run(FORWARD);
      m2DI.run(BACKWARD);  // entonces giramos a la izquierda
      m3AI.run(BACKWARD);
      m4AD.run(FORWARD);
    }
}

Con dos sensores va perfecto.

Cuando programo los cuatro sensores al recopilar NO me da error, lo cargo al arduino.

Pero no ejecuta lo que esta programado para los 4 sensores.

Porque? hay otra manera de hacerlo ?

Gracias, de antemano.

Con el arduino el tiempo es supersonico. :wink:

Si va perfecto con dos sensores no entiendo la insistencia de poner dos más.

Me puedes explicar, por favor, la necesidad de los 4 sensores si con dos de ellos tienes lo que necesitas?

Perdón por mi ignorancia!

if (digitalRead(s1D) == HIGH && digitalRead(s2I) == HIGH && digitalRead(s1D) == HIGH && digitalRead(s1D) == HIGH)

Esto no tiene sentido
Preguntas dos veces digitalRead(s1D) == HIGH
y dos veces digitalRead(s2I) == HIGH
Debiera ser asi agregando los externos.
Yo he modificado el código para que sea mas entendible para mi.

/*
 * SEGUIDOR DE LINEA NEGRA
 * 0 = NEGRO = NEGRO
 * 1 = BLANCO = BLANCO
 */
#include <AFMotor.h>

#define BLANCO  BLANCO
#define NEGRO   NEGRO

const byte sDE 		= A2;  // sensor Derecha Externo al pin A2.
const byte sD 		= A5;   // sensor Derecha al pin A5.
const byte sI 		= A4;   // sensor Izquierda al pin A4.
const byte sIE 		= A3;  // sensor Izquierda Externo al pin A3.

bool sensorValor_DE;  // guardamos el valor del sensor de la DERECHA EXTERNO. 
bool sensorValor_D;   // guardamos el valor del sensor de la DERECHA.
bool sensorValor_I;   // guardamos el valor del sensor de la IZQUIERDA.
bool sensorValor_IE;  // guardamos el valor del sensor de la IZQUIERDA EXTERNO.

AF_DCMotor m1DD(1);  // motor Derecha Delante.
AF_DCMotor m2DI(2);  // motor Derecha Izquierda.
AF_DCMotor m3AI(3);  // motor Atras Izquierda.
AF_DCMotor m4AD(4);  // motor Atras Derecha.

void setup() {
   
  Serial.begin(9600);  // abrimos el monitor serial
  
  pinMode(sDE, INPUT);  // declaramos sensor #3 como entrada
  pinMode(sD, INPUT);   // declaramos sensor #1 como entrada
  pinMode(sI, INPUT);   // declaramos sensor #2 como entrada  
  pinMode(sIE, INPUT);  // declaramos sensor #4 como entrada
  
  m1DD.setSpeed (100);  // Configura velocidad a 100 (de 0 a 255).
  m2DI.setSpeed (100);
  m3AI.setSpeed (100);
  m4AD.setSpeed (100);
}

void loop() {

  sensorValor_DE = digitalRead(A2);  // Recogemos los valores y los enviamos al monitor serial
  Serial.print("  Derecha Exterior = ");
  Serial.println( sensorValor_DE);
  
  sensorValor_D = digitalRead(A5);
  Serial.print("           Derecha = ");
  Serial.println( sensorValor_D);
  
  sensorValor_I = digitalRead(A4);
  Serial.print("         Izquierda = ");
  Serial.println( sensorValor_I);
  
  sensorValor_IE = !digitalRead(A3);  // aqui tenia que me daba el valor invertido
  									  // es un sensor de otra marca y para no liarme lo he cambiado.
  Serial.print("Izquierda Exterior = ");
  Serial.println( sensorValor_IE);
  Serial.println("--------------------------------");
  
  if (digitalRead(sD) == BLANCO && digitalRead(sIE) == BLANCO && digitalRead(sD) == BLANCO && digitalRead(sDE) == BLANCO)  
     paramos();         // robot se salio completamente de la guia negra 
     					// Como vuelve o RELEASE es marcha atras?

  if (digitalRead(sD) == BLANCO && digitalRead(sI) == NEGRO)    
     giroAizquierda();  

  if (digitalRead(sD) == NEGRO && digitalRead(sI) == BLANCO)
     giroAderecha();    

  if (digitalRead(sD) == NEGRO && digitalRead(sI) == NEGRO)
  	  avanzamos();      // bien camino correcto

  if (digitalRead(sDE) == BLANCO && digitalRead(sD) == BLANCO && digitalRead(sI) == NEGRO && digitalRead(sIE) == BLANCO)
      giroAizquierda(); 

  if (digitalRead(sDE) == NEGRO && digitalRead(sD) == NEGRO && digitalRead(sI) == BLANCO && digitalRead(sIE) == BLANCO)
      giroAderecha();   // 

  if (digitalRead(sDE) == NEGRO && digitalRead(sD) == BLANCO && digitalRead(sI) == BLANCO && digitalRead(sIE) == BLANCO) 
      giroAderecha();   // no veo como es posible esta situación

  if (digitalRead(sDE) == BLANCO && digitalRead(sD) == BLANCO && digitalRead(sI) == BLANCO && digitalRead(sIE) == NEGRO) 
      giroAizquierda(); // no veo como es posible esta situación
}


void paramos() {
	m1DD.run(RELEASE);   // si todos estan leen 1 = Blanco estan parados
    m2DI.run(RELEASE); 
    m3AI.run(RELEASE);
    m4AD.run(RELEASE);
}

void avanzamos() {
	m1DD.run(FORWARD);   // si los dos sensores derecha y izquierda 0 = negro
    m2DI.run(FORWARD);   // entonces avanzamos
    m3AI.run(FORWARD);
    m4AD.run(FORWARD); 
}

void giroAizquierda() {
	m1DD.run(FORWARD);
    m2DI.run(BACKWARD);  // entonces giramos a la izquierda
    m3AI.run(BACKWARD);
    m4AD.run(FORWARD);
}

void giroAderecha() {
	m1DD.run(BACKWARD);
    m2DI.run(FORWARD);   // entonces giramos a la derecha
    m3AI.run(FORWARD);
    m4AD.run(BACKWARD);
}

No hay grandes cambios, solo por ahora intento entenderte.
Me parece que los sensores estan muy separados, hablo de los externos.

Buenas,

surbyte, error mio, no lo repase bien.

Los cambios que has hecho los entiendo, pero el #define, no.

he buscado #define, su estructura y es correcta,
no entiendo por que me da error al recopilar.

error: 'BLANCO' was not declared in this scope

como lo declaro? con int?

Ahhh esto

#define BLANCO  BLANCO
#define NEGRO   NEGRO

hice una sustitución general y esto quedó mal

#define BLANCO  HIGH
#define NEGRO   LOW

OK, gracias

#define [nombre] [valor]

por que #define y no int?

Para que quieres usar un int o sea 16 bits para algo que usa solo un bit HIGH o 1 o TRUE y LOW o 0 o FALSE?
cuando trabajas por mucho tiempo con los microcontroladores, aprendes a optimizar variables y su uso para cada caso.

Uso #define solo porque el compilador reemplazara cada BLANCO con un HIGH pero para leerlo es mas fácil.
Se entiende mejor que hará el robot al menos para mi.
#define se vuelve una constante y esa memoria apunta a la flash del micro.
Pude usar bool pero seria un bit de memoria.
Como no es una variable sino una constante por eso.

Buenas, esta mañana lo he podido probar, he montado una pista ovalada.

En la recta va bien pero no en la curva ya que se sale y después realiza marcha atras pero se descontrola y no es capaz de volver corectamente a la linea negra.

iré practicando con el codigo...
si teneis alguna sugerencia...

Vamos de nuevo.
Pone el código con los sensores interiores. Y luego vemos como mejorar o predecir que esta por salirse con el agregado de los exteriores.

Esto es lo que tengo hasta ahora, también he realizado algunos cambios para tenerlo más claro.

He realizado pruebas, he variado la velocidad (más, menos)… he juntado lo máximo los sensores, tengo pensado ampliar la pista porque lo que he hecho es una pista oval (con dos cartulinas grandes blancas) y creo que el coche no se agarra lo suficiente. Además me da la impresión de que el coche tarda en poner marcha atras cuando pierde la linea negra en las curvas.

Si me puedes sugerir mejoras … te lo agradecería.
.
.

/*
 * SEGUIDOR DE LINEA NEGRA
 * COMPONENTES:
 * 
 * Aduino Uno R3, 
 * Shield Motor L293D, 
 * (3) Sensores TCRT5000 IR infrared line track foller sensor
 * (1) Sensor IR Keyes
 * (4) Motores 6v 
 * 1 Bateria 9v para Arduino (con interruptor ON-OFF)
 * 1 Bateria 12v para Shield Motor L293D (con interruptor ON-OFF)
 * 
 * VALORES:
 * 0 = NEGRO
 * 1 = BLANCO
 * 
 * con la ayuda de surbyte (foro arduino)
 */
#include <AFMotor.h>

#define BLANCO HIGH
#define NEGRO LOW

  // IZQ.EXT    IZQ.    DCHA.    DCHA.EXT
  //   (s4)     (s3)    (s2)       (s1)

const byte s1 = A3;      // sensor Izquierda Externo al pin A3.
const byte s2 = A4;      // sensor Izquierda al pin A4.
const byte s3 = A5;      // sensor Derecha al pin A5.
const byte s4 = A2;      // sensor Derecha Externo al pin A2.

bool sensorValors1;      // guardamos el valor del sensor de la DERECHA EXTERNO.
bool sensorValors2;      // guardamos el valor del sensor de la DERECHA.
bool sensorValors3;      // guardamos el valor del sensor de la IZQUIERDA.
bool sensorValors4;      // guardamos el valor del sensor de la IZQUIERDA EXTERNO.

AF_DCMotor m1DD(1);       // motor Derecha Delante.         ***************
AF_DCMotor m2DI(2);       // motor Izquierda Delante.       * m2DI - m1DD *
AF_DCMotor m3AI(3);       // motor Atras Izquierda.         *             *
AF_DCMotor m4AD(4);       // motor Atras Derecha.           * m3AI - m4AD *
                                                            ***************
void setup() {
  
  Serial.begin(9600);     // abrimos el monitor serial
  
  pinMode(s1, INPUT);     // declaramos los sensores como entrada
  pinMode(s2, INPUT);     
  pinMode(s3, INPUT);       
  pinMode(s4, INPUT);     
  
  m1DD.setSpeed (180);    // Configura velocidad a 180 (de 0 a 255).
  m2DI.setSpeed (180);
  m3AI.setSpeed (180);
  m4AD.setSpeed (180);
}

void loop() {

  // Recogemos los valores y los enviamos al monitor serial
  
  sensorValors4 = !digitalRead(A3);  
  Serial.print("Izquierda Exterior = ");
  Serial.println( sensorValors4);

  sensorValors3 = digitalRead(A4);
  Serial.print("         Izquierda = ");
  Serial.println( sensorValors3);
    
  sensorValors2 = digitalRead(A5);
  Serial.print("           Derecha = ");
  Serial.println( sensorValors2);

  sensorValors1 = digitalRead(A2);               
  Serial.print("  Derecha Exterior = ");
  Serial.println( sensorValors1);
   
  Serial.println("--------------------------------");

  // Accion a realizar según los resultados de los sensores.
  
  // IZQ.EXT    IZQ.    DCHA.    DCHA.EXT
  //   (s4)     (s3)    (s2)       (s1)

  // Con los 2 sensores centrales
  
   if (digitalRead(s3) == NEGRO && digitalRead(s2) == NEGRO)
       
      avanzamos();   
         
   if (digitalRead(s3) == NEGRO && digitalRead(s2) == BLANCO)    
       
      giroAizquierda();
       
   if (digitalRead(s3) == BLANCO && digitalRead(s2) == NEGRO)    
      
      giroAderecha();

   if (digitalRead(s3) == BLANCO && digitalRead(s2) == BLANCO)    
      atras();

// ----------------------------------------------------------------------------------------------------------------
   
  // Con los 4 sensores
   
  if (digitalRead(s4) == NEGRO && digitalRead(s3) == NEGRO && digitalRead(s2) == NEGRO && digitalRead(s1) == NEGRO)  
     
      avanzamos();  
     
  if (digitalRead(s4) == NEGRO && digitalRead(s3) == NEGRO && digitalRead(s2) == BLANCO && digitalRead(s1) == BLANCO)  
     
     giroAizquierda();
          
  if (digitalRead(s4) == BLANCO && digitalRead(s3) == BLANCO && digitalRead(s2) == NEGRO && digitalRead(s1) == NEGRO)  
     
     giroAderecha();
          
  if (digitalRead(s4) == BLANCO && digitalRead(s3) == BLANCO && digitalRead(s2) == BLANCO && digitalRead(s1) == BLANCO)  
     
     atras();  
}

// ACCIONES: avanzamos, giroAizquieda, giroAderecha, atras

void avanzamos() {
    m1DD.run(FORWARD);   // si los dos sensores derecha y izquierda 0 = negro
    m2DI.run(FORWARD);   // entonces avanzamos
    m3AI.run(FORWARD);
    m4AD.run(FORWARD);
}

void giroAizquierda() {
    m1DD.run(FORWARD);   // giramos a la izquierda
    m2DI.run(BACKWARD);  
    m3AI.run(BACKWARD);
    m4AD.run(FORWARD);    
}

void giroAderecha() {
    m1DD.run(BACKWARD);   // giramos a la derecha
    m2DI.run(FORWARD);   
    m3AI.run(FORWARD);   
    m4AD.run(BACKWARD);
}

void atras() {
    
    m1DD.run(BACKWARD);   // si todos estan en 1 = Blanco
    m2DI.run(BACKWARD);   // entonces atras
    m3AI.run(BACKWARD);
    m4AD.run(BACKWARD);
}

Hagamos una cosa. Para que sea mas fácil.
Veamos caso por caso.

Tu has visto esto, no se si fui yo o tu pero hayun error importante

// defines esto
const byte s1 = A3;      // sensor Izquierda Externo al pin A3.
const byte s2 = A4;      // sensor Izquierda al pin A4.
const byte s3 = A5;      // sensor Derecha al pin A5.
const byte s4 = A2;      // sensor Derecha Externo al pin A2.

// en el loop dice esto
  sensorValors4 = !digitalRead(A3);     // no debiera ser A2 o mejor s4?
  Serial.print("Izquierda Exterior = ");
  Serial.println( sensorValors4);

  sensorValors3 = digitalRead(A4);      // no debiera ser A5 o s3
  Serial.print("         Izquierda = ");
  Serial.println( sensorValors3);
    
  sensorValors2 = digitalRead(A5);     // no debiera ser A4 o s2
  Serial.print("           Derecha = ");
  Serial.println( sensorValors2);

  sensorValors1 = digitalRead(A2);     // no debiera ser A3 o s1          
  Serial.print("  Derecha Exterior = ");
  Serial.println( sensorValors1);

Estan todos MAL!!!!

Primera mejora: ahora que esta muchísimo mas claro al menos para mi, puedo seguir la idea.
El control de 2 sensores lo comento y continúo con el control de 4 sensores o bien pongo una llave selectora que lee ARDUINO como una entrada para trabajar con 2 o 4. un simple If en función del estado de esa entrada determina que usas. 2 o 4 sensores.

Mi simplificación

  // Con los 4 sensores
   
  if (digitalRead(s4) == NEGRO && digitalRead(s3) == NEGRO && digitalRead(s2) == NEGRO && digitalRead(s1) == NEGRO)  
      avanzamos();  // OK
     
  // Si externo derecho s1 ya detecta BLANCO girar a izquierda. No hace falta esperar a s2!!!
  if (digitalRead(s4) == NEGRO && digitalRead(s3) == NEGRO && digitalRead(s1) == BLANCO)  
      giroAizquierda();
  
  // Si externo izquierdo s4 ya detecta blanco girar a derecha. no hace falta esperar a S3 detectando BLANCO
  if (digitalRead(s4) == BLANCO && digitalRead(s2) == NEGRO && digitalRead(s1) == NEGRO)  
      giroAderecha();
          
  if (digitalRead(s4) == BLANCO && digitalRead(s3) == BLANCO && digitalRead(s2) == BLANCO && digitalRead(s1) == BLANCO)  
      atras();  
}

No debo esperar a que dos sensores vean BLANCO cuando 1 me alcanza para que ya gire.

El siguiente paso sería controlar la velocidad y cuando detecta BLANCO baje velocidad para atenuar la falla y hasta que restaure el control y este derecho no vuelvo a acelerar y asi.
Mi duda es si eso no provocaré un zig zag. Cosa que anticipo asi será.

Por ahora dime como funciona esto.
Pero recuerda comentar los if de 2 sensores. Ya no tienen sentido.

Buenas, el error fui yo.

Entiendo que ya no hacen falta medir con los dos sensores,
pero creo que podia ser una opcion poder elegir medir en 2 o en 4.

Medimos con los cuatro y para saber cuando girar con uno que este en BLANCO ya esta.

He modificado una APP para Android en MIT 2 INVENTOR, en la cual puedo manejarlo con las flechas, o bien activar el HC_SR04 o bien el Seguidor de Linea. (que pondria una opcion de medir en 2 sensores o en 4). Y tambien estoy experimentando para controlarlo con el Acelerometro...

A ver si mañana o pasado mañana lo puedo probar.

Gracias, de nuevo.