Diferencia entre revisiones de «Butialo: Ejemplo 8 - Seguidor de líneas con obstáculos, sin eventos, utilizando un sensor de grises y uno de distancia»

De Proyecto Butiá
Saltar a: navegación, buscar
(Configuración)
m (Configuración)
 
(No se muestran 12 ediciones intermedias de 2 usuarios)
Línea 2: Línea 2:
  
 
==Descripción==
 
==Descripción==
Se desea implementar un programa que permita al robot Butiá poder desplazarse en una mesa sin caerse de la misma.
 
  
El robot deberá avanzar mientras detecte un color semejante al de la mesa. En caso de detectar un color distinto al de la mesa, procederá a retroceder por un tiempo aleatorio para luego cambiar de sentido (izquierda o derecha), y así poder avanzar nuevamente.
+
Se desea implementar un seguidor de líneas de nivel avanzado que permita al robot Butiá seguir el rastro de una línea de color negro sobre el suelo eludiendo obstáculos.
 +
 
 +
El robot deberá avanzar mientras se encuentre en una zona oscura y no detecte la proximidad de un obstáculo. En caso de salirse de la línea, deberá girar para poder encontrar nuevamente una zona oscura y en caso de detectar un obstáculo procederá a aplicar una técnica de rodeo poder continuar avanzando por la línea de color negro.
  
 
==Solución==
 
==Solución==
Línea 10: Línea 11:
 
'''Descripción'''
 
'''Descripción'''
  
Como fue explicado en ejemplos anteriores, el sensor de escala de grises (en este caso, se conectó el sensor al puerto 2, por eso su nombre es “Grey_2”) debe ser calibrado previamente a la ejecución del programa a desarrollar para poder obtener los respectivos valores límites a partir del cual definimos que el robot se encuentra sobre la mesa.
+
Obtenemos el valor de la variable COLOR_NEGRO de la misma forma que lo hicimos en el Ejemplo 1. Además, debemos calibrar el valor de la variable DISTANCIA_OBSTACULO que refiera a la distancia mínima a partir de la cual el robot detecta la presentacia de un obstáculo y por lo tanto deberá esquivar el mismo utilizando una técnica de rodeo.
  
Calculando el valor medio, obtuvimos el valor de la variable COLOR_MESA (43000 para las pruebas realizadas).
+
El robot deberá seguir el rastro de la línea de color negro de la misma forma que se realizó en el Ejemplo 1, chequeando además la presencia de un obstáculo que deberá esquivar para luego regresar a línea negra.
Determinamos entonces que si el valor arrojado por el sensor es menor a 43000, el robot puede continuar avanzando sin peligro de caer de la mesa, en caso contrario se deberá evitar la caída.
+
  
El robot deberá retroceder en un tiempo aleatorio, dicho valor deberá ser calibrado en las variables MIN_TIEMPO_RETROCESO y MAX_TIEMPO_RETROCESO de forma de contemplar que no se caiga de la mesa en caso de que el tiempo sea muy grande. Para ello el robot se colocará en el centro de la mesa. De la misma forma, se calibrará los valores de MIN_TIEMPO_GIRO y MAX_TIEMPO_GIRO, considerando aquí los posibles valores entre 1° y 90° aproximadamente.
+
Una vez calibrados los valores de los sensores, se organiza la estructura de la solución en diferentes funciones de forma de modularizar y distinguir fácilmente las acciones. El programa principal quedaría de la siguiente forma:
 
+
Una vez calibrado el sensor y obtenidos los respectivos valores de tiempo máximo y mínimo de giro y retroceso, se organiza la estructura de la solución en diferentes funciones de forma de modularizar y distinguir fácilmente las acciones. El programa principal quedaría de la siguiente forma:
+
  
 
* '''programa principal'''
 
* '''programa principal'''
  
