Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Robot seguidor de línea - Control PID - Configuración de Android

Componentes y suministros

Arduino Nano R3
× 1
Sensor SparkFun RedBot - Seguidor de línea
× 1
Módulo de sensor de seguimiento de línea infrarrojo TCRT5000 4CH
× 1
dispositivo Android
× 1
portapilas 4xAA
× 2
Servo de rotación continua RobotGeek
× 2

Aplicaciones y servicios en línea

Arduino IDE
MIT App Inventor 2

Acerca de este proyecto

El propósito de este proyecto es construir un robot seguidor de línea con control PID. También usaremos un dispositivo Android para configurar fácilmente los principales parámetros de control para una mejor y más rápida sintonización.

Este proyecto es el primero de un proyecto más complejo de 2 partes donde mi intención es explorar la potencialidad de Line Follower Robots. En la 2ª parte:Maze Solver Robot, utilizando Inteligencia Artificial con Arduino, el robot explorará y resolverá Laberintos, utilizando técnicas sencillas de inteligencia artificial.

A continuación se muestra un video que muestra al robot siguiendo un circuito de línea:

Paso 1:lista de materiales

La lista de materiales necesarios es muy simple y el robot final es muy barato (alrededor de $ 75.00):

Cuerpo (se puede adaptar a sus necesidades):

  • 2 cuadrados de madera (80X80 mm)
  • 3 clips de carpeta
  • 2 ruedas de madera (diámetro:50 mm)
  • 1 lanzador de bolas
  • 9 bandas elásticas
  • Tira de marco de comando de 3M
  • Juntas de plástico para fijar el sensor
  • BreadBoard y cableado
  • 2 juegos de baterías de hidruro metálico 4XNi (5 V cada juego)
  • 2 X SM-S4303R Servo de plástico de 360 ​​grados de rotación continua
  • Arduino Nano
  • Módulo Bluetooth HC-06
  • 5 sensores de línea X (módulo de sensor de seguimiento de seguimiento de línea infrarrojo TCRT5000 4CH + 1 sensor de seguimiento independiente)
  • 1 LED
  • 1 botón

Paso 2:Configuración de los motores

Para los motores, se utilizaron 2 servos continuos (SM-S4303R). Se "pegarán" entre sí formando un bloque simple y sólido como puede ver en la foto (use la tira de comando de 3M, pegamento o cinta adhesiva de doble cara). Esos servos funcionarán a una velocidad determinada, definida por el ancho de pulso recibido en su entrada de datos. Para este servo específico, el ancho de pulso va de 1.0ms (1,000 microsegundos) a 2.0ms (2,000 microsegundos). Otros servos pueden funcionar con diferentes anchos de pulso.

Mirando en detalles:

  • Un pulso de 1.5ms colocará el servo en posición neutra o "detenido".
  • Un pulso de 1.0ms mandará al servo a la máxima velocidad (alrededor de 70 RPM) en una dirección
  • Un pulso de 2,0 ms a máxima velocidad en la dirección opuesta.
  • Pulso entre 1.0 y 1.5ms o 1.5ms y 2.0ms, generará una velocidad proporcional.

Una vez que tenga ambos servos conectados físicamente, siga el circuito de dibujo anterior para generarlos (5V o 6V externos) y aliméntelos con la señal de Arduino:

  • Servo izquierdo:Pin 5 de Arduino
  • Servo derecho:Pin 3 de Arduino

Una vez todos conectados, lo primero que se debe hacer es enviar un pulso de 1.5ms para verificar si los motores están "parados" (no en marcha). De lo contrario, los servos deben ajustarse hasta el punto muerto (busque el perno amarillo, debajo del servo).

NOTA :Si su servo no tiene este ajuste físico, intente cambiar el parámetro "1500" microsegundos dentro de la función (arriba o abajo) hasta que llegue al punto final.

El siguiente código de Arduino puede hacer el trabajo:

  #include  // Servo biblioteca Servo leftServo; Servo rightServo; Void setup () {leftServo.attach (5); rightServo.attach (3); leftServo.writeMicroseconds (1500); rightServo.writeMicroseconds (1500);} bucle vacío () {}  

