← Índice Valentina Tech
Laboratorio 5 · Curso de Programación · CircuitPython

El acelerómetro: la placa siente el movimiento y la inclinación

Objetivos

En este laboratorio aprenderás a:


Material necesario


Introducción

En el Lab 4 tu placa aprendió a ver con el sensor de luz. Descubriste que un buen
sistema no solo siente: sabe cada cuánto medir (muestreo) y sabe adaptarse al lugar
(calibración).

Hasta ahora la placa ha reaccionado a:

Ahora le vamos a dar un sentido nuevo, uno que ya conoces muy bien de tu propio cuerpo:

👉 el equilibrio: sentir el movimiento y la inclinación


🏃 ¿Qué es el acelerómetro?

Un acelerómetro es un sensor que mide movimiento e inclinación: si la placa está
quieta, si la sacudes, si la volteas o hacia dónde la ladeas.

🚲 ¿Te acuerdas de la bici del Lab 4? Cuando ibas rodando, tu oído interno (el
sentido del equilibrio) revisaba tu balance decenas de veces por segundo para que no te
cayeras. El acelerómetro es exactamente ese sentido, pero para tu placa.

🧠 Ejemplo cotidiano

Cuando giras el celular y la pantalla gira sola para acomodarse:

👉 está usando su acelerómetro para saber cómo lo estás sosteniendo

Y cuando tu celular o tu reloj cuentan tus pasos, también: sienten el "brinquito" de
cada pisada.

💡 Curiosidad: el acelerómetro es el héroe silencioso de los autos. Cuando hay un
choque, siente el frenón violentísimo en una fracción de segundo y dispara la bolsa de
aire
antes de que tú alcances a parpadear.


🤖 Recordatorio: esto es Computación Física

Como en el Lab 4, seguimos el mismo ciclo de siempre:

🌎 MUNDO  →  SENSOR  →  MUESTRAS  →  Python  →  DECISIÓN  →  LEDs  →  🌎 MUNDO

Antes el sensor era el ojo (la luz). Ahora es el equilibrio (el movimiento). El
código no cambia de idea: siente → piensa → responde. Y las tres herramientas que
aprendiste —mapeo, muestreo y calibración— funcionan igual con este sensor
nuevo.


🔬 El acelerómetro por dentro

El acelerómetro es un chip diminuto en el centro de la placa (su nombre técnico es
LIS3DH). Por dentro tiene una masa microscópica sujeta con resortes también
microscópicos: cuando la placa se mueve, la masa se recorre un poquitín, y el chip mide
cuánto se recorrió. Sus características:

En el código, los tres números llegan juntos:

x, y, z = cp.acceleration   # SIENTE: los tres ejes de una vez
print(x, y, z)              # míralos en la consola

💡 Curiosidad: es el mismo tipo de sensor que hace vibrar el control de los
videojuegos y que sabe cuándo volteaste la tablet.


🧭 El laboratorio en 3 fases

Igual que en el Lab 4, lo construimos como un ingeniero: primero lo básico, luego
confiable, y al final adaptable.


🟢 Fase 1 — Sentir el movimiento

Paso 1: leer los tres ejes

Corre este programa y inclina la placa despacio en todas direcciones mientras miras la
consola:

import time
from adafruit_circuitplayground import cp

while True:
    x, y, z = cp.acceleration
    print(x, y, z)
    time.sleep(0.2)

Observa: cuando la dejas plana sobre la mesa, x y y andan cerca de 0 y z cerca de
9.8 (¡la gravedad!). Al ladearla, esos números cambian. Ese es el idioma del sensor.

Paso 2: color según la inclinación

Ahora respondemos. Usamos el eje x (ladeo izquierda/derecha) para elegir un color:

import time
from adafruit_circuitplayground import cp

cp.pixels.brightness = 0.2

while True:

    x, y, z = cp.acceleration

    if x > 3:
        cp.pixels.fill((0, 0, 255))     # inclinada a un lado
    elif x < -3:
        cp.pixels.fill((255, 0, 0))     # inclinada al otro
    else:
        cp.pixels.fill((0, 255, 0))     # plana

    print(x, y, z)
    time.sleep(0.2)