Consiste en avanzar el robot hasta tanto no se encuentre en peligro de caer de la mesa, en caso contrario deberá retroceder de forma aleatoria. Luego de que se retrocede aleatoriamente, por un tiempo determinado, se utiliza la función girar_aleatorio() para que la siguiente vez que se avance, se haga en un sentido aleatorio.
+
Consiste en avanzar el robot hasta tanto no se encuentre en peligro de caer de la mesa, en caso contrario deberá retroceder de forma aleatoria. Luego de que se retrocede aleatoriamente, por un tiempo determinado, se utiliza la función girar_aleatorio() para que la siguiente vez que se avance, se haga en una dirección aleatoria.
  
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
 
while true do
 
while true do
 
     avanzar()
 
     avanzar()
     while (puedo_avanzar()) do
+
     while (es_negro() and not hay_obstaculo()) do
 
util.wait(INTERVALO_CHEQUEO)
 
util.wait(INTERVALO_CHEQUEO)
 
     end
 
     end
     retroceder_aleatorio()
+
     if hay_obstaculo() then
     girar_aleatorio()
+
esquivar_obstaculo()
 +
     else
 +
buscar_negro()
 +
util.wait(TIEMPO_CENTRADO)
 +
invertir_sentido()
 +
    end
 +
end
 +
</syntaxhighlight>
 +
 
 +
* '''invertir_sentido'''
 +
Cambia el sentido de izquierda a derecha o viceversa.
 +
 
 +
<syntaxhighlight lang="lua">
 +
local function invertir_sentido()
 +
    if sentido == "I" then
 +
sentido = "D"
 +
    else
 +
sentido = "I"
 +
    end
 
end
 
end
 
</syntaxhighlight>
 
</syntaxhighlight>
Línea 43: Línea 59:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
* '''puedo_avanzar'''
+
* '''retroceder'''
Retorna un valor booleano que indica si el robot se encuentra en peligro de caerse, según el valor obtenido por el sensor de grises y su comparación con la variable COLOR_MESA.
+
Retrocede el Butiá haciendo que los motores giren a una velocidad prefijada en la constante MOTOR_VEL.
  
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
local function puedo_avanzar()
+
local function retroceder()
     return (Grey_2.getValue() < COLOR_MESA)
+
     Motors.setvel2mtr(1, MOTOR_VEL, 1, MOTOR_VEL)
end</syntaxhighlight>
+
end
 +
</syntaxhighlight>
  
* '''chequear_giro_izquierda'''
+
* '''es_negro'''
Retorna un valor booleano que indica si el robot debe girar hacia la izquierda. Para girar de forma aleatoria, a izquierda o derecha, obtenemos un valor entre 0 y 1 con la función random de la bibloteca math. Si el valor randómico obtenido es mayor a 0.5 definimos que el giro será hacia la izquierda, retornando True y en caso contrario deberá girar a la derecha retornando False.
+
Retorna un valor booleano que indica si el robot está parado sobre la zona oscura, según el valor obtenido por el sensor de grises y su comparación con la constante COLOR_NEGRO.
  
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
local function chequear_giro_izquierda()
+
local function es_negro()
     local sentido = math.random (0, 1)
+
     local color = Grey_1.getValue()
     return sentido > 0.5
+
     return (color > COLOR_NEGRO)
 
end
 
end
 
</syntaxhighlight>
 
</syntaxhighlight>
  
* '''girar_aleatorio'''
+
* '''girar'''
Nuevamente utilizamos la función random para obtener un número aleatorio entre MIN_TIEMPO_GIRO y MAX_TIEMPO_GIRO y así definir el tiempo durante el cual el robot estará girando. Luego chequeamos con la función chequear_giro_izquierda() si el giro será en sentido izquierdo o derecho, dependiendo de ese valor se procederá entonces a girar en ese sentido con una velocidad definida por la variable VELOCIDAD_GIRO.
+
Gira el robot en el sentido correspondiente, el cual estará definido por la variable sentido.
  
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
local function girar_aleatorio()
+
local function girar()
     local tiempo_giro = math.random(MIN_TIEMPO_GIRO, MAX_TIEMPO_GIRO)
+
     if sentido == "I" then
    local izquierda = chequear_giro_izquierda()
+
Motors.setvel2mtr(0,MOTOR_GIRO_VEL,1,MOTOR_GIRO_VEL)
    if (izquierda) then
+
Motors.setvel2mtr(0, VELOCIDAD_GIRO, 1, VELOCIDAD_GIRO)
+
 
     else
 
     else
Motors.setvel2mtr(1, VELOCIDAD_GIRO, 0, VELOCIDAD_GIRO)
+
Motors.setvel2mtr(1,MOTOR_GIRO_VEL,0,MOTOR_GIRO_VEL)
 
     end
 
     end
     util.wait(tiempo_giro)
+
end
 +
</syntaxhighlight>
 +
 
 +
* '''buscar_negro'''
 +
Si el robot no encuentra color negro entonces deberá buscarlo. El robot hace un abanico, girando determinado tiempo en un sentido, para luego girar el doble de tiempo en el sentido opuesto. Esta acción culminará cuando se detecte que el robot está en una zona oscura.
 +
 
 +
<syntaxhighlight lang="lua">
 +
local function buscar_negro()
 +
     tiempo = 0.5
 +
    local tiempo_girando
 +
    while true do
 +
        tiempo_girando = 0
 +
        girar()
 +
        invertir_sentido()
 +
while (not es_negro() and tiempo_girando <= tiempo) do
 +
    util.wait(0.1)
 +
    tiempo_girando = tiempo_girando + 0.1
 +
        end
 +
if es_negro() then
 +
    break
 +
else
 +
    tiempo = tiempo * 2
 +
end
 +
    end
 +
end
 +
</syntaxhighlight>
 +
 
 +
* '''hay_obstaculo'''
 +
Retorna un valor booleano que indica si el robot ha detectado la presencia de un obstáculo, según el valor obtenido por el sensor de distancia y su comparación con la constante DISTANCIA_OBSTACULO.
 +
 
 +
<syntaxhighlight lang="lua">
 +
local function hay_obstaculo()
 +
    local distancia = Distanc_2.getValue()
 +
    return (distancia > DISTANCIA_OBSTACULO)
 +
end
 +
</syntaxhighlight>
 +
 
 +
* '''esquivar_obstaculo'''
 +
Al detectar la presencia de un obstáculo, el robot deberá actuar de la siguiente forma:
 +
1) Retroceder un tiempo determinado hasta alejarse lo suficiente como para poder girar.
 +
2) Girar a la derecha 90°.
 +
3) Avanza un tiempo determinado para alejarse del obstáculo.
 +
4) Girar a la izquierda 90°.
 +
5) Avanza un tiempo determinado para poder pasar el obstáculo.
 +
6) Girar a la izquierda 120° (=90*4/3)
 +
7) Avanza para volver a retomar la línea.
 +
 
 +
<syntaxhighlight lang="lua">
 +
local function esquivar_obstaculo()
 +
    local sentido_previo = sentido
 +
    retroceder()
 +
    util.wait(TIEMPO_RETROCESO)
 +
    sentido = "D"
 +
    girar()
 +
    util.wait(TIEMPO_GIRO_90_GRADOS)
 +
    avanzar()
 +
    util.wait(TIEMPO_AVANCE)
 +
    sentido = "I"
 +
    girar()
 +
    util.wait(TIEMPO_GIRO_90_GRADOS)
 +
    avanzar()
 +
    util.wait(TIEMPO_AVANCE * 3)
 +
    sentido = "I"
 +
    girar()
 +
    util.wait(TIEMPO_GIRO_90_GRADOS * 4 / 3)
 +
    avanzar()
 +
    while (not es_negro()) do
 +
util.wait(INTERVALO_CHEQUEO)
 +
    end
 +
    sentido = sentido_previo
 
end
 
end
 
</syntaxhighlight>
 
</syntaxhighlight>
Línea 79: Línea 163:
 
