Unidad 4
Introducción 📜
Sección titulada «Introducción 📜»En esta unidad vas a aprender a construir sistemas físicos interactivos integrando dispositivos de hardware que usan protocolos de comunicación serial ASCII.
Rúbrica de evaluación de la unidad 📝
Sección titulada «Rúbrica de evaluación de la unidad 📝»Requisito de salida (condición necesaria)
Sección titulada «Requisito de salida (condición necesaria)»Rúbrica analítica
Sección titulada «Rúbrica analítica»| Criterio (peso) | Cumple plenamente (5.0) | Se cumple medianamente (4.0) | Problemas importantes (3.0) | Falta comprensión básica (2.0) | No hay evidencia (0.0) |
|---|---|---|---|---|---|
| 1. Aplicación + bitácora (40%) | La app se ejecuta sin fallos en el entorno acordado. Evidencia completa y verificable en bitácora. Todo consistente con lo mostrado en la demo. | La app funciona y cumple lo esencial. La bitácora permite verificar, pero hay 1–2 vacíos menores | La app funciona parcialmente o depende de condiciones no declaradas. Bitácora con vacíos importantes o incompleta. | La app no corre o no demuestra lo requerido. La bitácora no permite verificación de la app. | No se entregaron evidencias o no se puede acceder a ellas |
| Evaluación | |||||
| 2. Sustentación (60%) | Responde a las preguntas con precisión, conectando: (a) lo que se ve, (b) cómo está hecho, y (c) por qué. Usa su bitácora para justificar decisiones. Reconoce límites/errores y propone cómo probar/mejorar. | Respuestas correctas pero con imprecisiones menores o justificación superficial. Usa parcialmente la bitácora para sustentar. | Responde solo “qué hizo” pero le cuesta explicar “cómo” o “por qué”. Necesita guía para conectar con su propia evidencia/bitácora. | No logra responder de forma coherente o responde sin relación con lo presentado/documentado. Evidencia falta de comprensión básica del trabajo entregado. | No se entregaron evidencias o no se puede acceder a ellas |
| Evaluación |
Seek: Investigación 💡
Sección titulada «Seek: Investigación 💡»En esta unidad estudiaremos un caso de estudio de un sistema físico interactivo y luego te pediré que apliques lo investigado y aprendido a la solución de un problema similar a los que te encontrarás en el mundo real.
Actividad 01
Sección titulada «Actividad 01»En esta actividad te voy a presentar el caso de estudio que vamos a analizar en esta unidad.
Nos han pedido adpatar un sistema físico interactivo a una pieza de arte generativo existente. El reto es adaptar el sistema para que reciba información desde un micro:bit y así controlar la pieza de arte generativo.
La pieza de arte generativo que vamos a adaptar es un sketch de p5.js tomado del sitio Generative Design y será esta
El proveedor de hardware nos ha entregado un dispositivo al que “no podemos” cambiarle el firmware, pero si conocemos su protocolo de comunicación:
from microbit import *
uart.init(115200)display.set_pixel(0,0,9)
while True: xValue = accelerometer.get_x() yValue = accelerometer.get_y() aState = button_a.is_pressed() bState = button_b.is_pressed() data = "{},{},{},{}\n".format(xValue, yValue, aState,bState) uart.write(data) sleep(100) # Envia datos a 10 HzEn nuestro “estudio de diseño” contamos con algunas herramientas para analizar el hardware: SerialTerminal.
Finalmente, la infraestructura de software que tenemos para integrar el hardware con la pieza de arte generativo está en este repositorio
Apply: Aplicación 🛠
Sección titulada «Apply: Aplicación 🛠»En esta actividad vamos a simular un escenario real de trabajo en el que se nos pide integrar un nuevo hardware con una pieza de arte generativo existente, pero además tenemos un sistema de software ya construido que no podemos romper.
Actividad 02
Sección titulada «Actividad 02»Te piden que construyas un sistema físico interactivo que integre el hardware del caso de estudio con una pieza de arte generativo, pero esta vez el hardware tiene un firmware diferente que no puedes cambiar, además debes usar la arquitectura de software que ya existe.
La documentación del disipositivo de hardware es esta:
-
El sensor envía tramas codificadas en ASCII a 115200 baudios a una frecuencia de 10 Hz.
-
Cada paquete inicia con el símbolo $ y termina con un salto de línea \n. Los valores se separan por el carácter | (pipe).
-
Este es el formato:
$T:tiempo|X:acel_x|Y:acel_y|A:estado_a|B:estado_b|CHK:checksum\n -
Este es el diccionario de datos:
T: Timestamp en milisegundos desde el arranque del dispositivo (entero).
X, Y: Valores del acelerómetro (enteros entre -2048 y 2047).
A, B: Estado de los botones, 1 presionado, 0 liberado.
CHK: Checksum calculable. Es un número entero de 3 dígitos que representa la suma de los valores absolutos de X, Y, A y B. -
Este es un ejemplo de una trama válida:
$T:45020|X:-245|Y:12|A:1|B:0|CHK:258\n(Cálculo de ejemplo: |-245| + |12| + 1 + 0 = 258)
-
Nota para el desarrollador: si la suma de las variables no coincide con el valor CHK, la trama está corrupta y tu sistema debe descartarla silenciosamente sin actualizar la vista, pero deberías registrar un mensaje de advertencia en la consola indicando que se recibió una trama corrupta.
-
La aplicación de arte generativo ya construida que nos entrega el equipo de diseño es esta:
// Copy from P_2_0_02//// Generative Gestaltung – Creative Coding im Web// ISBN: 978-3-87439-902-9, First Edition, Hermann Schmidt, Mainz, 2018// Benedikt Groß, Hartmut Bohnacker, Julia Laub, Claudius Lazzeroni// with contributions by Joey Lee and Niels Poldervaart// Copyright 2018//// http://www.generative-gestaltung.de//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.
function setup() { createCanvas(720, 720); noFill(); background(255); strokeWeight(2); stroke(0, 25);}
function draw() { if (mouseIsPressed && mouseButton == LEFT) { push(); translate(width / 2, height / 2);
// Debe mapearse al eje Y del acelerómetro. let circleResolution = int(map(mouseY + 100, 0, height, 2, 10));
// Debe mapearse al eje X del acelerómetro. let radius = mouseX - width / 2; let angle = TAU / circleResolution;
// Debe ser activado por el botón B del dispositivo. if (keyIsPressed) { fill(34, 45, 122, 50); } else { noFill(); }
beginShape(); for (let i = 0; i <= circleResolution; i++) { let x = cos(angle * i) * radius; let y = sin(angle * i) * radius; vertex(x, y); } endShape();
pop(); }}Arquitectura del sistema: guía de integración
Sección titulada «Arquitectura del sistema: guía de integración»Para resolver este caso de estudio, no basta con escribir código que funcione de forma aislada. Debes entender cómo fluyen los datos en la aplicación del caso de estudio, desde el hardware hasta el píxel en la pantalla. El proyecto utiliza una arquitectura desacoplada estructurada en tres capas principales:
- Capa de backend: el patrón adapter (carpeta adapters)
-
El servidor Node.js no sabe (ni le importa) qué hardware está conectado. Únicamente espera recibir un objeto de datos estandarizado.
-
El contrato: revisa el archivo MicrobitASCIIAdapter.js. Nota que hereda de BaseAdapter. Su única responsabilidad es leer los datos de texto crudo del puerto serial, validarlo y emitir un objeto JavaScript limpio mediante la llamada
this.onData?.({ x: num, y: num, btnA: bool, btnB: bool }). -
Tu reto: no debes modificar el servidor principal. Debes crear un nuevo archivo (ej. MicrobitV2Adapter.js) que procese el nuevo protocolo
($T:tiempo|X:...|CHK:...\n), realice la operación matemática del checksum para descartar tramas corruptas, y finalmente emita exactamente el mismo formato de objeto JSON que el adaptador anterior. Si tu adaptador cumple el contrato, el servidor funcionará mágicamente.
- Capa de transporte: el bridge (bridgeClient.js)
- Esta capa es transparente para ti. El servidor toma el objeto JSON emitido por tu Adaptador y lo transmite al navegador vía WebSockets. El archivo bridgeClient.js recibe este JSON y dispara el evento EVENTS.DATA. No necesitas modificar esta capa, pero debes saber que es la frontera entre Node.js y p5.js.
-
Capa de frontend: máquina de estados y renderizado (sketch.js)
El equipo de diseño te entregó un código de p5.js tradicional (todo ocurre dentro de setup y draw). No puedes simplemente pegar ese código en sketch.js.
La UI de este proyecto utiliza un patrón de Máquina de Estados Finitos (FSM) gestionado en la clase PainterTask. Debes separar la lógica gráfica del prototipo que te dieron en dos partes:
-
Ingesta de datos (updateLogic): aquí aterrizan los datos del hardware (ev.payload). Tu deber es escalar matemáticamente los valores crudos del acelerómetro (ej. usar map() para adecuar los rangos del protocolo a las proporciones de tu Canvas) y actualizar el estado de las variables (radios, resoluciones, colores).
-
Renderizado (drawRunning): esta función equivale al draw() del prototipo original. El renderizado es “tonto”; solo debe leer las variables almacenadas en el estado (ej. mb.x, mb.btnA) y limitarse a usar las funciones de dibujo geométrico (beginShape, vertex, etc.) de p5.js.
En resumen, lo que deberás hacer es traducir la nueva trama serial a un objeto JSON usando el patrón Adapter. Luego, toma el prototipo del equipo de diseño y extrae sus variables de mouse/teclado y conéctalas a la actualización de estado (updateLogic). Traslada la lógica de dibujo poligonal dentro del estado correspondiente de la máquina de estados.
-