miércoles, 4 de marzo de 2020

COMO HACER UN SEGUIDOR DE LINEA

INTRODUCCIÓN

Como hacer un seguidor de linea de manera sencilla empezando desde cero.

Utilizaremos sensores infrarrojos (TCRT5000) como "antenas" para identificar el mecanismo que necesitaremos para dirigir nuestro seguidor de linea por medio del modulo (PUENTE H L298N) que usaremos para activar los motorreductores DC que nos proporcionaran movimiento.

Para empezar conoceremos los materiales que se necesitan para realizar este proyecto, haré una lista con la respectiva descripción de cada uno:


Una vez conocido los elementos que vamos a trabajar puedes ver algunos vídeos de programación básica para el IDE de Arduino. clic aquí para ver vídeos relacionados a la programación.


Si no es el caso puesto que los vídeos no son lo tuyo puedes aprender aquí las funciones básicas de Arduino como su instalación entre otros.

Aun así aquí explicare algunos conceptos necesarios para realizar nuestro seguidor de linea.

Arduino es una plataforma de hardware libre con un microcontrolador que nos permite una conexión o circuito integrado programable capaz de realizar operaciones matemáticas complejas a gran velocidad; de cierto modo es una placa para prototipos de electrónica basada en un software y hardware libre.

Quiero saber mas de ARDUINO: sus funciones, sus variables, su estructura y su lenguaje.

Con la plataforma Arduino puedes crear/hacer casi todo,  el único limite es nuestra imaginación, y el interés que tengamos para finalizar u optimizar nuestro proyecto.
Arduino puede ser un sistema autónomo programado que realice una o varias tareas específicas, lo cual lo hace una gran herramienta para realizar proyectos autónomos o que nos den un resultado esperado entre otros;  


Quiero ver proyectos de ARDUINO

conociendo Arduino UNO:

ARDUINO UNO



COMPONENTES:
- AREF: (VERDE CLARO) Terminal con referencia analógica
- GND: (NARANJA)toma tierra
- PINES 1-13: (AZUL) terminales digitales
- PINES 0-1 : (AMARILLO)terminales digitales E/S serie- tx(trasmision)/rx(recepcion)
- RESET: ( BLANCO) botón de reinicio
- ICSP: (AZUL OSCURO) programador en serie circuito
- ATMEGA 328-PU: (ROJO)micro controlador
- PINES 0-5: (GRIS OSCURO) TERMINALES DE ENTRADA ANALÓGICA
- PINES 3,3V, 5V, VIN : (ROSADO)TERMINALES DE ALIMENTACIÓN
Vin es el voltaje de entrada a la placa del Arduino cuando se está utilizando una fuente de alimentación externa.
- PIN RESET: (MARRÓN)SE PONE LOW PARA RESETEAR EL MICROCONTROLADOR UTILIZADA TIPICAMENTE PARA AÑADIR UN BOTÓN DE RESET
- ENTRADA DE ALIMENTACIÓN: (VERDE) ENTRADA DE ALIMENTACIÓN EXTERNA

- PIN IOREF: (VIOLETA)Este pin esta conectado al de 5V situado a su lado y sirve para indicarle a la shield el voltaje de funcionamiento de la placa Arduino


Una vez identificado nuestro arduino uno, ahora podemos establecer conexiones con los componentes que queremos trabajar, lo primero a ejercer seria aprender a controlar nuestros motorreductores a ciertas velocidades y la identificación de los sentidos de giros esto lo haremos con nuestro puente H L298N así mas adelante entenderemos los estados en los cuales deberemos coordinar para dar condiciones a nuestro seguidor de linea.

Para ello necesitarán el IDE de arduino (entorno de desarrollo integrado de Arduino)El  es una aplicación multiplataforma que está escrita en el lenguaje de programación Java. 

Aprenderemos  algunos comandos y estructuras aunque esto lo aprenderéis mas a fondo en el link que he dejado en un principio.
también podéis descargar otras aplicaciones mas cómodas y fáciles de usar como lo es mBlock,  pero en esta ocasión utilizaremos el IDE de arduino.

Una vez descargado el programa e instalado te aparecerá una ventana así.


Estructura de Programación
Por lo general un programa en Arduino constará de 3 partes:
  1. Declaración de variables.
  2. Función de inicialización. (setup)
  3. Función de Loop. (Programa)
Declaración de Variables
Las variables son expresiones que almacenan valores, como las capturas o lecturas de los valores de entrada de un pin analógico o sensor. das valor a una variable, haciéndola igual al valor que quieres almacenar. Colocadas al principio del código pueden ser utilizadas en todo el programa. esto lo utilizaremos en el código final de nuestro seguidor para crear banderas o puntos de control cuando empecemos a establecer condiciones.
Declaración de funciones
Las funciones te permiten crear piezas modulares de código, de forma que se puedan realizar ciertas rutinas y retornar al área de código desde donde se realizó la llamada a la función. Colocadas al principio del código pueden ser utilizadas en todo el programa.
Función de inicialización.
void setup() La función setup() es llamada justo en el momento en que el programa comienza. Se utiliza para inicializar variables, definir los modos de entrada o salida de los pines, indicar librerías, etc.
Función de Loop. (Programa)
void loop() Después de crear la sección setup(), que inicializa y asigna los valores iniciales, la sección loop() hace precisamente lo que su nombre indica en inglés(bucle), y se repite continuamente, permitiendo que tu programa mute y responda. Se usa para controlar de forma activa la tarjeta Arduino. El tiempo del bucle, varía según el número de instrucciones que contenga. Y se puede conocer y controlar con las funciones de temporización (millis(), delay(), etc).   
En void loop pondremos las condiciones que nos enviara los sensores y los estados de giros de los motores.

CONOCIENDO EL PUENTE H L298N
NO ES NECESARIO RETIRAR EL JUMPER REGULADOR A MENOS QUE TENGAS UNA ALIMENTACIÓN MAYOR A 12v