Cómo lo lee el programa: x, y, z = cp.acceleration guarda los tres ejes; los if
miran solo x y eligen color. Ladea la placa a un lado y al otro para verlo cambiar; déjala
plana y se pone verde.

🎚️ La sensibilidad

Igual que con la luz, la sensibilidad —qué tanto reacciona a los cambios— la decides
tú, programando
. El acelerómetro tampoco tiene una perilla mágica:

👉 La sensibilidad no vive en el sensor: vive en cómo programas su respuesta.


🟡 Fase 2 — El muestreo

Deja el programa de la Fase 1 quieto, sin tocar la placa… y verás algo raro: los números
brincan solitos, aunque nadie la mueva. Como con la luz, hay que aprender a medir
bien
. A eso se le llama muestreo (lo viste en el Lab 4).

🧪 Nota clara — dos cosas engañan al acelerómetro:

1) La gravedad siempre está ahí. Aunque la placa esté quietecita, la Tierra la jala
con ≈ 9.8. Entonces "no se mueve" no es 0: es 9.8. Si queremos medir movimiento,
primero tenemos que descontar esa gravedad de fondo.

2) El sensor es tan fino que capta vibraciones que tú ni notas: el temblor de tu mano,
los pasos de alguien, el motorcito de un ventilador, la mesa. Una sola lectura puede caer
justo en un microtemblor y el número salta.

⚠️ Ojo, una diferencia con el Lab 4: con la luz apagábamos los LEDs para "no medirnos
a nosotros mismos". Aquí eso no hace falta: los LEDs no mueven la placa. El acelerómetro
tiene sus propios engaños (la gravedad y las vibraciones), así que usamos otros dos trucos:
promediar y suavizar.

➕ Juntar 3 números en 1: la magnitud

Tenemos tres ejes (x, y, z), pero para "¿cuánta fuerza hay en total?" queremos un
solo número
, sin importar la dirección. A ese número se le llama magnitud.

Piénsalo con una caja: si conoces su ancho, su alto y su fondo, puedes calcular el largo
de su diagonal (la línea de esquina a esquina). Se hace elevando cada lado al cuadrado,
sumándolos y sacando la raíz. Con los ejes es igual:

fuerza = (x * x + y * y + z * z) ** 0.5   # magnitud (la "diagonal")

💡 Curiosidad: esto es el famoso Teorema de Pitágoras… pero en 3D. El mismo que
usan los videojuegos para medir distancias en el espacio.

💻 Código completo de la Fase 2

Aquí el programa completo: mide la fuerza total con muestreo (promediar + suavizar),
le descuenta la gravedad para quedarse solo con el movimiento, y responde con color.
Cópialo tal cual; abajo lo explicamos paso a paso.

import time
from adafruit_circuitplayground import cp

cp.pixels.brightness = 0.2
movimiento = 0.0   # valor inicial para suavizar

while True:

    # --- MEDIR bien (muestreo) ---
    suma = 0
    for _ in range(10):
        x, y, z = cp.acceleration
        fuerza = (x * x + y * y + z * z) ** 0.5   # magnitud
        suma = suma + fuerza
        time.sleep(0.005)              # 10 lecturas en ~50 ms
    promedio = suma / 10

    extra = promedio - 9.8             # descuenta la gravedad
    if extra < 0:
        extra = -extra                 # siempre positivo
    movimiento = movimiento * 0.6 + extra * 0.4   # suaviza

    # --- RESPONDER con color según el nivel ---
    if movimiento < 1:
        cp.pixels.fill((0, 0, 255))    # azul: quieta
    elif movimiento < 4:
        cp.pixels.fill((0, 255, 0))    # verde: se mueve
    else:
        cp.pixels.fill((255, 0, 0))    # rojo: sacudida fuerte

    print(round(movimiento, 1))
    time.sleep(0.1)

