| Per començar | Elements d'entrada | Programació CircuitPython | Recursos CITCEA | |
| Elements no electrònics | Elements de sortida | Programació Arduino | ||
| Projectes | Elements de control | Dades pràctiques | Inici |
SeuBé és una samarreta que detecta si l'usuari seu en una bona postura i, en cas que no, l'avisa per tal que la corregeixi.
La llista de materials principals és la següent:
1 placa Circuit Playground Express
2 sensors de flexió (potes A1 i A4)
1 resistència de 10 kΩ
1 altaveu (pota A6)
1 motor de vibració (pota A7))
1 control del motor sobre una placa de prototipatge
1 tira de NeoPixel (pota A5)
La imatge següent mostra la disposició dels elements.

A continuació tenim el llistat del programa:
import time import board import analogio import digitalio import pwmio import neopixel
# CONFIGURACIÓN DE PINES:
# Sensores de flexión (0-65535):
sensor1 = analogio.AnalogIn(board.A1)
sensor2 = analogio.AnalogIn(board.A4)
# LEDs :
NUM_LEDS = 51
leds = neopixel.NeoPixel(
board.A5,
NUM_LEDS,
brightness=0.3,
auto_write=True
)
# Motor de vibración:
motor = digitalio.DigitalInOut(board.A7)
motor.direction = digitalio.Direction.OUTPUT
motor.value = False
# Altavoz:
buzzer = pwmio.PWMOut(board.A6, frequency=1000, duty_cycle=0, variable_frequency=True)
# VALORES PARA HACER EL CODIGO:
UMBRAL_MIN_ABAJO = 28500
UMBRAL_MAX_ABAJO = 45000
TIEMPO_LIMITE_PUNTUAL = 30 #30 segundos
TIEMPO_LIMITE_GLOBAL = 300 #5 minutos
DURACION_ALERTA = 2 #2 segundos
INTERVALO = 0.5
INTERVALO = 0.5
# FUNCIONES AUXILIARES
# Lee los 2 sensores y devuelve: [True o False , los valores de los sensores]
def leer_sensores():
v1 = sensor1.value
v2 = sensor2.value
valores = [v1,v2]
if v1 < UMBRAL_MIN_ABAJO or v1 > UMBRAL_MAX_ABAJO:
return True, valores
if v2 < UMBRAL_MIN_ABAJO or v2 > UMBRAL_MAX_ABAJO:
return True, valores
return False, valores
# Activa LEDs, motor y altavoz.
def activar_alertas():
leds.fill((255, 0, 0)) # rojo
buzzer.frequency = 490
buzzer.duty_cycle = 60000
def activar_motor():
motor.value = True
def desactivar_motor():
motor.value = False
# Desactiva LEDs, motor y altavoz.
def desactivar_alertas():
leds.fill((0, 0, 0)) # apagar LEDs
motor.value = False
buzzer.duty_cycle = 0
# Enciende los LEDs progresivamente como un dominó (1,5 segundos total)
def efecto_domino_naranja():
color_naranja = (255, 80, 0)
tiempo_total = 1.5
tiempo_por_led = tiempo_total / NUM_LEDS
leds.fill((0, 0, 0))
for i in range(NUM_LEDS):
leds[i] = color_naranja
time.sleep(tiempo_por_led)
def efecto_domino_rojo():
color_rojo= (255,0,0)
tiempo_total= 0.5
tiempo_por_led= tiempo_total / NUM_LEDS
leds.fill((0, 0, 0))
for i in range(NUM_LEDS):
leds[i] = color_rojo
time.sleep(tiempo_por_led)
# Activa el parpadeo hasta que la persona corrija la postura:
# ALERTA GRAVE: sonido -> luces -> vibración (en bucle)
def parpadeo_alerta_grave():
print("¡Llevas más de 5 minutos con mala postura!")
while True:
# 1. BEEP DEL ALTAVOZ:
buzzer.frequency = 466
buzzer.duty_cycle = 60000
time.sleep(0.25)
buzzer.duty_cycle = 0
time.sleep(0.15)
# 2. RÁFAGA DE LUCES ROJAS:
for _ in range(4):
leds.fill((255, 0, 0))
time.sleep(0.12)
leds.fill((0, 0, 0))
time.sleep(0.12)
# 3. VIBRACIÓN DEL MOTOR:
motor.value = True
time.sleep(0.5)
motor.value = False
time.sleep(0.2)
# COMPROBAR SI LA POSTURA YA ES CORRECTA:
malapostura, valores = leer_sensores()
print("Valores sensores:", [round(v) for v in valores])
if not malapostura:
print("Postura corregida. Reiniciando programa.")
desactivar_alertas()
time.sleep(0.5)
break
# Activa las luces, motor y altavoz durante 2 segundos (cuando llega a 30s).
def alerta_puntual():
print("30 segundos de mala postura")
# DOMINÓ NARANJA
efecto_domino_naranja()
# 1. SONIDO
buzzer.frequency = 466
buzzer.duty_cycle = 60000
time.sleep(1)
buzzer.duty_cycle = 0
time.sleep(0.1)
# 2. MOTOR
activar_motor()
time.sleep(1)
desactivar_motor()
# apagar todo por seguridad
desactivar_alertas()
# CODIGO PRINCIPAL:
contador_global = 0.0
contador_puntual = 0.0
alerta_puntual_ya_disparada = False
inicio_mala_postura = None
while True:
mala_postura, valores = leer_sensores()
print("Sensores:", [round(v) for v in valores],
"| Postura:", "MALA" if mala_postura else "CORRECTA",
"| Puntual:", round(contador_puntual, 1), "s",
"| Global:", round(contador_global, 1), "s")
if mala_postura:
if inicio_mala_postura is None:
inicio_mala_postura = time.monotonic()
contador_puntual = time.monotonic() - inicio_mala_postura
if contador_puntual >= TIEMPO_LIMITE_PUNTUAL and not alerta_puntual_ya_disparada:
alerta_puntual()
alerta_puntual_ya_disparada = True
total = contador_global + contador_puntual
if total >= TIEMPO_LIMITE_GLOBAL:
parpadeo_alerta_grave()
contador_global = 0.0
contador_puntual = 0.0
alerta_puntual_ya_disparada = False
inicio_mala_postura = None
print("Contadores reiniciados.\n")
else:
if inicio_mala_postura is not None:
contador_global += contador_puntual
print(f"Postura corregida. Acumulados {round(contador_puntual, 1)}s "
f"? Global total: {round(contador_global, 1)}s")
contador_puntual = 0.0
alerta_puntual_ya_disparada = False
inicio_mala_postura = None
desactivar_alertas()
time.sleep(INTERVALO)

Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.