Muchas máquinas robotizadas dependen de una variedad de interruptores táctiles para, por ejemplo, contar objetos en una línea de producción o alinearlos durante los procesos industriales. En estos casos los interruptores ofrecen una entrada de datos que ordenan otro tipo de salida programada de datos.
En el paso anterior enseñamos a andar al robot, pero lo hacía a ciegas ya que si tropezaba con un obstáculo allí se quedaba. Ahora vamos a colocarle unos sensores que le avisen de la presencia de obstáculos en su camino, además de indicarle si dicho obstáculo se encuentra a la derecha o a la izquierda. Con esa información podremos indicarle que realice un movimiento de desvío que lo evite y así pueda proseguir hacia su objetivo.
Para ello vamos a emplear dos bumpers, nombre técnico con el que se conoce a ciertos interruptores que cierran sus contactos cuando se presiona uno de ellos. En nuestro caso, los bumpers están conformados por dos alambres de acero y tienen el aspecto de bigotes o antenas. Los llamaremos bigotes porque sirven para detectar objetos como lo hacen los bigotes de un gato. En este paso los utilizaremos solos, pero pueden ser combinados con otros sensores como veremos más adelante.
Montando los bigotes
Antes de grabar un programa para que robot se mueva en función de lo que encuentra en su camino, necesitamos montarlos y probarlos primero. Vamos a utilizar los siguientes materiales:
- Dos alambres de acero.
- Dos tornillos de cabeza plana de 3×15 mm.
- Dos separadores metálicos de 3×10 mm.
- Dos arandelas de baquelita de 3 mm.
- Dos conectores de tres pines.
- Dos resistencias de 220 Ω.
- Dos resistencias de 10 Ω.
Primero debemos quitar los tornillos que unen la tarjeta Home Work con los dos separadores frontales. Colocamos un separador y una arandela de baquelita en cada uno de los tornillos.
Colocamos los tornillos sobre los agujeros de la tarjeta y atornillamos a los separadores que hay debajo, pero no debemos apretarlos completamente todavía. Enganchamos los bigotes a los tornillos y colocamos uno por encima de una de las arandelas y el otro por debajo, de tal forma que no se toquen entre sí.
Ahora podemos terminar de apretar los tornillos y colocar los conectores de tres pines:
Prueba de funcionamiento
Ahora vamos a construir el circuito eléctrico de los bigotes para añadirlo a los circuitos de zumbador y los servos que montamos en el paso anterior:
Cada bigote es una extensión mecánica de un interruptor normalmente abierto que tiene un extremo conectado a tierra. La razón de que los bigotes estén conectados a tierra (Vss) es que los agujeros en los bordes exteriores de la tarjeta están conectados a tierra. Los separadores y tornillos metálicos conectan la señal de tierra con los bigotes.
Podemos programar el módulo del microcontrolador para que detecte cuándo se presiona un bigote. Los pines o patitas de E/S conectados a cada interruptor están configurados como entradas y reciben un voltaje. Cuando los bigotes no se presionan, el voltaje que reciben es de 5 V (1 lógico). Pero si son presionados, el circuito se cierra con tierra y los pines reciben 0 V (0 lógico).
Colocamos las conexiones y resistencias como hemos visto en el diagrama anterior y ya podemos pasar a crear el programa de control:
Programa de prueba
Este programa está diseñado para que se puedan probar los bigotes y asegurar que funcionan correctamente. Lo que hace es mostrar el estado lógico de las entradas que corresponden a los pines P7 y P5 conectados a los bigotes (IN7 e IN5).
Todos los pines de E/S son de entrada por defecto, a menos que se programe lo contrario. Por lo tanto, los pines conectados a los bigotes tendrán un “1” si el voltaje que reciben es de 5 V (cuando el bigote no está presionado), o un “0” si lo que reciben es 0 V (cuando el bigote está presionado). Vamos a utilizar el debug terminal para mostrar esos valores:
- ‘ Programa de prueba. pruebabigotes.bs2
- ‘ Visualizar las líneas de E/S conectadas a los “bigotes”
- ‘ {$STAMP BS2}
- ‘ {$PBASIC 2.5}
- DEBUG “Estado bigotes”, CR,
- “Izquierda derecha”, CR,
- “_____ _____”
- DO
- DEBUG CRSRXY, 0, 3,
- “P5 = “, BIN1 IN5,
- “P7 = “, BIN1 IN7
- PAUSE 50
- LOOP
El terminal debería mostrar que que P7 y P5 tienen unos valores igual a 1. Si presionamos el bigote derecho contra el conector de tres pines hasta que haga buen contacto, deberíamos ver en el terminar: P5 = 1, P7 = 0. Si presionamos el bigote izquierdo de la misma forma, debería aparecer: P5 = 0, P7 = 1. Si presionamos ambos al mismo tiempo debería mostrar: P5 = 0, P7 = 0. Una vez que todo es correcto seguimos adelante.
NOTA: el comando CRSRXY es un formateador que permite ordenar la información que el programa envía al terminal. En el programa, el formateador coloca el cursor en la columna 0 y fila 3 para mostrar los datos de forma ordenada.
Otra forma de probar los bigotes
Imaginemos que tenemos que probar los bigotes cuando no disponemos de un ordenador para ver su estado en la terminal. ¿Cómo podríamos comprobar que se han montado correctamente? Una solución pasa por programar el microprocesador para que saque un valor determinado en función de cuál es la entrada que reciba. Podemos visualizarlo con un par de circuitos LED´s que se enciendan y se apaguen en función de si los bigotes están presionados o no.
Para montar este circuito necesitamos:
- Dos resistencias de 220 Ω (bandas roja, roja y marrón).
- Dos diodos LED.
Como siempre, antes de montar el circuito sobre la placa debemos recordar desconectar las pilas de la tarjeta y los servos. Seguiremos el siguiente esquema:
Una vez montado, volvemos a conectar las pilas, e introducimos el siguiente programa en el editor:
- ‘ Programa de prueba. pruebabigotesconleds.bs2
- ‘ Visualizar las líneas de E/S conectadas a los “bigotes”
- ‘ {$STAMP BS2}
- ‘ {$PBASIC 2.5}
- DEBUG “Estado bigotes”, CR,
- “Izquierda derecha”, CR,
- “_____ _____”
- DO
- DEBUG CRSRXY, 0, 3,
- “P5 = “, BIN1 IN5,
- ” P7 = “, BIN1 IN7
- PAUSE 50
- IF (IN7 = 0) THEN
- HIGH 1
- ELSE
- LOW 1
- ENDIF
- IF (IN5 = 0) THEN
- HIGH 10
- ELSE
- LOW 10
- ENDIF
- LOOP
Como vemos, lo que hemos hecho ha sido insertar dos bloques de código IF…THEN entre el comando de pausa y el comando de bucle. Los comandos IF…THEN los explicaremos un poco más tarde pero baste decir ahora que se emplean en PBASIC para tomar decisiones. La primera declaración pone P1 a nivel alto, de forma que el LED se iluminará cuando el bigote conectado a P7 esté presionado (IN7=0). La parte del ELSE hace que el LED se apague cuando el bigote no está presionado. La segunda declaración hace lo mismo para el otro bigote. Veamos cómo funciona:
Programando el robot para navegar con los bigotes
Ha llegado el momento de poner en práctica todo lo aprendido hasta ahora para lograr que el robot reaccione a la información que le facilitan los bigotes acerca de los obstáculos que puede encontrar en su camino y pueda guiarse con ella. Cuando el robot esté en movimiento y uno de sus bigotes se presione significará que ha tropezado con un obstáculo. El programa de exploración deberá comprobar esa entrada de información, decidir qué significa y, a partir de ahí, realizar la maniobra hay que ejecutar para evitar el obstáculo y dirigir al robot en otra dirección (debemos tener presente que se trata de un movimiento libre y no podremos controlar dónde acabará el recorrido).
El siguiente programa hace que el robot vaya hacia delante hasta que se encuentre con un obstáculo. En el momento en que sea detectado por los bigotes, las rutinas y subrutinas escritas en el capítulo anterior harán que el robot retroceda y gire. Después volverá a avanzar hacia delante hasta que se encuentre con otro obstáculo.
El microcontrolador que gobierna el robot tiene que ser programado para que tome decisiones cuando uno de los bigotes es presionado. El lenguaje PBASIC dispone de un comando llamado IF…THEN. La sintaxis es como sigue:
IF (condición) THEN… {ELSEIF (condición)}…{ELSE}…ENDIF
Los puntos suspensivos significan que se puede meter un trozo de código en su lugar. El comando hace que el robot ejecute el bloque de código para la primera condición que sea verdadera. Entonces, salta hasta el comando ENDIF y continúa desde ahí.
El siguiente programa muestra una forma de evaluar las entradas de datos proporcionadas por los bigotes para decidir a qué subrutina de movimiento llamar utilizando los comandos IF…THEN:
- ‘ Sorteo de obstaculos. andandoconbigotes.bs2
- ‘ El robot utiliza los bigotes para detectar
- ‘ objetos y navegar en función de los mismos
- ‘ {$STAMP BS2}
- ‘ {$PBASIC 2.5}
- DEBUG “Programa funcionando”
- ‘—–[ Variables ]
- pulseCount VAR Byte
- ‘—–[ Inicializacion ]
- FREQOUT 4, 2000, 3000
- ‘—–[ Rutina principal ]
- DO
- IF (IN5 = 0) AND (IN7 = 0) THEN
- GOSUB Back_Up
- GOSUB Turn_Left
- GOSUB Turn_Left
- ELSEIF (IN5 = 0) THEN
- GOSUB Back_Up
- GOSUB Turn_Right
- ELSEIF (IN7 = 0) THEN
- GOSUB Back_Up
- GOSUB Turn_Left
- ELSE
- GOSUB Forward_Pulse
- ENDIF
- LOOP
- ‘—–[ Subrutinas ]
- Forward_Pulse:
- PULSOUT 13, 650
- PULSOUT 12, 850
- PAUSE 20
- RETURN
- Turn_Left:
- FOR pulseCount = 0 TO 20
- PULSOUT 13, 650
- PULSOUT 12, 650
- PAUSE 20
- NEXT
- RETURN
- Turn_Right:
- FOR pulseCount = 0 TO 20
- PULSOUT 13, 850
- PULSOUT 12, 850
- PAUSE 20
- NEXT
- RETURN
- Back_Up:
- FOR pulseCount = 0 TO 20
- PULSOUT 13, 850
- PULSOUT 12, 650
- PAUSE 20
- NEXT
- RETURN
El comando IF…THEN en el programa principal comprueba el estado de los bigotes. Si los dos bigotes están presionados (IN5 = 0, IN7 = 0), el robot realizará un giro en “U” llamando a la subrutina Back_Up seguida de la subrutina Turn_Left dos veces (lo que supone un giro de 180o).
Si el bigote izquierdo es el único que está presionado (IN5 = 0), el programa ejecutará la subrutina Back_Up seguida de la subrutina Turn_Right para retroceder y girar a la derecha 90o. Por el contrario, si el bigote presionado es el derecho (IN7 = 0), el programa ejecutará la subrutina Back_Up seguida de la subrutina Turn_Left para retroceder y girar a la izquierda 90o. La única posibilidad que no está resuelta en el programa es cuando los dos bigotes no están presionados (IN5 = 1, IN7 = 1) en cuyo caso el comando ELSE llama a la subrutina Forward_Pulse y envía un pulso para que el robot avance en línea recta al no haber obstáculos.
Esta subrutina tiene un detalle que hemos resaltar:
- Forward_Pulse:
- PULSOUT 13, 650
- PULSOUT 12, 850
- PAUSE 20
- RETURN
Sólo envía un pulso y después devuelve el control al programa principal. Esto es importante porque permite al robot comprobar sus bigotes entre cada pulso que le hace avanzar (esto lo hace gracias al comando ENDIF). Significa que el robot comprueba si hay obstáculos alrededor de 40 veces por segundo mientras avanza hacia delante: cada pulso hacia delante hace que el robot avance medio centímetro por lo que es una buena idea enviar sólo un pulso para volver a comprobar los bigotes. Dado que el comando IF…THEN está dentro de un bucle DO…LOOP, cada vez que el programa realiza un pulso hacia delante entra en el bucle que envía el programa arriba hasta el comando DO. ¿Qué sucede entonces? Que el comando IF…THEN vuelve a comprobar los bigotes de nuevo y así sucesivamente. Si no lo hiciéramos así, cuando el robot entrara en la subrutina Forward_Pulse ya no volvería a comprobarlos.
Veamos el resultado de nuestros esfuerzos: