고급 예제

다양한 도구들을 가지고 마음껏 응용해보세요.

Wii 눈차크 가속도계

2014-08-14 15:37:29

개요 & 부품목록

출처 : wii 컨트롤러 - amazon

 


아두이노의 활용성은 무궁무진 합니다.
그중에서 게임을 좋아하는 사람들은 누구나 알만한 wii 전용 컨트롤러인 
눈차크(nunchuck)가 아두이노와 만나 어떤 일들을 할 수 있는지 살펴보겠습니다.

 

 

 

 

 


RC 나 로봇, 자이로 콥터등 각종 움직이는 사물들의 컨트롤러로 사용할수 있으며,
일반적인 조이스틱 컨트롤은 물론, 3축 센서를 활용해 신체의 움직임을 통해 컨트롤 할수 있는 또 다른 특징이 있습니다.

출처 : wii nunchuck 내부 - jamjarcollective

눈척을 분해 해보면 , 

사진 : 자이로센서 MPU-6050모듈


위와 같은 자이로센서를 발견할수 있습니다.
자이로 센서는 기본적으로 회전하는 물체의 역학운동을 이용해 위치 측정과 방향 설정등에 사용됩니다.
각각 x축 ,y축, z축 3개의 축의 센서값을 읽을 수 있어 다양하게 응용이 가능합니다.

그럼 눈차크와 아두이노의 연결방법을 알아보고 프로세싱 상에서 간단한 예제를 실습해 보겠습니다.

 

미리보기 동영상

 

 

부품목록

 
NO 부품명 수량 상세설명
1 오렌지 보드 1 아두이노 호환보드
2 브레드보드 1 브레드보드
3 눈차크  1 저항
4 눈차크 어댑터 1 점퍼 케이블
 
부품명 오렌지 보드 브레드보드 눈차크  눈차크 어댑터
파트 x1 x1 x1  x1

하드웨어 Making

회로도


 출처 : digistump

 

브레드보드 레이아웃





 

사진 : 눈척 어댑터

 




위와 같은 눈척 전용 어댑터를 이용하시면 편리하게 아두이노와 연결할 수 있습니다.

 

 

 

소프트웨어 Coding

아래의 코드를 아두이노에 업로드 합니다.

 

 

 

 

/*출처 : 아두이노 쿡북 
  최종수정 : 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

항상 진취적이고, 새로운 것을 추구하는 코코아팹 에디터입니다!

눈차크, 아두이노, 오렌지보드