==Configuración==
 
==Configuración==
  
Se debe colocar un sensor de escala de grises lo más cercano a la mesa, pero siempre sin tocarla, en la parte de adelante del Butiá.
+
Se debe colocar un sensor de escala de grises lo más cercano al suelo, pero siempre sin tocarlo, en la parte de adelante del Butiá.
 +
 
 +
En nuestro caso encastramos piezas de forma de generar el soporte para adherir el sensor al Butiá, quedando dicho sensor a ras del suelo.
  
En nuestro caso encastramos piezas de forma de generar el soporte para adherir el sensor al Butiá, quedando dicho sensor a ras de la mesa.
+
Además se debe colocar un sensor de distancia al frente del Butiá, de manera que sense lo que tiene por delante.
  
 
Se muestra a continuación una imagen ilustrativa de la configuración del robot vista desde arriba.
 
Se muestra a continuación una imagen ilustrativa de la configuración del robot vista desde arriba.
Línea 89: Línea 175:
 
==Video==
 
==Video==
  
 +
<youtube>maY-Xjjofp4</youtube>
  
 
==Código==
 
==Código==
  
[[Butialo: Ejemplo 3 - Seguidor de líneas con obstáculos, sin eventos, utilizando un sensor de grises y uno de distancia - Código]]
+
[[Butialo: Ejemplo 8 - Seguidor de líneas con obstáculos, sin eventos, utilizando un sensor de grises y uno de distancia - Código]]

Revisión actual del 16:55 15 oct 2012

Descripción

Se desea implementar un seguidor de líneas de nivel avanzado que permita al robot Butiá seguir el rastro de una línea de color negro sobre el suelo eludiendo obstáculos.

El robot deberá avanzar mientras se encuentre en una zona oscura y no detecte la proximidad de un obstáculo. En caso de salirse de la línea, deberá girar para poder encontrar nuevamente una zona oscura y en caso de detectar un obstáculo procederá a aplicar una técnica de rodeo poder continuar avanzando por la línea de color negro.

Solución

Descripción

Obtenemos el valor de la variable COLOR_NEGRO de la misma forma que lo hicimos en el Ejemplo 1. Además, debemos calibrar el valor de la variable DISTANCIA_OBSTACULO que refiera a la distancia mínima a partir de la cual el robot detecta la presentacia de un obstáculo y por lo tanto deberá esquivar el mismo utilizando una técnica de rodeo.

El robot deberá seguir el rastro de la línea de color negro de la misma forma que se realizó en el Ejemplo 1, chequeando además la presencia de un obstáculo que deberá esquivar para luego regresar a línea negra.

Una vez calibrados los valores de los sensores, se organiza la estructura de la solución en diferentes funciones de forma de modularizar y distinguir fácilmente las acciones. El programa principal quedaría de la siguiente forma:

  • programa principal

Consiste en avanzar el robot hasta tanto no se encuentre en peligro de caer de la mesa, en caso contrario deberá retroceder de forma aleatoria. Luego de que se retrocede aleatoriamente, por un tiempo determinado, se utiliza la función girar_aleatorio() para que la siguiente vez que se avance, se haga en una dirección aleatoria.

while true do
    avanzar()
    while (es_negro() and not hay_obstaculo()) do
	util.wait(INTERVALO_CHEQUEO)
    end
    if hay_obstaculo() then
	esquivar_obstaculo()
    else
	buscar_negro()
	util.wait(TIEMPO_CENTRADO)
	invertir_sentido()
    end
end
  • invertir_sentido

Cambia el sentido de izquierda a derecha o viceversa.

local function invertir_sentido()
    if sentido == "I" then
	sentido = "D"
    else
	sentido = "I"
    end
end
  • avanzar

Activa los motores haciendo que los mismos giren a una velocidad prefijada en la constante MOTOR_VEL.

local function avanzar()
    Motors.setvel2mtr(0, MOTOR_VEL, 0, MOTOR_VEL)
end
  • retroceder

