Hackster is hosting Hackster Holidays, Ep. 7: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 7 on Friday!
Remy Yoo
Published © GPL3+

Arduino Controlled Piano Robot: PiBot

Using one Arduino Uno board to control 88 solenoids to play piano.

IntermediateFull instructions providedOver 7 days18,615
Arduino Controlled Piano Robot: PiBot

Things used in this project

Hardware components

Arduino 101
Arduino 101
×1
Texas Instruments 74HC595
×11
IRFZ44N
N-Channel Mosfet
×88
12V Battery
×2
Capacitor 100 µF
Capacitor 100 µF
×11
Wire Cable - By the Foot
OpenBuilds Wire Cable - By the Foot
a lot of them.
×1
Breadboard (generic)
Breadboard (generic)
Or generic prototype board. Just about anything that will put things together.
×11
8 legs IC socket
Optional if you're confident that you won't burn ANY of these expensive 595
×11
Resistor 10k ohm
Resistor 10k ohm
Not used for this project but better to have for each mosfet
×88
1N4007 – High Voltage, High Current Rated Diode
1N4007 – High Voltage, High Current Rated Diode
Not used for this project but better to have for each mosfet
×88

Software apps and online services

Processing
Python
Binary MIDI file to text

Hand tools and fabrication machines

Hot glue gun (generic)
Hot glue gun (generic)

Story

Read more

Schematics

the concept

I'm sorry for un-professional drawing. This is the whole concept. There's no difference between Arduino -ShiftOut document's diagram except for the mosfet. I recommend looking at that too.

Code

Python Code for translation

Python
Takes textified mifi file and translates it to 11 sets of binary for arduino to take it.
output_file = open("translated.txt", "w")
input_file = open("megalocania.txt")
raw_input_data = input_file.read()
work_data = raw_input_data.splitlines()
result = []

#output_file = open("result.txt", "w")

def main():

    for a in work_data:
        temp_time = time_finder(a)
        
        
        if 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):
    #Takes boolean for if it is on or not, and note number.
    #Generates bit
    if(note >= 21 and note <= 28 and On):
        return str(2**(note - 21)) + ",0,0,0,0,0,0,0,0,0,0"
    elif(note >= 29 and note <= 36 and On):
        return "0," + str(2**(note - 29)) + ",0,0,0,0,0,0,0,0,0"
    elif(note >= 37 and note <= 44 and On):
        return "0,0," + str(2**(note - 37)) + ",0,0,0,0,0,0,0,0"
    elif(note >= 45 and note <= 52 and On):
        return "0,0,0," + str(2**(note - 45)) + ",0,0,0,0,0,0,0"
    elif(note >= 53 and note <= 60 and On):
        return "0,0,0,0," + str(2**(note - 53)) + ",0,0,0,0,0,0"
    elif(note >= 61 and note <= 68 and On):
        return "0,0,0,0,0," + str(2**(note - 61)) + ",0,0,0,0,0"
    elif(note >= 69 and note <= 76 and On):
        return "0,0,0,0,0,0," + str(2**(note - 69)) + ",0,0,0,0"
    elif(note >= 77 and note <= 84 and On):
        return "0,0,0,0,0,0,0," + str(2**(note - 77)) + ",0,0,0"
    elif(note >= 85 and note <= 92 and On):
        return "0,0,0,0,0,0,0,0," + str(2**(note - 85)) + ",0,0"
    elif(note >= 93 and note <= 100 and On):
        return "0,0,0,0,0,0,0,0,0," + str(2**(note - 93)) + ",0"
    elif(note >= 101 and note <= 108 and On):
        return "0,0,0,0,0,0,0,0,0,0," + str(2**(note - 101))
    else:
        return "0,0,0,0,0,0,0,0,0,0,0"