Paso 3:Ensamble el cuerpo y los motores para la prueba de movimiento

  • Con la tira del marco de comando de 3M, fije los 2 Servos al de la pieza de madera cuadrada.
  • Fije la segunda madera escuadrada a la de arriba usando los clips de encuadernación. Ajuste la longitud de la plataforma a sus necesidades.
  • Fije la rueda giratoria con el clip de carpeta.
  • La fuente de alimentación para los motores provendrá de uno de los conjuntos de baterías de 5V. Este juego de batería se instalará entre la placa de pruebas y el bastidor de la carrocería.
  • Conecte la batería que se utilizará con los servos:la izquierda de la red de alimentación lateral exclusivamente para la fuente de los servos
  • Conecte el Arduino Nano a la placa de pruebas
  • Conecte el GND de Power Grid a Arduino GND.
  • Conecte los Servos a Arduino:IZQUIERDA ==> Pin 5; DERECHA ==> Pin 3
  • Conecte el LED al Pin 13 de Arduino
  • Conecta el botón al Pin 9 de Arduino

Tenga en cuenta que debido a la forma en que se montan los servos (en oposición), el rango de velocidad es:

  • La velocidad de avance del servo derecho va de 1500us (detenido) a 2000us (máxima velocidad)
  • La velocidad de avance del servo izquierdo va de 1500us (detenido) a 1000 (máxima velocidad)

Se agrega un LED externo al pin 13, con fines de señalización y prueba (puede usar el LED interno de Arduino, en lugar de uno externo si lo desea, pero tenga en cuenta que será difícil verlo en el medio de los cables).

También hay un botón conectado al pin 9. Este botón es muy útil para propósitos de prueba y para el inicio del robot.

Por ejemplo:

  while (digitalRead (buttonPin)) {} motorTurn (IZQUIERDA, 500); motorTurn (DERECHA, 500);  

Tenga en cuenta que las 2 líneas que ordenarán al Robot que gire a la IZQUIERDA, espere 500ms y gire a la DERECHA solo sucederán después de presionar el botón (buttonPin =0). Antes de eso, el programa se detendrá en el ciclo infinito.