Retrocede el Butiá haciendo que los motores giren a una velocidad prefijada en la constante MOTOR_VEL.

local function retroceder()
    Motors.setvel2mtr(1, MOTOR_VEL, 1, MOTOR_VEL)
end
  • es_negro

Retorna un valor booleano que indica si el robot está parado sobre la zona oscura, según el valor obtenido por el sensor de grises y su comparación con la constante COLOR_NEGRO.

local function es_negro()
    local color = Grey_1.getValue()
    return (color > COLOR_NEGRO)
end
  • girar

Gira el robot en el sentido correspondiente, el cual estará definido por la variable sentido.

local function girar()
    if sentido == "I" then
	Motors.setvel2mtr(0,MOTOR_GIRO_VEL,1,MOTOR_GIRO_VEL)
    else
	Motors.setvel2mtr(1,MOTOR_GIRO_VEL,0,MOTOR_GIRO_VEL)
    end
end
  • buscar_negro

Si el robot no encuentra color negro entonces deberá buscarlo. El robot hace un abanico, girando determinado tiempo en un sentido, para luego girar el doble de tiempo en el sentido opuesto. Esta acción culminará cuando se detecte que el robot está en una zona oscura.

local function buscar_negro()
    tiempo = 0.5
    local tiempo_girando
    while true do
        tiempo_girando = 0
        girar()
        invertir_sentido()
	while (not es_negro() and tiempo_girando <= tiempo) do
	    util.wait(0.1)
	    tiempo_girando = tiempo_girando + 0.1
        end
	if es_negro() then
	    break
	else
	    tiempo = tiempo * 2
	end
    end
end
  • hay_obstaculo

Retorna un valor booleano que indica si el robot ha detectado la presencia de un obstáculo, según el valor obtenido por el sensor de distancia y su comparación con la constante DISTANCIA_OBSTACULO.

local function hay_obstaculo()
    local distancia = Distanc_2.getValue()
    return (distancia > DISTANCIA_OBSTACULO)
end
  • esquivar_obstaculo

Al detectar la presencia de un obstáculo, el robot deberá actuar de la siguiente forma: 1) Retroceder un tiempo determinado hasta alejarse lo suficiente como para poder girar. 2) Girar a la derecha 90°. 3) Avanza un tiempo determinado para alejarse del obstáculo. 4) Girar a la izquierda 90°. 5) Avanza un tiempo determinado para poder pasar el obstáculo. 6) Girar a la izquierda 120° (=90*4/3) 7) Avanza para volver a retomar la línea.

local function esquivar_obstaculo()
    local sentido_previo = sentido
    retroceder()
    util.wait(TIEMPO_RETROCESO)
    sentido = "D"
    girar()
    util.wait(TIEMPO_GIRO_90_GRADOS)
    avanzar()
    util.wait(TIEMPO_AVANCE)
    sentido = "I"
    girar()
    util.wait(TIEMPO_GIRO_90_GRADOS)
    avanzar()
    util.wait(TIEMPO_AVANCE * 3)
    sentido = "I"
    girar()
    util.wait(TIEMPO_GIRO_90_GRADOS * 4 / 3)
    avanzar()
    while (not es_negro()) do
	util.wait(INTERVALO_CHEQUEO)
    end
    sentido = sentido_previo
end

Configuración

Se debe colocar un sensor de escala de grises lo más cercano al suelo, pero siempre sin tocarlo, en la parte de adelante del Butiá.

En nuestro caso encastramos piezas de forma de generar el soporte para adherir el sensor al Butiá, quedando dicho sensor a ras del suelo.

Además se debe colocar un sensor de distancia al frente del Butiá, de manera que sense lo que tiene por delante.

Se muestra a continuación una imagen ilustrativa de la configuración del robot vista desde arriba.

Configuración

Video

Código

Butialo: Ejemplo 8 - Seguidor de líneas con obstáculos, sin eventos, utilizando un sensor de grises y uno de distancia - Código