from machine import Pin, PWM, I2C, ADC # Importa clases para manejar pines, PWM, I2C y entradas analógicas
import time # Módulo para manejo de tiempo
import dht # Librería para sensor DHT11
import ssd1306 # Librería para pantalla OLED SSD1306
# === Motores DC ===
pwm_A = PWM(Pin(2)) # PWM para motor A (ENA)
pwm_B = PWM(Pin(3)) # PWM para motor B (ENB)
pwm_A.freq(1000) # Frecuencia de PWM A a 1kHz
pwm_B.freq(1000) # Frecuencia de PWM B a 1kHz
in1 = Pin(16, Pin.OUT) # Dirección motor A (IN1)
in2 = Pin(17, Pin.OUT) # Dirección motor A (IN2)
in3 = Pin(18, Pin.OUT) # Dirección motor B (IN3)
in4 = Pin(19, Pin.OUT) # Dirección motor B (IN4)
# === Botones ===
emergency_button = Pin(15, Pin.IN, Pin.PULL_UP) # Botón de paro de emergencia
continue_button = Pin(13, Pin.IN, Pin.PULL_UP) # Botón para continuar
# === Sensor DHT11 (GP14) ===
dht_sensor = dht.DHT11(Pin(14)) # Sensor de temperatura y humedad
# === Sensor Ultrasónico HC-SR04 ===
trig = Pin(12, Pin.OUT) # Pin TRIG para enviar pulsos
echo = Pin(11, Pin.IN) # Pin ECHO para recibir el eco
# === Potenciómetro ===
pot = ADC(26) # Entrada analógica en GP26 para leer potenciómetro
# === Pantalla OLED ===
i2c = I2C(0, scl=Pin(1), sda=Pin(0)) # Inicializa bus I2C0 con SCL en GP1 y SDA en GP0
oled = ssd1306.SSD1306_I2C(128, 64, i2c) # Crea objeto OLED de 128x64 píxeles
# === Variables de estado ===
contador = 0 # Cuenta cuántos objetos se detectaron
objeto_detectado = False # Controla si hay objeto actual
velocidad_actual = 55 # Velocidad inicial de los motores
# === Función: Leer velocidad del potenciómetro ===
def leer_velocidad_pot():
lectura = pot.read_u16() # Lee valor ADC (0 - 65535)
velocidad = int((lectura / 65535) * 100) # Convierte a porcentaje (0 - 100%)
return max(20, velocidad) # Devuelve al menos 20% para evitar paro total
# === Función: Medir distancia con HC-SR04 ===
def medir_distancia_cm():
trig.low() # Asegura que TRIG comience en bajo
time.sleep_us(2) # Espera 2 microsegundos
trig.high() # Activa TRIG durante 10us
time.sleep_us(10)
trig.low()
while echo.value() == 0: # Espera a que llegue el eco (suba a 1)
pulse_start = time.ticks_us() # Marca inicio
while echo.value() == 1: # Mientras el eco esté activo
pulse_end = time.ticks_us() # Marca fin
duration = time.ticks_diff(pulse_end, pulse_start) # Duración del pulso
distancia = duration * 0.0343 / 2 # Calcula distancia en cm
return distancia
# === Función: Control de motor (dirección y velocidad) ===
def control_motor(motor, direction, speed):
duty = int((speed / 100) * 65535) # Convierte porcentaje a duty cycle de 16 bits
if motor == 'A' or motor == 'both':
if direction == 'forward':
in1.high()
in2.low()
elif direction == 'backward':
in1.low()
in2.high()
else:
in1.low()
in2.low()
pwm_A.duty_u16(duty) # Aplica duty cycle al motor A
if motor == 'B' or motor == 'both':
if direction == 'forward':
in3.high()
in4.low()
elif direction == 'backward':
in3.low()
in4.high()
else:
in3.low()
in4.low()
pwm_B.duty_u16(duty) # Aplica duty cycle al motor B
# === Función: Detener ambos motores ===
def stop_motors():
control_motor('both', None, 0) # Envía velocidad 0
# === Función: Iniciar motores con velocidad actual ===
def start_motors():
global velocidad_actual
velocidad_actual = leer_velocidad_pot() # Lee velocidad desde potenciómetro
control_motor('both', 'forward', velocidad_actual) # Enciende motores hacia adelante
# === Inicio de motores al arrancar ===
start_motors()
# === Bucle principal ===
while True:
# === Paro de emergencia ===
if emergency_button.value() == 0: # Si se presiona botón de emergencia
time.sleep(0.05)
if emergency_button.value() == 0:
print("¡Paro de emergencia activado!")
stop_motors() # Detiene los motores
oled.fill(0)
oled.text("EMERGENCIA", 10, 10)
oled.text("Motores OFF", 10, 30)
oled.text("Esperando...", 10, 50)
oled.show()
while continue_button.value() == 1: # Espera a que se presione "continuar"
time.sleep(0.1)
print("Botón continuar presionado.")
oled.fill(0)
oled.text("Reanudando", 20, 20)
oled.show()
time.sleep(1)
start_motors() # Reactiva motores
# === Lectura de distancia con ultrasonido ===
try:
distancia = medir_distancia_cm()
if distancia < 15 and not objeto_detectado: # Si se detecta objeto cercano
contador += 1
objeto_detectado = True # Evita contar múltiples veces el mismo objeto
print("Objeto detectado. Total:", contador)
elif distancia >= 15:
objeto_detectado = False # Reinicia bandera si no hay objeto
except Exception as e:
print("Error en sensor ultrasónico:", e)
# === Lectura de temperatura y humedad ===
try:
dht_sensor.measure()
temp = dht_sensor.temperature() # Temperatura en °C
hum = dht_sensor.humidity() # Humedad relativa %
except Exception as e:
temp = '--'
hum = '--'
print("Error DHT11:", e)
# === Ajuste de velocidad desde potenciómetro ===
nueva_velocidad = leer_velocidad_pot()
if abs(nueva_velocidad - velocidad_actual) > 2: # Solo si el cambio es notable
velocidad_actual = nueva_velocidad
control_motor('both', 'forward', velocidad_actual)
# === Mostrar valores por consola ===
print("Temp: {} C | Humedad: {}% | Objetos: {} | Velocidad: {}%".format(temp, hum, contador, velocidad_actual))
# === Mostrar valores en OLED ===
oled.fill(0)
oled.text("Temp: {} C".format(temp), 0, 0)
oled.text("Humedad: {}%".format(hum), 0, 10)
oled.text("Vel: {}%".format(velocidad_actual), 0, 20)
oled.text("Objeto: {}".format(contador), 0, 35)
oled.text("Motores: ON", 0, 50)
oled.show()
time.sleep(0.1) # Pequeño retardo entre ciclos