Brise

Jimi handless : 무인 기타 연주기 본문

Linux

Jimi handless : 무인 기타 연주기

naudhizb 2014. 9. 20. 12:56
반응형


사람의 손으로 하지 않고


기계로만 악기를 연주 할 수 있을까?


하는 마음에서 시작하여


세컨드 기타의 역할을 충분히 담당할 수 있을 만한 기타를 만들어보고 싶어


만들게 되었다.


간단한 아이디어 스케치(http://naudhizb.tistory.com/323)를 통해 
구현하는 것을 분석한 결과

무인 기타 연주기를 만들기 위해 해결해야하는 문제가 2가지가 있었다.


- 어떻게 박자에 맞게 작동시키는가.

- 실제로 작동을 어떻게 시키는가.



전자의 경우에는 리눅스에서 있는 타이머를 활용하였고,


후자의 경우에는 GPIO를 빠른 시간에 기동하고 

pwm도 하드웨어적으로 구현가능한 

아두이노를 사용하기로 하였다.

(다만, 통신의 문제때문에 3.3v IO를 가지는 아두이노 듀에를 사용하였다.)



전체적인 구조 스케치는 다음과 같다.


라즈베리파이에서는 악보를 분석하여 timer 작동주기마다 아두이노로 작동 데이터를 보내게 된다.


아두이노는 받은 데이터를 분석하여 실제로 작동하게 된다.





라즈베리 파이에서 이 프로젝트에서는

6,8,10번핀만 사용한다. 모든 액추에이팅 부분은 아두이노에서 처리한다.



<회로, 구동부>


위의 그림은 실제 결선이 어떠한 방식으로 될지 스케치한 그림이다.


7.4v 배터리를 직접 솔레노이드에 연결하고 MOSFET으로 제어를 하게 된다.


(3.3v로 구동시킬 수 있는 MOSFET을 찾아야 한다 데이터 시트를 참고할 것,

필자의 경우 몇번의 실수 끝에 IRL540 을 찾아 사용했다.)


제어 신호는 아두이노로부터 받으며 솔레노이드는 총 6*3 = 18개가 된다.


(NMOS의 경우 +단이 아닌 -단에 붙어서 작동한다.

+   ---> 솔레노이드 ---> MOSFET ----> -  

와 같이 이어진다.)


제어신호의 float을 방지하기 위해 GND와 연결한 Pulldown register를 장착하였다.

(실제 회로에서는 4.7k 저항)



위 그림은 위에서 언급한 것들을 실제로 구현한 회로이다. 


회로가 만들어 졌다면 이제 실제 구동하는 부분을 제작할 차례이다.





코드를 누르는 부분은 솔레노이드로 만들었다. 

푸쉬형 솔레노이드로 리턴 스프링과 C-링을 대체하여 마개(노란색)을 제작하여 붙이고 

연장 로드(회색 포맥스)를 401록타이트를 이용하여 붙였다.


솔레노이드가 가하는 힘이 강하지 않기 때문에 Deformation의 우려가 적고

공간이 협소하겨 제대로 된 마운트를 제작하기 힘들기 때문에

강력 양면테이프를 이용하여 솔레노이드를 부착하였다. 





서보모터의 경우 결선을

+ 는 레귤레이터에서나오는 5v전원을

- 는 그라운드

Signal은 아두이노의 PWM포트에 연결하였다.


아두이노의 기본 pwm은 490Hz 에서 1000Hz이고 아날로그 서보의 PWM주기는 50Hz이므로

50Hz의 PWM을 생성해주는 서보 라이브러리를 사용하였다.



스트로크 부분 제작(프로토타입)

서보모터와 포맥스, 피크를 이용하여

줄을 튕길 수 있게 만들었다.


서보모터를 낮게 달면 줄을 튕기면서 생기는 반동때문에

6줄이 제대로 안쳐지는 경우가 많아 위와 같이 만들었다.



스트로크 부분 제작(보완)

프로토타입에서는 다운스트로크나 업스트로크가 2번 연속해서 나왔을 때에

제대로 연주가 불가능했다.

때문에 피크를 줄에서 뗄수 있는 서보모터를 하나 더 장착하여 작동시키고

연장로드를 약하게( 포맥스->플라스틱) 하여 잘 작동시키게 하였다.



기타를 연주할 때 

>솔레노이드의 작동때문에

> 스트로크 때문에


기타의 소리를 죽이는 뮤트부분의 개발이 필요했고, 

서보모터와 포맥스, 스펀지(검은색)을 이용하여 그 부분을 만들었다.







<라즈베리파이>



라즈베리파이 부분의 코드는 위와 같다.



라즈베리파이에서 하는 역할은 위의 그림을 다시 상기시켜보면

1. 음악을 가지고 와서 저장

2. 음악의 속도에 맞는 속도로 타이머 생성

3. 각각의 코드에 맞는 시그널 생성, 전송이다.






위의 과정을 자세히 풀어서 생각하면 필요한 것들이 생겨난다.


1. 음악을 가지고 와서 저장

파일 Open 텍스트값 Read, Code저장

파일 Close

( 파일 입출력은 시스템콜을 사용하기 때문에 속도가 더뎌 메모리상에 변수를 저장해 놓는다.)


2. 음악의 속도에 맞는 속도로 타이머 생성

BPM 입력받음( 아규먼트로)

BPM의 단위( Beat / min)을 ( second / Beat)로 변환

위의 시간에 맞는 타이머를 생성


3. 각각의 코드에 맞는 시그널 생성, 전송이다.

시리얼 통신 채널 생성

코드를 바이너리 형태로 변환


위의 내용이 라즈베리파이 코드 내에 구현되어 있다.


물론 개발 단계 자체가 폭포수 개발이라 코드가 깔끔하지 않고 너저분한 점이 있지만,

코드 내용 자체가 어렵지 않으므로 충분히 이해 할 수 있을 것이라 생각한다.








*아마 가장 이해하기 힘든 부분이 아두이노로 보내는 바이너리 코드 부분일 것이라 생각해서

추가 설명을 달아둔다.



입력 받는 텍스트의 경우

C E Em F G G C.... 

와 같은 포맷으로 입력 된다.


그 포맷을 띄어쓰기 단위로 저장하여(3바이트 배열) 값을 strcmp로 적절한 값에 매칭하여 숫자로 저장한다.


각 코드는 각 노드에 따라 3바이트로 저장되고 이 코드는 코드가 변할 때마다 날아가게 된다.





그리고 바이트의 순서에 따른 문제를 회피하고자 각 바이트는 독립적인 명령을 가진다.

전송되는 바이트의 구조는 다음과 같다.



상위비트 2개는 이 제어코드가 코드를 제어할 것인지 스트로크를 제어할 것인지를 알려준다.

예를 들어


0b 01 010101 이라면

2번 노드의 1번줄, 3번줄, 5번줄을 누르고, 2,4,6번 줄을 떼라는 명령이 된다.




스트로크의 경우 조금 다르게 되는데


3가지의 기능을 구현한다. Mute기능과 stroke on/off stroke up/down이다.


사실 6비트가 아닌 3비트로도 구현이 가능하지만, 가시적으로 잘 보기 위해서 위와 같이 코딩했다.


예를 들어서


0b11 10 01 10 이라면

뮤트 off

스트로크 on

스트로크 up 이 된다.






코드 평가 

많은 사람들이 간과하는 것중 하나는

리눅스란 운영체제는 잘 돌아가는 것처럼 느껴지지만

실시간성이 전혀 보장되지 않는다는 것이다.


(OS가 없는 아두이노에서는 타이머를 만들면 그 시간에 거의 맞춰서 일어날 수밖에 없지만

라즈베리파이에서는 그렇지 않다. 같은 시간에 일어날 수도 있다.)


때문에 커널의 변경이 없는 한도에서 최대한 퍼포먼스를 높이기 위해 SCHED FIFO를 사용했다.

물론 이 기능을 제대로 쓰기 위해서는 시스템콜(printf)를 모두 없애야 한다.


프로그램에서 타이머의 편차에 영향을 끼치는 요소는 다음과 같다.

- OS의 스케줄링 방식에 의해 실제 일어나는 시간이 달라짐

- 일어나는 시간 편차 + 계산시간 편차 + 시리얼 전송시간 편차가 라즈베리파이 부분에서 생성

- 아두이노는 풀링 방식으로 받고 있고, 풀링하는 시간동안의 편차 발생

- 액추에이터 변경함수를 콜하고 실제 구동하는 데까지 생기는 편차


이 오차들을 모두 합했을 때에 아래 오실로스코프를 확인해보았을 때(printf를 넣으면 매우 오차가 커진다. 시스템콜이 시간이 많이 들어서...) 0.02ms = 20us 정도를 가진다.



sched_fifo on


sched fifo off


주기 시간의 편차가 약간 줄어들었음을 알 수 있다.


만약 더 실시간성이 중요한 프로젝트를 진행한다면 Xenomai를 설치(http://naudhizb.tistory.com/280)하고

제노마이 API를 이용해 코딩한다면 매우 정확한 시간과 execution time을 얻을 수 있다.


실제 연주 결과는 다음과 같다.










< 아두이노 >


아두이노는 위에서 언급한 제어 코드를 받아 풀링 방식으로 무한루프를 돌면서 제어를 하게 된다.

코드는 다음과 같다.





아두이노는 코드자체가 어렵지 않고 이해하기 쉽기 때문에 따로 설명할 필요는 없을 듯 하다.


참고로 서보를 사용하기 위해 50Hz의 PWM을 만들어내는 서보 라이브러리를 사용하였다.


사실 아두이노의 레지스터 맵까지 사용하면 라즈베리파이에서 사용 하는 것보다 훨씬 정확한 타이머를 만들 수 있지만, 개발시간의 제약으로 그렇게 하지 못한점이 아쉬웠다.


회로적 지식이 더 있다면(mux를 이용한 IO확장) 더욱 재밋는 프로젝트를 진행할 수 있을 것이라고 생각한다.








개선할 수 있는 점

- RTOS커널을 이용한 실시간성 향상 / 아두이노 코드 개발을 통한 실시간성 향상

- 버퍼나 멀티플렉서를 이용한 코드 부분 IO연장

- 솔레노이드 이외의 액추에이터 구성



Reference


Reference.hwp


raspberryPi_B.pdf


irl540npbf.pdf


MCSMO-0630S06STD.pdf







Thanks to

Team 깽판

조건희

김의태

이영섭














반응형
Comments