Es momento de dar voz a nuestros robots. Hace tiempo explicamos una manera de obtener un montón de sonidos para nuestros robots .
Si nos hemos hecho ya una lista personalizada de sonidos para almacenar dentro de una tarjeta SD, ahora tendremos que crear una aplicación que nos permita poder ejecutar las canciones que estan guardadas en función de los sucesos o sensores del robot.
Para ello, vamos a explicar de manera sencilla este proceso mediante la plataforma de programación de ArduBlockly, en la que encontraremos facilmente los bloques para llevar a cabo este divertido ejercicio.
Introducción y conexión
Para realizar este ejercicio necesitaremos
- Un módulo MP3 DFPlayer
- Una tarjeta SD
- Un mini altavoz
… Una placa Arduino y cables
Para realizar la conexión de estos elementos podemos proceder tal y como aparece en la figura.
Para entender un poco mejor qué es lo que estamos conectando, podemos observar la siguiente imagen que nos indican cuales son los pines de conexión de este dispositivo.
Nosotros en principio solo utilizaremos los siguiente pines
- Los cables RX y TX de recepción y transmisión respectivamente para enviar y recibir información de la placa al módulo.
- Los cables de conexión al altavos SPK_1 y SPK_2 ( referidos como Speaker1 y Speaker2 )
- Los cables de alimentación VCC y GND, como en todos los dispositivos.
El resto de pines permiten otras opciones más avanzadas o para un control externo mediante hardware.
En fin, nosotros procederemos a simplificar este proceso programandolo con las opciones que nos permite la siguiente librería DFRobotDFPlayerMini. También podemos instalarla a través del gestor de librerías de Arduino, tal y como aparece en la figura.
Preparar la tarjeta SD con música
Para poder escuchar las canciones, primero hay que hacer una busqueda de los archivos mp3 que queremos reproducir.
Para ello tenemos varias opciones.
- Crear nuestras grabaciones propias
- Descargar archivos mp3
Las opciones son muy variadas, pero lo más importante a tener en cuenta es lo siguiente. La tarjeta SD es un formato de almacenamiento mediante archivos y estos archivos tienen un nombre específico y están contenidos en unas carpetas determinadas.
A través de esta librería se pueden acceder a través de archivos y ficheros mediante unas determinadas funciones, pero hay veces que pueden no funcionar correctamente. Para que funcionen sin problema, vamos a renombrar todos los archivos de música con un número, indicativo de la posición ordenada dentro de toda la lista de reproducción.
- 0001.mp3
- 0002.mp3
- 0003.mp3
- ….
- 9999.mp3
Puede haber hasta un total de 9999 canciones en una carpeta, dentro de 10 carpetas distintas. Pero nuestra recomendación es que las canciones estén ubicadas en la raiz de la tarjeta. Es decir que no estén contenidas en ninguna carpeta o en todo caso estar contenidas en una carpeta con el nombre “mp3”
En caso de estar contenidas en carpetas ditintas, éstas han de estar nombradas con un número a su vez y su máximo es de 10. Pero en un principio dejaremos los archivos fuera de ellas en una primera prueba.
De todas maneras, no hace falta llenar la tarjeta por completo, así que podremos guardar otros archivos que no sean necesariamente de música.
Este proceso de buscar, encontrar y ordenar canciones en una lista lleva más tiempo del que nos podemos imaginar aunque parezca mentira, pero el resultado merecerá la pena.
A programar
Para programar lo primero que vamos a tener en cuenta es que vamos a hacer uso de la comunicación serie mediante la librería SoftwareSerial. Para ello, vamos a conectar a los pines de comunicación TX y RX del módulo con los pines 10 y 11. Nos tendremos que acordar que los pines van cruzados. RX de la placa con el TX del módulo y viceversa.
Este apartado nos muestra como vincular el módulo MP3 con la comunicación serie, pero ahora nos toca reproducir canciones. Con el siguiente bloque del menú tendremos todas las opciones de reproducción de un archivo mp3.
Pero aún con esto no sabemos cuál de ellas estamos reproduciendo. Por defecto el cursor de la lista de reproducción siempre se dispondrá sobre la primera canción. Si elegimos Next, nos reproducirá la siguiente canción y el cursor se movera a la siguiente, por lo que si volvemos a seleccionar Next, nos moveremos a la tercera y así sucesivamente.
Para especificar cuál de las canciones queremos reproducir vamos a utilizar el siguiente bloque.
En este punto hemos de tener cuidado… Las canciones tienen una duración determinada. Esta duración puede verse obstruida si en un momento definimos que se ejecute otra canción a mitad de la que está reproduciendo.
Entonces en este ejemplo, nuestra canción se reproduce en un loop y hemos puesto un delay después de que se vuelva a ejecutar la misma.
De cualquier manera, tanto como si dura más de un segundo como si no, la canción estará cortada o el programa bloqueado si hacer nada por el delay.
Esta NO es la mejor manera de realizar este programa. Así que vamos a complicarnos con un control para elegir la canción a través del monitor serie.
Control por Monitor Serie.
Antes de nada, hemos de comentar que este control por monitor serie, puede ser el mismo que podriamos aplicar si tuvieramos un módulo Bluetooth que se comunique de forma inalámbrica; pero este caso lo veremos más adelante.
Para realizar el control por monitor serie lo que vamos a hacer es ejecutar sus funciones cuando le definamos una letra en la lectura.
Por ejemplo.
- Play –> w
- Next –> d
- Previous –>a
- Pause –> s
- Stop –> x
- Random –> r
Pero además de eso, vamos a desarrollar el algoritmo para elegir una canción en concreto de toda la lista mediante un parámetro numérico y otros caracteres para leer datos de nuestro modulo mp3
- Play Song number –> e10 (Ejecuta la canción número 10 )
- Set Volume –> c10 ( Pondremos el volumen a 10 de un máximo de 30 )
Y el código creado será el siguiente.
#include <SoftwareSerial.h> #include <DFRobotDFPlayerMini.h> char serialData; int nsong; int v; SoftwareSerial comm(10,11); DFRobotDFPlayerMini mp3; void setup() { Serial.begin(9600); comm.begin(9600); mp3.begin(comm);serialData = (char)((' ')); } void loop() { if (Serial.available()) { serialData = (Serial.read()); if (serialData == ('w')) { Serial.println("Play Song"); mp3.start(); } else if (serialData == ('a')) { Serial.println("Previous Song"); mp3.previous(); } else if (serialData == ('s')) { Serial.println("Pause"); mp3.pause(); } else if (serialData == ('d')) { Serial.println("Next Song"); mp3.next(); } else if (serialData == ('x')) { Serial.println("Stop"); mp3.stop(); } else if (serialData == ('r')) { Serial.println("Random"); mp3.randomAll(); } else if (serialData == ('e')) { nsong = (int)(((Serial.readString()).toInt())); Serial.print("Play Song Number"); Serial.println(nsong); mp3.play(nsong); } else if (serialData == ('c')) { v = (int)(((Serial.readString()).toInt())); Serial.print("Set Volume (Max 30) to "); Serial.println(v); mp3.volume(v); } } }
Una vez que hemos subido nuestro programa solamente hace falta acceder a nuestro monitor serie y escribir letras para ver cómo se comporta nuestro programa.
Para finalizar con este programa, vamos a proporcionarle algo de robustez, ya que la comunicación y la conexión con la tarjeta SD puede a veces dar problemas y puede ser un verdadero quebradero de cabeza si no sabemos por qué no funciona nuestro módulo.
Para ello vamos a utilizar un modo de verificacion de errores. Para ello hemos de integrar en nuestro programa el siguiente modo de debug y a través del monitor serie nos proporionará la razón de su mal funcionamiento. Si conocemos la razón podremos arreglarlo.
*Estos fallos pueden aparecer cuando se utilizan funciones más avanzadas de este módulo.
#include <SoftwareSerial.h> #include <DFRobotDFPlayerMini.h> char serialData; int nsong; int v; SoftwareSerial comm(10,11); DFRobotDFPlayerMini mp3; String DFPlayerStatus(uint8_t type, int value){ String error; switch (type) { case TimeOut: error = "Time Out!"; break; case WrongStack: error = "Stack Wrong!"; break; case DFPlayerCardInserted: error = "Card Inserted!"; break; case DFPlayerCardRemoved: error = "Card Removed!"; break; case DFPlayerCardOnline: error = "Card Online!"; break; case DFPlayerPlayFinished: error = "Number:"; error += value; error += " Play Finished!"; break; case DFPlayerError: //Serial.print("DFPlayerError:"); switch (value) { case Busy: error = "Card not found"; break; case Sleeping: error = "Sleeping"; break; case SerialWrongStack: error = "Get Wrong Stack"; break; case CheckSumNotMatch: error = "Check Sum Not Match"; break; case FileIndexOut: error = "File Index Out of Bound"; break; case FileMismatch: error = "Cannot Find File"; break; case Advertise: error = "In Advertise"; break; default: error = "DFPlayerError: Unknown"; break; } break; default: break; } return error; } void setup() { Serial.begin(9600); comm.begin(9600); mp3.begin(comm); serialData = (char)((' ')); } void loop() { if (mp3.available()) { Serial.println((DFPlayerStatus(mp3.readType(),mp3.read()))); } if (Serial.available()) { serialData = (Serial.read()); if (serialData == ('q')) { Serial.println("Connecting..."); if (mp3.begin(comm)) { Serial.println("Success"); } else { Serial.println("Please insert the SD card or check the connection"); } } else if (serialData == ('w')) { Serial.println("Play Song"); mp3.start(); } else if (serialData == ('a')) { Serial.println("Previous Song"); mp3.previous(); } else if (serialData == ('s')) { Serial.println("Pause"); mp3.pause(); } else if (serialData == ('d')) { Serial.println("Next Song"); mp3.next(); } else if (serialData == ('x')) { Serial.println("Stop"); mp3.stop(); } else if (serialData == ('r')) { Serial.println("Random"); mp3.randomAll(); } else if (serialData == ('e')) { nsong = (int)(((Serial.readString()).toInt())); Serial.print("Play Song Number"); Serial.println(nsong); mp3.play(nsong); } else if (serialData == ('c')) { v = (int)(((Serial.readString()).toInt())); Serial.print("Set Volume (Max 30) to "); Serial.println(v); mp3.volume(v); } } }
Con este ejercicio finalizaremos la introducción para crear un robot parlanchín y ahora podremos centrarnos en lo que cuesta tiempo… Encontrar los sonidos o canciones que queremos reproducir y en función de otros sensores.
4 comments