def set_bit_prev(On, note, index):
    #Same as set_bit but previous aware
    temp = result[index]
    temp = temp[(temp.find(",") + 1):]
    
    if(note >= 21 and note <= 28):
        local_temp = temp[0:temp.find(",")]
        if(On):
            return str(int(local_temp) + (2**(note - 21))) + temp[temp.find(","):]
        if(not On):
            return str(int(local_temp) - (2**(note - 21))) + temp[temp.find(","):]
        
    elif(note >= 29 and note <= 36):
        local_temp = temp[(temp.find(",") + 1):indexTh(temp, ",", 2)]
        if(On):
            return temp[0:temp.find(",") + 1] + str(int(local_temp) + (2**(note - 29))) + temp[indexTh(temp, ",", 2):]
        if(not On):
            return temp[0:temp.find(",") + 1] + str(int(local_temp) - (2**(note - 29))) + temp[indexTh(temp, ",", 2):]
        
    elif(note >= 37 and note <= 44):
        local_temp = temp[(indexTh(temp, ",", 2) + 1):indexTh(temp, ",", 3)]
        if(On):
            return temp[0:indexTh(temp, ",", 2) + 1] + str(int(local_temp) + (2**(note - 37))) + temp[indexTh(temp, ",", 3):]
        if(not On):
            return temp[0:indexTh(temp, ",", 2) + 1] + str(int(local_temp) - (2**(note - 37))) + temp[indexTh(temp, ",", 3):]
        
    elif(note >= 45 and note <= 52):
        local_temp = temp[(indexTh(temp, ",", 3) + 1):indexTh(temp, ",", 4)]
        if(On):
            return temp[0:indexTh(temp, ",", 3) + 1] + str(int(local_temp) + (2**(note - 45))) + temp[indexTh(temp, ",", 4):]
        if(not On):
            return temp[0:indexTh(temp, ",", 3) + 1] + str(int(local_temp) - (2**(note - 45))) + temp[indexTh(temp, ",", 4):]
        
    elif(note >= 53 and note <= 60):
        local_temp = temp[(indexTh(temp, ",", 4) + 1):indexTh(temp, ",", 5)]
        if(On):
            return temp[0:indexTh(temp, ",", 4) + 1] + str(int(local_temp) + (2**(note - 53))) + temp[indexTh(temp, ",", 5):]
        if(not On):
            return temp[0:indexTh(temp, ",", 4) + 1] + str(int(local_temp) - (2**(note - 53))) + temp[indexTh(temp, ",", 5):]
        
    elif(note >= 61 and note <= 68):
        local_temp = temp[(indexTh(temp, ",", 5) + 1):indexTh(temp, ",", 6)]
        if(On):
            return temp[0:indexTh(temp, ",", 5) + 1] + str(int(local_temp) + (2**(note - 61))) + temp[indexTh(temp, ",", 6):]
        if(not On):
            return temp[0:indexTh(temp, ",", 5) + 1] + str(int(local_temp) - (2**(note - 61))) + temp[indexTh(temp, ",", 6):]
        
    elif(note >= 69 and note <= 76):
        local_temp = temp[(indexTh(temp, ",", 6) + 1):indexTh(temp, ",", 7)]
        if(On):
            return temp[0:indexTh(temp, ",", 6) + 1] + str(int(local_temp) + (2**(note - 69))) + temp[indexTh(temp, ",", 7):]
        if(not On):
            return temp[0:indexTh(temp, ",", 6) + 1] + str(int(local_temp) - (2**(note - 69))) + temp[indexTh(temp, ",", 7):]
        
    elif(note >= 77 and note <= 84):
        local_temp = temp[(indexTh(temp, ",", 7) + 1):indexTh(temp, ",", 8)]
        if(On):
            return temp[0:indexTh(temp, ",", 7) + 1] + str(int(local_temp) + (2**(note - 77))) + temp[indexTh(temp, ",", 8):]
        if(not On):
            return temp[0:indexTh(temp, ",", 7) + 1] + str(int(local_temp) - (2**(note - 77))) + temp[indexTh(temp, ",", 8):]
        
    elif(note >= 85 and note <= 92):#error here
        local_temp = temp[(indexTh(temp, ",", 8) + 1):indexTh(temp, ",", 9)]
        if(On):
            return temp[0:indexTh(temp, ",", 8) + 1] + str(int(local_temp) + (2**(note - 85))) + temp[indexTh(temp, ",", 9):]
        if(not On):
            return temp[0:indexTh(temp, ",", 8) + 1] + str(int(local_temp) - (2**(note - 85))) + temp[indexTh(temp, ",", 9):]
        
    elif(note >= 93 and note <= 100):
        local_temp = temp[(indexTh(temp, ",", 9) + 1):indexTh(temp, ",", 10)]
        if(On):
            return temp[0:indexTh(temp, ",", 9) + 1] + str(int(local_temp) + (2**(note - 93))) + temp[indexTh(temp, ",", 10):]
        if(not On):
            return temp[0:indexTh(temp, ",", 9) + 1] + str(int(local_temp) - (2**(note - 93))) + temp[indexTh(temp, ",", 10):]
        
    elif(note >= 101 and note <= 108):
        local_temp = temp[(indexTh(temp, ",", 10) + 1):]
        if(On):
            return temp[0:indexTh(temp, ",", 10) + 1] + str(int(local_temp) + (2**(note - 101)))
        if(not On):
            return temp[0:indexTh(temp, ",", 10) + 1] + str(int(local_temp) - (2**(note - 101)))
        

def indexTh(in_string, find_this, th):
    #Takes String, string to find, and order to find string to find at that order
    #returns index
    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):
    #Takes a string and finds time, returns it as an int
    time_end = in_string.index(" ")
    return int(in_string[0:time_end])

def time_finder_comm(in_string):
    #Takes a string and finds time, returns it as an int comma
    time_end = in_string.index(",")
    return int(in_string[0:time_end])
    
