Introduction: Escenario De Historias Interactivas

Escenario de historias interactivas es un proyecto desarrollado para el curso de Vídeo y Televisión Digital de la Universidad Autónoma de Occidente. El objetivo de este proyecto es brindar a niños la oportunidad de crear historias y compartirlas, interactuando con un espacio que permita dar vida a las historias.

El proyecto está compuesto por dos etapas:

  1. Diseño de personajes y animaciones.
  2. Construcción del módulo.
  3. Integración de sistemas.
  4. Integración de otros componentes (pantalla y cámara).
  5. Integración de sistema de reconocimiento y conexión a Arduino.

MATERIALES

  • Madera MDP 9mm (2.15 x 2.44 m).
  • Papel Contact transparente (4m).
  • Etiquetas instructivas.
  • Tornillo para madera autoperforante (60 und).
  • Silicona caliente (12 barras).
  • Tubos de PVC (1m de 1/4'', 2m de 1/2'').
  • C de aluminio (3 und).
  • Acrílico (55 x 35 cm).
  • Cable de cobre (20m).
  • Jumpers (20 und).
  • Cinta de enmascarar.
  • Cinta negra.
  • Fuente de 12V (Adaptador AC\DC).
  • Fuente de 110V (Conexión corriente alterna directa / tomacorriente).
  • Cámara web.
  • Pantalla de 19''.
  • Cable VGA.
  • 15 muñecos.
  • 15 espacios.
  • Arduino MEGA.
  • Módulo RFID-RC522.

Este proyecto integra sistemas explicados en otros Instructables:

Step 1: Diseño De Personajes Y Animaciones

  • Usando Adobe Illustrator se crearon las representaciones de los objetos físicos (muñecos y escenarios) con el fin de animarlos.
  • Teniendo los vectores de cada personaje, se pasó a Adobe After Effects (también puede usarse Adobe Animate u otra herramienta para animar) donde se realizaron las animaciones (ver tutoriales, ejemplo: 1 y 2). Estas animaciones se deben guardar como secuencia de PNG con fondo transparente (como se muestra en las imágenes) para sobre ponerlas en los escenarios correspondientes y que así el niño tenga la posibilidad de jugar con ellas (ver gif para ejemplo de animación).

Step 2: Diseño Y Corte De Estructura

Para la estructura se realizan unos planos que describen cuáles serán las partes del módulo y de ese modo serán cortadas. Para este proyecto los orificios del techo (necesarios para la lluvia) se realizaron con

Step 3: Montaje De Estructura

Las partes de la estructura se unieron con tornillos y silicona, que a su vez sirve para evitar que el agua pase por los orificios de los tornillos. En la base se colocan dos etiquetas para indicar al usuario dónde debe colocar sus juguetes y tarjetas de identificación, las cuales se pueden descargar en los siguientes links:

Step 4: Instalación De Tuberías Y Canaletas

  • Para las canaletas se usan 3 tubos de PVC (1 de 80cm y 2 de 90cm), estos deben ubicarse en la parte superior de la base del módulo y pegarse con silicona asegurando que quede firme.
  • La tubería se debe ubicar dentro de la base del módulo a la derecha del mismo (visto desde atrás), encajando el codo el espacio correspondiente a la salida del humo.

Step 5: Integración De Sistemas: Lluvia

  1. Se ubica la manguera en el techo perforado para insertar los palitos que harán la función de rociador.
  2. En el piso se ubica una bomba de agua dentro del recipiente que contiene el líquido, a la que también llega la manguera de las canaletas con el fin de recuperar el agua expulsada en la lluvia.

Step 6: Integración De Sistemas: Niebla

  1. En la parte de arriba de la parte posterior de la estructura se une la resistencia usando 3 C metálicas.
  2. Se pega el sistema de ventilación unido al tubo de entrada.
  3. En el tubo de salida se conecta un tubo de PVC que se une en la parte inferior a otro tubo de PVC con un codo de PVC.

Step 7: Integración De Sistemas: Tiempo Del Día

