MID Taller de Productos
Table of Contents
Profesores: Carolina Pino - Francisca Meza —– Ayudante: Cristóbal Ogrodnik Bert
Encargo 01 - Concepto verbo #
CONCEPTO #
El proceso de realización del encargo de crear algo en base al concepto del verbo “levantar” de Richard Serra en el Parque Quinta Normal involucró varias etapas y reflexiones creativas. A continuación, describiré el proceso detalladamente:
Observación inicial: Al llegar al Parque Quinta Normal, noté que había mucho ruido y la gente hablaba en tono elevado. Esta experiencia me llevó a seleccionar el verbo “levantar” debido a su conexión con la elevación del tono de voz y la presencia destacada del ruido en el entorno.
Reflexión y asociación de ideas: Al regresar al parque después de grabar, noté que la atmósfera había cambiado drásticamente. Ya no había mucha gente, sino numerosas parejas disfrutando del parque y compartiendo amor. Aquí surgió una conexión entre el verbo “levantar” y el concepto del amor, ya que las parejas se levantan mutuamente el ánimo en momentos difíciles y brindan apoyo fundamental.
Idea conceptual: Considerando la dependencia de la cercanía en el amor y la necesidad de comunicación a larga distancia, se me ocurrió la idea de crear un prototipo con electrónica. Este consistiría en una lámpara que, al ser tocada, encendería la luz correspondiente en la lámpara de la pareja, incluso si estuviera al otro lado del mundo. La conexión inalámbrica a través de Wi-Fi permitiría esta interacción.
Significado de los colores: Para representar diferentes emociones y estados de ánimo, decidí asignar colores a las distintas intensidades de presión sobre la lámpara. Si se presiona con fuerza, la luz sería roja, simbolizando la felicidad. Una presión moderada activaría una luz amarilla, que representaría un estado de ánimo normal. Por último, una presión suave se traduciría en una luz azul, simbolizando la tristeza, ya que en esos momentos uno a menudo carece de energía para realizar actividades.
Desarrollo técnico: Aunque inicialmente planeé utilizar la plataforma Arduino Cloud IoT para lograr la conexión inalámbrica a través de Wi-Fi, lamentablemente no pude hacerla funcionar. En su lugar, opté por desarrollar un prototipo más básico que funcionara de forma presencial y estuviera conectado a pilas doble A para encender las luces de manera sencilla.
En resumen, el proceso de creación de este encargo implicó una observación inicial, una reflexión sobre la conexión entre el verbo “levantar” y las experiencias vividas en el parque, la generación de una idea conceptual que involucrara electrónica y la asociación de colores con diferentes intensidades de presión. Aunque no se pudo realizar la conexión inalámbrica planificada debido a dificultades técnicas, el prototipo final fue diseñado para permitir que las parejas se comuniquen a través de la luz y transmitan diferentes estados de ánimo, basándose en la idea original de “levantar” el ánimo en el amor.
Encargo 02 - Drawdio #
DRAWDIO #
El Drawdio es un pseudo instrumento musical diseñado originalmente por Jay Silver en el MIT Media Lab. Utiliza un circuito integrado 555 Timer IC y componentes adicionales para generar sonidos a través de un lápiz conductor y una superficie conductora, como papel. Los componentes y materiales utilizados fueron:
- Electrónica
- 1 x 555 Timer IC (circuito integrado)
- 1 x PNP Transistor
- 1 x Resistor de 270 KΩ
- 1 x Resistor de 10 KΩ
- 1 x Resistor de 10 MΩ
- 1 x Resistor de 10 Ω
- 1 x Condensador 0.1 μF
- 1 x Condensador 100μF
- 1x Condensador cerámico 570 pF
- 1 x Parlante pequeño de 8 ohms
- 2 x Pilas AAA
El proceso fue un tanto tedioso ya que el diagrama que pasaron estaba malo, pero fue solucionado con otro encontrado en internet (créditos al Juan-k) y funcionó de maravilla.
#
Posterior a eso, se le dio vuelta al concepto del Drawdio y del verbo “almacenar” y se creó una especie de caja de seguridad, en donde al intentarla abrir suena.
Encargo 03 - Drawdio 2 remix #
DRAWDIO 2 - EL REMIX #
El encargo consistió en la combinación de dos elementos: el Drawdio y el Arduino. El Drawdio es un pseudo instrumento musical diseñado originalmente por Jay Silver en el MIT Media Lab, mientras que Arduino es una plataforma de prototipado electrónico de código abierto.
El Drawdio utiliza un circuito integrado 555 Timer IC y componentes adicionales para generar sonidos a través de un lápiz conductor y una superficie conductora, como papel. El Arduino, por otro lado, es una placa programable que permite controlar dispositivos electrónicos.
En este proyecto, se decidió integrar el Drawdio con el Arduino para realizar modificaciones en el sonido generado por el Drawdio. Para lograr esto, se utilizó un potenciómetro conectado al Arduino para controlar el volumen del sonido. Además, se añadió una funcionalidad adicional de controlar un LED RGB en base al valor del potenciómetro.
#
El código modificado permitió ajustar el color del LED RGB en función del valor del potenciómetro. Cuando el valor del potenciómetro era bajo, el LED mostraba un color azul intenso. A medida que el valor del potenciómetro aumentaba, el LED cambiaba a verde y, finalmente, a rojo cuando el valor del potenciómetro era máximo.
Además, se modificó el sonido generado por el Drawdio utilizando el Arduino. En lugar de utilizar el circuito del 555 Timer IC, se generó el tono directamente desde el Arduino, controlando la frecuencia del tono en base al valor del potenciómetro. De esta manera, el sonido del Drawdio se modificaba de forma progresiva, siendo más suave cuando el valor del potenciómetro era bajo y más fuerte a medida que el valor del potenciómetro aumentaba.
#
En resumen, el proyecto logró integrar el Drawdio y el Arduino, permitiendo controlar el color del LED RGB y modificar el sonido del Drawdio en base al valor del potenciómetro. Esto proporcionó una experiencia interactiva y personalizable para explorar la música generada por el Drawdio. Abajo se encuentra la descarga del código Arduino utilizado.
const int RED_PIN = 9;
const int GREEN_PIN = 10;
const int BLUE_PIN = 11;
const int POT_PIN = A0; // Pin del potenciómetro
const int SPEAKER_PIN = 3; // Pin de salida del parlante
const int DISPLAY_TIME = 200; // used in mainColors() to determine the
// length of time each color is displayed.
void setup() {
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
pinMode(SPEAKER_PIN, OUTPUT);
Serial.begin(9600);
}
void loop() {
int potValue = analogRead(POT_PIN);
// Controlar el color del LED RGB
if (potValue < 341) {
analogWrite(RED_PIN, 0);
analogWrite(GREEN_PIN, 0);
analogWrite(BLUE_PIN, 255);
} else if ((potValue > 342) and (potValue < 682)) {
analogWrite(RED_PIN, 0);
analogWrite(GREEN_PIN, 255);
analogWrite(BLUE_PIN, 0);
} else if (potValue > 682) {
analogWrite(RED_PIN, 255);
analogWrite(GREEN_PIN, 0);
analogWrite(BLUE_PIN, 0);
}
// Controlar el sonido del Drawdio modificando la frecuencia del tono
int frequency = map(potValue, 0, 1023, 100, 10000);
tone(SPEAKER_PIN, frequency);
Serial.println(potValue);
delay(10);
}
Encargo 04 - Sensor de color #
Cubo infinito de leds vibrador #
Este encargo comenzó con la realización de 3 tareas del libro de ejercicios de electrónica.
#
Luego se formaron parejas y fui con Catalina Plencovich, en donde se nos asignó el sensor de color. Decidimos realizar un cubo de leds infinito con espejos y un parlante hackeado que, al vibrar, generase patrones en base al color dado. Aunque no se pudo lograr eso último, uno puede tocar el vibrador y así sentir el color que se está viendo.
Se tuvo la intención de hacer patrones con la vibración, es decir, que cada color tuviese su patrón asociado. No se consiguió.
-
Este fue el resultado final de la parte 1, ya que de momento queda que forme los patrones.



