[26호] ICT 융합 공모전 – 레이저모듈과 포토센서를 이용한 레이저하프 악기 제작
레이저모듈과 포토센서를 이용한 레이저하프 악기 제작
글 | 동양미래대학교 박창용, 권용선, 김준범, 이동건, 임지원, 홍동의
1. 작품개요
마이크로프로세서 보드 및 그 밖의 전자부품을 이용하여 기존의 현을 이용한 하프와는 별개로 레이저모듈과 포토센서를 이용하여 실제 현이 없는 하프를 제작하였다. 일상에서 쉽게 접해보지 못하는 악기인 하프를 제작함으로써 보다 다양한 악기를 체험하고자 하였으며 간단한 회로구성만으로 하프의 동작을 구현했다는 점을 볼 때 간단한 전자회로 예제 교육용으로도 사용이 가능할 것으로 본다.
2. 작품설명
동아리 내에서 아두이노 프로그래밍 학습차 MIDI 실드 실습을 하였는데 피아노와 같은 흔히 접해볼 수 있는 악기 말고 독특한 악기를 제작해보는 건 어떨까 고민하던 중, 현을 전자회로로 조작할 수 있는 것을 구상해 보았고, 일상에서 접하기 힘든 하프를 제작해 보기로 결정하였다.
본 레이저하프에는 아두이노 보드를 이용하여 프로그래밍하였다. 하프가 현이 많은 점을 미루어보아 센서를 정밀하게 동작시키기 위해 레이저모듈을 이용하였고, 그에 따른 센서는 포토센서로 하였다. 아두이노 보드에 MIDI실드를 이용하여 하프 음계 외에 다른 종류의 음계 표현이 가능하다.
2.1 주요동작 및 특징
하프의 현을 레이저로 표현했다는 것이 가장 큰 특장점이다. 적외선 발광 다이오드같은 타 발광 다이오드는 빛의 퍼짐 현상이 있어 정확한 조작을 필요로 하는 장비에는 적합하지 않다. 따라서 빛의 퍼짐현상이 적은 레이저 모듈을 이용하여 작품을 제작하였다. 이는 사용자가 악기를 다루는데 보다 정확하게 동작시킬 수 있게 도움을 준다.
2.2 전체 시스템 구성
2.2.1 구성 재료
아두이노 Mega 2560, MIDI Shield(VS1053b), 파워서플라이(UP15S05L, 입력: 100-240V, 출력: DC5V 3A), 외부스피커, 5V 레이저 모듈(40mA, 규격 17.3mm * 6mm), 포토트랜지스터 수광부(ST-1KLA), 시멘트저항 4.7Ω 10W, 탄소피막저항 4.7kΩ, 택트스위치
2.2.2 주요 부품 사진
2.2.3 알고리즘도
2.3 개발환경
Arduino의 Processing 언어 및 Arduino IDE Tool을 사용하였다. Processing 언어는 초보자도 쉽게 이해할 수 있는 장점이 있다. 다음은 레이저하프 프로그래밍을 하기위해 참고한 아두이노의 기본 예제이다.
void setup() {
Serial,begin(9600);
}
void loop() {
int sensorValue = analogRead(AO);
float voltage = sensorValue;
Serial.println(Voltage);
delay(200);
}
3. 단계별 제작과정
3.1 스피커를 제어하는 기본 레이저모듈 회로
PHOTO TR의 Collector 단자에 5V, Emitter 단자에 GND를 연결한 뒤 Base에 빛을 가해주면 Collector와 Emitter 사이에 전류가 흐르게 된다. 이를 이용하여 Emitter와 GND 사이에 높은 수치의 저항(여기선 4.7kΩ을 사용하였다.)을 연결하면 트랜지스터에 전류가 흐를 시 이 저항에 거의 모든 전압이 걸리기 때문에 저항에 DIGITAL IN 핀을 연결하여 사용하였다.
레이저 값을 받으면 DIGITAL IN 단자에 5V, 레이저 값을 받지 못하면(손으로 레이저를 가리면) DIGITAL IN 단자에 0V가 입력되어 이를 디지털 제어용으로 활용할 수 있었다.
5V 3A의 전원이 병렬 레이저 모듈과 센서 회로에 나뉘어 들어가기 때문에 실제 전류는 약 절반인 1.5A가 센서 회로에 공급하기로 설계하였으나 트랜지스터의 라이트 정격 전류가 최대 16mA인 것을 감안하여 실제로는 아두이노 내의 5V 및 GND 단자를 이용하여 센서의 전원을 공급하였다.
3.2 하드웨어 제작
테스트용으로 제작하였기 때문에 나무 등 튼튼한 재료로 제작하지는 않았다. 저렴하고 간단하게 테스트할 수 있도록 우드락을 겹겹이 붙여서 하프의 기본 틀을 제작하였다. 우드락의 재질이 튼튼하지만 나무처럼 단단하지 않아서 조금이라도 휘는 경우 레이저 길이 틀어져서 오류를 일으키는 점이 발생했던 것을 보아 다음 제작시에는 나무 등 우드락보다 더욱 튼튼한 재료를 사용할 생각이다.
3.3 아두이노 회로 연결
본 레이저하프에는 34개의 현을 구현하기 위한 34개의 센서 및 34개의 레이저 말고도 3개의 스위치를 추가하였다. 첫 번째 스위치는 MIDI 실드의 악기 종류 초기화 버튼, 두 번째 스위치는 악기 종류 위로 변경 버튼, 세 번째 스위치는 악기 종류 아래로 변경 버튼이다. MIDI Shield에서는 128가지의 악기를 사용할 수 있어 이를 이용하고자 하였다. 따라서 본 레이저하프에서 이 스위치를 이용하여 하프음 말고도 피아노 음 같은 여러 가지 음을 표현할 수 있다.
3.4 문제점
3.4.1 프로토타입의 사이즈 문제
이번에 제작한 테스트용 레이저하프는 사이즈가 작기 때문에 아두이노 기판을 포함한 브레드보드 및 기타 회로를 내부로 넣지 못하여 외관상 보기 좋지 않았다. 따라서 다음에 제작할 레이저하프에는 이를 고려할 생각이다.
3.4.2 하프 음계의 반음 표현
본 레이저하프는 반음을 프로그래밍하지 않고 기본음만 34가지 음을 프로그래밍하였다. 하지만 실제 하프에서는 페달을 이용하여 반음을 표현할 수 있는데, 이를 다른 스위치를 이용하여 반음을 소리낼 수 있는 프로그래밍을 제작 중에 있다. 이의 프로그램이 추가되면 실제 하프와 거의 흡사한 구동을 할 수 있을 것이라 생각한다.
3.4.2 하프의 음의 크기
본 레이저하프는 음의 크기가 제어되지 않는다. 따라서 이중 현을 프로그래밍하여 속도를 계산하여 음의 크기를 조절하는 프로그램도 모색중에 있다.
4. 기타
다음은 본 레이저하프에 프로그래밍된 소스코드이다.
#include <SoftwareSerial.h>
#define senU 5 // upper instruments select sensor
#define senD 6 // down instruments select sensor
#define senA 7 // initialize sensor
// ——————————
#define sen1 8 // 34
#define sen2 9 // 33
……(생략)
#define sen34 53 // 1
SoftwareSerial mySerial(2, 3); // (RX, TX)
#define defaultPatch 46 //악기 초기화 버튼 설정 악기번호
byte note = 0;
byte resetMIDI = 4;
byte byteData;
int patch = 0; //악기 대응, 연주될 악기 종류 (0~127: 기본 128 가지 선택가능)
int bn1 = 60; // “1do”
int bn2 = 62; // “ray”
……(생략)
int bn34 = 117;
int value1;
int value2;
……(생략)
int value34;
int valueU;
int valueD;
int valueA;
boolean bs1 = false;
boolean bs2 = false;
……(생략)
boolean bs34 = false;
boolean bsU = false;
boolean bsD = false;
boolean bsA = false;
void setup() {
pinMode(sen1, INPUT);
digitalWrite(sen1, HIGH);
pinMode(sen2, INPUT);
digitalWrite(sen2, HIGH);
……(생략)
pinMode(sen34, INPUT);
digitalWrite(sen34, HIGH);
pinMode(senU, INPUT);
digitalWrite(senU, HIGH);
pinMode(senD, INPUT);
digitalWrite(senD, HIGH);
pinMode(senA, INPUT);
digitalWrite(senA, HIGH);
Serial.begin(31250); // bit per sec
mySerial.begin(31250);
//Reset the VS1053
pinMode(resetMIDI, OUTPUT);
digitalWrite(resetMIDI, LOW);
delay(100);
digitalWrite(resetMIDI, HIGH);
delay(100);
patch = defaultPatch;
talkMIDI(0xb0, 0, 0);
talkMIDI(0xb0,20, 0);
talkMIDI(0xc0, patch, 0);
}
void loop() {
value1 = digitalRead(sen1);
value2 = digitalRead(sen2);
……(생략)
value34 = digitalRead(sen34);
valueU = digitalRead(senU);
valueD = digitalRead(senD);
valueA = digitalRead(senA);
if( !bs1 && !value1 ) {
noteOn(0, bn1, 100);
bs1 = true;
}
else if( bs1 && value1 ) {
noteOff(0, bn1, 0);
bs1 = false;
}
if( !bs2 && !value2 ) {
noteOn(0, bn2, 100);
bs2 = true;
}
else if( bs2 && value2 ) {
noteOff(0, bn2, 0);
bs2 = false;
……(생략)
if( !bs34 && !value34 ) {
noteOn(0, bn34, 100);
bs34 = true;
}
else if( bs34 && value34 ) {
noteOff(0, bn34, 0);
bs34 = false;
}
if( !bsD && !valueD ) {
patch–;
if( patch < 0 ) patch = 127;
talkMIDI(0xc0, patch, 0);
bsD = true;
}
else if( bsD && valueD ) {
bsD = false;
}
if( !bsU && !valueU ) {
patch++;
if( patch > 127 ) patch = 0;
talkMIDI(0xc0, patch, 0);
bsU = true;
}
else if( bsU && valueU ) {
bsU = false;
}
if( !bsA && !valueA ) {
patch = defaultPatch;
talkMIDI(0xb0, 0, 0);
talkMIDI(0xb0,20, 0);
talkMIDI(0xc0, patch, 0);
bsA = true;
}
else if( bsA && valueA ) {
bsA = false;
}
if(Serial.available() > 0)
{
byteData = Serial.read();
Serial.write(byteData);
}
}
void noteOn(byte channel, byte note, byte attack_velocity) {
talkMIDI( (0×90 | channel), note, attack_velocity);
}
void noteOff(byte channel, byte note, byte release_velocity) {
talkMIDI( (0×80 | channel), note, release_velocity);
}
void talkMIDI(byte cmd, byte data1, byte data2) {
mySerial.write(cmd );
mySerial.write(data1 );
if( (cmd & 0xF0) <= 0xB0)
mySerial.write(data2 );
}