Se ubican las dos regletas de LEDs en las partes laterales del frente de la estructura, pasando los cables por los orificios hacia atrás.

Step 8: Integración De Sistemas: Frío/calor

En los extremos de la parte posterior de la estructura se ubican dos bases de madera sobre las cuales se colocan las placas Peltier, la de calor a la izquierda y la de frío a la derecha (vista desde el frente).

Step 9: Integración De Sistemas: Viento

  1. Se ubican las dos cajas de madera a los extremos de la parte frontal de la estructura, estas protegerán los ventiladores del agua.
  2. Los ventiladores se ubican dentro de las cajas, pasando los cables por los orificios.

Step 10: Integración De Cámara Y Pantalla

En la parte superior de la pieza frontal de la estructura se ubica la pantalla, pasando por el orificio correspondiente el cable que se conectará al computador. Por otra parte, la pantalla se ubica sobre el soporte hecho en madera y se conecta al computador con un cable VGA.

Step 11: Conexión E Integración De RFID

  • El sistema de luz/noche está conectado a los pines analógicos, los demás a pines digitales.
  • Las fuentes se conectan al tomacorriente.
  • La conexión de RDIF se muestra en la tabla.

Step 12: Código

En Arduino:

//SDA(SS) D10 // MEGA 44
//SCK D13 // MEGA 52 //MOSI D11 // MEGA 51 //MISO D12 // MEGA 50 //GND //RST D9 //3.3V

//LED1 D13 //LED2 D05 //SERVO D11

#include #include

#define RST_PIN 9 //Pin 9 para el reset del RC522 #define SS_PIN 44 //Pin 10 para el SS (SDA) del RC522 MFRC522 mfrc522(SS_PIN, RST_PIN); ///Creamos el objeto para el RC522

int lluvia = 12; int ledrojo = 21; int ledverde = 22; int ledazul = 23; int viento = 3; int placa1 = 10; int placa2 = 8; int humo = 7; int ventilador = 5; int cont; void setup() { Serial.begin(9600); //Iniciamos La comunicacion serial pinMode(lluvia, OUTPUT); //Led pinMode(viento, OUTPUT); SPI.begin(); //Iniciamos el Bus SPI mfrc522.PCD_Init(); // Iniciamos el MFRC522 //Serial.println(" ---Leyendo tarjetas---"); cont = 0; }

byte ActualUID[4]; //almacenará el código del Tag leído byte systemStart[4] = {0x93, 0xCE, 0xCE, 0xC5}; // Inicia sistema byte id[4] = {0x24, 0x1E, 0x09, 0xC8}; // ID byte id2[4] = {0x7B, 0xFC, 0x70, 0xB7}; byte llover[4] = {0x17, 0x9F, 0xA6, 0x4C}; byte colegio[4] = {0x84, 0xA6, 0x3B, 0x5B}; byte parque[4] = {0x4E, 0x44, 0xB4, 0x32}; byte casa[4] = {0x05, 0xD3, 0xD3, 0xC3}; byte granja[4] = {0xFD, 0x2C, 0xBE, 0x72}; byte restaurante[4] = {0x2E, 0x88, 0xB8, 0x32}; byte noche[4] = {0x2B, 0x1B, 0x61, 0x0A}; byte dia[4] = {0xC0, 0xEC, 0x44, 0x63}; byte niebla[4] = {0xAD, 0xBF, 0x3A, 0x42};

byte mujerT[4] = {0x17, 0x9F, 0xA6, 0x4C}; byte girlT[4] = {0x2B, 0x1B, 0x61, 0x0A}; byte vientoSuave[4] = {0xDE, 0x1B, 0xB6, 0xEE}; //viento suave byte vientoFuerte[4] = {0x5E, 0xF4, 0xB5, 0x32}; //viento fuerte byte grabarVideo[4] = {0x84, 0xA6, 0x3B, 0x5B}; byte vientoOff[4] = {0x1E, 0x2C, 0xF4, 0xE5}; byte frio[4] = {0x55, 0x34, 0x31, 0xC4};

byte calor[4] = {0x0B, 0xD5, 0x59, 0x86};

//byte tarde[4] = {0xD3, 0xAD, 0x3B, 0x5B}; pendiete

int contdia, contnoche = 0; void loop() { if ( mfrc522.PICC_IsNewCardPresent()) { //Seleccionamos una tarjeta if ( mfrc522.PICC_ReadCardSerial()) { // Enviamos serialemente su UID //Serial.println(" Id targejta: "); for (byte i = 0; i < mfrc522.uid.size; i++) { //Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); //Serial.print(mfrc522.uid.uidByte[i], HEX); ActualUID[i] = mfrc522.uid.uidByte[i]; } //Serial.println(""); //comparamos los UID para determinar si es uno de nuestros usuarios if (compareArray(ActualUID, systemStart)) { cont++; if (cont < 2) { int data = 1; digitalWrite(humo, HIGH); Serial.write(data); } else if (cont > 1) { cont = 0; //ALL LOW BELLOW //digitalWrite(, LOW); //etc int data = 2; Serial.write( data); } }

if (compareArray(ActualUID, id)) { int data = 3; Serial.write( data); } if (compareArray(ActualUID, id2)) { int data = 30; Serial.write( data); } if (compareArray(ActualUID, colegio)) { int data = 4; Serial.write( data); } if (compareArray(ActualUID, parque)) { int data = 5; Serial.write( data); } if (compareArray(ActualUID, casa)) { int data = 6; Serial.write( data); } if (compareArray(ActualUID, granja)) { int data = 7; Serial.write( data); } if (compareArray(ActualUID, restaurante)) { int data = 8; Serial.write( data); } if (compareArray(ActualUID, mujerT)) { int data = 15; Serial.write( data); } if (compareArray(ActualUID, girlT)) { int data = 16; Serial.write( data); }

if (compareArray(ActualUID, vientoSuave)) { for (int vel = 100; vel <= 1000; vel += 100) { digitalWrite(viento, HIGH); delay(vel); digitalWrite(viento, LOW); delay(vel); digitalWrite(viento, HIGH); delay(vel); } }

if (compareArray(ActualUID, vientoFuerte)) { digitalWrite(viento, HIGH); int data = 2; //Serial.print(data); }

if (compareArray(ActualUID, vientoOff)) { digitalWrite(viento, LOW); int data = 2; }

if (compareArray(ActualUID, frio)) { cont++; if (cont < 2) { digitalWrite(placa1, HIGH);

int data = 2; Serial.println(data); } else if (cont > 1) { cont = 0; digitalWrite(placa1, LOW);

int data = 1; Serial.println( data); } }

if (compareArray(ActualUID, calor)) { cont++; if (cont < 2) { digitalWrite(placa2, HIGH);

int data = 2; Serial.println(data); } else if (cont > 1) { cont = 0; digitalWrite(placa2, LOW);

int data = 1; Serial.println( data); } }

if (compareArray(ActualUID, llover)) { cont++; if (cont < 2) { digitalWrite(lluvia, HIGH);

} else if (cont > 1) { cont = 0; digitalWrite(lluvia, LOW); }

} if (compareArray(ActualUID, niebla)) { cont++; if (cont < 2) { digitalWrite(ventilador, HIGH);

} else if (cont > 1) { cont = 0; digitalWrite(ventilador, LOW); }

}

if (compareArray(ActualUID, dia)) { contdia++; if (contdia == 1) {

setcolor(255, 0, 0); int dato = 10; Serial.write(dato); } else if (contdia == 2) { contdia = 0; setcolor(0, 0, 0); } }

// Terminamos la lectura de la tarjeta tarjeta actual mfrc522.PICC_HaltA();

} } }

//Función para comparar dos vectores boolean compareArray(byte array1[], byte array2[]) { if (array1[0] != array2[0])return (false); if (array1[1] != array2[1])return (false); if (array1[2] != array2[2])return (false); if (array1[3] != array2[3])return (false); return (true); }

void setcolor(int red, int green, int blue) { analogWrite(ledrojo, red); analogWrite(ledverde, green); analogWrite(ledazul, blue); }

En Processing:

import processing.video.*;
import processing.serial.*; Serial myPort; //-- Capture video; float avgX = 0; float avgY = 0; color trackColor; float threshold = 25; //--

Animation animation2, animation3, animation4, animation5, animationPerro, animationMujer, animationGirl, animationNiebla; //Animation2 animation1;

float xpos; float ypos; float drag = 3; int imageWidth, imageHeight=0; PImage parque; PImage colegio; PImage escenario; PImage systemOff; PImage systemStart; PImage dia; PImage noche; PImage id; PImage granja; PImage fondo; PImage casa; PImage restaurante; int valor; int cont=0; void setup() { fullScreen(); String portName = Serial.list()[0]; myPort = new Serial(this, portName, 9600); //size(720, 480); //size(1680, 1050); background(255); frameRate(30); //animation1 = new Animation2("agua/animacionprofesor", 96); animation2 = new Animation("viento_suave/viento_suave", 50, 2); animation3 = new Animation("mujerquieta", 288, 3); //animation4 = new Animation("mujercamina", 122); //animation5 = new Animation("reflejo/mujercamina", 144); animationPerro = new Animation("perro/perro", 50, 2); animationMujer = new Animation("mujerquieta/mujerquieta", 60, 2); animationGirl = new Animation("niñaquieta/niñaquieta", 60, 2); animationNiebla = new Animation("ambiente/humo/humo", 77, 5); // ypos = height * 0.25; parque = loadImage("escenarios/parque.png"); granja = loadImage("escenarios/granja.png"); colegio = loadImage("escenarios/colegio.png"); casa = loadImage("escenarios/casa.png"); restaurante = loadImage("escenarios/restaurante.png"); dia = loadImage("escenarios/dia.png"); noche = loadImage("escenarios/noche.png"); systemOff = loadImage("systemStart/off.png"); systemStart = loadImage("systemStart/start.png"); id = loadImage("systemStart/id.png"); //image(systemOff, 0, 0);

fondo= loadImage("escenarios/fondo.png"); escenario = systemOff; systemOff.resize(width, height); image(escenario, 0, 0); systemStart.resize(width, height); parque.resize(500, 400); colegio.resize(500, 400); restaurante.resize(500, 400); granja.resize(500, 400); dia.resize(width, height); noche.resize(width, height); id.resize(width, height);

}

//-- int tempNiebla=0; PFont name; boolean condicion, condicionDia=false; PVector v; PVector screenPos; float previous, current; void draw() { if (myPort.available() > 0) { valor = myPort.read(); if (valor ==1) { condicion=true; condicionDia=false; escenario = systemStart; launch("C:\\Users\\David\\Documents\\TV\\" +"uploadYoutube.bat"); } if (valor ==2) { //Apagado condicion=false; condicionDia=false; println(condicion); background(0); } if (valor ==3) { println(condicion); condicionDia=true; escenario = id; } if (valor ==30) { condicionDia=true; escenario = id; } if (valor ==4) { //fondo = dia; escenario = colegio; } if (valor ==5) { //fondo=dia; escenario = parque; } if (valor ==6) { //fondo=dia; escenario = casa; } if (valor ==7) { //fondo=dia; escenario = granja; } if (valor ==8) { //fondo=dia; escenario = restaurante; } if (valor ==9) { escenario = id; } if (valor ==10) { fondo= dia; } if (valor ==11) { fondo= noche; } } image(fondo, 0, 0); if (valor == 1 || valor ==2) { image(escenario, 0, 0); } if (valor ==3 && condicion==true) { image(escenario, 0, 0); name = createFont("font/HappyFox.otf", 95); textFont(name); fill(254); text("Juan", width/1.8, height/1.14); } if (valor ==30 && condicion==true) { image(escenario, 0, 0); name = createFont("font/HappyFox.otf", 95); textFont(name); fill(254); text("Nicolás", width/1.8, height/1.14); } if (valor ==4 && condicionDia==true) { image(fondo, 0, 0); image(escenario, 0, 0); animationPerro.display(width/3-animationPerro.getWidth()/2, height/1.004-animationPerro.getHeight()/2); //animationMujer.display(avgX-animationMujer.getWidth()/2, avgY-animationMujer.getHeight()/2); animationMujer.display(width/2.2-animationMujer.getWidth()/2, height/1.004-animationMujer.getHeight()/2); animationGirl.display(width/1.5-animationGirl.getWidth()/2, height/1.004-animationGirl.getHeight()/2); if (tempNiebla==1) { niebla(); } } else if (valor==4) { image(fondo, 0, 0); image(escenario, width/10, height/2.5); animationPerro.display(width/3-animationPerro.getWidth()/2, height/1.7-animationPerro.getHeight()/2); animationMujer.display(width/1.5-animationMujer.getWidth()/2, height/1.7-animationMujer.getHeight()/2); animationGirl.display(width/1.9-animationGirl.getWidth()/2, height/1.7-animationGirl.getHeight()/2); if (tempNiebla==1) { niebla(); } } else if (valor==5) { image(fondo, 0, 0); image(escenario, width/10, height/2.5); animationPerro.display(width/3-animationPerro.getWidth()/2, height/1.7-animationPerro.getHeight()/2); animationMujer.display(width/1.5-animationMujer.getWidth()/2, height/1.7-animationMujer.getHeight()/2); animationGirl.display(width/1.9-animationGirl.getWidth()/2, height/1.7-animationGirl.getHeight()/2); if (tempNiebla==1) { niebla(); } } else if (valor==6) { image(fondo, 0, 0); image(escenario, width/10, height/2.5); animationPerro.display(width/3-animationPerro.getWidth()/2, height/1.7-animationPerro.getHeight()/2); animationMujer.display(width/1.5-animationMujer.getWidth()/2, height/1.7-animationMujer.getHeight()/2); animationGirl.display(width/1.9-animationGirl.getWidth()/2, height/1.7-animationGirl.getHeight()/2); if (tempNiebla==1) { niebla(); } } else if (valor==7) { image(fondo, 0, 0); image(escenario, width/10, height/2.5); animationPerro.display(width/3-animationPerro.getWidth()/2, height/1.7-animationPerro.getHeight()/2); animationMujer.display(width/1.5-animationMujer.getWidth()/2, height/1.7-animationMujer.getHeight()/2); animationGirl.display(width/1.9-animationGirl.getWidth()/2, height/1.7-animationGirl.getHeight()/2); if (tempNiebla==1) { niebla(); } } else if (valor==8) { image(fondo, 0, 0); image(escenario, width/10, height/2.5); animationPerro.display(width/3-animationPerro.getWidth()/2, height/1.7-animationPerro.getHeight()/2); animationMujer.display(width/1.5-animationMujer.getWidth()/2, height/1.7-animationMujer.getHeight()/2); animationGirl.display(width/1.9-animationGirl.getWidth()/2, height/1.7-animationGirl.getHeight()/2); if (tempNiebla==1) { niebla(); } } else if (valor==100) { image(escenario, 0, 0); animationPerro.display(width/3-animationPerro.getWidth()/2, height/1.7-animationPerro.getHeight()/2); animationMujer.display(width/1.5-animationMujer.getWidth()/2, height/1.7-animationMujer.getHeight()/2); animationGirl.display(width/1.9-animationGirl.getWidth()/2, height/1.7-animationGirl.getHeight()/2); } else if (valor==101) { image(escenario, 0, 0); animationPerro.display(width/3-animationPerro.getWidth()/2, height/1.7-animationPerro.getHeight()/2); animationMujer.display(width/1.5-animationMujer.getWidth()/2, height/1.7-animationMujer.getHeight()/2); animationGirl.display(width/1.9-animationGirl.getWidth()/2, height/1.7-animationGirl.getHeight()/2); }

}

void niebla() { animationNiebla.display(0-animationNiebla.getWidth()/2, 0-animationNiebla.getHeight()/2); }

public void execCommand(String text) { Runtime rt = Runtime.getRuntime(); try { rt.exec(text); System.out.println("cls"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }