코코아팹은 누구나 창의적 아이디어를 현실로 만들어 낼 수 있도록
만들고, 공유하고, 배울 수 있는 터전이
되고자 합니다.
아이디와 비밀번호를 잊으셨나요?아이디 / 비밀번호 찾기
코코아팹 회원이 아니신가요? 회원가입
2014-08-14 15:37:29
아두이노의 활용성은 무궁무진 합니다.
그중에서 게임을 좋아하는 사람들은 누구나 알만한 wii 전용 컨트롤러인
눈차크(nunchuck)가 아두이노와 만나 어떤 일들을 할 수 있는지 살펴보겠습니다.
위와 같은 자이로센서를 발견할수 있습니다.
자이로 센서는 기본적으로 회전하는 물체의 역학운동을 이용해 위치 측정과 방향 설정등에 사용됩니다.
각각 x축 ,y축, z축 3개의 축의 센서값을 읽을 수 있어 다양하게 응용이 가능합니다.
그럼 눈차크와 아두이노의 연결방법을 알아보고 프로세싱 상에서 간단한 예제를 실습해 보겠습니다.
NO | 부품명 | 수량 | 상세설명 |
1 | 오렌지 보드 | 1 | 아두이노 호환보드 |
2 | 브레드보드 | 1 | 브레드보드 |
3 | 눈차크 | 1 | 저항 |
4 | 눈차크 어댑터 | 1 | 점퍼 케이블 |
부품명 | 오렌지 보드 | 브레드보드 | 눈차크 | 눈차크 어댑터 |
파트 | x1 | x1 | x1 | x1 |
위와 같은 눈척 전용 어댑터를 이용하시면 편리하게 아두이노와 연결할 수 있습니다.
아래의 코드를 아두이노에 업로드 합니다.
/*출처 : 아두이노 쿡북
최종수정 : www.kocoafab.cc */
#include <Wire.h> // Wire 라이브러리를 초기화 합니다.
const int vccPin = A3;// 아날로그 3 핀이 눈차크의 전원을 제공합니다.
const int gndPin = A2;// 아날로그 2 핀이 그라운드 를 제공합니다.
const int dataLength =6;// 요청할 데이터의 길이(바이트의 수)를 정합니다.
static byte rawData[dataLength];// 눈차크 데이터를 저장할 배열을 설정합니다.
enum nunchuckItems { joyX,joyY,accelX,accelY,accelZ,btnZ,btnC};
// 각각 조이스틱 x축, 조이스틱 y축, 가속도 y, 가속도 z , 버튼 z , 버튼 c 를 배열합니다.
void setup(){ //전원핀의 초기상태를 안정화 하기 위해 아래의 설정을 합니다.
pinMode(gndPin, OUTPUT);//그라운드핀을 출력으로 설정합니다
pinMode(vccPin, OUTPUT);// 전원핀을 출력으로 설정합니다.
digitalWrite(gndPin,LOW);//그라운드 핀을 low상태로 설정합니다.
digitalWrite(vccPin,HIGH);// 전원핀을 high상태로 설정합니다.
delay(100);//100밀리 초동안 대기합니다.
Serial.begin(9600); //시리얼 통신을 준비합니다.
nunchuckInit();// 눈차크와의 I2C 통신을 설정합니다.
}
void loop(){
nunchuckRead();
int acceleration = getValue(accelX);
if((acceleration >= 75) && (acceleration <= 185))
{
byte x =map(acceleration, 75,185,0,63);
//map함수는 75부터 185 사이의 값에 대해 0부터 63 사이의 값을 반환 합니다.
Serial.write(x);
}
delay(20);
}
void nunchuckInit(){
Wire.begin(); //i2c 버스에 연결합니다.
Wire.beginTransmission(0x52);// 0x52로 전송합니다.
Wire.write((byte)0x40);//메모리 주소를 전송합니다.
Wire.write((byte)0x00);//0을 전송합니다.
Wire.endTransmission();//전송종료
}
static void nunchuckRequest(){ // 눈차크에게 데이터를 요청합니다.
Wire.beginTransmission(0x52);//0x52로 전송합니다.
Wire.write((byte)0x00);//1을 전송합니다.
Wire.endTransmission();//전송종료
}
boolean nunchuckRead(){//눈차크로부터 데이터를 수신합니다.
int cnt = 0;
Wire.requestFrom (0x52,dataLength);//데이터 요청
while(Wire.available()){
rawData[cnt] = nunchuckDecode(Wire.read());
cnt++;
}
nunchuckRequest();//다음 데이터 요청
if (cnt >= dataLength)
return true;//6바이트가 수신되면 성공
else
return false;
}
static char nunchuckDecode (byte x){// 데이터를 인코딩 합니다.
return (x ^ 0x17) + 0x17;
}
int getValue(int item){
if(item <=accelZ)
return (int) rawData[item];
else if (item == btnZ)
return bitRead(rawData[5],0) ? 0:1;
else if (item ==btnC)
return bitRead(rawData[5],1)? 0: 1;
}
소프트웨어 & 하드웨어 설명
1.스케치 설명
#include <Wire.h> // Wire 라이브러리를 초기화 합니다.
const int vccPin = A3;// 아날로그 3 핀이 눈차크의 전원을 공급합니다.
const int gndPin = A2;// 아날로그 2 핀이 그라운드 를 공급합니다.
본 예제에서는 Wire.h 라는 아두이노에 포함되어 있는 I2C 라이브러리를 사용합니다.
해당 링크를 통해 보다 더 자세한 내용을 확인하세요
enum nunchuckItems { joyX,joyY,accelX,accelY,accelZ,btnZ,btnC};
// 각각 조이스틱 x축, 조이스틱 y축, 가속도 y, 가속도 z , 버튼 z , 버튼 c 를 배열합니다
enum은 열거형 상수를 만들 때 사용하며 , 눈차크에서 반환 된 센서 값의 목록을 만드는데 사용합니다.
void setup(){ //전원핀의 초기상태를 안정화 하기 위해 아래의 설정을 합니다.
pinMode(gndPin, OUTPUT);//그라운드핀을 출력으로 설정합니다
pinMode(vccPin, OUTPUT);// 전원핀을 출력으로 설정합니다.
digitalWrite(gndPin,LOW);/그라운드 핀을 low상태로 설정합니다.
digitalWrite(vccPin,HIGH);// 전원핀을 high상태로 설정합니다.
delay(100);//100밀리 초동안 대기합니다.
setup은 눈차크에 전원 공급을 위해 각 핀을 초기화 합니다.
void nunchuckInit(){
Wire.begin();
Wire.beginTransmission(0x52);//0x52의 위치와 통신
Wire.write((byte)0x40);
Wire.write((byte)0x00);
Wire.endTransmission();// 통신종료
I2C 통신은 Wire.begin() 함수로 시작합니다. 본 예제에서는 아두이노가 0X52 위치에 있는 눈차크와 통신합니다.
static void nunchuckRequest(){
Wire.beginTransmission(0x52);
Wire.write((byte)0x00);
Wire.endTransmission();
nunchuckRequest와 nunchuckRead는 데이터를 요청하고 읽을때 사용됩니다.
boolean nunchuckRead(){
int cnt = 0;
Wire.requestFrom (0x52,dataLength);
while(Wire.available()){
rawData[cnt] = nunchuckDecode(Wire.read());
cnt++;
}
Wire.available는 I2C인터페이스를 사용하여, 사용가능한 데이터가 있을때
Wire.read()를 이용하여 데이터를 읽어온뒤
nunchuck Decode를 통해 스케치에서 사용할 수 있는 숫자로 변환합니다.
그런다음, rawData 버퍼에 저장합니다.
아래의 코드를 프로세싱에서 실행합니다.
(아두이노 업로드를 먼저 진행하시고, USB연결을 해제하지 마세요.)
import processing.serial.*; //시리얼 통신 라이브러리를 불러옵니다. Serial myPort; public static final short portIndex =1; void setup() { size(200,200);//실행 창의 크기를 200,200 크기로 설정합니다. String portName = Serial.list()[0];// 대괄호안의 숫자는 현재 사용중인 포트의 배열입니다. myPort = new Serial(this, portName, 9600); } void draw() { if(myPort.available() >0) {//사용 가능한 데이터가 있을때 int y = myPort.read();//데이터를 읽고 저장합니다. background(255);//배경색을 흰색(255)로 설정합니다. line(0,63-y,127,y);//선을 그립니다. } } import processing.serial.*;//시리얼 통신 라이브러리를 불러옵니다. Serial myPort; // 시리얼 클래스로부터 객체를 생성합니다. public static final short portIndex = 1; void setup() { size(200, 200); // 사용중인 포트중 하나를 엽니다. myPort = new Serial(this,Serial.list()[2], 9600);//[]안의 숫자는 사용중인 포트중 아두이노와 연결된 포트의 번호입니다. } void draw() { if ( myPort.available() > 0) { // 만약 데이터가 사용가능한 상태일때, int y = myPort.read(); // 데이터를 읽고, 변수 y로 선언합니다. background(255); // 실행창의 배경색을 흰색(255)으로 설정합니다. line(0,63-y,127,y); // 라인을 그립니다. } }
String portName = Serial.list()[0];// 대괄호안의 숫자는 현재 사용중인 포트의 배열입니다.
만약 프로세싱에서 실행을 했을때 정상적으로 화면이 출력되지 않을때는
[]안의 포트번호를 0부터 5 혹은 6까지 변경해 보세요.
이는 아두이노와 연결되 USB 시리얼 포트의 배열을 의미합니다.
kocoafabeditor
항상 진취적이고, 새로운 것을 추구하는 코코아팹 에디터입니다!