FUNCIONAMIENTO
Para que entiendas un poco de la función del puente H es que sus circuitos tienen una simetría parecida a la letra H de ahí viene su nombre, entonces que es lo hace? y como establecemos giros a nuestros motores?.

La respuesta esta en entender los estados de los controles de giro. este esquema nos da una lógica del funcionamiento.
Primer caso 
En el esquema identificamos a los controles de giro los cuales son:(IN1, IN2) que hacen parte de los controles del motor A y (IN3, IN4) que hacen parte de los controles del motor B.  aquí vemos que los interruptores no están conectados al circuito por lo tanto no habrá ningún movimiento.


Una vez sabiendo la lógica del puente H sabremos que hacer en el IDE de arduino luego les explico las funciones que utilizaremos.

Segundo caso:
Podemos entender lo que sucede en un giro en este caso un giro horario.

Aquí vemos que el interruptor IN1 se activo o sea se conecto al circuito y IN2 permanece apagado no se conecto al circuito(luego entenderán que es activo o apagado en el IDE de arduino) y el interruptor IN3 se apago, y el IN4 se activo; lo que entonces sucede es que el  motor A avanzara hacia un sentido(horario) y el motor B retrocederá  en ese sentido(horario) que es lo mismo que el motor B avance en sentido anti-horario.  En conclusión nuestro carrito girara en sentido horario sobre su mismo eje.


Tercer caso:
En este esquema verán que es la función contraria al segundo caso.

Entonces: vemos que IN1 esta apagado y IN2 esta activo; el Motor A retrocederá.
luego vemos que IN3 esta activo y IN4 esta apagado; el Motor B avanzara.

Concluyendo que el carrito girara en sentido anti-horario sobre su mismo eje.






Este sistema tiene un inconveniente: si se accionan contemporáneamente los dos interruptores de la izquierda  o los dos interruptores de la derecha se producirá un cortocircuito de la alimentación como podemos observar en la figura, por lo tanto es necesario evitar esta programación.



Cuarto caso.
Ahora veremos lo que es un avance para los motores:
Vemos IN1(ACTIVO) y in IN3(ACTIVO) por lo tanto acudiendo al anterior esquema, IN2 Y IN4 deberán estar apagados.
Como conclusión el robot entonces avanzaría.

Este caso haciéndolo al revés nos daría entonces que nuestro carrito retrocede.


NOTA: estos ejemplos de los casos son la manera simplificada de explicar la función de los puente H

Ya sabiendo la lógica del puente H podemos programar arduino no sin antes aclarar que para activar o apagar un interruptor  utilizamos valores ALTOS o BAJOS, estas palabras en ingles las conocemos como HIGH y LOW; en este sentido entonces decimos que un interruptor activado es: (HIGH) o sea un valor alto, y si queremos un interruptor apagado entonces lo escribimos como(LOW) o sea un valor bajo .

Programación L298N control de motores 

Primero tendremos que hacer las conexiones y por comodidad puedes ensamblar tu chasis o plataforma junto con los motores con sus respectivos cables y puedes colocar las llantas de goma o los encoders para observar mejor el sentido de giro.

Aquí es sumamente importante las conexiones de los moto reductores al puente H, puesto que los cables deben ir cruzados (como puedes apreciar en el esquema); esto pasa por lo que un motor es izquierdo y el otro es derecho. hacemos esto también para que se cumplan los casos que hemos aprendido anteriormente.
También procura que el puente H este en la posición que nosotros hemos establecido para el correcto funcionamiento de este código, es decir; la alimentación del motor A debe coincidir con el motor-reductor izquierdo y la alimentación del motor B debe conectarse con el motor-reductor derecho.
Si no lo quieres hacer así ten en cuenta la lógica en la programación.

Nota: recuerda colocar el GND de Arduino y el GND de las baterías en el GND del puente H, también recuerda la alimentación del arduino que basta por el momento la conexión usb con tu computadora.

Una vez hecho las indicaciones podemos programar.

PROGRAMACIÓN L298N: CONTROL DE DOS MOTOR-REDUCTORES  

Ahora puedes guiarte con esta programación, también puedes copiarla y pegarla

Como ya sabes la estructura del IDE de arduino, puedes programar libremente tu robot pero primero identifica los sentidos de giro.

Te explico brevemente los 4 variables y funciones que trabajaremos :

int: ENTERO; es un tipo de dato principal que nos almacena números

ESTRUCTURA:
 int nombre de la variable= el valor que asigna a esa variable.
Ejem;  
int ENA=10

pinMode: Configura el pin especificado para que se comporte como entrada (INPUT) o salida(OUTPUT)
Sintaxis:
pinMode(pin, mode)
Ejem; como ENA= 10 le hemos dado un valor numérico a una variable entonces podemos colocar en pin la variable ENA en vez de colocar el numero 10, luego en mode lo pondremos como salida ya que queremos enviarle comandos a ese pin. si fuese entrada es porque queremos recibir datos de ese pin.
pinMode(ENA,OUTPUT)

digitalWrite: Escriba un HIGH o un LOW como valor en un pin digital.
Sintaxis
digitalWrite(pin, valor)
ejem; como ENA=10 que le dimos como numero de pin digital entonces no es necesario escribir 10 si no, la variable ENA, entonces:
digitalWrite(ENA,HIGH) // activo 
digitalWrite(ENA,LOW) // APAGADO
Como ENA en el puente H es el control de velocidad entonces al ponerle HIGH que es un valor alto= 1; a ese pin se le enviara la máxima intensidad al motor, para regular esa velocidad entonces necesitaremos valores análogos, eso lo haremos mas adelante.
Si se le pone LOW que es un valor bajo= 0; entonces el motor se apagara por la falta de energía.
Esto lo hemos aprendido en los casos del puente H así que ahora sabemos como hacer esos casos en el IDE de arduino.