// Definición de los pines
const int pinR = 9;
const int pinB = 10;
const int pinG = 11;
const int s0 = 4;
const int s1 = 5;
const int s2 = 6;
const int s3 = 7;
const int out = 8;
const int speakerPin = 3; // Pin digital utilizado para el parlante
int frequency = 0; // Variable para almacenar la frecuencia actual
void setup()
{
Serial.begin(9600);
pinMode(s0, OUTPUT);
pinMode(s1, OUTPUT);
pinMode(s2, OUTPUT);
pinMode(s3, OUTPUT);
pinMode(out, INPUT);
// Configuración de los pines como salidas
pinMode(pinR, OUTPUT);
pinMode(pinB, OUTPUT);
pinMode(pinG, OUTPUT);
digitalWrite(s0, HIGH);
digitalWrite(s1, HIGH);
pinMode(speakerPin, OUTPUT);
}
void loop()
{
int R = getRojo();
delay(200);
int V = getVerde();
delay(200);
int A = getAzul();
delay(200);
Serial.print("Int R " + String(R));
Serial.print(" -- Int V " + String(V));
Serial.println(" -- Int A " + String(A));
if (R > V && V > A && R >20 && V > 8) {
Serial.print(" EL COLOR ES CELESTE");
// Encender el color azul
digitalWrite(pinR, HIGH);
digitalWrite(pinB, LOW);
digitalWrite(pinG, HIGH);
frequency = 10; // Actualizar la frecuencia solo si es diferente de cero
tone(speakerPin, frequency); // Generar el tono en el parlante con la nueva frecuencia ingresada
}
if (R > V && V < A && R > 13 && V <= 16) {
Serial.print(" EL COLOR ES VERDE CLARO");
// Encender el color rojo
digitalWrite(pinR, HIGH);
digitalWrite(pinB, HIGH);
digitalWrite(pinG, LOW);
frequency = 50; // Actualizar la frecuencia solo si es diferente de cero
tone(speakerPin, frequency); // Generar el tono en el parlante con la nueva frecuencia ingresada
}
else if (R < V && V > A && R >= 5 && V <= 11) {
Serial.print(" EL COLOR ES ROSADO");
}
if (R < V && V > A && R > 7 && V <= 29) {
Serial.print(" EL COLOR ES ROJO");
// Encender el color verde
digitalWrite(pinR, LOW);
digitalWrite(pinB, HIGH);
digitalWrite(pinG, HIGH);
frequency = 90; // Actualizar la frecuencia solo si es diferente de cero
tone(speakerPin, frequency); // Generar el tono en el parlante con la nueva frecuencia ingresada
}
else
{
Serial.print(" EL COLOR NO HA SIDO REGISTRADO");
}
Serial.print(" ");
}
int getRojo()
{
//leer color rojo
digitalWrite(s2, LOW);
digitalWrite(s3, LOW);
int ROJO = pulseIn(out, LOW);
return ROJO;
}
int getAzul()
{
//leer color azul
digitalWrite(s2, LOW);
digitalWrite(s3, HIGH);
int AZUL = pulseIn(out, LOW);
return AZUL;
}
int getVerde()
{
//leer color verde
digitalWrite(s2, HIGH);
digitalWrite(s3, HIGH);
int VERDE = pulseIn(out, LOW);
return VERDE;
}
Encargo 05 - Reloj de arena digital #
Reloj del tiempo #
En este nuevo proyecto, tuve nuevamente el placer de trabajar junto a Catalina Plencovich, formando un gran equipo. Se nos encomendó la tarea de crear un reloj de arena digital que simulara el movimiento y caída de la arena utilizando LEDs. Decidimos ser creativos y, además de cumplir con el encargo, creamos una interesante combinación de relojes de arena: uno digital, uno de arena real y otro con agua.
Aunque el proyecto no estuvo exento de desafíos, supimos enfrentar y superar diversas problemáticas para llevarlo a buen puerto. Entre las más destacadas, encontramos la típica situación de que el Arduino no funcionara a pesar de tener todo correctamente conectado, la presencia de una pequeña roca en el reloj de arena real y la formación de burbujas en el reloj de agua.



Los elementos electrónicos fundamentales fueron:
- Arduino Uno
- Giroscopio Mpu6050
- 2 matrices leds 8x8



