.. note::
Hola, bienvenido a la comunidad de entusiastas de SunFounder Raspberry Pi & Arduino & ESP32 en Facebook. ¡Explora más a fondo Raspberry Pi, Arduino y ESP32 con otros entusiastas!
**¿Por qué unirse?**
- **Soporte experto**: Resuelve problemas postventa y desafíos técnicos con la ayuda de nuestra comunidad y equipo.
- **Aprende y comparte**: Intercambia consejos y tutoriales para mejorar tus habilidades.
- **Avances exclusivos**: Obtén acceso anticipado a anuncios de nuevos productos y vistas previas.
- **Descuentos especiales**: Disfruta de descuentos exclusivos en nuestros productos más recientes.
- **Promociones festivas y sorteos**: Participa en sorteos y promociones de temporada.
👉 ¿Listo para explorar y crear con nosotros? Haz clic en [|link_sf_facebook|] y únete hoy mismo.
.. _py_avoid:
Evitación de Obstáculos
===========================
En este proyecto, PiCrawler usará un módulo ultrasónico para detectar obstáculos frente a él.
Cuando PiCrawler detecte un obstáculo, enviará una señal y buscará otra dirección para avanzar.
.. .. image:: img/avoid1.png
**Ejecutar el Código**
.. raw:: html
.. code-block::
cd ~/picrawler/examples
sudo python3 4_avoid.py
Cuando el programa comienza, PiCrawler se pone de pie.
Mide continuamente la distancia utilizando el sensor ultrasónico
y muestra el valor en la terminal.
Si se detecta un obstáculo dentro de 15 cm:
- Se reproduce un sonido de advertencia.
- El robot realiza un pequeño giro hacia la izquierda.
Si el camino está despejado:
- El robot avanza hacia adelante.
El robot continúa evitando obstáculos automáticamente hasta que presione Ctrl+C.
Antes de salir, se sienta de forma segura.
**Código**
.. note::
Puedes **Modificar/Restablecer/Copiar/Ejecutar/Detener** el código a continuación. Pero antes de eso, necesitas ir a la ruta del código fuente como ``picrawler\examples``. Después de modificar el código, puedes ejecutarlo directamente para ver el efecto.
.. raw:: html
.. code-block:: python
from picrawler import Picrawler
from robot_hat import Music, Ultrasonic, Pin
import time
import signal
music = Music()
crawler = Picrawler()
sonar = Ultrasonic(Pin("D2"), Pin("D3")) # Ultrasonic trigger/echo pins
music.music_set_volume(100) # Set speaker volume
alert_distance = 15 # Obstacle warning distance (cm)
speed = 80 # Movement speed
# ----------------------------
# Add hardware timeout to sonar.read()
# Prevent program from freezing
# ----------------------------
class Timeout(Exception):
pass
def _alarm_handler(signum, frame):
raise Timeout()
signal.signal(signal.SIGALRM, _alarm_handler)
# Read distance once with timeout protection
def safe_read_once(timeout_s=1):
try:
signal.alarm(timeout_s)
d = sonar.read()
signal.alarm(0)
return d
except Timeout:
signal.alarm(0)
return None
except Exception:
signal.alarm(0)
return None
# Read multiple times and return median value (anti-noise)
def read_distance_filtered(n=5, gap=0.03, timeout_s=1):
vals = []
for _ in range(n):
d = safe_read_once(timeout_s=timeout_s)
if d is not None and d > 0:
vals.append(d)
time.sleep(gap)
if not vals:
return None
vals.sort()
return vals[len(vals)//2] # Median filter
def main():
distance = read_distance_filtered(n=5, gap=0.03, timeout_s=1)
print("distance:", distance)
if distance is None:
time.sleep(0.15) # Wait if read failed
return
if distance <= alert_distance:
# Obstacle detected → play sound and turn
try:
music.sound_play_threading('./sounds/sign.wav', volume=100)
except Exception as e:
print("sound error:", e)
crawler.do_action('turn left angle', 1, speed)
time.sleep(0.5) # Quiet window after movement
else:
# Path clear → move forward
crawler.do_action('forward', 1, speed)
time.sleep(0.4)
if __name__ == "__main__":
try:
crawler.do_step('stand', 40) # Stand before starting
time.sleep(1.0)
while True:
main()
except KeyboardInterrupt:
print("\nStop.")
finally:
try:
crawler.do_step('sit', 40) # Sit before exit
time.sleep(1.0)
except Exception:
pass
**¿Cómo funciona?**
#. Bloque de Inicialización
.. code-block:: python
music = Music()
crawler = Picrawler()
sonar = Ultrasonic(Pin("D2"), Pin("D3"))
music.music_set_volume(100)
alert_distance = 15
speed = 80
Este bloque inicializa los tres módulos principales:
- ``music``: controla la reproducción de sonido.
- ``crawler``: controla el movimiento de PiCrawler.
- ``sonar``: mide la distancia usando el sensor ultrasónico.
También establece el volumen del altavoz, el umbral de detección de obstáculos (cm)
y la velocidad de movimiento.
#. Bloque de Configuración de Timeout (evita que ``sonar.read()`` se congele)
.. code-block:: python
class Timeout(Exception):
pass
def _alarm_handler(signum, frame):
raise Timeout()
signal.signal(signal.SIGALRM, _alarm_handler)
El controlador ultrasónico puede bloquearse mientras espera la señal de eco.
Este bloque instala un manejador de señales para que el programa pueda interrumpir
una llamada bloqueada de ``sonar.read()`` y continuar ejecutándose.
#. Función: safe_read_once()
.. code-block:: python
def safe_read_once(timeout_s=1):
try:
signal.alarm(timeout_s)
d = sonar.read()
signal.alarm(0)
return d
except Timeout:
signal.alarm(0)
return None
except Exception:
signal.alarm(0)
return None
Esta función lee la distancia ultrasónica una vez con protección de tiempo límite.
- Si la lectura es exitosa, devuelve el valor de la distancia.
- Si ocurre un timeout o falla, devuelve ``None`` en lugar de quedarse bloqueado.
#. Función: read_distance_filtered()
.. code-block:: python
def read_distance_filtered(n=5, gap=0.03, timeout_s=1):
vals = []
for _ in range(n):
d = safe_read_once(timeout_s=timeout_s)
if d is not None and d > 0:
vals.append(d)
time.sleep(gap)
if not vals:
return None
vals.sort()
return vals[len(vals)//2]
Esta función mejora la fiabilidad leyendo múltiples muestras:
- Los valores inválidos (``None`` o ``<= 0``) se ignoran.
- Los valores restantes se ordenan.
- Se devuelve el valor mediano para reducir el ruido.
#. Función: main() (decisión y acción principal)
.. code-block:: python
def main():
distance = read_distance_filtered(...)
if distance is None:
return
if distance <= alert_distance:
music.sound_play_threading(...)
crawler.do_action('turn left angle', 1, speed)
else:
crawler.do_action('forward', 1, speed)
Esta es la lógica principal de control:
- Lee un valor de distancia filtrado.
- Si la lectura falla, se omite este ciclo.
- Si un obstáculo está más cerca que ``alert_distance``, reproduce un sonido de advertencia y gira a la izquierda.
- De lo contrario, avanza hacia adelante.
#. Bloque de Entrada del Programa (bucle continuo + salida segura)
.. code-block:: python
if __name__ == "__main__":
try:
crawler.do_step('stand', 40)
while True:
main()
except KeyboardInterrupt:
print("\nStop.")
finally:
crawler.do_step('sit', 40)
Este bloque controla el flujo general del programa:
- El crawler se pone de pie antes de comenzar.
- El programa ejecuta ``main()`` repetidamente en un bucle infinito.
- Presionar Ctrl+C detiene el bucle.
- El crawler se sienta antes de que el programa finalice.