산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

Arduino 제어 피아노 로봇:PiBot

구성품 및 소모품

아두이노 101
× 1
Texas Instruments 74HC595
× 11
IRFZ44N
N-채널 MOSFET
× 88
12V 배터리
× 2
커패시터 100μF
× 11
OpenBuilds 유선 케이블 - 도보
많습니다.
× 1
브레드보드(일반)
또는 일반 프로토타입 보드. 모든 것을 하나로 묶을 수 있는 모든 것.
× 11
8 다리 IC 소켓
이 비싼 595개를 태우지 않을 것이라고 확신하는 경우 선택 사항
× 11
저항 10k 옴
이 프로젝트에는 사용되지 않지만 각 MOSFET에 대해 사용하는 것이 좋습니다.
× 88
1N4007 – 고전압, 고전류 정격 다이오드
이 프로젝트에는 사용되지 않지만 각 MOSFET에 대해 사용하는 것이 좋습니다.
× 88

필요한 도구 및 기계

뜨거운 글루건(일반)

앱 및 온라인 서비스

처리
파이썬
이진 MIDI 파일을 텍스트로

이 프로젝트 정보

시작 방법:

몇 년 전 Yamaha는 자동 피아노를 도입했습니다. 어리고 순진한 나는 악기 가게 유리창 뒤에서 피아노가 연주하는 것을 보았습니다.

잡담은 그만하고, 정말 하고 싶었던 것 외에는 이 프로젝트를 시작한 큰 이유가 없습니다.

개요:

Arduino Mega의 단일 보드는 약 $40이며 88개의 솔레노이드를 제어하려면 2개가 필요합니다. 그것은 꽤 비싸다. 대신 저렴한 Arduino Uno와 11개의 시프트 레지스터를 구입하십시오. 시프트 레지스터는 적은 수의 출력 핀으로 많은 출력(보통 LED)을 제어하는 ​​방법입니다. 기본적으로 11개의 시프트 레지스터와 88개의 솔레노이드를 제어하는 ​​하나의 Arduino입니다.

시프트 레지스터를 사용하기 때문에 PC는 MIDI com 대신 Arduino에 비트 세트를 보냅니다. MIDI 파일은 미리 비트 세트로 변환됩니다.

하드웨어:

중국에서 직접 솔레노이드를 받았을 때 이 솔레노이드가 피아노 건반을 누르기에 충분히 강하지 않다는 것을 알았습니다. 물론 가장 안쪽에서 피아노 건반을 누르는 것이 더 힘이 들지만 피아노를 망가뜨리지 않는 최선의 방법이라고 생각했습니다. 결국 충분한 전력을 얻기 위해 12V 솔레노이드를 통해 24V를 밀어 넣었습니다.

88 솔레노이드는 전력을 많이 소모하고 비싼 PSU를 사러 갈 수 없어서 아버지의 자동차 배터리로 가기로 결정했습니다. (그는 이제 아무데도 가지 않을 것입니다!)

그렇게 하면 시프트 레지스터와 MOSFET 각각이 컨트롤러 보드에 들어갈 것입니다.

595 오른쪽에 소켓이 있어 태울 수 있습니다. (한 번 했습니다.) Circuit Diagram은 여기에서 예제 2와 정확히 동일합니다. LED를 MOSFET 게이트로 교체하십시오. 보시다시피 추가 저항으로 인해 비용이 증가하고 해당 보드에 납땜하면 손가락이 녹기 때문에 풀다운 저항이 없습니다. 좀 더 심각한 측면에서 이러한 MOSFET은 5V에서 열리고 4V 정도에서 닫힙니다. 수많은 테스트를 통해 확인했습니다. (이론적으로 정확하지 않습니다. 내 말을 듣지 마십시오.)

마지막으로 솔레노이드를 붙일 플라스틱 판을 얻습니다. 뜨거운 접착제와 플라스틱 판을 사용하는 것은 뜨거워질 수 있다는 점을 생각하면 좋지 않지만 제가 감당할 수 있는 최선입니다.

그런 다음 솔레노이드 전선의 한쪽을 배터리의 양극에 연결합니다.

소프트웨어:

가장 첫 번째 단계는 미디 파일을 얻는 것입니다.

두 번째 단계는 미디를 텍스트 형식으로 가져오는 것입니다. 이것은 이 편리한 웹사이트에서 할 수 있습니다:http://flashmusicgames.com/midi/mid2txt.php.

간단하게 하기 위해 박자표, 템포 및 파를 무시합니다. 템포는 나중에 시간을 곱할 수 있습니다. 기본적으로 다음과 같은 파일이 필요합니다.

이제 이를 파이썬 코드(첨부)를 통해 실행하여 시간에 따른 8비트 데이터 11세트를 생성합니다.

COM 처리를 통해 Arduino로 보낼 준비가 되었습니다.

처리 과정에서 이러한 데이터를 보내는 방법과 Arduino가 데이터를 처리하는 방법을 알아보려면 첨부 파일을 참조하세요.