def note_finder(in_string):
    #Takes a string, looks for n=, returns n value as an int
    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):
    #takes a string, looks for On or Off, return true if On
    start = in_string.index(" ") + 1
    end = in_string.index("ch=") - 1
    if in_string[start:end] == "On":
        return True
    elif in_string[start:end] == "Off":
        return False

main()

Processing to send data to the arduino

Processing
Reads the translated text file and sends it to the arduino.
Must mod tempo multiplier if tempo is different than 50000.
Reverses bytes because it shifts from left to right. (Text file assumes right to left)
import processing.serial.*;

Serial myPort;
String[] inputLines;


void setup()
{
  myPort = new Serial(this, "COM3", 9600);
  inputLines = loadStrings("translated.txt");
  run();
}

void run()
{
  //reads time and sends data bt line using data method
  int lastTime = 0;
  
  for(int i = 0; i < inputLines.length; i++)
  {
    String temp = inputLines[i];
    
    //*5 is a tempo multiplier. increase the number if tempo is lower.
    delay((Integer.parseInt(temp.substring(0, temp.indexOf(","))) - lastTime) * 5);
    lastTime = Integer.parseInt(temp.substring(0, temp.indexOf(",")));
    send(temp.substring(temp.indexOf(",") + 1));
  }
}

void send(String data)
{
  //String first = data.substring(indexOforder(data, ",", 1), (indexOforder(data, ",", 2) + 1));
  //String second = data.substring(indexOforder(data, ",", 2), (indexOforder(data, ",", 3) + 1));
  //String third = data.substring(indexOforder(data, ",", 3), (indexOforder(data, ",", 4) + 1));
  //String forth = data.substring(indexOforder(data, ",", 4), (indexOforder(data, ",", 5) + 1));
  //String fifth = data.substring(indexOforder(data, ",", 5), (indexOforder(data, ",", 6) + 1));
  //String sixth = data.substring(indexOforder(data, ",", 6), (indexOforder(data, ",", 7) + 1));
  //String seventh = data.substring(indexOforder(data, ",", 7), (indexOforder(data, ",", 8) + 1));
  //String eighth = data.substring(indexOforder(data, ",", 8), (indexOforder(data, ",", 9) + 1));
  //String ninth = data.substring(indexOforder(data, ",", 9), (indexOforder(data, ",", 10) + 1));
  //String tenth = data.substring(indexOforder(data, ",", 10), (indexOforder(data, ",", 11) + 1));
  //String eleventh = data.substring(indexOforder(data, ",", 11), (indexOforder(data, ",", 12) + 1));
  
  //inverse declare
  String eleventh = data.substring( 0 , indexOforder(data, ",", 1));
  String tenth = data.substring((indexOforder(data, ",", 1) + 1), (indexOforder(data, ",", 2)));
  String ninth = data.substring((indexOforder(data, ",", 2) + 1), (indexOforder(data, ",", 3)));
  String eighth = data.substring((indexOforder(data, ",", 3) + 1), (indexOforder(data, ",", 4)));
  String seventh = data.substring((indexOforder(data, ",", 4) + 1), (indexOforder(data, ",", 5)));
  String sixth = data.substring((indexOforder(data, ",", 5) + 1), (indexOforder(data, ",", 6)));
  String fifth = data.substring((indexOforder(data, ",", 6) + 1), (indexOforder(data, ",", 7)));
  String forth = data.substring((indexOforder(data, ",", 7) + 1), (indexOforder(data, ",", 8)));
  String third = data.substring((indexOforder(data, ",", 8) + 1), (indexOforder(data, ",", 9)));
  String second = data.substring((indexOforder(data, ",", 9) + 1), (indexOforder(data, ",", 10)));
  String first = data.substring(indexOforder(data, ",", 10) + 1);
  
  myPort.write("888f");
  myPort.write(first + "f");
  myPort.write(second + "f");
  myPort.write(third + "f");
  myPort.write(forth + "f");
  myPort.write(fifth + "f");
  myPort.write(sixth + "f");
  myPort.write(seventh + "f");
  myPort.write(eighth + "f");
  myPort.write(ninth + "f");
  myPort.write(tenth + "f");
  myPort.write(eleventh + "f");
  myPort.write("999f");
}

int indexOforder(String data, String find, int order)
{
  int currentOrder = 0;
  int lastLocation = 0;
  
  while(currentOrder < order)
  {
    lastLocation = data.indexOf(find, (lastLocation + 1));
    currentOrder += 1;
  }
  
  return lastLocation;
}

Arduino code

Arduino
Simple code for arduino. Takes inputs from Serial. 888 and 999 are reserved for shift register open and close command.
No preview (download only).

Credits

Remy Yoo
3 projects • 7 followers
Random guy building random stuff

Comments