Mememe: un reproductor MP3 para Ada
Ada es muy pequeña, pero muy lista. Podría poner música ella sola con el WinAMP si le dejara el ratón. Pero no le voy a dejar el ratón. Así que la alternativa era evidente: fabricarle un reproductor de música que funciona con muñecos. Pones un muñeco encima y suena su música. Un muñeco = una playlist. Lo quitas, pones otro, y cambia la música. Interfaz de usuario de nivel: un año y medio.
La idea
Primero, como en los proyectos serios, la fase de diseño. El wireframe está hecho sin KiCad ni nada. Las especificaciones técnicas importantes ya están todas ahí: que la tarjeta SD va en FAT16 o FAT32, que cada playlist es una carpeta numerada con sus mp3 dentro, y unos cuantos cables de colores que luego, sorprendentemente, resultaron ser más o menos verdad.

Los componentes
La lista de la compra es corta y barata:
- Un Arduino Nano, que hace de cerebro.
- Un DFPlayer Mini, un reproductor de mp3 chino que cuesta dos euros y lleva lector de tarjeta SD incorporado. Le hablas por serie y él reproduce lo que le pidas.
- Un lector RFID RC522, también de dos euros, para detectar qué muñeco hay encima.
- Un altavoz de 4 ohmios rescatado del cajón, claro.
- Y la joya de la corona: una batería que venía de regalo con el Nesquik grande. Una powerbank promocional que llevaba años esperando su momento de gloria. Era este.
- Algunos conectores y botones variados para rematar: Una entrada usb-c para recargarlo, un pulsador para pasar a la siguiente canción y poco más.