Con esto, quieta en la mesa el número se queda cerca de 0 y la placa se pone azul;
muévela y pasa a verde; sacúdela y se pone roja.

🔎 Explicación paso a paso

1. Preparar (antes del bucle).

movimiento = 0.0   # primer valor, para poder suavizar después

Guardamos un primer valor de movimiento porque el suavizado (paso 4) necesita recordar
el valor anterior.

2. Promediar en el tiempo.

suma = 0
for _ in range(10):
    x, y, z = cp.acceleration
    fuerza = (x * x + y * y + z * z) ** 0.5
    suma = suma + fuerza
    time.sleep(0.005)
promedio = suma / 10

Tomamos 10 muestras de la magnitud repartidas en ~50 ms y sacamos su promedio
(súmalas todas y divide entre 10). Así, un microtemblor en una lectura queda diluido
entre las demás.

3. Descontar la gravedad.

extra = promedio - 9.8
if extra < 0:
    extra = -extra

La gravedad mete un 9.8 de fondo siempre. Se lo restamos para quedarnos solo con el
movimiento. El if lo vuelve positivo (nos interesa cuánto se mueve, no hacia dónde).

4. Suavizar con memoria.

movimiento = movimiento * 0.6 + extra * 0.4

Igual que en el Lab 4: 60 % del valor anterior + 40 % del nuevo. Como confía más en lo
que ya sabía, una lectura rara casi no lo mueve. Los dos números suman 1 para no cambiar
la escala.

5. Responder con color según el nivel.

if movimiento < 1:
    cp.pixels.fill((0, 0, 255))
elif movimiento < 4:
    cp.pixels.fill((0, 255, 0))
...

El mismo mapeo por niveles del Lab 4, pero ahora sobre el movimiento ya limpio.

🧠 Idea grande: el mismo muestreo (promediar + suavizar) que limpiaba la luz limpia
el movimiento. Cambia el sensor, pero la técnica de ingeniería es la misma.


🔵 Fase 3 — La calibración

Ya mides estable, pero queda un problema: dimos por hecho que quieto = 9.8. En la vida
real cada placa marca un poquito distinto (una 9.7, otra 9.9), y una mesa con
vibración no es lo mismo que una mesa firme. Si el 9.8 está mal, tu movimiento sale
corrido. La solución es calibrar (como en el Lab 4).

🧭 Calibrar aquí es enseñarle a la placa cuánto marca estando quieta, en esta
mesa, para medir el movimiento a partir de ahí.

⚖️ La báscula que se pone en cero

¿Alguna vez viste una báscula de cocina? Antes de pesar la harina, pones el tazón vacío
encima y aprietas "TARA": la báscula marca 0 aunque el tazón sí pesa. Le enseñaste
"esto es mi cero", y a partir de ahí solo mide lo que agregas.

Vamos a hacer justo eso: al arrancar, con la placa quietecita, medimos su reposo (su
"tazón vacío"). Después, movimiento = fuerza − reposo. Ya no un 9.8 adivinado: el valor
real de tu placa.

suma = 0
for _ in range(50):
    x, y, z = cp.acceleration
    suma = suma + (x * x + y * y + z * z) ** 0.5
    time.sleep(0.01)
reposo = suma / 50      # cuánto marca ESTA placa estando quieta

Y como en el Lab 4, en vez de umbrales fijos usaremos el porcentaje (nivel) entre el
mínimo (quieta) y el máximo movimiento que la placa haya visto.

💻 Código completo de la Fase 3

import time
from adafruit_circuitplayground import cp

cp.pixels.brightness = 0.2

# --- CALIBRAR el reposo: "poner en cero" al arrancar ---
suma = 0
for _ in range(50):
    x, y, z = cp.acceleration
    suma = suma + (x * x + y * y + z * z) ** 0.5
    time.sleep(0.01)
reposo = suma / 50
print("reposo:", round(reposo, 1))

movimiento = 0.0
mov_max = 1         # se irá subiendo

