Caja Musical orientada a bebés.
Autores: Daniel Francisco Pandolfo Mendoza, Fernando Sanz Zambrana, Mohamed El Kanboui Bouaacha.
Explicación del Proyecto.
La idea de nuestro proyecto es una caja musical orientada para bebés con el fin de facilitar su sueño. Esta caja es controlada por medio de una aplicación móvil con la que el usuario es capaz de :
- Abrir y cerrar la caja.
- Reproducir una canción concreta.
- Para la reproducción de la canción.
- Cambiar el volumen de la música.
- Reproducir en bucle todas las canciones.
- Encender y apagar la luz.
- Poner un color concreto a la luz.
- Habilitar un cambio automático del color de las luces.
- Activar un temporizador que permita cerrar por completo la caja (apagando la luz y parando la música).
Componentes Utilizados.
Componente/Producto | Precio |
Altavoz | 2,17 € |
Módulo Bluetooth | 5,10 € |
Tarjeta SD | 6,42 € |
Pila | 2 € |
Pegamento Instantáneo | 1,90 € |
DFPlayer | 6 € |
2 Rollos de Plástico | 1,2 € |
Caja de cartón | 0 € |
Kit de Arduino | 0 € |
Total | 24,79 € |
Problemas encontrados.
Problema 1. Incompatibilidad entre las comunicaciones seriales del reproductor y el módulo bluetooth.
Al juntar en el prototipo estos dos componentes, se apreciaba un comportamiento indeseado. Al investigar se averiguó que se debía a la librería SoftwareSerial, que no permitía el uso simultáneo de dos comunicaciones con el microcontrolador.
Solución al problema 1.
Con un análisis del funcionamiento del sistema, se llegó a la conclusión de que no se necesitaba un uso simultáneo de las comunicaciones. Así que se hizo uso de la función .listen(), provista por la librería y que permite dar prioridad a unas comunicaciones seriales frente a otras.
Problema 2. El amplificador requería de una librería especial.
El amplificador se compró con el objetivo de reproducir audios de tipo .wav y .mp3, sin embargo, no cumplía con su propósito.
Solución del problema 2.
Para solucionar el problema se instaló la librería “DFplayermini.h”. Esta librería ya permitía conectarse con el amplificador y reproducir los archivos con las extensiones anteriormente mencionada.
Problema 3. La caja contenía material defectuoso
Concretamente, la pila estaba agotada.
Solución al problema 3.
Se optó por comprar un repuesto para dicho material.
Problema 4. Potencia lumínica insuficiente.
La intensidad de la fuente lumínica de la caja, en este caso 2 leds RGB, era insuficiente para proyectar en el techo el patrón del papel trasparente que se situaba en la tapa de la caja.
Solución al problema 4.
No se ha conseguido proyectar el patrón en el techo con las herramientas de las que se disponían.
Problema 5. Pin PWM
La placa cuenta con 6 pines PWM, sin embargo, necesitábamos 7 para el sistema: 3 para el LED, 2 para el DFPlayer, 1 para el módulo bluetooth y otro para el servomotor.
Solución al problema 5. Los colores que emite el LED siempre tienen el componente rojo en 0 o 255, por lo que no se necesitaba una escritura analógica, bastaba con una digital.
Vídeo demostración.
Código.
A continuación, se muestra el código que implementa la parte software del proyecto.
// LIBRERIAS NECESARIAS #include <Servo.h> #include <SoftwareSerial.h> #include "DFRobotDFPlayerMini.h" //===== CONSTANTES ===== // bluetooth: #define RX_BT 9 // PWM #define TX_BT 8 // No PWM // DFPlayer: #define RX_DFP 6 // PWM #define TX_DFP 5 // PWM // led: #define LED_ROJO 12 #define LED_VERDE 10 #define LED_AZUL 11 // servo: #define PIN_SERVO 3 Servo motor; // Variables de estado int colorActual = 1; bool cerrada; // VARIABLES GLOBALES SoftwareSerial BTSerial(RX_BT,TX_BT); SoftwareSerial DFPlayerSerial(RX_DFP,TX_DFP); // Comunicacion entre placa y DFPlayer. DFRobotDFPlayerMini moduloDFP; // Componente DFPlayer // FUNCIONES AUXILIARES String decodificarEntrada(String, int*); void darColorRGB(int, int, int); void abrirTapa(bool); void actualizarColor(int); //________________________________________________________ void setup() { // Inicializar leds y servo pinMode(LED_ROJO, OUTPUT); pinMode(LED_VERDE, OUTPUT); pinMode(LED_AZUL, OUTPUT); motor.attach(PIN_SERVO); motor.write(0); cerrada = true; darColorRGB(0, 0, 0); // Inicializar comunicaciones seriales BTSerial.begin(9600); DFPlayerSerial.begin(9600); //----------------------------- // Inicializacion de DFPlayer if (!moduloDFP.begin(DFPlayerSerial)) { //Usar softwareSerial para comunicarse con la placa while (true){ // Fallo en la conexion al DFP actualizarColor(0); actualizarColor(2); } } moduloDFP.setTimeOut(500); // Tiempo de comunicacion DFP-placa //----Ajustar volumen---- moduloDFP.volume(30); // Volumen (0~30). //----Ajustar ecualizador---- moduloDFP.EQ(DFPLAYER_EQ_NORMAL); //----Ajustar dispositivo del que leer. SD como predeterminado---- moduloDFP.outputDevice(DFPLAYER_DEVICE_SD); } void loop() { // Atender la comunicacion bluetooth BTSerial.listen(); if (BTSerial.available()) { String mensaje = BTSerial.readStringUntil('/'); int valor; String componenteID = decodificarEntrada(mensaje, &valor); if(componenteID.equals("CJT")){ // Cerrar el sistema abrirTapa(false); moduloDFP.pause(); darColorRGB(0,0,0); } else if (componenteID.equals("CJ")) { // Abrir/Cerrar caja abrirTapa(valor); } else if(componenteID.equals("REPCAN")){ if(!cerrada){ DFPlayerSerial.listen(); moduloDFP.play(valor); } } else if(componenteID.equals("PAUCAN")){ // Parar cancion if(!cerrada){ DFPlayerSerial.listen(); moduloDFP.pause(); } } else if(componenteID.equals("ALLCAN")){ // Reproducir todas las canciones if(!cerrada){ DFPlayerSerial.listen(); moduloDFP.enableLoopAll(); } } else if(componenteID.equals("ONECAN")){ // Reproducir en bucle la misma cancion if(!cerrada){ DFPlayerSerial.listen(); moduloDFP.disableLoopAll(); moduloDFP.loop(moduloDFP.readCurrentFileNumber()); } } else if(componenteID.equals("VOL")){ // Ajustar volumen if(!cerrada){ DFPlayerSerial.listen(); int volumen = valor*30 / 100; moduloDFP.volume(volumen); } } else if(componenteID.equals("L") || // Apaga/Enciende luces componenteID.equals("COL")){ // Cambia a color concreto if(valor==0)darColorRGB(0,0,0); else{ actualizarColor(valor); } } else if(componenteID.equals("NEXTCOL")){ // Pasar al siguiente color colorActual = (colorActual%9) + 1; actualizarColor(colorActual); } } } void actualizarColor(int colorID) { switch (colorID) { case 0: darColorRGB(0, 0, 0); case 1: darColorRGB(255, 255, 255); break; case 2: darColorRGB(255, 0, 0); break; case 3: darColorRGB(0, 0, 255); break; case 4: darColorRGB(0, 255, 255); break; case 5: darColorRGB(0, 255, 0); break; case 6: darColorRGB(255, 0, 255); break; case 7: darColorRGB(255, 165, 0); break; case 8: darColorRGB(255, 51, 249); break; case 9: darColorRGB(255, 255, 0); break; default: darColorRGB(0, 0, 0); break; } } //________________________________________________________ void darColorRGB(int r, int g, int b) { if(r>0)digitalWrite(LED_ROJO, HIGH); else digitalWrite(LED_ROJO, LOW); analogWrite(LED_VERDE, g); analogWrite(LED_AZUL, b); } void abrirTapa(bool abrir) { for (int i = 0; i <= 100; i++) { if (abrir) motor.write(i); else motor.write(100 - i); delay(15); } cerrada = !abrir; } String decodificarEntrada(String mensaje, int* valor) { // Descomponer el mensaje entrante int indiceSeparador = mensaje.indexOf('_'); if(indiceSeparador != -1){ *valor = mensaje.substring(indiceSeparador + 1, mensaje.length()).toInt(); return mensaje.substring(0, indiceSeparador); }else{ *valor = -1; return mensaje.substring(0, mensaje.length()); } }