El siguiente código se puede utilizar como base para una prueba de motor completa (hacia adelante, hacia atrás, parada completa, girar a la izquierda, girar a la derecha). Si es necesario, debe ajustar los retrasos para el ángulo de giro requerido dependiendo de sus motores (también, a veces, los valores de pulso izquierdo y derecho deben ser un poco diferentes para compensar cualquier falta de equilibrio de los motores.

FDDQRQOIN4TTVY0.ino

Paso 4:el módulo Bluetooth (opcional)

El módulo Bluetooth HC-06 debe instalarse en la placa de pruebas como se muestra en el dibujo. Se utilizará la biblioteca Arduino SoftSerial.

Debajo de las conexiones de clavijas del HC-06:

  • Pin Tx a Arduino pin 10 (Rx)
  • Pin RX a Arduino pin 11 (Tx)
  • VCC / GND a Arduino 5V / GND

El robot funcionará con o sin Bluetooth. El código está construido de manera que si no activa el BT, los parámetros predeterminados serán los que utilizará el robot. Por lo tanto, no se preocupe si prefiere no instalar el módulo HC-06, el código seguirá funcionando bien. En la última parte de este tutorial, exploraré cómo usar una aplicación de Android para enviar datos para un mejor ajuste de los parámetros del robot y / o mover el robot en modo manual. Dejaré el uso de Bluetooth y la aplicación como opcional en caso de que alguien quiera explorar más el uso de un robot seguidor de línea para competencias, por ejemplo.

Paso 5:agregar los sensores de línea

Conecte los cables a los pines Arduino como se muestra a continuación:

  • Sensor 0 =12
  • Sensor 1 =18
  • Sensor 2 =17
  • Sensor 3 =16
  • Sensor 4 =19
  • Fije los 5 sensores en una barra de plástico como se muestra en las fotos
  • Se recomienda etiquetar los sensores con fines de prueba. El nombre de los sensores va de "0" (más a la izquierda) a "4" (más a la derecha)
  • Pase los cables debajo del marco, usando las bandas elásticas para fijarlos. Tenga cuidado de no confundirse con las ruedas o el Caster.
  • Se arregló el segundo juego de baterías de 5V y conéctelo a Arduino Vin.

En mi caso utilizo un módulo con 4 sensores integrados + 1 extra. Todos ellos son compatibles. Para simplificar, en el diagrama incluí 5 sensores independientes que se conectan entre sí. Los resultados finales son los mismos en ambas configuraciones.

Paso 6:implementación de la lógica del sensor de infrarrojos

El sensor de infrarrojos consta de un LED de infrarrojos individual y un fotodiodo de infrarrojos. La luz de infrarrojos emitida por el LED incide en la superficie y se refleja en el fotodiodo de infrarrojos. El fotodiodo genera entonces un voltaje de salida proporcional al nivel de reflectancia de la superficie (valores más altos para "superficies claras" y más bajos para "superficies negras / oscuras").

En el caso de los sensores utilizados, un circuito integrado en el módulo genera como salida una señal digital simple (ALTA:Oscuro; BAJO:Claro). Un potenciómetro instalado en el módulo (ver foto) ajustará el nivel correcto de luz para ser considerado "oscuro" o "claro". Funciona de manera que cuando el color de la luz reflejada es negro / oscuro, se genera un nivel digital ALTO ("1") en su salida y un BAJO ("0") para otro color más claro. Usé aquí un módulo integrado con 4 sensores y un módulo adicional con un sensor único (forma diferente, pero misma lógica). La combinación es una matriz de 5 sensores que encontré que es buena para un control agradable y suave, como se explica a continuación.

La matriz de 5 sensores está montada de manera que si solo un sensor está centrado con relación a la línea negra, solo ese sensor específico producirá un ALTO. Por otro lado, el espacio entre sensores debe calcularse para permitir que 2 sensores puedan cubrir todo el ancho de la línea negra simultáneamente, produciendo también un ALTO en ambos sensores (ver las imágenes de arriba).

Las posibles salidas de la matriz de sensores cuando se sigue una línea son:

  • 0 0 0 0 1
  • 0 0 0 1 1
  • 0 0 0 1 0
  • 0 0 1 1 0
  • 0 0 1 0 0
  • 0 1 1 0 0
  • 0 1 0 0 0
  • 1 1 0 0 0
  • 1 0 0 0 0

Tener 5 sensores permite la generación de una "variable de error" que ayudará a controlar la posición del robot sobre la línea, como se muestra a continuación.

Consideremos que la condición óptima es cuando el robot está centrado, con la línea justo debajo del "sensor del medio" (Sensor 2). La salida de la matriz será:0 0 1 0 0 y en esta situación, el "error" será "cero". Si el robot comienza a moverse hacia la izquierda (la línea "parece moverse" a la derecha "), el error debe aumentar con una señal positiva. Si el robot comienza a moverse hacia la derecha (la línea" parece moverse "a la izquierda"), en el De la misma forma, el error debe aumentar, pero ahora con señal negativa.

La variable de error relacionada con el estado del sensor será:

0 0 1 0 0 ==> Error =0

  • 0 0 0 0 1 ==> Error =4
  • 0 0 0 1 1 ==> Error =3
  • 0 0 0 1 0 ==> Error =2
  • 0 0 1 1 0 ==> Error =1
  • 0 1 1 0 0 ==> Error =-1
  • 0 1 0 0 0 ==> Error =-2
  • 1 1 0 0 0 ==> Error =-3
  • 1 0 0 0 0 ==> Error =-4

Mirando el código de Arduino, cada uno de los sensores se definirá con un nombre específico (considere que el sensor de seguimiento de línea más a la izquierda debe asignarse con una etiqueta "0"):

  const int lineFollowSensor0 =12; const int lineFollowSensor1 =18; const int lineFollowSensor2 =17; const int lineFollowSensor3 =16; const int lineFollowSensor4 =19;  

Para almacenar los valores de cada sensor se creará una variable de matriz:

  int LFSensor [5] ={0, 0, 0, 0, 0};  

Cada posición de la matriz se actualizará constantemente con la salida de cada uno de los sensores:

  LFSensor [0] =digitalRead (lineFollowSensor0); LFSensor [1] =digitalRead (lineFollowSensor1); LFSensor [2] =digitalRead (lineFollowSensor2); LFSensor [3] =digitalRead (lineFollowSensor3); LFSensor [4] =digitalRead (lineFollowSensor4);  

Teniendo el valor de cada uno de los sensores, se debe implementar una lógica para generar la variable de error:

  if ((LFSensor [0] ==0) &&(LFSensor [1] ==0) &&(LFSensor [2] ==0) &&(LFSensor [3] ==0) &&(LFSensor [4] ==1)) error =4; si no ((LFSensor [0] ==0) &&(LFSensor [1] ==0) &&(LFSensor [2] ==0) &&(LFSensor [3] ==1) &&(LFSensor [4] ==1)) error =3; más si ((LFSensor [0] ==0) &&(LFSensor [1] ==0) &&(LFSensor [2] ==0) &&(LFSensor [3] ==1) &&(LFSensor [4] ==0)) error =2; si no ((LFSensor [0] ==0) &&(LFSensor [1] ==0) &&(LFSensor [2] ==1) &&(LFSensor [3] ==1) &&(LFSensor [4] ==0)) error =1; si no ((LFSensor [0] ==0) &&(LFSensor [1] ==0) &&(LFSensor [2] ==1) &&(LFSensor [ 3] ==0) &&(LFSensor [4] ==0)) error =0; si no ((LFSensor [0] ==0) &&(LFSensor [1] ==1) &&(LFSensor [2] ==1) &&(LFSensor [3] ==0) &&(LFSensor [4] ==0)) error =- 1; else if ((LFSensor [0] ==0) &&(LFSensor [1] ==1 ) &&(LFSensor [2] ==0) &&(LFSensor [3] ==0) &&(LFSensor [4] ==0)) error =-2; si no ((LFSensor [0] ==1) &&(LFSensor [1] ==1) &&(LFSensor [2] ==0) &&(LFSensor [3] ==0) &&(LFSensor [4] ==0)) error =-3; si no ((LFSensor [0] ==1) &&(LFSensor [1] ==0) &&(LFSensor [2] ==0) &&(LFSensor [3] ==0) &&(LFSensor [4] ==0)) error =-4;  

Paso 7:Dirección de control (Control proporcional - P)

¡Perfecto! En este punto, nuestro Robot está ensamblado y operativo. Debe realizar algunas pruebas básicas con los motores, leer la salida de los sensores y probarlos en una línea. Lo que falta es el "cerebro" real, los primeros pasos de una "inteligencia artificial". Lo conseguiremos, implementando una lógica de control que garantizará que el Robot se mantenga siguiendo la línea.

Control proporcional simple:

Suponga que el robot se está ejecutando sobre una línea y la salida de la matriz de sensores es: "0 0 1 0 0" . El error correspondiente es "0". En esta situación, ambos motores deben funcionar hacia adelante con velocidad constante.

Por ejemplo:

Definición de la variable: iniMotorSpeed ​​=250 ; significa que el servo IZQUIERDO recibirá pulsos de 1.250us y el servo DERECHO de 1.750us. Con esos parámetros, el Robot avanzará a la mitad de la velocidad. Recuerde que la velocidad de avance del servo DERECHO variará con una longitud de pulso de 1,500us (detenido) a 2,000us (velocidad completa) y el servo IZQUIERDO de 1,500us (detenido) a 1,000us (velocidad completa).

  rightServo.writeMicroseconds (1500 + iniMotorPower); leftServo.writeMicroseconds (1500 - iniMotorPower);  

Supongamos ahora que el Robot se conduce hacia la izquierda (es como la "LÍNEA va a la derecha") y cubre también el sensor 3. La salida de la matriz será: "0 0 1 1 0" y el error =1 . En esta situación, lo que necesita es girar el Robot hacia la derecha. Para hacer eso, debe disminuir la velocidad del servo DERECHO lo que significa disminuir la longitud del pulso. Además, la velocidad del servo IZQUIERDO debe aumentar, lo que significa disminuir la longitud del pulso del servo IZQUIERDO. Para hacer eso, necesitamos cambiar la función de control del motor:

  rightServo.writeMicroseconds (1500 + iniMotorPower - error); ==> Error positivo:disminuir velocityleftServo.writeMicroseconds (1500 - iniMotorPower - error); ==> Error positivo:aumentar la velocidad  

La lógica anterior es correcta, pero es fácil de entender que sumar o restar "1" microsegundo en la longitud del pulso no generará la corrección requerida en un tiempo realista. Es intuitivo que el número a sumar o restar debe ser mayor, por ejemplo 50, 100, etc. Para obtener eso, el "error" debe ser multiplicado por una constante (llamémoslo "K"). Una vez que la influencia de esta constante sea proporcional al error, la denominaremos "Constante proporcional:Kp" .

La función motora será:

  int Kp =50; rightServo.writeMicroseconds (1500 + iniMotorPower - Kp * error); leftServo.writeMicroseconds (1500 - iniMotorPower - Kp * error);  

Podemos resumir lo que sucederá con los motores como se muestra a continuación:

  • Matriz de sensores: 0 0 1 0 0 ==> error =0 ==> Longitud del pulso del servo derecho =1,750us ==> Longitud del pulso del servo izquierdo =1,250us (ambos motores a la misma velocidad)
  • Matriz de sensores: 0 0 1 1 0 ==> error =1 ==> Longitud del pulso del servo derecho =1,700us (más lento) ==> Longitud del pulso del servo izquierdo =1,200us (más rápido)

Si la situación es la contraria y el Robot se conduce hacia la derecha, el error sería "negativo" y la velocidad de los servos debería cambiar:

  • Matriz de sensores: 0 0 1 0 0 ==> error =0 ==> Longitud del pulso del servo derecho =1,750us ==> Longitud del pulso del servo izquierdo =1,250us (ambos motores a la misma velocidad)
  • Matriz de sensores: 0 1 1 0 0 ==> error =-1 ==> Longitud del pulso del servo derecho =1.800us (más rápido) ==> Longitud del pulso del servo izquierdo =1.300us (más lento)

En este punto está claro que cuanto más se conduzca el Robot hacia un lado, mayor será el error y más rápido deberá volver al centro. La velocidad con la que el Robot reaccionará ante el error será proporcional a este. Esto se llama "Control proporcional" , ese es el componente "P" de una red de control más compleja, el PDI (Proporcional, Derivado, Integral).

Paso 8:Control PID (opcional)

En caso de que quieras saltar a esta parte, también está bien. Puede quedarse con el control proporcional explicado en el último paso, o quemar algunos sesos para implementar un sistema de control más complejo en su robot, es su elección.

Si tomó una decisión, ¡vámonos!

PID (Proporcional, Derivado e Integral) es uno de los esquemas de control más comunes que existen. La mayoría de los lazos de control industrial utilizan algún tipo de control PID. Hay muchas formas de ajustar un bucle PID, incluida la técnica manual utilizada en este ejemplo.

Piense en PID como un simple resorte. Un resorte tiene una longitud original, que cuando se ve perturbada por expansión o contracción, tiende a recuperar su longitud original en el menor tiempo posible. De manera similar, un algoritmo PID en un sistema tiene un valor establecido de una cantidad física particular que se va a controlar, llamado " punto establecido ’, Que cuando se modifica por algún motivo, el sistema controla las demás funciones necesarias para volver al punto de ajuste original en el menor tiempo posible. Los controladores PID se utilizan siempre que sea necesario controlar una cantidad física y hacerla igual a un valor especificado. Ejemplo, controlador de crucero en automóviles, robots, reguladores de temperatura, reguladores de voltaje, etc.

¿Cómo funciona PID?

El sistema calcula el " error "O" desviación ’De la cantidad física desde el punto de ajuste, midiendo el valor actual de esa cantidad física usando un sensor (es). Para volver al punto de ajuste, este " error ’Debe minimizarse e idealmente debe ser igual a cero. Además, este proceso debería ocurrir lo más rápido posible. Idealmente, no debería haber ningún retraso en la respuesta del sistema al cambio en su punto de ajuste.

Puede encontrar más información en muchos libros y sitios web, incluido aquí.

Implementando PID

i) Término de error (e):