delay: Pausa el programa por la cantidad de tiempo (en milisegundos) especificado como parámetro. (Hay 1000 milisegundos en un segundo).

primer código
                                                                                                             
//esto te servirá para identificar los sentidos de giro, si! hiciste bien los pasos recomendados.
// este código hará que tu robot avance por 3 segundos y se detenga por 2 segundos, retroceda por 3
//segundos y se detenga por 2 segundos y se repita el ciclo ya que estas indicaciones estarán en void
//loop. si no sucede esto es porque conectaste los cables mal o la posición de tu puente H esta distinto

int IN1 = 9;    // la variable IN1 es el pin digital 9
int IN2 = 8;    // la variable IN2 es el pin digital 8
int ENA = 10; //la variable ENA es el pin digital 10
int IN3 = 7;     //la variable IN3 es el pin digital 7
int IN4 = 6;     //la variable IN2 es el pin digital 6
int ENB = 5;    //la variable ENA es el pin digital 5

void setup() {             // se inicializa solo una vez

 pinMode (IN1, OUTPUT);   // a todos los pines los queremos en salida puesto que estaremos
 pinMode (IN2, OUTPUT);   // enviando indicaciones a cada uno de ellos.
 pinMode (ENA, OUTPUT);
 pinMode (IN3, OUTPUT);
 pinMode (IN4, OUTPUT);
 pinMode (ENB, OUTPUT);
}

void loop() {                //se repite continuamente
 digitalWrite(ENA, HIGH);    // activamos ENA para enviar la máxima intensidad al motor izquierdo
                             //como IN1 y IN2 son los controles de giro del motor izquierdo entonces le daremos una indicación.
digitalWrite(IN1, HIGH);     // IN1 lo activaremos para girar en sentido horario
 digitalWrite(IN2, LOW);     // entonces IN2 deberá apagarse para no crear cortocircuito como entendimos anteriormente.
digitalWrite(ENB, HIGH);    // aquí haremos lo mismo, activamos ENB, el motor derecho

 digitalWrite(IN3, HIGH);    //IN3 lo activamos para girar en sentido horario
 digitalWrite(IN4, LOW);     //apagamos IN4 para no tener dos interruptores conectados al circuito del motor derecho.
                           
 delay(3000);               //demora 3 segundo. lo que hicimos fue el caso 4 del puente H los dos motores irán en sentido horario lo cual es lo mismo que el carro avanza hacia adelante.

                           //ahora apagaremos los dos motores por dos segundos.
 digitalWrite(ENA, LOW);   //simplemente cogemos el pin de velocidad en valores bajos
 digitalWrite(ENB, LOW);   //ENA Y ENB EN LOW los dos motores se apagan

 delay(2000);              //2 segundos duran apagados los dos motores
                           //ahora queremos indicar lo contrario del caso 4, en vez de que avancen los dos motores; retrocedan por 3 segundos
 digitalWrite(ENA, HIGH);  // siempre activamos ENA para realizar un sentido de giro
                           // EL SENTIDO DE GIRO NOS LO DA IN1 Y IN2
 digitalWrite(IN1, LOW);   // apagamos ahora IN1
 digitalWrite(IN2, HIGH);  //activamos IN2 PUEDEN VER QUE ES LO CONTRARIO AL AVANCE
 digitalWrite(ENB, HIGH);  //hacemos lo mismo en el motor derecho; activamos la velocidad máxima
 digitalWrite(IN3, LOW);   //apagamos IN3
 digitalWrite(IN4, HIGH);  //activamos IN4

 delay(3000);    // durara 3 segundos retrocediendo

                    //nuevamente apagamos los motores por dos segundos basta con copiar el codigo que los apaga.
 digitalWrite(ENA, LOW);
 digitalWrite(ENB, LOW);
 delay(2000);

}  
                                                                                                                                                                   

Fin del primer código puedes copiar y pegarlo  si tus ruedas hacen la lógica de la programación puedes continuar con lo siguiente.

EJERCICIO:
Intenta hacer girar solo una rueda? e.e 


PROGRAMACIÓN L298N: VELOCIDAD DE LOS MOTOR-REDUCTORES  

Ahora entenderemos como regular la velocidad o intensidad de los motores, si pudiste lograr el ejercicio 1 entonces estas preparado para lo que haremos a continuación.

Puedes ver que en este codigo hay 2 funciones nuevas lo demás ya lo conoces en el primer codigo.

Estas 2 funciones son:

for(){}  for es una estructura de control, se usa para repetir un bloque de declaraciones encerradas entre llaves. Un contador de incremento se usa generalmente para incrementar y terminar el ciclo. for es útil para cualquier operación repetitiva, y a menudo se usa en combinación con matrices para operar en colecciones de datos / pines.

Sintaxis

for (initialization; condition; increment) {
  // statement(s);
}Parámetros
initialization: sucede primero y exactamente una vez. condition: cada vez a través del bucle, condition se prueba; si es así true
el bloque de instrucción y el incremento se ejecuta, entonces la condición 
se prueba nuevamente. Cuando la condición se vuelve false
el ciclo termina. increment: ejecutado cada vez a través del ciclo 
cuando condition es true.
Código de ejemplo
// Atenúa un LED con un pin PWM
int PWMpin = 10;  // LED en serie con resistencia de 470 ohmios en el pin 10

void setup() {
  // no se necesita setup
}

void loop() {
  for (int i = 0; i <= 255; i++) {   
    analogWrite(PWMpin, i);
    delay(10);
  }
}

analogWrite; infórmate mas sobre esta función.
este codigo es la clave para nosotros dar valores de intensidad o sea en ves de escribir HIGH o LOW que son las condiciones de digitalWrite. Ahora podemos escribir valores  entre 0 (siempre apagado) y 255 (siempre encendido). 
En este caso aprendemos dos cosas a la vez tu si quieres puedes hacerlo sin el for y también te servirá solo debes poner valores entre 0 y 255, nosotros haremos lo mismo pero dando valores a una variable que no se pase de esta regla. entonces con la función analogWrite de escribir valores y aplicando el ejemplo de la estructura de control for y nombrando una variable con int VELOCIDAD; entonces VELOCIDAD al tener un valor numérico y una condición lo pondremos en el valor de un motor en este caso el motor A  

ES DECIR:
       valor inicial de velocidad = 0       //incremento de VELOCIDAD+10
for(VELOCIDAD=0; VELOCIDAD<256; VELOCIDAD=VELOCIDAD+10)
                               //condición de la velocidad no se pasara de 255
{
 analogWrite(ENA, VELOCIDAD); //en vez de un numero ponemos la variable VELOCIDAD
 digitalWrite(IN1,HIGH);    //sentido de giro avance..
 digitalWrite(IN2, LOW);    

 delay(30);    //
duración de bucle al pasar 30 (ms) se sumara 10 de intensidad 

}                           
Nota: esto es una explicación breve de lo que se hará en el segundo codigo, también es claro decir que lo motores necesitan cierta energía o intensidad para apreciar movimiento por lo general los moto reductores DC empiezan a avanzar en 85 ejemplo: analogWrite(ENA,85);  entonces si la intensidad es mas baja que 85  los motores no avanzaran y pitaran.

Segundo codigo
                                                                                                                                                                   
//en este segundo codigo haremos que nuestro carrito incremente su velocidad; lo primero que hará 
//es incrementar gradualmente el motor izquierdo o motor A hacia adelante, luego se detendrá al 
//llegar a su máxima velocidad durante un tiempo, después el motor A retrocede con un incremento 
//gradual y después se apagara,  luego el motor derecho o motor B hará el mismo procedimiento que 
//hizo el motor A, después los dos motores avanzaran incrementando su velocidad se apagaran y 
//finalmente ambos motores retrocedan y se apagan, y se vuelve a repetir void loop(){}
int IN1 = 9;                 //nombramos a todos nuestros pines
int IN2 = 8;
int ENA = 10;
int IN3 = 7;
int IN4 = 6;
int ENB = 5;
int VELOCIDAD;      //nombramos esta variable sin un valor numérico

void setup() {


 pinMode (IN1, OUTPUT);     //todos serán salidas como ya sabemos
 pinMode (IN2, OUTPUT);
 pinMode (ENA, OUTPUT);
 pinMode (IN3, OUTPUT);
 pinMode (IN4, OUTPUT);
 pinMode (ENB, OUTPUT);
 }
void loop() {  //se abre corchete de loop
 for(VELOCIDAD = 0; VELOCIDAD < 256; VELOCIDAD++)
{  
 analogWrite(ENA, VELOCIDAD);    //así es como funciona un giro hacia la derecha
 digitalWrite(IN1,HIGH);                    //los controles de giro indican avance
 digitalWrite(IN2, LOW);                    
         //al no activar el motor B pues se quedara apagado y solo funcionara el motor A  delay(30);
 // esta primera declaración hace que cada 30(ms) se sume la VELOCIDAD en 1 cuando esta
//velocidad llegue a ser mayor a 85 el sentido de giro es de avance.
  }

 digitalWrite(ENA, LOW);

 delay(500);           // se apaga el motor izquierdo

for(VELOCIDAD = 0; VELOCIDAD < 256; VELOCIDAD++)
{
 analogWrite(ENA, VELOCIDAD);    //
 digitalWrite(IN1,LOW);         //retroceso
 digitalWrite(IN2, HIGH);

 delay(30);

//esta segunda declaración tiene semejanza con el primero solo que cambia su sentido de giro.
  }

 digitalWrite(ENA, LOW);

 delay(500);                             //lo apagamos por 500(ms)

for(VELOCIDAD = 0; VELOCIDAD < 256; 
VELOCIDAD++){
 analogWrite(ENB, VELOCIDAD);
 digitalWrite(IN3,HIGH);
 digitalWrite(IN4, LOW);

 delay(30);

  //  la tercera declaración es lo mismo que la primera solo que para el motor B
  }
digitalWrite(ENB, LOW);
 delay(500);        //apagamos el motor B por ese tiempo.

 for(VELOCIDAD = 0; VELOCIDAD < 256; 
VELOCIDAD++){
 analogWrite(ENB, VELOCIDAD);
 digitalWrite(IN3,LOW);
 digitalWrite(IN4, HIGH);

 delay(30);

//la cuarta declaración es lo mismo que la segunda solo que para el motor B
  }

 digitalWrite(ENB, LOW);

 delay(500);           //apagamos el motor B

for(VELOCIDAD = 0; VELOCIDAD < 256; 
VELOCIDAD=VELOCIDAD+10)
{
 analogWrite(ENA, VELOCIDAD);   //se activa el motor A
 digitalWrite(IN1,HIGH);                    //sentido de giro avance 
 digitalWrite(IN2, LOW);
 analogWrite(ENB, VELOCIDAD);   //se activa el motor B
 digitalWrite(IN3,HIGH);                    //sentido de giro avance
 digitalWrite(IN4, LOW);

 delay(30);

//  los dos motores avanzan con un incremento de 10 cada 30 (ms)

  }

 digitalWrite(ENA, LOW);   //apagamos el motor A

 digitalWrite(ENB, LOW);   //apagamos el motor B
 delay(500);               // por 500 (ms)

 for(VELOCIDAD = 0; VELOCIDAD < 256; 
VELOCIDAD=VELOCIDAD+10){
 analogWrite(ENA, VELOCIDAD);  //activamos el motor A
 digitalWrite(IN1,LOW);                    
 digitalWrite(IN2, HIGH);                    //sentido de giro retroceso
 analogWrite(ENB, VELOCIDAD);  //activamos el motor B
 digitalWrite(IN3,LOW);                    
 digitalWrite(IN4, HIGH);                 //sentido de giro retroceso

 delay(30);  


//por cada 30 ms se incrementa 10 de intensidad

  }
 digitalWrite(ENA, LOW);     //apagamos el motor A
 digitalWrite(ENB, LOW);     //apagamos el motor B
 delay(500);   //por 500 (ms) o medio segundo

}// se cierra corchete de loop

//fin del segundo codigo

                                                                                                                                                                   

Ejercicio 2: programa al robot para que haga los siguientes movimientos. 












CONCLUSIÓN DEL CONTROL DEL PUENTE H


NOTA: para desactivar un motor basta con no ponerlo en la programación.



CONOCIENDO SENSORES TCRT5000
Es un sensor que emite luz infrarroja, mediante un fotodiodo, que es reflejada por una superficie y captada por un fototransistor. El fototransistor es sensible a la luz recibida y genera una corriente en función dicha cantidad de luz que se transforma en voltaje eléctrico.

Como ya sabes utilizaremos estos sensores como antenas para que siga una linea.  un par de estos módulos de luz son suficientes para el proyecto.
tiene 4 conexiones:
  • VCC: Alimentación. Conectar a los pines de +5V.
  • GND: Masa. Conectar a los pines 0V (GND).
  • DO: Salida digital. Se puede conectar a los pines digitales de Arduino
  • AO: Salida analógica. Conectar a pines analógicos de Arduino.

El nivel de señal analógica que proporciona el sensor dependerá por tanto de la cantidad de luz recibidaEsto puede depender de múltiples factores como la distancia de reflexión (distancia a la que se coloca el sensor con respecto a la superficie); el color de la superficie y la cantidad de luz infrarroja en el ambiente (dispone de un filtro para eliminar los efectos de la luz ambiental y de día, pero su uso en entornos exteriores está totalmente desaconsejado). Este tipo de sensores pueden utilizarse con diversos propósitos como la detección de objetos (presencia o no presencia) como un contacto de proximidad, ya que disponen de un corto alcance (máximo unos 15mm). En robótica, su principal utilidad es en aplicaciones del tipo seguilíneas en la que el sensor devolverá un valor distinto de función del color del suelo. Por ejemplo, si el suelo es de color negro el nivel de reflexión es muy bajo y el sensor devuelve un valor de señal elevado (lógica contraria). Si por el contrario el fondo del suelo es de color blanco el sensor apenas devuelve señal.

El módulo dispone además de un comparador analógico que lo que permite es establecer con un potenciómetro el nivel de referencia (de señal analógica) que queremos y por encima de ese nivel activará una señal digital, mientras que cuando esté por debajo de ese nivel la señal estará desactivada. Esto tiene sobretodo utilidad para su uso como contacto de proximidad. 

Esquema eléctrico 

Puedes profundizar la funcionalidad de los sensores en esta pagina web.
PROGRAMACIÓN TCRT5000  CONTROL
Que es lo primero que haremos para aprender a usar nuestros sensores, vamos hacer que estos nos den valores digitales o sea unos y ceros.
Como saben la lógica de los sensores; que cuando un sensor esta en zona negra o lejos de un objeto el fototransistor le llegará poca cantidad de luz puesto que el color negro absorbe la luz o bien como no hay objeto cerca que hagan rebotar los diodos entonces le llegará muy poca cantidad de luz, al pasar esto hay una lógica contraria que cuando no hay luz nos enviará niveles analógicos muy altos, entonces cuando hay mucha luz; los sensores pueden estar en zona blanca por lo tanto basándonos en la lógica contraria nos enviará niveles analógicos muy bajos.

Con esta analogía podemos predecir que valores digitales o sea en unos y ceros nos estará llegando cuando el sensor este en zonas negras o blancas.

Conclusión de valores digitales.
En zona negra: niveles de señal muy altos, es decir; (HIGH) =  1
En zona blanca: niveles de señal muy bajos, es decir; (LOW) = 0

Claves para entender el primer codigo

 Este primer codigo nos confirmara la conclusión anterior. 

Las nuevas funciones las explicare brevemente antes de iniciar el codigo:

const  la palabra clave significa constante. Es un calificador de variable que modifica el comportamiento de la variable, convirtiendo una variable en " solo lectura ". Esto significa que la variable se puede usar como cualquier otra variable de su tipo, pero su valor no se puede cambiar. Obtendrá un error de compilación si intenta asignar un valor a una const variable.
Las constantes definidas con la const palabra clave obedecen las reglas de alcance de variables que rigen otras variables. Esto, y las dificultades del uso #define, hacen que la const palabra clave sea un método superior para definir constantes y se prefiere sobre el uso #define.
FUNCIONES DE SERIAL 
Serial Se utiliza para la comunicación entre la placa Arduino y una computadora u otros dispositivos. Todas las placas Arduino tienen al menos un puerto serie (también conocido como UART o USART), y algunas tienen varias. 
En Uno, Nano, Mini y Mega, los pines 0 y 1 se utilizan para comunicarse con la computadora. Conectar cualquier cosa a estos pines puede interferir con esa comunicación, incluso causar cargas fallidas a la placa.
Puede utilizar el monitor serie incorporado del entorno Arduino para comunicarse con una placa Arduino. Haga clic en el botón del monitor en serie en la barra de herramientas y seleccione la misma velocidad en baudios utilizada en la llamada a begin().  
           
Serial.begin    Establece la velocidad de datos en bits por segundo (baudios) para la transmisión de datos en serie. Para comunicarse con Serial Monitor, asegúrese de usar una de las velocidades en baudios enumeradas en el menú en la esquina inferior derecha de su pantalla. Sin embargo, puede especificar otras velocidades, por ejemplo, para comunicarse a través de los pines 0 y 1 con un componente que requiere una velocidad de transmisión particular. 

Sintaxis
Serial.begin(speed)

ejemplo:
Serial.begin(9600)

