|
|
Robobo: Sensores Infrarrojos
Contenidos
Introducción
Un sensor infrarrojo es un dispostivo optoeléctronico que permite captar radiación electromagnética en el rango infrarrojo, que no es visible para el ojo humano. En robótica se utilizan habitualmente para medir distancias, utilizando un LED infrarrojo que emite radiación de manera constante y un fotoreceptor que puede medir la cantidad de luz recibida tras impactar con los objetos que tenga alrededor. Como todos los sensores, tienen unos límites de detección fuera de los cuales no perciben nada.
Si quieres más información sobre cómo funcionan estos sensores, puedes visitar esta web.
Robobo cuenta con varios sensores infrarrojos que le permiten detectar si hay objetos cerca: cinco en la parte delantera y tres en la parte trasera, como se muestra en la figura inferior. Ojo, estos sensores no nos dan la distancia en centímetros o metros, sino que nos devuelven la intensidad de luz recibida. Por tanto, cuanto más altos sean los valores devueltos por un infrarrojo, más cerca estarán los objetos de alrededor.
IMPORTANTE: No todos los sensores tienen la misma inclinación. FrontR, FrontL, y BackC están ligeramente inclinados hacia abajo, para poder medir la distancia al suelo y poder detectar agujeros o bordes en mesas. El resto apunta hacia delante para poder detectar objetos enfrente o detrás.
Para saber los valores de los sensores, se puede usar la ventana de monitorización:
readIRSensor(id)
Función: Lee el valor medido por el sensor infrarrojo indicado.
Parámetros:
- id (IR): El sensor del que se quiere obtener el valor. Ver Enumerado IR.
Devuelve:
- Valor medido (int). Los valores son positivos. Cuanto mayor es el valor devuelto, menor es la distancia a la que se encuentra el objeto detectado. Este valor no depende de la iluminación visible, pero sí de la superficie a detectar, ya que la reflexión puede cambiar.
Enumerado IR
- BackR: ‘Back-R’. Trasero derecho.
- BackC: ‘Back-C’. Trasero central.
- FrontR: ‘Front-R’. Frontal derecho medio.
- FrontRR: ‘Front-RR’. Frontal derecho extremo.
- FrontC: ‘Front-C’. Frontal central.
- FrontL: ‘Front-L’. Frontal izquierdo medio.
- FrontLL: ‘Front-LL’. Frontal izquierdo extremo.
- BackL: ‘Back-L’. Trasero izquierdo.
Para probar este método, primero debemos importar las librerías necesarias y realizar la conexión con el robot:
from robobopy.Robobo import Robobo
from robobopy.utils import Wheels
from robobopy.utils.IR import IR
#Se conecta con Robobo en el simulador
rob = Robobo("localhost")
rob.connect()
A continuación, probaremos un pequeño programa que resuelve este caso:
El siguiente programa hace que Robobo se mueva hacia delante hasta que encuentre un obstáculo cercano en el sensor delantero central (el valor de 100 es orientativo, y debe ser ajustado al tipo de objeto a detectar). Cuando eso ocurre, se mueve hacia atrás durante 1 segundo para separase del obstáculo, luego gira en el sitio 180º aproximadamente y, finalmente, se mueve en dirección contraria durante 2 segundos
Se recomienda probarlo en el entorno AVOID THE BLOCK.
#Arranca motores
rob.moveWheels(30,30)
#Se mueve de forma constante hasta que detecte un bloque de frente
while rob.readIRSensor(IR.FrontC) < 100:
rob.wait(0.1)
rob.stopMotors()
rob.moveWheelsByTime(-20,-20,1)
rob.moveWheelsByTime(28,-28,1)
rob.moveWheelsByTime(30,30,2)
rob.disconnect()
El programa anterior es un ejemplo muy importante para comprender cómo se deben usar los sensores en robótica:
Primero, el robot se empieza a mover sin tiempo predefinido
Entramos en un bucle que comprueba si el valor del sensor delantero frontal es menor que 100 (objeto cercano). Mientras eso no ocurra y los valores leídos sean mayores de 100 (objeto lejano), el programa se quedará ejecutando el bucle, que no debe hacer nada, y avanzando hacia delante.
NOTA 1: Es recomendable evitar lecturas del sensor demasiado frecuentes para evitar que el procesador del robot se ralentice, por lo que hemos puesto simplemente una espera de 0.1 segundos dentro del bucle. Esto quiere decir que mediremos cada 0.1 segundos, más que suficiente en este ejemplo.
NOTA 2: La condición de terminación del bucle es un < y no un ==, ¿por qué?. Pues porque estamos programando un sistema real, con un sensor real, y que devuelva un valor exacto de 100 es casi imposible. Lo más probable es que nos devuelva valores como 100.5, 100.4, 99.8, etc. Al poner un <, en cuanto el valor medido baje de 100, el bucle se termina, logrando el efecto deseado.
- Tras salir del bucle, se para el robot.
NOTA 3: En los sistemas reales existen inexactitudes diversas que debemos suponer que pueden ocurrir para programar adecuadamente el comportamiento. En este caso, al utilizar un <, el robot no parará exactamente cuando detecte 100, y además, detener los motores no es inmediato (inercia). 4. Las 3 instrucciones finales del ejemplo anterior hacen que el robot se mueva hacia atrás, gire y vuelva a moverse en dirección contraria.
Por tanto, debes comprender como funcionan los puntos 1, 2 y 3 anteriores con claridad, ya que permiten que el robot se pare delante de un objeto independientemente de la distancia a la que se encuentre. Esto hace que el comportamiento sea realmente autónomo, y pueda funcionar en entornos desconocidos a priori. Para comprobarlo, vete a las opciones de RoboboSim y activa Comportamiento aleatorio en mundos. Ahora, cada vez que reinicies el escenario, el bloque estará a una distancia distinta, pero el programa anterior funcionará igualmente.
En las siguiente capturas se muestra la relación entre la distancia y el valor del sensor que recibe:
En la pestaña de los sensores en la pantalla de monitorización se pueden apreciar los siguientes valores:
Los sensores Front-LL y Front-RR dan unos valores más bajos que Front-C por su posición, ya que estos miran desde una dirección más alejada a la pared frontal.
Los sensores Front-L, Front-R y Back-C dan esos valores cuando están en el suelo.
Si el Robobo se acerca más a la pared:
Dará estos valores:
Es importante recordar que los valores leídos no equivalen a una distancia real en metros, sino que representa la intensidad de la señal generada por los sensores. La distancia a la que se encuentre y el material del objeto influyen en los valores. Habrá otros obstáculos en los que el valor puede cambiar bastante incluso si están a la misma distancia.
Ahora, para que podáis probar los sensores que miran al suelo, hay que cargar el mundo AVOID FALLING AND PUSH (No te preocupes por los obstáculos pequeños, ya que tiene una pinza para empujarlos o apartarlos) y abrir la página web de monitorización de Robobo y comprobar qué valores dan los sensores Front-R,Front-L y Back-C:
El funcionamiento es el siguiente:
Robobo dice "Voy hacia delante" y acto seguido avanza recto a una velocidad de 30.
Si Front-L o Front-R detectan un precicipio (El valor de los sensores empieza a disminuír hasta valores igual o inferiores a 25), se parará
Robobo dirá "Ahora voy a andar hacia atrás*, y avanzará hacia atrás a una velocidad de 40.
Cuando detecte un precicipio con el sensor Back-C, el robot se volverá a detener.
Robobo dirá "Ya no me muevo más" y se terminará el programa.
rob.connect()
rob.sayText("VOY HACIA DELANTE")
rob.moveWheels(30,30)
#Se mueve hacia adelante hasta que se acerque a un precipicio
while rob.readIRSensor(IR.FrontR) > 25 and rob.readIRSensor(IR.FrontL) > 25:
rob.wait(0.1)
#Se detiene y dice que andará hacia atrás
rob.stopMotors()
rob.sayText("AHORA VOY A ANDAR HACIA ATRÁS")
#Se mueve hacia atrás hasta que encuentre un precipicio
rob.moveWheels(-40,-40)
while rob.readIRSensor(IR.BackC) > 25:
rob.wait(0.1)
#Se detiene y termina el programa
rob.stopMotors()
rob.sayText("YA NO ME MUEVO MÁS")
rob.disconnect()
¿Habéis visto cómo cambian los valores al acercarse a los precipios?
readAllIRSensor()
Función: Lee el valor de todos los sensores infrarrojos.
Parámetro:
- Valores medidos (dict). Es un diccionario con los valores medidos por todos los sensores IR de la base. Las claves del diccionario son de tipo string, e indican el sensor IR correspondiente. Los valores del diccionario son de tipo int e indican el valor medido por el IR correspondiente
Para probar este método, en el mismo mundo anterior, reinicia el escenario y ejecuta estas instrucciones:
El siguiente programa a cargar en el mundo FOUR WALLS hace que Robobo se mueva hacia adelante hasta que encuentra un obstáculo cercano en el sensor delantero central:
Los diccionarios son conjunto de datos que contienen valores asociados a una clave. En el caso de este método las claves son los nombres de los sensores infrarrojos. Aquí se usará la clave 'Front-C'.
El primer bucle sirve para evitar que haya un error a la hora de comparar los valores de las claves en el siguiente bucle, ya que en el momento en que se ejecuta el Robot, es probable que los sensores no estén detectando nada. Por eso la condición del while es que el método sea igual a una lista vacía.
En el segundo bucle, cuando el valor de FrontC sea igual o mayor que 100 (el valor es orientativo, y debe ser ajustado al nivel de luz y al tipo de objeto a detectar), el robot se detendrá.
from robobopy.Robobo import Robobo
from robobopy.utils import Wheels
from robobopy.utils.IR import IR
rob = Robobo("localhost")
rob.connect()
#Se mueve hacia adelante
rob.moveWheels(30,30)
#Se carga el bucle con tal de que se asegure de que ha recibido los primeros valores sin ningún problema
while (rob.readAllIRSensor()==[]):
rob.wait(0.1)
#Robobo se mueve hasta que detecte un objeto de frente
while rob.readAllIRSensor()['Front-C'] < 100:
rob.wait(0.1)
#Se apagan los motores y se termina el programa
rob.stopMotors()
rob.disconnect()
AVISO: A veces, cuando se ejecutan varios comandos a la vez y/o en poco tiempo en un bucle, puede saltar el aviso en RoboboSim de que el robot está recibiendo demasiados comandos, por lo que se recomienda usar el comando wait() entre los comandos o no usar tantos comandos en modo no bloqueante de forma simultánea.
EJERCICIO 1
Abre el mapa Avoid the Block y crea el siguiente programa:
- Robobo tiene que avanzar a una velocidad de 25 y evitar el bloque que tiene enfrente. Para ello, si detecta el objeto con el sensor FrontC con un valor mínimo de 150 se tiene que detener.
- Después, el robot deberá girar 90º hacia la derecha, de forma que Robobo quede en paralelo a la caja.
- Avanza hacia delante hasta que no detecte el bloque con ningún IR (En este caso, los sensores FrontL, FrontLL y BackL)
#INSERTAR CÓDIGO AQUÍ
EJERCICIO 2
En el mapa Simple Maze, crea un programa que haga lo siguiente:
- El robot debe avanzar hacia delante hasta que se encuentre una pared de frente.
- En ese momento, el robot se pondrá en paralelo a la pared a su izquierda o a su derecha (esto lo decidirá el alumno preguntando al usuario por pantalla) lo máximo que pueda. No se usará moveWheelsByTime() ni moveWheelsByDegrees(), sino que Robobo girará hasta que los sensores cercanos a la pared detecten la pared. Por ejemplo, si Robob gira hacia la izquierda, los sensores Front-RR y Back-R deberán de detectar la pared y estén en paralelo.
- Cada que encuentre una nueva pared de frente dirá "TENGO UNA PARED ENFRENTE", se posicionará y después dira "VOY A SEGUIRLA".
- Estas secuencias las repetirá 5 veces, una vez acabe, se detendrá.
#INSERTAR CÓDIGO AQUÍ
EJERCICIO 3
Cargad el mundo AVOID FALLING y crea un programa en el que el:
- El robot avance de forma recta a una velocidad de 40 hasta que esté cerca de un precipicio o esté cerca de un obstáculo.
- Una vez cerca, el robot se tiene que detener, poner cara de asustado y decir "CASI ME CAIGO".
- Después, el robot tiene que retroceder un poco y girar hacia la derecha. Luego pondrá cara normal
- Si en lugar de un precipicio es un obstáculo que tenga de frente, que realice lo mismo pero diciendo "CASI CHOCO".
- Estas secuencias las repetirá 8 veces, una vez acabe, se detendrá.
#INSERTAR CÓDIGO AQUÍ