Esto es igual a la diferencia entre el punto de ajuste y el valor actual de la cantidad que se está controlando. Error = set_point - valor_actual (en nuestro caso, la variable de error se obtiene de la posición de Robot sobre la línea

ii) Término proporcional (P):

Este término es proporcional al error.

P =error

Este valor es responsable de la magnitud del cambio requerido en la cantidad física para alcanzar el punto de ajuste. El término de proporción es lo que determina el tiempo de subida del bucle de control o la rapidez con que alcanzará el punto de ajuste.

iii) Término integral (I):

Este término es la suma de todos los valores de error anteriores.

I =I + error

Este valor es responsable de la rapidez de respuesta del sistema al cambio desde el punto de ajuste. El término integral se usa para eliminar el error de estado estable requerido por el término proporcional. Por lo general, los robots pequeños no usan el término integral porque no nos preocupa el error de estado estable y puede complicar el " ajuste de bucle ".

iv) Término diferencial o derivado (D):

Este término es la diferencia entre el error instantáneo del punto de ajuste y el error del instante anterior.

D =error - error anterior

Este valor es responsable de ralentizar la tasa de cambio de la cantidad física cuando se acerca al punto de ajuste. El término derivado se utiliza para reducir el sobreimpulso o cuánto debería " corregir ".