Serial.print: Imprime datos en el puerto serie como texto ASCII legible para humanos. Este comando puede tomar muchas formas. Los números se imprimen utilizando un carácter ASCII para cada dígito. Los flotadores se imprimen de manera similar como dígitos ASCII, por defecto con dos decimales. Los bytes se envían como un solo carácter. Los caracteres y las cadenas se envían tal cual. Por ejemplo-
  • Serial.print(97) da "97"
  • Serial.print(1.23456) da "1.23"
  • Serial.print('P') da "P"
  • Serial.print("hola mundo") da "Hola mundo".
    
Serial.println  : Este comando toma las mismas formas que Serial.print () .
Lo distinto es que imprime las variables en una nueva linea.

Esquema de dos sensores 



Primer codigo

                                                                                                                                                                   
//este codigo nos dice valores digitales de los sensores
int sensorD = A0;    //nombramos a un pin análogo sensorD
int lecturaD = 0;      //variable de lectura del sensor derecho

int sensorI = A1;     //nombramos a otro pin análogo sensorI
int lecturaI = 0;        //variable de lectura del sensor izquierda
void setup() {
Serial.begin(9600);   //abrimos el puerto serial en 9600 bps
pinMode(A0, INPUT);  //ponemos de entrada a los pines A0 y A1 puesto que queremos que ambos
pinMode(A1, INPUT);  //nos envíen datos desde las señales de los dos sensores.

}
void loop() {
  //lectura de sensores IR
  lecturaD = digitalRead(sensorD);  //declaramos la igualdad de la lecturaD con los valores digitales //que nos lea el sensor derecho
  lecturaI = digitalRead(sensorI);    //declaramos la igualdad de la lecturaI con los valores digitales //que nos lea el sensor izquierdo

  // impresion de sensores IR
   Serial.print("Sensor IZQUIERDO : ");  //imprimimos en una linea la frase indicada
   Serial.print(lecturaI);      // en seguida de la frase, nos escribe la lectura del sensor izquierdo
 
   Serial.print(" Sensor DERECHO : ");   //imprimimos en la misma linea la frase indicada
   Serial.println(lecturaD);   //al lado de lo anterior se escribe la lectura del sensor derecho
       //pero println nos crea una nueva linea en monitor serial haciendo que la impresión de los         
       //sensores IR se escriba verticalmente
   delay(5000);  //tiempo de lectura de 5 segundos

}
                                                                                                                                                  

CON LA ANTERIOR PROGRAMACIÓN COMPROBAMOS LO ANTERIOR DICHO, ENTONCES:

NEGRO=1
BLANCO=0
SEGUIDOR DE LINEA 

Ya casi damos por terminado esta primera parte del seguidor de linea. que configuración vamos a indicarle a nuestros motores cuando los sensores o "antenas" nos envíen señales o cambios de estado, para entenderlo brevemente indicare los estados posibles que nos envía los sensores y sus respectivas acciones para el modelo de seguidor de linea que nos permita avanzar en una zona blanca 
                   
ES DECIR EL ROBOT SEGUIRÁ EN LA ZONA BLANCA Y CUANDO DETECTE LA NEGRA RETORNARA NUEVAMENTE A LA ZONA BLANCA.  

ejemplo de esta versión de seguidor de linea:
Nota: con ayuda de este codigo brevemente podrás hacer que tu seguidor de linea avance en una linea negra y que no salga de esta solo es cuestión de lógica. 

Con esas condiciones que hemos hecho podemos hacer 

Esquema del seguidor de linea



Codigo del seguidor de linea
En este codigo no explicare todo puesto que la mayoría de los comandos son los mismos a los anteriores programaciones lo único distinto son algunos comparadores y algunas variables que utilizaremos como banderas o puntos de control para identificar los cambios de estado que nos envía nuestros sensores, es decir que solo explicaremos

if [Estructura de control]
Descripción
la declaración verifica si hay una condición y ejecuta la declaración o el conjunto de declaraciones si la condición es 'verdadera'.
Sintaxis
if (condition) {
  //statement(s)
}Parámetros
condition: es una expresión booleana (es decir, puede ser true false).

else [Estructura de control]
Descripción
El if…​else permite un mayor control sobre el flujo de código que el básico if de declaración, al permitir múltiples pruebas para agruparse. else ejecutará una cláusula (si es que existe) si if produce la condición en la declaración falseelse puede proceder con otra if prueba, de modo que se puedan ejecutar múltiples pruebas mutuamente excluyentes al mismo tiempo.
Cada prueba procederá a la siguiente hasta que se encuentre una prueba verdadera. Cuando se encuentra una prueba verdadera, se ejecuta su bloque de código asociado y el programa salta a la línea que sigue a toda la construcción if / elseSi ninguna prueba resulta ser verdadera, el else bloque predeterminado se ejecuta, si hay uno presente, y establece el comportamiento predeterminado.
Tenga en cuenta que un else if en un bloque puede usarse con o sin un else en el bloque de terminación y viceversa. Si else if permite un número ilimitado de tales sucursales.

Sintaxis

if (condition1) {
  // se hace la cosa A
}
else if (condition2) {
  // se hace la cosa B
}
else {
  // se hace la cosa C
}Código de ejemplo   
A continuación se muestra un extracto de un código para el sistema
de sensor de temperatura
if (temperature >= 70) {
  // ¡Peligro! Apaga el sistema.
}
else if (temperature >= 60) { // 60 <= temperature < 70
  // ¡Advertencia! Se requiere atención del usuario.
}
else { // temperature < 60
  // ¡Seguro! Continuar las tareas habituales.
}

&&  (doble ampersand) es un operador booleano
Descripción
La lógica Y true solo se produce si ambos operandos son true.

Código de ejemplo
Este operador se puede usar dentro de la condición de una instrucción if .
if (digitalRead(2) == HIGH && digitalRead(3) == HIGH) { si AMBOS interruptores dicen ALTO
   // declaraciones      // es decir si la primera condición se cumple y la otra condición se cumple se realiza la declaración que pongamos.
}
 : [Operadores booleanos]