while True:

    # --- MEDIR bien (promediar + suavizar) ---
    suma = 0
    for _ in range(10):
        x, y, z = cp.acceleration
        suma = suma + (x * x + y * y + z * z) ** 0.5
        time.sleep(0.005)
    fuerza = suma / 10

    extra = fuerza - reposo        # a partir del cero aprendido
    if extra < 0:
        extra = -extra
    movimiento = movimiento * 0.6 + extra * 0.4

    # --- CALIBRAR: recordar el mayor movimiento... y olvidarlo de a poco ---
    mov_max = mov_max * 0.90       # olvida los sacudones viejos poco a poco
    if mov_max < 1:
        mov_max = 1               # nunca baja de aquí (no dividir entre casi cero)
    if movimiento > mov_max:
        mov_max = movimiento

    # --- NIVEL: el porcentaje entre quieta y el máximo (0 a 1) ---
    nivel = movimiento / mov_max

    # --- RESPONDER según el nivel (ya no hay números fijos) ---
    if nivel < 0.25:
        cp.pixels.fill((0, 0, 255))      # azul: casi quieta
    elif nivel < 0.5:
        cp.pixels.fill((0, 255, 255))    # cian
    elif nivel < 0.75:
        cp.pixels.fill((0, 255, 0))      # verde
    else:
        cp.pixels.fill((255, 0, 0))      # rojo: lo más brusco

    print(round(movimiento, 1), round(nivel, 2))
    time.sleep(0.1)

👉 Al arrancar, déjala quieta un segundo (mientras aprende su reposo). Luego dale una
buena sacudida una vez: así aprende su máximo y los colores se reparten solos
entre "quieta" y "sacudón".

🧠 ¿Por qué mov_max = mov_max * 0.90? Si la placa solo recordara su sacudón más
fuerte y nunca lo olvidara, la vara de medir quedaría clavada muy alto: después de un
sacudón bestia, un movimiento normal se vería chiquito y todo se quedaría en azul. Por
eso, en cada vuelta, el máximo baja un poquito (se queda con el 90 %): así olvida de a
poco
los sacudones viejos —en un par de segundos— y la escala se vuelve a repartir según
cómo la mueves ahora, de modo que el azul, el cian, el verde y el rojo salgan parejos.
El if mov_max < 1 es un piso para que "quieta" siga siendo azul y no dividir entre casi
cero.

La calibración también servía para la luz, para las básculas, los termómetros y los
robots de Marte (Lab 4). Aquí ves que el mismo truco —enseñarle al aparato un número de
tu mundo real— sirve para un sensor completamente distinto.


Retos del laboratorio


🟢 Reto 1: Semáforo de movimiento

Cambia los colores para que:

💡 Objetivo: asociar niveles de movimiento con señales visuales.


🟡 Reto 2: Nivel de burbuja

Haz que el LED que se enciende apunte hacia donde inclinas la placa (como la burbujita
de un nivel de carpintero). Si está plana, todo en verde.

💡 Objetivo: usar los ejes x y y para saber la dirección, no solo la fuerza.


🔴 Reto 3: Alarma anti-robo

Deja la placa quieta "vigilando" en verde. Si alguien la mueve:

💡 Objetivo: crear un sistema de alerta (como el de una caja fuerte o una mochila).


Resumen del laboratorio

En este laboratorio aprendiste, en 3 fases:

Ahora tu placa no solo ve el mundo:

👉 ahora también siente cómo la mueves y responde como un sistema vivo


🚀 Puente a la Misión 5. Sentir el movimiento es solo la mitad de la historia; la otra
mitad es controlarlo. En la misión convertirás tu CPX en el mando de la nave:
usando la calibración y los ejes de este laboratorio, tu placa se hará pasar por un
teclado y "tecleará" las flechas según cómo la inclines, para girar el modelo 3D
de la Astra-7 y revisar sus daños. Sentir el movimiento y controlar el movimiento son
la misma idea.

Valentina Tech · Circuit Playground Express · CircuitPython