*참고:제 코딩 습관이 좋지 않아 읽기 어려울 수 있습니다. Arduino가 실제 피아노에서 데이터를 오른쪽으로 밀어넣기 때문에 프로세싱은 데이터를 오른쪽에서 왼쪽으로 보냅니다.

작동하는 작업:

문제 해결:

전문 엔지니어가 이 글을 본다면 이 전체 시스템에 많은 문제가 있을 것이라고 생각할 것입니다. 그리고 많은 문제가 있습니다.

솔레노이드가 플레이트에 핫 글루로 접착되기 때문에 솔레노이드가 과열되어 핫 글루가 녹는 것이 큰 문제였습니다. 해결책은 단순히 그것들을 제거하고 150C까지 견딜 수 있는 양면 테이프로 교체하는 것이었습니다.

<섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">

코드

<울>
  • 번역용 Python 코드
  • arduino로 데이터를 보내기 위한 처리
  • Arduino 코드
  • 번역을 위한 Python 코드Python
    텍스트화된 mifi 파일을 가져와서 arduino가 사용할 수 있도록 11개의 바이너리 세트로 변환합니다.
    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():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):# 켜져 있는지 여부와 메모 번호에 대한 부울 값을 취합니다. # 비트 생성 if(note>=21 and note <=28 and On):return str(2**(note - 21)) + ",0,0,0,0,0,0,0,0,0 ,0" elif(참고>=29 및 참고 <=36 및 켜짐):반환 "0," + str(2**(주 - 29)) + ",0,0,0,0,0,0, 0,0,0" elif(참고>=37 및 참고 <=44 및 켜기):반환 "0,0," + str(2**(참고 - 37)) + ",0,0,0,0 ,0,0,0,0" elif(참고>=45 및 참고 <=52 및 켜짐):"0,0,0," + str(2**(주 - 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(참고>=61 및 참고 <=68 및 켜짐):return "0,0,0,0,0," + str(2**( 참고 - 61)) + ",0,0,0,0,0" elif(참고>=69 및 참고 <=76 및 켜기):반환 "0,0,0,0,0,0," + str (2**(참고 - 69)) + ",0,0,0,0" elif(참고>=77 및 참고 <=84 및 켜기):"0,0,0,0,0,0, 0," + str(2**(참고 - 77)) + ",0,0,0" elif(참고>=85 및 참고 <=92 및 켜짐):"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**(참고 - 93)) + ",0" elif(참고>=101 및 참고 <=108 및 켜짐):"0,0,0,0,0,0,0,0,0,0,"을 반환합니다. + str(2**(참고 - 101)) else:"0,0을 반환합니다. ,0,0,0,0,0,0,0,0,0"def set_bit_prev(On, note, index):#set_bit와 같지만 이전 인식 temp =result[index] temp =temp[(temp.find (",") + 1):] if(참고>=21 및 참고 <=28):local_temp =temp[0:temp.find(",")] if(On):return str(int(local_temp) + (2**(주 - 21)) + temp[temp.find(","):] if(not On):반환 str(int(local_temp) - (2**(주 - 21))) + temp[temp.find(","):] elif(참고>=29 및 참고 <=36):local_temp =temp[(temp.find(",") + 1):indexTh(temp, "," , 2)] if(On):반환 temp[0:temp.find(",") + 1] + str(int(local_temp) + (2**(참고 - 29))) + temp[indexTh(temp , ",", 2):] if(on이 아님):반환 temp[0:temp.find(",") + 1] + str(int(local_temp) - (2**(참고 - 29))) + temp[indexTh(temp, ",", 2):] elif(참고>=37 및 참고 <=44):local_temp =temp[(indexTh(temp, ",", 2) + 1):indexTh(temp , ",", 3)] if(On):반환 temp[0:indexTh(temp, ",", 2) + 1] + str(int(local_temp) + (2**(참고 - 37))) + 온도[in dexTh(temp, ",", 3):] if(not On):return temp[0:indexTh(temp, ",", 2) + 1] + str(int(local_temp) - (2**(참고) - 37))) + temp[indexTh(temp, ",", 3):] elif(참고>=45 및 참고 <=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**(참고) - 45))) + temp[indexTh(temp, ",", 4):] if(not On):return temp[0:indexTh(temp, ",", 3) + 1] + str(int(local_temp) ) - (2**(참고 - 45))) + temp[indexTh(temp, ",", 4):] elif(참고>=53 및 참고 <=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**(참고 - 53))) + temp[indexTh(temp, ",", 5):] if(not On):반환 temp[0:indexTh(temp, ",", 4) + 1] + str(int(local_temp) - (2**(참고 - 53)) + temp[indexTh(temp, ",", 5):] elif(참고>=61 및 참고 <=68):local_temp =temp[(indexTh(temp, ",", 5) + 1):indexTh(temp, ",", 6)] if(On):반환 temp[0:indexTh(temp, ",", 5) + 1 ] + str(int(local_temp) + (2**(참고 - 61)) + temp[indexTh(temp, ",", 6):] if(not On):temp[0:indexTh(temp, ",", 5) + 1] + str(int(local_temp) - (2**(참고 - 61)) + temp[indexTh(temp, ",", 6):] elif(참고>=69 및 참고 <=76):local_temp =temp[(indexTh(temp, ",", 6) + 1):indexTh(temp, ",", 7)] if(On):반환 temp[0:indexTh(temp, ",", 6) + 1] + str(int(local_temp) + (2**(참고 - 69)) + temp[indexTh(temp, ",", 7):] if(not On):반환 temp[0:indexTh(temp, ",", 6) + 1] + str(int(local_temp) - (2**(참고 - 69))) + temp[indexTh(temp, ",", 7):] elif(참고>=77 및 참고 <=84):local_temp =temp[(indexTh(temp, ",", 7) + 1):indexTh(temp, ",", 8)] if(On):반환 temp[0:indexTh(temp, ",", 7) + 1] + str(int(local_temp) + (2**(참고 - 77))) + temp[indexTh(temp, ",", 8):] if(not On):return temp[0:indexTh(temp, ",", 7) + 1] + str(int(local_temp) - (2**(참고 - 77))) + temp[indexTh(temp , ",", 8):] elif(참고>=85 및 참고 <=92):#error here local_temp =temp[(indexTh(temp, ",", 8) + 1):indexT h(temp, ",", 9)] if(On):return temp[0:indexTh(temp, ",", 8) + 1] + str(int(local_temp) + (2**(참고 - 85) ))) + temp[indexTh(temp, ",", 9):] if(not On):return temp[0:indexTh(temp, ",", 8) + 1] + str(int(local_temp) - (2**(참고 - 85))) + temp[indexTh(temp, ",", 9):] elif(참고>=93 및 참고 <=100):local_temp =temp[(indexTh(temp, ", ", 9) + 1):indexTh(temp, ",", 10)] if(On):반환 temp[0:indexTh(temp, ",", 9) + 1] + str(int(local_temp) + (2**(참고 - 93))) + temp[indexTh(temp, ",", 10):] if(not On):return temp[0:indexTh(temp, ",", 9) + 1] + str(int(local_temp) - (2**(참고 - 93))) + temp[indexTh(temp, ",", 10):] elif(참고>=101 및 참고 <=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):# 문자열, 찾을 문자열, 찾을 문자열을 찾는 순서를 취합니다. 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 + 1def time_finder(in_string):#문자열을 가져와서 시간을 찾아 int로 반환 time_end =in_string.index(" ") return int(in_string[0:time_end])def time_finder_comm(in_string):# 문자열을 가져와서 시간을 찾아 int 쉼표로 반환 time_end =in_string.index(",") return int(in_string[0:time_end]) def note_finder(in_string):#문자열을 가져와서 n=을 찾습니다. n 값을 int로 반환 num_start =in_string.index("n=") + 2 num_end =in_string.index("v=") - 1 반환 int(in_string[num_start:num_end])def on_off_finder(in_string):#takes 문자열은 On 또는 Off를 찾고 On start =in_string.index(" ") + 1 end =in_string.index("ch=") - in_string[start:end] =="On"이면 1이면 true를 반환합니다. return True elif in_string[start:end] =="Off":Falsemain()을 반환
    arduino로 데이터를 보내기 위한 처리처리
    번역된 텍스트 파일을 읽어서 arduino로 보냅니다.
    템포가 50000과 다른 경우 템포 승수를 수정해야 합니다.
    왼쪽에서 오른쪽으로 이동하기 때문에 바이트를 뒤집습니다. (텍스트 파일은 오른쪽에서 왼쪽으로 가정)
    import processing.serial.*;Serial myPort;String[] inputLines;void setup(){ myPort =new Serial(this, "COM3", 9600); inputLines =loadStrings("translated.txt"); run();}void run(){ // 시간을 읽고 데이터 메소드를 사용하여 데이터 bt 라인을 보냅니다. int lastTime =0; for(int i =0; i  
    Arduino 코드Arduino
    아두이노를 위한 간단한 코드. 직렬에서 입력을 가져옵니다. 888 및 999는 시프트 레지스터 열기 및 닫기 명령용으로 예약되어 있습니다.
    미리 보기 없음(다운로드 전용).

    회로도

    전문적이지 않은 그림을 그려서 죄송합니다. 이것이 전체 개념입니다. 아두이노 -ShiftOut 문서의 다이어그램은 MOSFET을 제외하고는 차이가 없습니다. 그것도 보시는 걸 추천합니다.

    제조공정

    1. Bluetooth를 통해 제어되는 Raspberry Pi Robot
    2. Arduino 및 Raspberry Pi로 인터넷 제어 비디오 스트리밍 로봇 구축
    3. 라즈베리 파이를 사용하는 Wi-Fi 제어 로봇
    4. Raspberry Pi를 통한 Alexa 제어 LED
    5. 아이언맨
    6. 나를 찾기
    7. Arduino 가습기 제어
    8. 음성 제어 로봇
    9. MobBob:Android 스마트폰으로 제어되는 DIY Arduino 로봇
    10. Arduino 조이스틱