Descripción

El resultado lógico NO es  VERDADERO si el operando es FALSO y viceversa.

Código de ejemplo

Este operador se puede usar dentro de la condición de una instrucción if .
if (!x) { // SI X NO ES VERDADERO
  // DECLARACIONES
}
Se puede usar para invertir el valor booleano.
x = !y; // el valor invertido de y se almacena en x


El principal problema para el control del seguidor de linea son las curvas ya que los motores necesitan una cantidad de energía minina para poder realizar movimiento, este movimiento no lo hace eficaz en las curvas puesto que este se saldría de la linea o la zona o bien la velocidad no es suficiente para mover el peso del robot.

La solución que nosotros hemos dado para este problema es hacer un sistema de control en los giros que nos permita un movimiento que puede ser progresivo o bien por intervalos de arranque y retroceso.
para entender esto y no extendernos mas con explicaciones en este blog

Pongamos de ejemplo que pasaría entonces en un giro izquierda

Viendo la tabla de condiciones; me indica que un giro izquierda, se debe apagar el motor izquierdo y se activa el motor derecho a una velocidad, entonces para que podamos girar suavemente bajo cierta velocidad de avance debemos hacer un freno en el mismo motor derecho, para que este de las curvas lentamente.
 A la hora de dar respuesta a los motores en ese freno, la mejor opción es retrocediendo ese motor derecho que estamos haciendo por intervalos para provocar un giro izquierda suave.
 La clave es que ese retroceso sea menor al del arranque así poder apreciar mas el movimiento hacia adelante.

A que me refiero con intervalo:  el motor derecho avanzara y se detendrá repetitiva mente hasta no necesitar mas el giro.
es decir que el carrito girara hacia la izquierda con intervalos de detenimiento.

Después de lograr el giro con intervalos de detenimiento vamos a tener que poner otra condición de avance justo después que termine el giro es decir: cuando el seguidor linea girá hacia un sentido, se active automáticamente en otra condición que permita el avance. 

Por ultimo hacemos la condición que nos permita que el sistema reconozca el avance (o sea en blanco) cuando los sensores anteriormente estaban en negro (o sea en retroceso),  es decir; cuando los sensores estén en negro o bien distanciados del suelo u objeto se active automáticamente la condición que permita avance cuando los sensores detecten zona blanca.

Se debe tener en cuenta la tabla de condiciones del seguidor de linea en zona blanca para entender las 4 condiciones con sus respectivos casos o estados.  La volveré a poner para que la tengas mas cerca:
NEGRO=1

BLANCO=0
                                                                                                                                                                   
//codigo básico  para seguidor de linea blanca
//
//
int sensorD = A1;     //A1 es el sensor derecho
int sensorI = A0;       //A0 es el sensor izquierdo

const int IN1 = 13;    //pines del motor izquierdo
const int IN2 = 12;  
const int ENA = 9;

const int IN3 = 11;    //pines del motor derecho
const int IN4 = 10;  
const int ENB = 5;

int a=0;     //bandera con igualdad 0
int b=1;     //bandera con igualdad 1
int vel;       //variable 

void setup (){    //se inicia solo una vez
  pinMode (IN1, OUTPUT);   //todos los pines de los dos motores en salidas
  pinMode (IN2, OUTPUT);
  pinMode (IN3, OUTPUT);
  pinMode (IN4, OUTPUT);
  pinMode (ENA, OUTPUT);
  pinMode (ENB, OUTPUT);
  pinMode( A0, INPUT);         // los dos sensores en entradas
  pinMode( A1, INPUT);
 
  Serial. begin(9600);    //abrimos el puerto serial en 9600 bps

// al inicializar el robot dura apagado un segundo
//motor izquierdo
//se para el motor izquierdo  digitalWrite (IN1, LOW);    
  digitalWrite (IN2, LOW);
  digitalWrite (ENA, LOW);

  // Motor derecho
  // Se para el motor derecho
  digitalWrite (IN3, LOW);
  digitalWrite (IN4, LOW);
  digitalWrite (ENB, LOW);
  delay(1000);
  
}