Para lograr la funcionalidad deseada, utilizamos varias bibliotecas en nuestro código. Una de ellas fue para el manejo del acelerómetro, permitiendo determinar la orientación del triángulo en el reloj de arena. Además, empleamos una librería llamada “LedControl” para controlar la matriz de LEDs, permitiéndonos implementar efectos visuales con el encendido y apagado de cada led por separado y crear una visualización por multiplexación, creando así la ilusión de movimiento y dinamismo.
Para ejecutar este código, se necesitan las bibliotecas “MPU6050_tockn.h” y “LedControl.h” instaladas.
// Fotorresistencia
const int fotorresistenciaPin = 0; // Usamos '0' para representar el pin analógico A0
int valorMapeado = 1;
#include "Arduino.h"
#include
#include "LedControl.h"
#include "Delay.h"
#define MATRIX_A 1
#define MATRIX_B 0
MPU6050 mpu6050(Wire);
// valores entregados: 260/330/400
#define ACC_THRESHOLD_LOW -25
#define ACC_THRESHOLD_HIGH 25
// Matriz
#define PIN_DATAIN 11 // DIN
#define PIN_CLK 13 // CLK
#define PIN_LOAD 10 // CS
// Acelerómetro
#define PIN_X mpu6050.getAngleX()
#define PIN_Y mpu6050.getAngleY()
// Rotary Encoder
#define PIN_ENC_1 3
#define PIN_ENC_2 2
#define PIN_ENC_BUTTON 7
#define PIN_BUZZER 14
// This takes into account how the matrixes are mounted
#define ROTATION_OFFSET 90
// in milliseconds
#define DEBOUNCE_THRESHOLD 500
#define DELAY_FRAME 50 //Velocidad de caída
#define DEBUG_OUTPUT 1
#define MODE_HOURGLASS 0
#define MODE_SETMINUTES 1
#define MODE_SETHOURS 2
byte delayHours = 0;
byte delayMinutes = 1;
int mode = MODE_HOURGLASS;
int gravity;
LedControl lc = LedControl(PIN_DATAIN, PIN_CLK, PIN_LOAD, valorMapeado);
NonBlockDelay d;
int resetCounter = 0;
bool alarmWentOff = false;
/**
* Get delay between particle drops (in seconds)
*/
long getDelayDrop() {
// since we have exactly 60 particles we don't have to multiply by 60 and then divide by the number of particles again :)
return delayMinutes + delayHours * 60;
}
#if DEBUG_OUTPUT
void printmatrix() {
Serial.println(" 0123-4567 ");
for (int y = 0; y<8; y++) {
if (y == 4) {
Serial.println("|----|----|");
}
Serial.print(y);
for (int x = 0; x<8; x++) {
if (x == 4) {
Serial.print("|");
}
Serial.print(lc.getXY(0,x,y) ? "X" :" ");
}
Serial.println("|");
}
Serial.println("-----------");
}
#endif
coord getDown(int x, int y) {
coord xy;
xy.x = x-1;
xy.y = y+1;
return xy;
}
coord getLeft(int x, int y) {
coord xy;
xy.x = x-1;
xy.y = y;
return xy;
}
coord getRight(int x, int y) {
coord xy;
xy.x = x;
xy.y = y+1;
return xy;
}
bool canGoLeft(int addr, int x, int y) {
if (x == 0) return false; // not available
return !lc.getXY(addr, getLeft(x, y)); // you can go there if this is empty
}
bool canGoRight(int addr, int x, int y) {
if (y == 7) return false; // not available
return !lc.getXY(addr, getRight(x, y)); // you can go there if this is empty
}
bool canGoDown(int addr, int x, int y) {
if (y == 7) return false; // not available
if (x == 0) return false; // not available
if (!canGoLeft(addr, x, y)) return false;
if (!canGoRight(addr, x, y)) return false;
return !lc.getXY(addr, getDown(x, y)); // you can go there if this is empty
}
void goDown(int addr, int x, int y) {
lc.setXY(addr, x, y, false);
lc.setXY(addr, getDown(x,y), true);
}
void goLeft(int addr, int x, int y) {
lc.setXY(addr, x, y, false);
lc.setXY(addr, getLeft(x,y), true);
}
void goRight(int addr, int x, int y) {
lc.setXY(addr, x, y, false);
lc.setXY(addr, getRight(x,y), true);
}
int countParticles(int addr) {
int c = 0;
for (byte y=0; y<8; y++) {
for (byte x=0; x<8; x++) {
if (lc.getXY(addr, x, y)) {
c++;
}
}
}
return c;
}
bool moveParticle(int addr, int x, int y) {
if (!lc.getXY(addr,x,y)) {
return false;
}
bool can_GoLeft = canGoLeft(addr, x, y);
bool can_GoRight = canGoRight(addr, x, y);
if (!can_GoLeft && !can_GoRight) {
return false; // we're stuck
}
bool can_GoDown = canGoDown(addr, x, y);
if (can_GoDown) {
goDown(addr, x, y);
} else if (can_GoLeft&& !can_GoRight) {
goLeft(addr, x, y);
} else if (can_GoRight && !can_GoLeft) {
goRight(addr, x, y);
} else if (random(2) == 1) { // we can go left and right, but not down
goLeft(addr, x, y);
} else {
goRight(addr, x, y);
}
return true;
}
void fill(int addr, int maxcount) {
int n = 8;
byte x,y;
int count = 0;
for (byte slice = 0; slice < 2*n-1; ++slice) {
byte z = slice ACC_THRESHOLD_HIGH) { return 0; }
if (y > ACC_THRESHOLD_HIGH) { return 270; }
if (x < ACC_THRESHOLD_LOW) { return 180; }
}
int getTopMatrix() {
return (getGravity() == 90) ? MATRIX_A : MATRIX_B;
}
int getBottomMatrix() {
return (getGravity() != 90) ? MATRIX_A : MATRIX_B;
}
void resetTime() {
for (byte i=0; i<2; i++) {
lc.clearDisplay(i);
}
fill(getTopMatrix(), 60);
d.Delay(getDelayDrop() * 1000);
}
/**
* Traverse matrix and check if particles need to be moved
*/
bool updateMatrix() {
int n = 8;
bool somethingMoved = false;
byte x,y;
bool direction;
for (byte slice = 0; slice < 2*n-1; ++slice) {
direction = (random(2) == 1); // randomize if we scan from left to right or from right to left, so the grain doesn't always fall the same direction
byte z = slice ACC_THRESHOLD_HIGH || z < ACC_THRESHOLD_LOW) {
resetCounter++;
Serial.println(resetCounter);
} else {
resetCounter = 0;
}
if (resetCounter > 20) {
Serial.println("RESET!");
resetTime();
resetCounter = 0;
}
}
void displayLetter(char letter, int matrix) {
// Serial.print("Letter: ");
// Serial.println(letter);
lc.clearDisplay(matrix);
lc.setXY(matrix, 1,4, true);
lc.setXY(matrix, 2,3, true);
lc.setXY(matrix, 3,2, true);
lc.setXY(matrix, 4,1, true);
lc.setXY(matrix, 3,6, true);
lc.setXY(matrix, 4,5, true);
lc.setXY(matrix, 5,4, true);
lc.setXY(matrix, 6,3, true);
if (letter == 'M') {
lc.setXY(matrix, 4,2, true);
lc.setXY(matrix, 4,3, true);
lc.setXY(matrix, 5,3, true);
}
if (letter == 'H') {
lc.setXY(matrix, 3,3, true);
lc.setXY(matrix, 4,4, true);
}
}
void renderSetMinutes() {
fill(getTopMatrix(), delayMinutes);
displayLetter('M', getBottomMatrix());
}
void renderSetHours() {
fill(getTopMatrix(), delayHours);
displayLetter('H', getBottomMatrix());
}
void knobClockwise() {
Serial.println("Clockwise");
if (mode == MODE_SETHOURS) {
delayHours = constrain(delayHours+1, 0, 64);
renderSetHours();
} else if(mode == MODE_SETMINUTES) {
delayMinutes = constrain(delayMinutes+1, 0, 64);
renderSetMinutes();
}
Serial.print("Delay: ");
Serial.println(getDelayDrop());
}
void knobCounterClockwise() {
Serial.println("Counterclockwise");
if (mode == MODE_SETHOURS) {
delayHours = constrain(delayHours-1, 0, 64);
renderSetHours();
} else if (mode == MODE_SETMINUTES) {
delayMinutes = constrain(delayMinutes-1, 0, 64);
renderSetMinutes();
}
Serial.print("Delay: ");
Serial.println(getDelayDrop());
}
volatile int lastEncoded = 0;
volatile long encoderValue = 0;
long lastencoderValue = 0;
long lastValue = 0;
void updateEncoder() {
int MSB = digitalRead(PIN_ENC_1); //MSB = most significant bit
int LSB = digitalRead(PIN_ENC_2); //LSB = least significant bit
int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value
if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue--;
if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue++;
// Serial.print("Value: ");
// Serial.println(encoderValue);
if ((encoderValue % 4) == 0) {
int value = encoderValue / 4;
if (value > lastValue) knobClockwise();
if (value < lastValue) knobCounterClockwise();
lastValue = value;
}
lastEncoded = encoded; //store this value for next time
}
/**
* Button callback (incl. software debouncer)
* This switches between the modes (normal, set minutes, set hours)
*/
volatile unsigned long lastButtonPushMillis;
void buttonPush() {
if((long)(millis() - lastButtonPushMillis) >= DEBOUNCE_THRESHOLD) {
mode = (mode+1) % 3;
Serial.print("Switched mode to: ");
Serial.println(mode);
lastButtonPushMillis = millis();
if (mode == MODE_SETMINUTES) {
lc.backup(); // we only need to back when switching from MODE_HOURGLASS->MODE_SETMINUTES
renderSetMinutes();
}
if (mode == MODE_SETHOURS) {
renderSetHours();
}
if (mode == MODE_HOURGLASS) {
lc.clearDisplay(0);
lc.clearDisplay(1);
lc.restore();
resetTime();
}
}
}
/**
* Setup
*/
void setup() {
Serial.begin(9600);
mpu6050.calcGyroOffsets(true);
// Serial.begin(9600);
mpu6050.begin();
// while (!Serial) {
// ; // wait for serial port to connect. Needed for native USB
// }
// setup rotary encoder
pinMode(PIN_ENC_1, INPUT);
pinMode(PIN_ENC_2, INPUT);
pinMode(PIN_ENC_BUTTON, INPUT);
digitalWrite(PIN_ENC_1, HIGH); //turn pullup resistor on
digitalWrite(PIN_ENC_2, HIGH); //turn pullup resistor on
digitalWrite(PIN_ENC_BUTTON, HIGH); //turn pullup resistor on
attachInterrupt(digitalPinToInterrupt(PIN_ENC_1), updateEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(PIN_ENC_2), updateEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(PIN_ENC_BUTTON), buttonPush, RISING);
// Serial.println(digitalPinToInterrupt(PIN_ENC_1));
// Serial.println(digitalPinToInterrupt(PIN_ENC_2));
// Serial.println(digitalPinToInterrupt(PIN_ENC_BUTTON));
randomSeed(analogRead(A0));
// init displays
for (byte i=0; i<2; i++) {
lc.shutdown(i,false);
lc.setIntensity(i,0);
}
resetTime();
}
/**
* Main loop
*/
void loop() {
int valorFotorresistencia = analogRead(fotorresistenciaPin);
// Mapear el valor de la fotorresistencia al rango 1-13
int valorMapeado = map(valorFotorresistencia, 0, 1023, 13, 1);
mpu6050.update();
Serial.println("angleX : ");
Serial.println(mpu6050.getAngleX());
Serial.println("\tangleY : ");
Serial.println(mpu6050.getAngleY());
delay(DELAY_FRAME);
// update the driver's rotation setting. For the rest of the code we pretend "down" is still 0,0 and "up" is 7,7
gravity = getGravity();
lc.setRotation((ROTATION_OFFSET + gravity) % 360);
// handle special modes
if (mode == MODE_SETMINUTES) {
renderSetMinutes(); return;
} else if (mode == MODE_SETHOURS) {
renderSetHours(); return;
}
// resetCheck(); // reset now happens when pushing a button
bool moved = updateMatrix();
bool dropped = dropParticle();
// alarm when everything is in the bottom part
if (!moved && !dropped && !alarmWentOff && (countParticles(getTopMatrix()) == 0)) {
alarmWentOff = true;
alarm();
}
// reset alarm flag next time a particle was dropped
if (dropped) {
alarmWentOff = false;
}
}
Encargo 06 - MidTerm #
ADVOLUTION: Espejo emocional viajero #
El presente exámen de Diseño describe un prototipo de interacción emocional que combina tecnologías de reconocimiento facial en tiempo real con Arduino y Python para crear una experiencia única y personalizada.
El objetivo principal del prototipo es generar emociones específicas a partir del reconocimiento facial y proporcionar una respuesta visual a través de luces LED y una matriz de LEDs 8x8 que simula un reloj de arena digital. La idea es implementar esta interacción emocional en espacios relacionados con viajes o agencias de viajes, donde dependiendo de la emoción del usuario, se le ofrecerá un destino con una oferta de tiempo limitado.
Componentes:
-
Dispositivo de Captura de Imágenes: Se utiliza una cámara web conectada a una computadora para capturar imágenes faciales en tiempo real. Se emplea la biblioteca mediapipe de Python para la detección y seguimiento facial.
-
Procesamiento de Imágenes y Reconocimiento Emocional: La librería DeepFace de Python se utiliza para analizar las imágenes capturadas y extraer la emoción dominante del usuario en tiempo real.
-
Interacción con Arduino: Se establece una conexión serial entre la computadora y un Arduino, el cual controla un LED RGB y una matriz de LEDs 8x8.
-
Respuesta Visual del Prototipo:
-
LED RGB: El LED RGB cambia de color según la emoción detectada: azul para tristeza, rojo para enojo, verde para felicidad y morado para sorpresa.
-
Matriz de LEDs 8x8: Representa un reloj de arena digital, donde la parte superior se llena de forma aleatoria cuando se detecta una emoción, y luego “cae” hacia la parte inferior.
-
-
Interfaz de Usuario: En el futuro, se puede implementar una interfaz de usuario en una pantalla LED o una pantalla para proporcionar información adicional sobre el destino sugerido basado en la emoción del usuario.



