Nota

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 [aquí] y únete hoy mismo.

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.

Ejecutar el Código

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

Nota

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.

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?

  1. Bloque de Inicialización

    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.

  2. Bloque de Configuración de Timeout (evita que sonar.read() se congele)

    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.

  3. Función: safe_read_once()

    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.

  4. Función: read_distance_filtered()

    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.

  5. Función: main() (decisión y acción principal)

    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.

  6. Bloque de Entrada del Programa (bucle continuo + salida segura)

    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.