void loop(){    // todas las condiciones y los estados estarán en loop
///////////////////// sabemos que NEGRO es = 1 y BLANCO es = 0
//este primer if controlara todo nuestro sistema de control, a partir de los diferentes estados o casos
//que vamos a tener respecto al posicionamiento del seguidor de linea
//para esta versión vamos a utilizar las compuertas dobles ampersand
//en esta función lo que esta haciendo es realmente preguntar si ambos sensores están en 1
//se va a leer el  sensorD y la lectura del sensorI 
if(digitalRead(A1) && digitalRead(A0))   //si los dos sensores están NEGRO == 1   (1 == 1)
//entonces retrocedemos el seguidor de linea
{
  // Motor izquierdo
  // Al mantener un pin LOW y el otro HIGH el motor izquierdo retrocede
  digitalWrite (IN1, LOW);
  digitalWrite (IN2, HIGH);
  analogWrite (ENA, 120); //Velocidad motor A  
  // Motor derecho
  // Al mantener un pin LOW y el otro HIGH el motor derecho retrocede
  digitalWrite (IN3, LOW);
  digitalWrite (IN4, HIGH);
  analogWrite (ENB, 120); //Velocidad motor B  
  delay(150);    //retrocede 150 ms 
    
a=0;   //se activa la bandera o punto de control   a=0  por primera vez
}
else if(!digitalRead(A1) && digitalRead(A0))     (1  ,   0)
    //si el sensor derecho  es diferente de la señal del sensor izquierdo se declara lo siguiente
{
  a=1; se activa bandera de giro izquierda
   //giro izquierda con intervalo de detenimiento
// para hacer un giro lento se pueden hacer de varias maneras esta es una forma:
  //el motor izquierdo se apaga
  digitalWrite (IN1, LOW);
  digitalWrite (IN2, LOW);   
  analogWrite (ENA, 0); //Velocidad motor A 
  // el motor derecho se activa hacia adelante con 210 de velocidad
  digitalWrite (IN3, HIGH);   
  digitalWrite (IN4, LOW);   
  analogWrite (ENB, 210);
  delay (15);   // cada 15 ms

  //stop o freno vemos que el motor B tiene la configuración de retroceso, pero su velocidad es menor
// al arranque hacia adelante igual que el intervalo de tiempo.
  //el motor izquierdo se mantiene apagado
 digitalWrite (IN1, LOW);
  digitalWrite (IN2, LOW);
  analogWrite (ENA, 0);          
  //el motor derecho se activa hacia atrás con 150 de velocidad
digitalWrite (IN3, LOW);
  digitalWrite (IN4, HIGH);
  analogWrite (ENB, 150);
  delay(12);   // cada 12 ms
}
else if(digitalRead(A1) && !digitalRead(A0))    (0  ,   1)
          //esta condición es la contraria de la anterior 
{          
 a=1;   //se activa bandera de giro derecha 
   //giro derecha
   //  Motor izquierdo
  // Se activa el motor izquierdo
  digitalWrite (IN1, HIGH);
  digitalWrite (IN2, LOW);
  analogWrite (ENA, 220); //Velocidad motor A 
//se apaga el motor derecho
  digitalWrite (IN3, LOW);
  digitalWrite (IN4, LOW);
  analogWrite (ENB, 0);

delay (15);  cada 15 ms

     //stop 
// se activa el motor izquierdo hacia atrás en 150 de velocidad
  digitalWrite (IN1, LOW);
  digitalWrite (IN2, HIGH);
  analogWrite (ENA, 150);
  //se mantiene apagado el motor derecho
  digitalWrite (IN3, LOW);
  digitalWrite (IN4, LOW);
  analogWrite (ENB, 0);

  delay(12); cada 12 ms

}
else  //los sensores no están en negro
{
  b=1;   //si no suceden los 3 anteriores casos entonces se activa b=1
            
}
//esta es la condición que nos permitirá un avance justo después que suceda un sentido de giro
if(a==1 && b==1) //es decir, cuando se termine el giro sea izquierda o derecha se detecte que los dos
//sensores están en blanco o sea en b=1 indicaremos que el robot avanzara después de un giro si
//detecta la zona blanca.
{
  a=0;  desactivamos la bandera a
  b=0; desactivamos la bandera b
//las desactivamos para que en la próxima condición se identifique el cambio de los sensores después de detectar negro
 // EL ROBOT AVANZA CUANDO ESTE EN ZONA BLANCA
   // Motor izquierdo
  // Al mantener un pin HIGH y el otro LOW el motor AVANZA
  digitalWrite (IN1, HIGH);
  digitalWrite (IN2, LOW);
  analogWrite (ENA, 100); //Velocidad motor A
  // Motor derecho
  // Al mantener un pin HIGH y el otro LOW el motor AVANZA
  digitalWrite (IN3, HIGH);
  digitalWrite (IN4, LOW);
  analogWrite (ENB, 100); 
  delay(1);   // cada ms responderá los motores hacia adelante cuando tenga pista en blanco esto le //permitirá mayor reacción a la hora a la hora de tener un cambio de estado o de giro.

}
// esta es la condición final que nos permitirá que cuando el seguidor de linea este en negro y pase a
//blanco identifique el cambio y avance 
if(b==1 && a==0)  //PUEDES VERLO PARA HACER UN AVANCE RÁPIDO O UN AVANCE
//CON DETENIMIENTO LO CONFIGURAS EN LA SEGUNDA RUTINA O BLOQUE  DE ESTA
//CONDICIÓN.
{

//esta primer rutina activa la bandera por segunda vez a=0  lo que pasa es que este rutina de 100 ms
//hacia adelante de 100 velocidad se restara con la primera bandera a=0 (retroceso)dando una
//resultante cuando los sensores estén en negro.
  // Motor izquierdo
  // Al mantener un pin HIGH y el otro LOW el motor AVANZA
  digitalWrite (IN1, HIGH);
  digitalWrite (IN2, LOW);
  analogWrite (ENA, 100); //Velocidad motor A
  // Motor derecho
  // Al mantener un pin HIGH y el otro LOW el motor avanza
  digitalWrite (IN3, HIGH);
  digitalWrite (IN4, LOW);
  analogWrite (ENB, 100); 
  delay(100);

//RUTINA NOS SIRVE PARA SUMAR O RESTAR LA VELOCIDAD DEL AVANCE DE LA
//ANTERIOR CONDICIÓN ES DECIR CUANDO LOS SENSORES ESTÁN EN BLANCO
//PUEDES CONFIGURAR LO A TU ANTOJO AQUÍ LE SUMAREMOS LA VELOCIDAD Y EL
//TIEMPO.
   // Motor izquierdo
  // Al mantener un pin HIGH y el otro LOW el motor AVANZA
  digitalWrite (IN1, HIGH);
  digitalWrite (IN2, LOW);
  digitalWrite (ENA, 120);
  // Motor derecho
  //  Al mantener un pin HIGH y el otro LOW el motor avanza
  digitalWrite (IN3, HIGH);
  digitalWrite (IN4, LOW);
  digitalWrite (ENB, 120);
  delay(10);
}
}
                                                                                                                                                                   

☺️

Hasta aquí damos por finalizado este proyecto. Espero haberles podido ayudar pueden comentar si tienen dudas o contactarme.




2 comentarios:

Unknown dijo...

Excelente iniciativa!

Andres Carvajal dijo...

Muchas gracias, Haré otra página web, y explicaré mejor el proyecto.

COMO HACER UN SEGUIDOR DE LINEA

INTRODUCCIÓN Como hacer un seguidor de linea de manera sencilla empezando desde cero. Utilizaremos sensores infrarrojos (TCRT5000) c...