Ojo con las etiquetas RFID, que aquí hay trampa: hay principalmente dos tipos y no son compatibles entre sí. Las de 125 kHz (las típicas de llaveros de garaje) y las de 13,56 MHz (tipo MIFARE, las de los abonos de transporte). El RC522 solo lee las de 13,56 MHz, así que si compras las otras te quedas mirando el lector y el lector mirándote a ti. Yo compré unas monedas adhesivas de 13,56 MHz, que para pegarlas debajo de un muñeco son perfectas.
El código
La lógica es sencilla: el RC522 lee el identificador único de la pastilla RFID del muñeco, el Arduino lo busca en una tabla que dice qué carpeta de la SD le corresponde, y le ordena al DFPlayer que reproduzca esa carpeta. Cuando se acaba una canción salta a la siguiente, y cuando se acaba la carpeta, silencio. También hay un botón para saltar de canción, para cuando la canción del Pollito Pío ya ha sonado suficientes veces (spoiler: nunca ha sonado suficientes veces).
No os pongo aquí el tocho entero porque esto es un blog, no un repositorio, pero lo dejo desplegable para quien quiera copiarlo:
Ver el código completo del Arduino
#include <DFRobotDFPlayerMini.h>
#include <SoftwareSerial.h>
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 9
#define SS_PIN 10
#define BUTTON_PIN 6 // Pin para el botón
MFRC522 mfrc522(SS_PIN, RST_PIN);
SoftwareSerial SerialMP3(4, 5);
DFRobotDFPlayerMini myDFPlayer;
struct TagFolder {
byte uid[7];
uint8_t folder;
};
TagFolder tagMap[] = {
{{0x08, 0xD3, 0x0E, 0x01, 0x99, 0x37, 0xA3}, 1}, // dibujos
{{0x05, 0xa1, 0x13, 0x16, 0x46, 0xA2, 0x89}, 2} // pollito pio
};
#define NUM_TAGS (sizeof(tagMap)/sizeof(tagMap[0]))
byte lastUID[7] = {0}; // Último UID leído
bool isPlaying = false;
bool tagPresente = false;
uint8_t currentFolder = 0;
uint8_t currentTrack = 0;
void setup() {
Serial.begin(9600);
SerialMP3.begin(9600);
SPI.begin();
mfrc522.PCD_Init();
pinMode(BUTTON_PIN, INPUT_PULLUP);
myDFPlayer.begin(SerialMP3);
delay(2000);
myDFPlayer.volume(20);
myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);
byte version = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
Serial.print("Versión del lector: 0x");
Serial.println(version, HEX);
Serial.println("Sistema listo. Pon un moñeco.");
}
bool sameUID(byte *uid1, byte *uid2, byte len) {
for (byte i = 0; i < len; i++) {
if (uid1[i] != uid2[i]) return false;
}
return true;
}
uint8_t buscarCarpetaPorUID(byte *uid, byte uidSize) {
for (uint8_t i = 0; i < NUM_TAGS; i++) {
if (sameUID(uid, tagMap[i].uid, uidSize)) {
return tagMap[i].folder;
}
}
return 0;
}
void detenerReproduccion() {
myDFPlayer.stop();
memset(lastUID, 0, sizeof(lastUID));
tagPresente = false;
isPlaying = false;
currentFolder = 0;
currentTrack = 0;
Serial.println("Fin de la carpeta.");
}
void loop() {
static bool tagAnteriorPresente = false;
static unsigned long lastDebounceTime = 0;
static bool buttonLast = HIGH;
// Botón para siguiente pista
bool buttonState = digitalRead(BUTTON_PIN);
if (buttonLast == HIGH && buttonState == LOW && millis() - lastDebounceTime > 200) {
Serial.println("CLICK!");
if (isPlaying) {
currentTrack++;
uint16_t n = myDFPlayer.readFileCountsInFolder(currentFolder);
n = myDFPlayer.readFileCountsInFolder(currentFolder);
n = myDFPlayer.readFileCountsInFolder(currentFolder);//tres veces por un bug raro
if (currentTrack > n) {
detenerReproduccion();
} else {
myDFPlayer.playFolder(currentFolder, currentTrack);
Serial.print("Siguiente pista: ");
Serial.println(currentTrack);
}
}
lastDebounceTime = millis();
}
buttonLast = buttonState;
// Lectura de tarjeta
if (mfrc522.PICC_IsNewCardPresent()) {
if (mfrc522.PICC_ReadCardSerial()) {
byte *uid = mfrc522.uid.uidByte;
byte uidSize = mfrc522.uid.size;
// ¿UID diferente al anterior?
if (!sameUID(uid, lastUID, uidSize)) {
Serial.print("ID del moñeco detectado: ");
for (byte i = 0; i < mfrc522.uid.size; i++) {
Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(mfrc522.uid.uidByte[i], HEX);
}
Serial.println();
uint8_t folder = buscarCarpetaPorUID(uid, uidSize);
if (folder > 0) {
myDFPlayer.stop();
delay(200);
currentFolder = folder;
currentTrack = 1;
myDFPlayer.playFolder(currentFolder, currentTrack);
Serial.print("Moñeco detectado! Reproduciendo carpeta: ");
Serial.println(currentFolder);
memcpy(lastUID, uid, uidSize);
isPlaying = true;
tagPresente = true;
} else {
Serial.println("Tag no reconocido.");
}
} else {
// Mismo tag detectado
if (false && !isPlaying) {
myDFPlayer.start();
isPlaying = true;
Serial.println("Reanudando reproducción.");
}
}
tagAnteriorPresente = true;
mfrc522.PICC_HaltA();
}
} else {
// No hay tag presente ahora pero antes sí → retirado
if (false && tagAnteriorPresente) {
myDFPlayer.pause();
isPlaying = false;
tagPresente = false;
Serial.println("Tag retirado. Reproducción en pausa.");
tagAnteriorPresente = false;
}
}
// Comprobamos si ha terminado la pista
if (myDFPlayer.available()) {
uint8_t tipo = myDFPlayer.readType();
Serial.print("Evento recibido: ");
Serial.println(tipo);
if (tipo == 11) {
delay(200); // Evita saturar el módulo
currentTrack++;
uint16_t n = myDFPlayer.readFileCountsInFolder(currentFolder);
n = myDFPlayer.readFileCountsInFolder(currentFolder);
n = myDFPlayer.readFileCountsInFolder(currentFolder);//tres veces por un bug raro
if (currentTrack > n) {
detenerReproduccion();
} else {
myDFPlayer.playFolder(currentFolder, currentTrack);
Serial.print("Avance automático a pista: ");
Serial.println(currentTrack);
}
}
}
}
Detalle a apreciar: hay una consulta al DFPlayer que se hace tres veces seguidas «por un bug raro». No preguntéis. Funciona así y así se queda.
La caja
Todo el tinglado se mete en una caja de madera que en su vida anterior era una caja de lápices. Dentro van el altavoz, la electrónica, la batería del Nesquik y una cantidad de cable que en la protoboard parecía razonable y aquí dentro parece una cesta de mimbre.

Por fuera, en cambio, la cosa queda bastante digna: rejilla para el altavoz, una ruedecita de volumen (que me regaló hace muchos años un señor en Electrónica Burriana porque ya era muy vintage), el botón de pasar canción, el de encendido con su lucecita (me encanta ese botón) y, arriba, un hueco redondo donde encaja la peana del muñeco, justo encima del lector RFID.

Los muñecos
Y aquí viene la parte que no estaba en el plan: los muñecos se han convertido en una afición en sí misma. Los compro en el mercadillo de los domingos, figuritas de las de toda la vida, tipo ComicSpain, Bullyland y compañía. El protocolo es siempre el mismo: cada vez que a Ada le engancha una música nueva, hay que salir de expedición a buscar un muñeco adecuado (y barato), pegarle en la peana una base de Warhammer, meterle dentro la pastilla RFID, apuntar su identificador en la tabla del código, y a funcionar.
Así que la estantería va creciendo: Aladdín, Baloo, David el Gnomo, la Pantera Rosa en varias de sus encarnaciones… Cada uno con su playlist. Una discoteca de vinilos, pero en muñecos.

Al final, el aparato ha cumplido exactamente lo que prometía: Ada pone su música sola, la cambia cuando quiere, y el ratón sigue siendo mío. Y de regalo, una excusa estupenda para dar una vuelta y comprar muñecos en el mercadillo “por necesidad”. Todos ganamos.