Funcionamiento del Prototipo:
-
El prototipo comienza capturando imágenes faciales en tiempo real mediante la cámara web.
-
La biblioteca mediapipe procesa las imágenes y detecta la cara del usuario, mientras la librería DeepFace analiza la imagen y extrae la emoción dominante del usuario.
-
El resultado de la emoción se utiliza para cambiar el color del LED RGB y activar la matriz de LEDs 8x8.
-
El LED RGB se ilumina con el color correspondiente a la emoción detectada. La matriz de LEDs 8x8 se llena de forma aleatoria en la parte superior, simulando un reloj de arena.
-
Luego, los LEDs de la matriz “caen” hacia la parte inferior, creando un efecto visual interesante.
-
Si el usuario muestra otra emoción, el proceso se repite y el prototipo responde en consecuencia.
-
El prototipo puede ofrecer un destino basado en la emoción detectada, lo que crea una experiencia interactiva y personalizada para el usuario.
Proyecciones futuras




El prototipo se puede implementar en espacios relacionados con viajes o agencias de viajes, como aeropuertos, estaciones de tren o agencias de turismo. La interacción emocional permitirá ofrecer destinos turísticos adecuados para el estado de ánimo del usuario, lo que crea una experiencia única y atractiva. Además, el uso de pantallas LED o pantallas como interfaz de usuario proporcionará información detallada sobre el destino sugerido y ofertas especiales de tiempo limitado, lo que aumentará el atractivo del prototipo para los usuarios.
#
En conclusión, prototipo de interacción emocional con destino aleatorio representa una experiencia innovadora y única para los usuarios en espacios relacionados con viajes. La combinación de tecnologías de reconocimiento facial en tiempo real con Arduino y Python permite una respuesta visual dinámica y personalizada, lo que mejora la interacción del usuario y crea un ambiente emocionante. La implementación futura del prototipo en espacios turísticos y agencias de viajes tiene el potencial de atraer y cautivar a los usuarios, al tiempo que ofrece destinos sugeridos y ofertas especiales en función de sus emociones.
Código Python:
# Importamos las librerias
from deepface import DeepFace
import cv2
import mediapipe as mp
import serial
import time
# Declaramos la deteccion de rostros
detros = mp.solutions.face_detection
rostros = detros.FaceDetection(min_detection_confidence= 0.8, model_selection=0)
# Dibujo
dibujorostro = mp.solutions.drawing_utils
# Realizamos VideoCaptura
cap = cv2.VideoCapture(1)
espera = 0.03
# Arduino
def enviar_numero_a_arduino(numero):
arduino.write(str(numero).encode())
#print(f"Enviando número: {numero}")
time.sleep(2)
arduino = serial.Serial("COM5", 9600)
time.sleep(2)
# Empezamos
while True:
# Leemos los fotogramas
ret, frame = cap.read()
# Leemos imagen
#img =cv2.imread("img.png")
#img = cv2.resize(img, (0, 0), None, 0.18, 0.18)
#ani, ali, c = img.shape
# Correccion de color
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Procesamos
resrostros = rostros.process(rgb)
# Deteccion
if resrostros.detections is not None:
# Registramos
for rostro in resrostros.detections:
# Extraemos informacion de ubicacion
al, an, c = frame.shape
box = rostro.location_data.relative_bounding_box
xi, yi, w, h = int(box.xmin * an), int(box.ymin * al), int(box.width * an), int(box.height * al)
xf, yf = xi + w, yi + h
# Dibujamos
cv2.rectangle(frame, (xi, yi), (xf, yf), (255, 255, 0), 1)
#frame[10:ani + 10, 10:ali+10] = img
# Informacion
#info = DeepFace.analyze(rgb, actions=['age', 'gender', 'race', 'emotion'], enforce_detection= False)
info = DeepFace.analyze(rgb, actions=['emotion'], enforce_detection= False)
# Edad
#edad = info['age']
# Emociones
emociones = info['dominant_emotion']
# Race
#race = info['dominant_race']
# Genero
#gen = info['gender']
#print(str(gen) + " de " + str(edad) + " años de edad, con estado de animo " + str(emociones) + " de etnia " + str(race))
# Traducimos
# Emociones
if emociones == 'angry':
numero = 1
time.sleep(espera)
if emociones == 'disgust':
numero = 1
time.sleep(espera)
if emociones == 'fear':
numero = 3
time.sleep(espera)
if emociones == 'happy':
numero = 2
time.sleep(espera)
if emociones == 'sad':
numero = 3
time.sleep(espera)
if emociones == 'surprise':
numero = 5
time.sleep(espera)
if emociones == 'neutral':
numero = 1
time.sleep(espera)
enviar_numero_a_arduino(numero)
# Mostramos info
#cv2.putText(frame, str(gen), (65, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)
#cv2.putText(frame, str(edad), (75, 90), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)
#cv2.putText(frame, str(emociones), (75, 135), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)
#cv2.putText(frame, str(race), (75, 180), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)
# Mostramos los fotogramas
#cv2.imshow(" Deteccion de Edad ", frame)
# Leemos el teclado
t = cv2.waitKey(5)
if t == 27:
break
cv2.destroyAllWindows()
cap.release()
Código Arduino: #
#include "Arduino.h"
#include "LedControl.h"
#include "Delay.h"
/////////////////////////////////////////////// MATRICES ///////////////////////////////////////////////
#define MATRIX_A 1
#define MATRIX_B 0
// Values are 260/330/400
#define ACC_THRESHOLD_LOW 300
#define ACC_THRESHOLD_HIGH 360
// Matrix
#define PIN_DATAIN 5 // DIN
#define PIN_CLK 4 // CLK
#define PIN_LOAD 6 // CS
// Esto tiene en cuenta cómo se montan las matrices.
#define ROTATION_OFFSET 90
// in milliseconds
#define DEBOUNCE_THRESHOLD 500
#define DELAY_FRAME 100 //Velocidad de caida de particulas, original 100. A mayor numero, más lento.
#define DEBUG_OUTPUT 1
#define MODE_HOURGLASS 0
#define MODE_SETMINUTES 1
#define MODE_SETHOURS 2
byte delayHours = 0;
byte delayMinutes = 1;
int mode = MODE_HOURGLASS;
int gravity;
LedControl lc = LedControl(PIN_DATAIN, PIN_CLK, PIN_LOAD, 8);
NonBlockDelay d;
int resetCounter = 0;
bool alarmWentOff = false;
/////////////////////////////////////////////// LED RGB ///////////////////////////////////////////////
int LEDROJO = 9; // pin 9 a anodo LED rojo
int LEDVERDE = 10; // pin 10 a anodo LED verde
int LEDAZUL = 11; // pin 11 a anodo LED azul
int numero = 8;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////// CÓDIGO ///////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Obtener retraso entre caídas de partículas (en segundos)
*/
long getDelayDrop() {
// como tenemos exactamente 60 partículas, no tenemos que multiplicar por 60 y luego dividir por el número de partículas nuevamente
return delayMinutes + delayHours * 60;
}
#if DEBUG_OUTPUT
void printmatrix() {
Serial.println(" 0123-4567 ");
for (int y = 0; y<8; y++) {
if (y == 4) {
Serial.println("|----|----|");
}
Serial.print(y);
for (int x = 0; x<8; x++) {
if (x == 4) {
Serial.print("|");
}
Serial.print(lc.getXY(0,x,y) ? "X" :" ");
}
Serial.println("|");
}
Serial.println("-----------");
}
#endif
coord getDown(int x, int y) {
coord xy;
xy.x = x-1;
xy.y = y+1;
return xy;
}
coord getLeft(int x, int y) {
coord xy;
xy.x = x-1;
xy.y = y;
return xy;
}
coord getRight(int x, int y) {
coord xy;
xy.x = x;
xy.y = y+1;
return xy;
}
bool canGoLeft(int addr, int x, int y) {
if (x == 0) return false; // not available
return !lc.getXY(addr, getLeft(x, y)); // you can go there if this is empty
}
bool canGoRight(int addr, int x, int y) {
if (y == 7) return false; // not available
return !lc.getXY(addr, getRight(x, y)); // you can go there if this is empty
}
bool canGoDown(int addr, int x, int y) {
if (y == 7) return false; // not available
if (x == 0) return false; // not available
if (!canGoLeft(addr, x, y)) return false;
if (!canGoRight(addr, x, y)) return false;
return !lc.getXY(addr, getDown(x, y)); // you can go there if this is empty
}
void goDown(int addr, int x, int y) {
lc.setXY(addr, x, y, false);
lc.setXY(addr, getDown(x,y), true);
}
void goLeft(int addr, int x, int y) {
lc.setXY(addr, x, y, false);
lc.setXY(addr, getLeft(x,y), true);
}
void goRight(int addr, int x, int y) {
lc.setXY(addr, x, y, false);
lc.setXY(addr, getRight(x,y), true);
}
int countParticles(int addr) {
int c = 0;
for (byte y=0; y<8; y++) {
for (byte x=0; x<8; x++) {
if (lc.getXY(addr, x, y)) {
c++;
}
}
}
return c;
}
bool moveParticle(int addr, int x, int y) {
if (!lc.getXY(addr,x,y)) {
return false;
}
bool can_GoLeft = canGoLeft(addr, x, y);
bool can_GoRight = canGoRight(addr, x, y);
if (!can_GoLeft && !can_GoRight) {
return false; // we're stuck
}
bool can_GoDown = canGoDown(addr, x, y);
if (can_GoDown) {
goDown(addr, x, y);
} else if (can_GoLeft&& !can_GoRight) {
goLeft(addr, x, y);
} else if (can_GoRight && !can_GoLeft) {
goRight(addr, x, y);
} else if (random(2) == 1) { // Podemos ir a izquierda y derecha, pero no abajo
goLeft(addr, x, y);
} else {
goRight(addr, x, y);
}
return true;
}
void fill(int addr, int maxcount, bool fromTop = false) {
int n = 8;
byte x, y;
int count = 0;
for (byte slice = 0; slice < 2 * n - 1; ++slice) {
byte z = slice < n ? 0 : slice - n + 1;
for (byte j = z; j <= slice - z; ++j) {
y = fromTop ? j : 7 - j;
x = slice - j;
lc.setXY(addr, x, y, (++count <= maxcount));
}
}
}
/**
* Detectar la orientación usando el acelerómetro
*
* | up | right | left | down |
* --------------------------------
* 400 | | | y | x |
* 330 | y | x | x | y |
* 260 | x | y | | |
*/
int getGravity() {
/*
int x = analogRead(PIN_X);
int y = analogRead(PIN_Y);
if (y < ACC_THRESHOLD_LOW) { return 0; }
if (x > ACC_THRESHOLD_HIGH) { return 90; }
if (y > ACC_THRESHOLD_HIGH) { return 180; }
if (x < ACC_THRESHOLD_LOW) { return 270; }
*/
int x = 180; // Agregado
int y = 180; // Agregado
return x; // Agregado
return y; // Agregado
}
int getTopMatrix() {
return (getGravity() == 90) ? MATRIX_A : MATRIX_B;
}
int getBottomMatrix() {
return (getGravity() != 90) ? MATRIX_A : MATRIX_B;
}
// // Para ver cuantos granos iniciales de arriba parten **********************
/*
//int totalParticles = random(65); // Generar un número aleatorio entre 0 y 64
int totalParticles = 4;
*/
void resetTime() {
for (byte i = 0; i < 2; i++) {
lc.clearDisplay(i);
}
//int totalParticles = random(62); // Generar un número aleatorio entre 0 y 64
int totalParticles = 4;
int particlesMatrixA = totalParticles;
int particlesMatrixB = 64 - totalParticles;
// Llenar ambas matrices desde la parte superior
fill(getTopMatrix(), particlesMatrixA, true);
fill(getBottomMatrix(), particlesMatrixB, true);
d.Delay(getDelayDrop() * 1000);
}
/**
* Atraviese la matriz y compruebe si es necesario mover las partículas
*/
bool updateMatrix() {
int n = 8;
bool somethingMoved = false;
byte x,y;
bool direction;
for (byte slice = 0; slice < 2*n-1; ++slice) {
direction = (random(2) == 1); // RANDOM de izq o der de granito al no haber centro
byte z = slice ACC_THRESHOLD_HIGH || z < ACC_THRESHOLD_LOW) {
resetCounter++;
Serial.println(resetCounter);
} else {
resetCounter = 0;
}
if (resetCounter > 20) {
Serial.println("RESET!");
resetTime();
resetCounter = 0;
}
}
void displayLetter(char letter, int matrix) {
// Serial.print("Letter: ");
// Serial.println(letter);
lc.clearDisplay(matrix);
lc.setXY(matrix, 1,4, true);
lc.setXY(matrix, 2,3, true);
lc.setXY(matrix, 3,2, true);
lc.setXY(matrix, 4,1, true);
lc.setXY(matrix, 3,6, true);
lc.setXY(matrix, 4,5, true);
lc.setXY(matrix, 5,4, true);
lc.setXY(matrix, 6,3, true);
if (letter == 'M') {
lc.setXY(matrix, 4,2, true);
lc.setXY(matrix, 4,3, true);
lc.setXY(matrix, 5,3, true);
}
if (letter == 'H') {
lc.setXY(matrix, 3,3, true);
lc.setXY(matrix, 4,4, true);
}
}
void renderSetMinutes() {
fill(getTopMatrix(), delayMinutes);
displayLetter('M', getBottomMatrix());
}
void renderSetHours() {
fill(getTopMatrix(), delayHours);
displayLetter('H', getBottomMatrix());
}
void knobClockwise() {
Serial.println("Clockwise");
if (mode == MODE_SETHOURS) {
delayHours = constrain(delayHours+1, 0, 64);
renderSetHours();
} else if(mode == MODE_SETMINUTES) {
delayMinutes = constrain(delayMinutes+1, 0, 64);
renderSetMinutes();
}
Serial.print("Delay: ");
Serial.println(getDelayDrop());
}
void knobCounterClockwise() {
Serial.println("Counterclockwise");
if (mode == MODE_SETHOURS) {
delayHours = constrain(delayHours-1, 0, 64);
renderSetHours();
} else if (mode == MODE_SETMINUTES) {
delayMinutes = constrain(delayMinutes-1, 0, 64);
renderSetMinutes();
}
Serial.print("Delay: ");
Serial.println(getDelayDrop());
}
volatile int lastEncoded = 0;
volatile long encoderValue = 0;
long lastencoderValue = 0;
long lastValue = 0;
void updateEncoder() {
/*
int MSB = digitalRead(PIN_ENC_1); //MSB = most significant bit
int LSB = digitalRead(PIN_ENC_2); //LSB = least significant bit
*/
int MSB = 0; //MSB = most significant bit //Agregado
int LSB = 0; //LSB = least significant bit //Agregado
int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value
if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue--;
if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue++;
// Serial.print("Value: ");
// Serial.println(encoderValue);
if ((encoderValue % 4) == 0) {
int value = encoderValue / 4;
if (value > lastValue) knobClockwise();
if (value < lastValue) knobCounterClockwise();
lastValue = value;
}
lastEncoded = encoded; //store this value for next time
}
/**
* Button callback (incl. software debouncer)
* Esto cambia entre los modos (normal, establecer minutos, establecer horas)
*/
volatile unsigned long lastButtonPushMillis;
void buttonPush() {
if((long)(millis() - lastButtonPushMillis) >= DEBOUNCE_THRESHOLD) {
mode = (mode+1) % 3;
Serial.print("Modo cambiado a: ");
Serial.println(mode);
lastButtonPushMillis = millis();
if (mode == MODE_SETMINUTES) {
lc.backup(); // we only need to back when switching from MODE_HOURGLASS->MODE_SETMINUTES
renderSetMinutes();
}
if (mode == MODE_SETHOURS) {
renderSetHours();
}
if (mode == MODE_HOURGLASS) {
lc.clearDisplay(0);
lc.clearDisplay(1);
lc.restore();
resetTime();
}
}
}
/////////////////////////////////////////////// SETUP ///////////////////////////////////////////////
void setup() {
Serial.begin(9600);
pinMode(LEDROJO, OUTPUT); // todos los pines como salida del led RGB
pinMode(LEDVERDE, OUTPUT);
pinMode(LEDAZUL, OUTPUT);
randomSeed(analogRead(A0));
// init displays
for (byte i=0; i<2; i++) {
lc.shutdown(i,false);
lc.setIntensity(i,0); //Controla la intensidad de brillo en las particulas
}
resetTime();
}
/////////////////////////////////////////////// LOOP ///////////////////////////////////////////////
void loop() {
////////////////////////// MATRICES ////////////////////////////////
delay(DELAY_FRAME);
// actualizar la configuración de rotación del controlador. Para el resto del código pretendemos que "abajo" sigue siendo 0,0 y "arriba" es 7,7
gravity = getGravity();
lc.setRotation((ROTATION_OFFSET + gravity) % 180);
// manejar modos especiales
if (mode == MODE_SETMINUTES) {
renderSetMinutes(); return;
} else if (mode == MODE_SETHOURS) {
renderSetHours(); return;
}
// resetCheck(); // el reinicio ahora ocurre al presionar un botón
bool moved = updateMatrix();
bool dropped = dropParticle();
// alarma cuando todo está en la parte inferior
if (!moved && !dropped && !alarmWentOff && (countParticles(getTopMatrix()) == 0)) {
alarmWentOff = true;
resetTime(); //Agregado
}
// reset alarm flag next time a particle was dropped
if (dropped) {
alarmWentOff = false;
}
////////////////////////////// Colores led rgb /////////////////////////////////
///*
// Esperamos a recibir un número desde Python
//while (!Serial.available()) {
// delay(10);
//}
// Leemos el número enviado desde Python
if (Serial.available()>0){
numero = Serial.parseInt();
delay(100);
// Si el número es mayor o igual a 5, encendemos el LED
if (numero == 1) {
analogWrite(LEDROJO, 255);
analogWrite(LEDVERDE, 0);
analogWrite(LEDAZUL, 0);
//delay(2000);
}
else if (numero == 2){
analogWrite(LEDROJO, 0);
analogWrite(LEDVERDE, 255);
analogWrite(LEDAZUL, 0);
//delay(2000);
}
else if (numero == 3) {
analogWrite(LEDROJO, 0);
analogWrite(LEDVERDE, 0);
analogWrite(LEDAZUL, 255);
//delay(2000);
}
else if (numero == 4) { // Cian
analogWrite(LEDROJO, 0);
analogWrite(LEDVERDE, 255);
analogWrite(LEDAZUL, 255);
//delay(2000);
}
else if (numero == 5) { // Morado
analogWrite(LEDROJO, 255);
analogWrite(LEDVERDE, 0);
analogWrite(LEDAZUL, 255);
//delay(2000);
}
else if (numero == 6) { // Amarillo
analogWrite(LEDROJO, 255);
analogWrite(LEDVERDE, 40);
analogWrite(LEDAZUL, 10);
//delay(2000);
}
else if (numero == 7) { // Blanco
analogWrite(LEDROJO, 255);
analogWrite(LEDVERDE, 255);
analogWrite(LEDAZUL, 255);
//delay(2000);
}
else if (numero == 8) { // Naranjo
analogWrite(LEDROJO, 255);
analogWrite(LEDVERDE, 10);
analogWrite(LEDAZUL, 0);
//delay(2000);
}
else if (numero == 9) { // Rosa
analogWrite(LEDROJO, 255);
analogWrite(LEDVERDE, 10);
analogWrite(LEDAZUL, 10);
//delay(2000);
}
/*
else if (numero >= 10) { // APAGADO
analogWrite(LEDROJO, 0);
analogWrite(LEDVERDE, 0);
analogWrite(LEDAZUL, 0);
//delay(2000);
}
*/
// Esperamos un poco para evitar recibir datos repetidos
//delay(100);
}
}
Encargo 07 - Avance FinalTerm #
Publigramas #
Idea publigramasEncargo 08 - Testeo #
Testeo Publigrama #
publigramas testeoEncargo 09 - FinalTerm #
Publigrama | La publicidad del futuro #
El presente exámen de Diseño describe un proyecto de publicidad interactiva que combina tecnologías de visualización 3D con hologramas y electrónica que permite esta interactividad a través de “botones de luz”.
#
PUBLIGRAMA Presentación finalFabricación:
Soldadura y corte fierros
Corte láser MDF
Electrónica y programación:
Proyección publicidad interactiva en hologramas









Código Python: #
import serial
import time
import cv2
import threading
def enviar_numero_a_arduino(numero):
arduino.write(str(numero).encode())
time.sleep(2)
def reproducir_video(ruta_video):
cap = cv2.VideoCapture(ruta_video)
# Verificar si se puede abrir el video
if not cap.isOpened():
print("Error al abrir el video.")
return
# Obtener dimensiones de la ventana de video
window_name = "Reproduciendo video"
cv2.namedWindow(window_name, cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty(window_name, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
while True:
ret, frame = cap.read()
if not ret:
# Fin del video, salir de la reproducción
break
# Mostrar el fotograma en pantalla completa
cv2.imshow(window_name, frame)
# Esperar 30 ms y verificar si se presionó la tecla 'q' para salir
if cv2.waitKey(30) & 0xFF == ord('q'):
break
if valor_anterior != valor:
break
# Cerrar ventana al finalizar la reproducción
cv2.destroyAllWindows()
# Función para reproducir el video en un hilo separado
def reproducir_video_thread(ruta_video):
thread = threading.Thread(target=reproducir_video, args=(ruta_video,))
thread.start()
return thread
# Configurar comunicación con Arduino
arduino = serial.Serial("COM5", 9600)
time.sleep(2)
# Rutas de los videos
ruta_rojo = r'D:\Baul\Ale_UAI_Cosas\2023\2do semestre\Taller_prod_Caaro_pino_fran\E07_publicida\Final\Videos\2vid_rojo.mp4'
ruta_verde = r'D:\Baul\Ale_UAI_Cosas\2023\2do semestre\Taller_prod_Caaro_pino_fran\E07_publicida\Final\Videos\2vid_verde.mp4'
ruta_azul = r'D:\Baul\Ale_UAI_Cosas\2023\2do semestre\Taller_prod_Caaro_pino_fran\E07_publicida\Final\Videos\2vid_azul.mp4'
ruta_amarilla = r'D:\Baul\Ale_UAI_Cosas\2023\2do semestre\Taller_prod_Caaro_pino_fran\E07_publicida\Final\Videos\2vid_amarillo.mp4'
ruta_morada = r'D:\Baul\Ale_UAI_Cosas\2023\2do semestre\Taller_prod_Caaro_pino_fran\E07_publicida\Final\Videos\2vid_morado.mp4'
ruta_cian = r'D:\Baul\Ale_UAI_Cosas\2023\2do semestre\Taller_prod_Caaro_pino_fran\E07_publicida\Final\Videos\2vid_cian.mp4'
ruta_blanco = r'D:\Baul\Ale_UAI_Cosas\2023\2do semestre\Taller_prod_Caaro_pino_fran\E07_publicida\Final\Videos\2vid_blanco.mp4'
# Inicializar el valor anterior
valor_anterior = None
video_thread = None
while True:
valor = arduino.readline().decode('utf-8').strip()
print(valor)
# Interrumpir el video en curso si se recibe un nuevo valor
if video_thread is not None and video_thread.is_alive():
video_thread.join() # Esperar a que el hilo de reproducción termine
cv2.destroyAllWindows()
if valor == valor_anterior:
# Si el valor es igual al valor anterior, reproducir el video actual nuevamente
if valor == '1':
video_thread = reproducir_video_thread(ruta_rojo)
elif valor == '2':
video_thread = reproducir_video_thread(ruta_verde)
elif valor == '3':
video_thread = reproducir_video_thread(ruta_azul)
elif valor == '4':
video_thread = reproducir_video_thread(ruta_amarilla)
elif valor == '5':
video_thread = reproducir_video_thread(ruta_morada)
elif valor == '6':
video_thread = reproducir_video_thread(ruta_cian)
elif valor == '7':
video_thread = reproducir_video_thread(ruta_blanco)
else:
# Si el valor es diferente al valor anterior, actualizar el valor anterior y reproducir el video correspondiente
valor_anterior = valor
if valor == '1':
video_thread = reproducir_video_thread(ruta_rojo)
elif valor == '2':
video_thread = reproducir_video_thread(ruta_verde)
elif valor == '3':
video_thread = reproducir_video_thread(ruta_azul)
elif valor == '4':
video_thread = reproducir_video_thread(ruta_amarilla)
elif valor == '5':
video_thread = reproducir_video_thread(ruta_morada)
elif valor == '6':
video_thread = reproducir_video_thread(ruta_cian)
elif valor == '7':
video_thread = reproducir_video_thread(ruta_blanco)
Código Arduino: #
#include "Arduino.h"
int espera = 100;
int aumento = 10;
int num_inicial = 50;
int num_final = 52;
/////////////////////////////////////////////// SENSORES ///////////////////////////////////////////////
int sens_1 = 9;
int sens_2 = 10;
int sens_3 = 11;
//int sens_4 = 10;
//int sens_5 = 9;
//int sens_6 = 8;
/////////////////////////////////////////////// LED RGB ///////////////////////////////////////////////
int l_rojo = 2;
int l_verde = 3;
int l_azul = 4;
int l_amarillo = 5;
//int l_morado = A0; // ROJO
//int l_cian = A1; // VERDE
//int l_rgb = A2; // AZUL
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////// CÓDIGO ///////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////// SETUP ///////////////////////////////////////////////
void setup() {
Serial.begin(9600);
pinMode(sens_1, INPUT);
pinMode(sens_2, INPUT);
pinMode(sens_3, INPUT);
//pinMode(sens_4, INPUT);
//pinMode(sens_5, INPUT);
//pinMode(sens_6, INPUT);
pinMode(l_rojo, OUTPUT);
pinMode(l_verde, OUTPUT);
pinMode(l_azul, OUTPUT);
//pinMode(l_amarillo, OUTPUT);
//pinMode(l_morado, OUTPUT);
//pinMode(l_cian, OUTPUT);
//pinMode(l_rgb, OUTPUT);
digitalWrite(l_rojo , HIGH);
digitalWrite(l_verde , HIGH);
digitalWrite(l_azul , HIGH);
}
void loop() {
/////////////////////////////////////////////// LOOP ///////////////////////////////////////////////
////////////////////////////// SENSORES /////////////////////////////////
////////// ROJO /////////
if ((digitalRead(sens_1) == HIGH) & (digitalRead(sens_2)== LOW) & ((digitalRead(sens_3)== LOW))) {
// Enviar el mensaje "sensor activado" por el puerto serial
num_final = 1;
if (num_inicial != num_final){
Serial.println("1");
num_inicial = 1;
}
delay(espera);
}
////////// VERDE /////////
else if ((digitalRead(sens_2) == HIGH) & (digitalRead(sens_1)== LOW) & ((digitalRead(sens_3)== LOW))) {
// Enviar el mensaje "sensor activado" por el puerto serial
num_final = 2;
if (num_inicial != num_final){
Serial.println("2");
num_inicial = 2;
}
delay(espera);
}
////////// AZUL /////////
else if ((digitalRead(sens_3) == HIGH) & (digitalRead(sens_1)== LOW) & ((digitalRead(sens_2)== LOW))) {
// Enviar el mensaje "sensor activado" por el puerto serial
num_final = 3;
if (num_inicial != num_final){
Serial.println("3");
num_inicial = 3;
}
delay(espera);
}
////////// AMARILLO /////////
else if ((digitalRead(sens_1) == HIGH) & (digitalRead(sens_2)== HIGH) & ((digitalRead(sens_3)== LOW))) {
// Enviar el mensaje "sensor activado" por el puerto serial
num_final = 4;
if (num_inicial != num_final){
Serial.println("4");
num_inicial = 4;
}
delay(1500);
}
////////// MORADO /////////
else if ((digitalRead(sens_1) == HIGH) & (digitalRead(sens_3)== HIGH) & ((digitalRead(sens_2)== LOW))) {
// Enviar el mensaje "sensor activado" por el puerto serial
num_final = 5;
if (num_inicial != num_final){
Serial.println("5");
num_inicial = 5;
}
delay(1500);
}
////////// CIAN /////////
else if ((digitalRead(sens_2) == HIGH) & (digitalRead(sens_3)== HIGH) & ((digitalRead(sens_1)== LOW))) {
// Enviar el mensaje "sensor activado" por el puerto serial
num_final = 6;
if (num_inicial != num_final){
Serial.println("6");
num_inicial = 6;
}
delay(1500);
}
else if ((digitalRead(sens_2) == HIGH) & (digitalRead(sens_3)== HIGH) & ((digitalRead(sens_1)== HIGH))) {
// Enviar el mensaje "sensor activado" por el puerto serial
num_final = 7;
if (num_inicial != num_final){
Serial.println("7");
num_inicial = 7;
}
delay(espera);
}
/*
else if ((digitalRead(sens_4) == HIGH)) {
// Enviar el mensaje "sensor activado" por el puerto serial
Serial.println("7");
/*
digitalWrite(l_rojo , LOW);
digitalWrite(l_verde , LOW);
digitalWrite(l_azul , LOW);
digitalWrite(l_amarillo,LOW);
analogWrite(l_morado,0);
analogWrite(l_cian,0);
analogWrite(l_rgb,0);
*/
delay(espera+aumento);
}
/*
}
/*
////////////////////////////// Colores led rgb /////////////////////////////////
///*
// Esperamos a recibir un número desde Python
//while (!Serial.available()) {
// delay(10);
//}
// Leemos el número enviado desde Python
if (Serial.available()>0){
numero = Serial.parseInt();
delay(100);
// Si el número es mayor o igual a 5, encendemos el LED
if (numero == 1) {
//analogWrite(LEDROJO, 255);
//delay(2000);
}
else if (numero == 2){
//analogWrite(LEDROJO, 0);
//delay(2000);
}
else if (numero == 3) {
//analogWrite(LEDROJO, 0);
//delay(2000);
}
delay(espera);
}
}
*/
Reseñas series #
ENSAYOS SERIES #
The Billion dollar code
Olafur Eliasson: El diseño del Arte
There are no articles to list here yet.