PiBot: Robot Pianista con Arduino para Interpretación Musical de Precisión
Componentes y materiales
- Arduino 101 ×1
- Registro de desplazamiento 74HC595 (Texas Instruments) ×11
- MOSFET N-Channel IRFZ44N ×88
- Batería 12V (tipo coche) ×2
- Condensador 100 µF ×11
- Cable de alambre (OpenBuilds) ×1 (gran cantidad)
- Protoboard (genérica) ×11
- Zócalo IC de 8 patas ×11 (opcional, para proteger los 74HC595)
- Resistencia 10 kΩ ×88 (recomendada para cada MOSFET)
- Diodo 1N4007 ×88 (recomendado para cada MOSFET)
Herramientas necesarias
- Pistola de pegamento caliente
Aplicaciones y servicios online
- Processing (IDE)
- Python
- Conversor de archivo MIDI binario a texto
Sobre el proyecto
Cómo comenzó
Hace años vi un piano automático de Yamaha en una tienda. Desde entonces quise construir mi propio robot pianista. No hay una razón profunda: simplemente tenía ganas de hacerlo.
Visión general
Controlar 88 solenoides (uno por tecla) con dos Arduino Mega sería costoso. En su lugar, usé un Arduino Uno barato y 11 registros de desplazamiento (74HC595) para expandir las salidas. Cada registro controla 8 solenoides, sumando 88 en total. El PC envía tramas de bits al Arduino (no MIDI directo); el archivo MIDI se convierte previamente a bits mediante un script Python.
Hardware
Los solenoides comprados en China resultaron demasiado débiles para pulsar las teclas desde la posición interior. La solución fue alimentarlos a 24V (siendo de 12V) para obtener la fuerza necesaria. El consumo total es alto, así que usé una batería de coche (12V) como fuente de alimentación.
Cada registro de desplazamiento y sus MOSFETs asociados se montaron en una placa controladora. El esquema sigue el ejemplo 2 de la hoja de datos del 74HC595, reemplazando los LEDs por las puertas de los MOSFETs. No se usaron resistencias pull-down para ahorrar coste y soldadura; los MOSFETs cierran por debajo de 4V (comprobado experimentalmente).
Los solenoides se fijaron sobre una placa de plástico con pegamento caliente, pero el calor derretía el pegamento. Finalmente se usó cinta de doble cara resistente a 150°C.
Software
- Obtener un archivo MIDI.
- Convertirlo a texto con esta herramienta online.
- Procesar el texto con el script Python adjunto para generar 11 grupos de 8 bits con marcas de tiempo.
- Enviar los datos al Arduino mediante Processing (puerto serie).
El código Python, Processing y Arduino se incluye en la sección de código.
Solución de problemas
- Sobrecalentamiento de solenoides: derretían el pegamento caliente. Solucionado con cinta doble cara de alta temperatura.
Código
Script Python (traducción MIDI → bits)
output_file = open("translated.txt", "w")
input_file = open("megalocania.txt")
raw_input_data = input_file.read()
work_data = raw_input_data.splitlines()
result = []
def main():
for a in work_data:
temp_time = time_finder(a)
if not result:
result.append(str(temp_time) + ",")
if on_off_finder(a):
result[-1] += set_bit(True, note_finder(a))
elif not on_off_finder(a):
result[-1] += set_bit(True, note_finder(a))
elif time_finder_comm(result[-1]) == temp_time:
result[-1] = str(temp_time) + "," + set_bit_prev(on_off_finder(a), note_finder(a), -1)
elif time_finder_comm(result[-1]) != temp_time:
result.append(str(temp_time) + "," + set_bit_prev(on_off_finder(a), note_finder(a), -1))
for b in result:
output_file.write(b)
output_file.write("\n")
output_file.close()
def set_bit(On, note):
# Genera 11 campos de 8 bits según la nota (21-108)
if 21 <= note <= 28 and On:
return str(2**(note-21)) + ",0,0,0,0,0,0,0,0,0,0"
elif 29 <= note <= 36 and On:
return "0," + str(2**(note-29)) + ",0,0,0,0,0,0,0,0,0"
# ... (resto de rangos omitidos por brevedad)
else:
return "0,0,0,0,0,0,0,0,0,0,0"
def set_bit_prev(On, note, index):
# Similar a set_bit pero actualiza el campo correspondiente en la línea previa
# ... (implementación omitida)
def indexTh(in_string, find_this, th):
# Encuentra la posición de la ocurrencia 'th' de find_this
order = 1
last_index = 0
while True:
temp = in_string.find(find_this, last_index)
if temp == -1: return -1
if order == th: return temp
order += 1
last_index = temp + 1
def time_finder(in_string):
time_end = in_string.index(" ")
return int(in_string[:time_end])
def time_finder_comm(in_string):
comma = in_string.index(",")
return int(in_string[:comma])
def note_finder(in_string):
num_start = in_string.index("n=") + 2
num_end = in_string.index("v=") - 1
return int(in_string[num_start:num_end])
def on_off_finder(in_string):
start = in_string.index(" ") + 1
end = in_string.index("ch=") - 1
return in_string[start:end] == "On"
main()
Processing (envío de datos al Arduino)
import processing.serial.*;
Serial myPort;
String[] inputLines;
void setup() {
myPort = new Serial(this, "COM3", 9600);
inputLines = loadStrings("translated.txt");
run();
}
void run() {
int lastTime = 0;
for (int i = 0; i < inputLines.length; i++) {
String temp = inputLines[i];
delay((Integer.parseInt(temp.substring(0, temp.indexOf(","))) - lastTime) * 5); // multiplicador de tempo
lastTime = Integer.parseInt(temp.substring(0, temp.indexOf(",")));
send(temp.substring(temp.indexOf(",") + 1));
}
}
void send(String data) {
// Invierte el orden de los 11 bytes porque el piano físicamente va de derecha a izquierda
String eleventh = data.substring(0, indexOforder(data, ",", 1));
String tenth = data.substring(indexOforder(data, ",", 1)+1, indexOforder(data, ",", 2));
// ... (resto de subcadenas)
String first = data.substring(indexOforder(data, ",", 10)+1);
myPort.write("888f");
myPort.write(first + "f");
myPort.write(second + "f");
// ... hasta eleventh
myPort.write("999f");
}
int indexOforder(String data, String find, int order) {
int currentOrder = 0, lastLocation = 0;
while (currentOrder < order) {
lastLocation = data.indexOf(find, lastLocation + 1);
currentOrder++;
}
return lastLocation;
}
Código Arduino (recepción y control de solenoides)
El sketch lee por puerto serie los 11 bytes precedidos por "888f" y terminados en "999f", y los volca a los registros de desplazamiento para activar los MOSFETs. El código completo está en el repositorio.
Esquemáticos
Diagrama de conexiones (basado en el ejemplo 2 del 74HC595 con MOSFETs):
Proceso de manufactura
- Construya un robot Raspberry Pi controlado por Bluetooth con retroalimentación de audio
- Construya un robot con streaming de vídeo controlado por Internet con Arduino y Raspberry Pi
- Construye un Robot Raspberry Pi Controlado por Wi‑Fi con Python – Guía Paso a Paso
- Controla LEDs con Alexa mediante Raspberry Pi – Guía paso a paso fácil
- Construye un Iron Man animado con Arduino: componentes, sensores y guía paso a paso
- Find Me: Localizador Inteligente de Objetos con Arduino y Bluetooth
- Controlador de Humidificador DIY con Arduino y Relé: Configuración Segura de Alto Voltaje
- Construye un robot controlado por voz con Arduino Nano
- MobBob: Robot Arduino Impreso en 3D, Controlado por Smartphone Android
- Construye un volante joystick personalizado con Arduino para gaming
- Arduino 101: Construye un Podómetro con Sensor DHT11 y Pantalla LCD