Ecuación:

PIDvalue =(Kp * P) + (Ki * I) + (Kd * D)

Dónde:

Kp es la constante utilizada para variar la magnitud del cambio necesario para alcanzar el punto de ajuste. Ki es la constante utilizada para variar la velocidad a la que el cambio debe introducirse en la cantidad física para alcanzar el punto de ajuste. Kd es la constante utilizada para variar la estabilidad del sistema.

Un método para ajustar el bucle puede ser Método tentativo Try-error :

Establezca la variable Kd en 0 y sintonice primero el término Kp solo. Kp de 25 es un buen lugar para comenzar en nuestro caso aquí. En el último paso usamos un Kp de 50 que funciona muy bien con mi Robot. Una vez que el robot responde razonablemente, sintonice la parte derivada del bucle de control ( Kd ). Primero establezca el valor de Kp y Kd cada uno a la mitad del valor de Kp. Por ejemplo, si el robot responde razonablemente con un Kp =50, entonces configure Kp =25 y Kd =25 para comenzar. Aumente la ganancia de Kd (derivada) para disminuir el sobreimpulso, disminuya si el robot se vuelve inestable.

  • Si el robot reacciona con demasiada lentitud, aumente el valor.
  • Si el robot parece reaccionar rápidamente volviéndose inestable, disminuya el valor.

Otro componente del bucle a considerar es la frecuencia de muestreo / bucle real . Acelerar este parámetro o ralentizarlo puede marcar una diferencia significativa en el rendimiento del robot. Esto lo establece el retraso declaraciones que tiene en su código. Es un método tentativo Try-error para obtener el resultado óptimo.

Basado en el enfoque anterior, se implementó la siguiente función:

  void calculatePID () {P =error; I =I + error; D =error-previousError; PIDvalue =(Kp * P) + (Ki * I) + (Kd * D); previousError =error;}  

La constante Kp simple utilizada en el último paso será reemplazada por este PIDvalue más completo :

  void motorPIDcontrol () {int leftMotorSpeed ​​=1500 - iniMotorPower - PIDvalue; int rightMotorSpeed ​​=1500 + iniMotorPower - PIDvalue; leftServo.writeMicroseconds (leftMotorSpeed); rightServo.writeMicroseconds (rightMotorSpeed);}  

Pero tenga en cuenta que si tiene Kd y Ki =0 , PIDvalue es solo el error Kp * utilizado en el último paso.

Paso 9:el código final

En este paso, el robot puede seguir un bucle constante y lo hará sin detenerse. El programa de bucle sería:

  void loop () {readLFSsensors (); // leer sensores, almacenar valores en Sensor Array y calcular "error" calculatePID (); motorPIDcontrol ();}  

Pero para una operación más completa y real, es importante agregar al menos un par de comandos básicos " "hecho" con la línea ". Por ejemplo, introduzcamos una nueva variable:" modo ". Definiremos 3 estados para esta variable:

Modo:

  • #define STOPPED 0
  • #define FOLLOWING_LINE 1
  • #define NO_LINE 2

Si todos los sensores encuentran una línea negra, la salida de la matriz de sensores sería:1 1 1 1 1. En esta condición, podemos definir el modo como "DETENIDO" y el robot debe realizar un " punto final ".

  if ((LFSensor [0] ==1) &&(LFSensor [1] ==1) &&(LFSensor [2] ==1) &&(LFSensor [3] ==1) &&(LFSensor [4] ==1)) {mode =DETENIDO;}  

Otra situación común con Follower Line Robots es cuando encuentra " no line ", o la salida de la matriz de sensores es:0 0 0 0 0. En este caso, podemos programarlo para que gire hacia atrás 180o o gire en ángulos pequeños hasta que se encuentre una línea y se reanude la condición normal de seguimiento de línea.

  else if ((LFSensor [0] ==0) &&(LFSensor [1] ==0) &&(LFSensor [2] ==0) &&(LFSensor [3] ==0) &&( LFSensor [4] ==0)) {mode =NO_LINE;}  

El loop () completo sería:

  void loop () {readLFSsensors (); interruptor (modo) {caso DETENIDO:motorStop (); descanso; case NO_LINE:motorStop (); motorTurn (IZQUIERDA, 180); descanso; case FOLLOWING_LINE:calculatePID (); motorPIDcontrol (); descanso; }}  

El código final real integrará algo de lógica adicional y también algunas variables que deben inicializarse, etc. Durante la explicación anterior las dejé fuera por simplicidad, pero todo debería quedar claro mirando el código final.

A continuación se muestra el código Arduino final:

FUXCUEAIN699SZC.ino FLD2J3KIN699SZF.h FOFYXFZIN699SZT.ino FMPX9KJIN699SZU.ino FFE5AZ3IN699T06.ino

Paso 10:ajuste del control PID con la aplicación de Android

In the previous code, you can find at "robotDefines.h " tab the following definitions for the constants to be used with the PID control:

float Kp=50;float Ki=0;float Kd=0; 

As explained at previous step, the best way to define the correct constant to be used with a PID controller is using the "Try-error" methodology. The bad side of that is that you must re-compile the program each time that you must change it. One way to speed-up the process is to use the Android App to send the constants at the "Set-Up Phase" .

I developed an Android App exclusively for that. In short there are the traditional manual commands:

  • FW, BW, Left, Right and Stop where the app will send respectively to the BT module:'f', 'b', 'l', 'r' and 's'.

Also 3 sliders were included, one for each PID constants:

  • Kd:"d/XXX" where "XXX" it is a number from 0 to 100.
  • Kp:"p/XXX"
  • Ki:"i/XXX"

An extra button was included that will work exactly as the button connected on Arduino Pin9. You can use one or the other, it does not matter.

Below you can find the .aia file that can be modified at MIT AppInventor and the .apk file to be installed directly in your Android device.

FTH62BVIN699T4B.aia F60H7R0IN699T4I.apk

Step 11:Changing the Code for PID remote tuning

During the Setup, we will introduce a loop where you can send the PID parameters to the Robot before you put him over the line:

 while (digitalRead(buttonPin) &&!mode) { checkBTcmd(); // verify if a comand is received from BT remote control manualCmd (); command =""; } checkPIDvalues(); mode =STOPPED; 

The manual command function will be:

void manualCmd(){ switch (command[0]) { case 'g':mode =FOLLOWING_LINE; descanso; case 's':motorStop(); //turn off both motors break; case 'f':motorForward(); descanso; case 'r':motorTurn(RIGHT, 30); motorStop(); descanso; case 'l':motorTurn(LEFT, 30); motorStop(); descanso; case 'b':motorBackward(); descanso; case 'p':Kp =command[2]; descanso; case 'i':Ki =command[2]; descanso; case 'd':Kd =command[2]; descanso; }}  

In the video, you can see some tests using the Android App. Below the final code including the PID setup via Android:

FGAEB9BIN7QQQAW.ino FBMONSNIN7QQQCD.ino F8B3CDHIN7QQQCL.h FNOMRUNIN7QQQCP.ino FA3K57ZIN7QQQCR.ino

Step 12:Conclusion

This is the first part of a more complex project, exploring the potentiality of a line follower robot. In the next part, I will develop a Maze solve robot, based on this this project here. Hopefully I can contribute for others to learn more about electronics, robot, Arduino, etc.

The update files for this project can be found at GITHUB. For more tutorials, please visit my Blog:MJRoBot.org

Greetings from the south of the world!

Thanks

Marcelo

Código

  • Fragmento de código n. ° 1
  • Code snippet #2
  • Fragmento de código n. ° 3
  • Fragmento de código n. ° 5
  • Code snippet #6
  • Code snippet #10
  • Fragmento de código n. ° 11
  • Fragmento de código n. ° 12
  • Code snippet #15
  • Code snippet #17
  • Code snippet #18
Fragmento de código n. ° 1 Texto sin formato
#include  // Servo library Servo leftServo;Servo rightServo;Void setup(){ leftServo.attach(5); rightServo.attach(3); leftServo.writeMicroseconds(1500); rightServo.writeMicroseconds(1500);}void loop(){}
Code snippet #2Plain text
while(digitalRead(buttonPin)) { }motorTurn (LEFT, 500);motorTurn (RIGHT, 500);
Fragmento de código n. ° 3 Texto sin formato
const int lineFollowSensor0 =12;const int lineFollowSensor1 =18;const int lineFollowSensor2 =17;const int lineFollowSensor3 =16;const int lineFollowSensor4 =19;
Fragmento de código n. ° 5 Texto sin formato
LFSensor[0] =digitalRead(lineFollowSensor0);LFSensor[1] =digitalRead(lineFollowSensor1);LFSensor[2] =digitalRead(lineFollowSensor2);LFSensor[3] =digitalRead(lineFollowSensor3);LFSensor[4] =digitalRead(lineFollowSensor4);
Code snippet #6Plain text
if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==1 )) error =4;else if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==1 )&&(LFSensor[4]==1 )) error =3; else if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==1 )&&(LFSensor[4]==0 )) error =2;else if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==1 )&&(LFSensor[3]==1 )&&(LFSensor[4]==0 )) error =1;else if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==1 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =0;else if((LFSensor[0]==0 )&&(LFSensor[1]==1 )&&(LFSensor[2]==1 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =- 1;else if((LFSensor[0]==0 )&&(LFSensor[1]==1 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =-2;else if((LFSensor[0]==1 )&&(LFSensor[1]==1 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =-3;else if((LFSensor[0]==1 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =-4;
Code snippet #10Plain text
void calculatePID(){ P =error; I =I + error; D =error-previousError; PIDvalue =(Kp*P) + (Ki*I) + (Kd*D); previousError =error;}
Fragmento de código n. ° 11 Texto sin formato
void motorPIDcontrol(){ int leftMotorSpeed =1500 - iniMotorPower - PIDvalue; int rightMotorSpeed =1500 + iniMotorPower - PIDvalue; leftServo.writeMicroseconds(leftMotorSpeed); rightServo.writeMicroseconds(rightMotorSpeed);}
Fragmento de código n. ° 12 Texto sin formato
void loop (){ readLFSsensors(); // read sensors, storage values at Sensor Array and calculate "error" calculatePID(); motorPIDcontrol();}
Code snippet #15Plain text
void loop() { readLFSsensors(); switch (mode) { case STOPPED:motorStop(); descanso; case NO_LINE:motorStop(); motorTurn(LEFT, 180); descanso; case FOLLOWING_LINE:calculatePID(); motorPIDcontrol(); descanso; }} 
Code snippet #17Plain text
 while (digitalRead(buttonPin) &&!mode) { checkBTcmd(); // verify if a comand is received from BT remote control manualCmd (); command =""; } checkPIDvalues(); mode =STOPPED;
Code snippet #18Plain text
void manualCmd(){ switch (command[0]) { case 'g':mode =FOLLOWING_LINE; descanso; case 's':motorStop(); //turn off both motors break; case 'f':motorForward(); descanso; case 'r':motorTurn(RIGHT, 30); motorStop(); descanso; case 'l':motorTurn(LEFT, 30); motorStop(); descanso; case 'b':motorBackward(); descanso; case 'p':Kp =command[2]; descanso; case 'i':Ki =command[2]; descanso; case 'd':Kd =command[2]; descanso; }} 
Github
https://github.com/Mjrovai/MJRoBot-Line-Followerhttps://github.com/Mjrovai/MJRoBot-Line-Follower

Esquemas

oIDhLcHQ30lDgVBXZvb8.fzz

Proceso de manufactura

  1. El futuro de la robótica
  2. Sensor de seguimiento de línea con RPi
  3. Control de actuador y sensor Raspberry Pi
  4. ROBOT WIFI DE FRAMBUESA PI CONTROLADO DESDE EL TELÉFONO INTELIGENTE DE ANDROID
  5. Automatización:Línea de robot rediseñada
  6. Línea de robot SCARA ampliada
  7. Control remoto universal usando Arduino, 1Sheeld y Android
  8. Seguidor de línea industrial para suministro de materiales
  9. Robot seguidor de línea de velocidad V4
  10. Control PID de Robot Gripper en Matlab / Simulink
  11. Control de calidad de la línea de envasado automatizado