아두이노 에어마우스
프로젝트/FPS 게임 컨트롤러

아두이노 에어마우스

반응형

 

공중에서 사용할 수 있는 에어마우스를 일상 생활에서 쓸 일은 그리 많지는 않다. 최근들어 다양한 기능을 지원하는 스마트 티비의 개발과 함께 좀 더 다양한 동작을 할 수있는 에어마우스 형태의 등장했긴 했으나 아직까지 컴퓨터를 사용하면서 에어마우스를 쓸 일은 거의 없는것 같다.

 

하지만 게임이라면 이야기가 달라진다. FPS 게임의 경우 총의 조준을 마우스로 하지만 실감나는 게임을 위해 실제 총과 비슷한 콘솔을 이용하기도 한다. (Wii의 눈차크, 플레이스테이션등) 그래서 이번에는 FPS 게임을 위한 FPS 게임 컨트롤러 프로토타입을 제작해 볼 것이다.

 

 

우선은 MPU6050과 NRF24L01 모듈이 필요하다. 무선으로 제작할 계획이기 때문에 NRF24L01 모듈을 이용했으며 사용법은 하단의 링크를 참고하자

반응형

http://diy-project.tistory.com/2?category=710046

 

NRF24L01 모듈 사용하기

1. NRF24L01 모듈 NRF24L01을 아두이노와 함께 사용하기 위해서는 다음과 같은 것들이 필요합니다. 아두이노 우노 (또는 나노) x2, NRF24L01 모듈 x2, 가변저항 x1, 서보모터 x1, 등등 위의 사진은 NRF24L01의

diy-project.tistory.com

 

무선이기 때문에 송신부와 수신부를 각각 제작해야한다. 각각의 모습은 아래와 같다.

 

송신부

 

 

수신부

 

 

출처 : https://microcontrollerelectronics.com/using-an-nrf24l01-module-to-scan-the-2-4ghz-frequency-range/

 

 

처음에는 MPU6050의 기본 예제를 이용해서 에어마우스를 구연하려고 했으나 어마어마한 딜레이로 마우스가 절대 부드럽게 움직이지 않았다. 수많은 검색 끝에 국내에서 에어마우스에 관해 쓸만한 자료 두 곳을 찾았다. 소스코드는 두 곳을 모두 참고해 작성했다.

 

1. https://kocoafab.cc/make/view/445

 

아두이노 에어마우스

HID 기기로 인식하게 만드는 아두이노 레오나르도와 자이로/가속도 센서 mpu-6050 을 사용하여 에어마우스를 만든 프로젝트입니다. 준비물 아두이노 레오나르도 MPU-6050 Jumper Cable 배치 회로도

kocoafab.cc

2. http://cafe.naver.com/arduinostory/18039

 

아두이노 소수점 연산이 안되나요?

대한민국 모임의 시작, 네이버 카페

cafe.naver.com

 

첫번째 참고 사이트에서 국내의 거의 유일한 에어마우스의 완성도 높은 코드를 구할 수 있다. 하지만 많은 사람들이 I2C 통신 오류로 실패를 한 코드 이기도 하다. 필자 또한 스케치에 이 코드를 업로드 했을때 I2C관련 오류로 삽질을 좀 했다. 결국 두번째 사이트에서 해답을 찾을 수 있었는데, 첫번째 사이트의 코드가 완전한 코드가 아니었기 때문에 오류가 발생 한 것이다. 두 곳의 코드를 합쳐 수정한 코드는 아래와 같다.

 

 

송신부

#include <SPI.h>
#include "RF24.h"
#include <Wire.h>
#include "Kalman.h"
 
int msg[2]={0,0};
int msg1 = 0;
int msg2 = 0;
 
byte address[6] = "1Node";
RF24 radio(7,8);  // CE, CSN
 
int16_t gyroX, gyroZ;
 
int Sensitivity = 600;
 
int delayi = 3;
 
 
uint32_t timer;
 
uint8_t i2cData[14]; // Buffer for I2C data
 
const uint8_t IMUAddress = 0x68; // AD0 is logic low on the PCB
const uint16_t I2C_TIMEOUT = 1000; // Used to check for errors in I2C communication
 
uint8_t i2cWrite(uint8_t registerAddress, uint8_t data, bool sendStop) {
  return i2cWrite(registerAddress,&data,1,sendStop); // Returns 0 on success
}
 
uint8_t i2cWrite(uint8_t registerAddress, uint8_t* data, uint8_t length, bool sendStop) {
  Wire.beginTransmission(IMUAddress);
  Wire.write(registerAddress);
  Wire.write(data, length);
  return Wire.endTransmission(sendStop); // Returns 0 on success
}
 
uint8_t i2cRead(uint8_t registerAddress, uint8_t* data, uint8_t nbytes) {
  uint32_t timeOutTimer;
  Wire.beginTransmission(IMUAddress);
  Wire.write(registerAddress);
  if(Wire.endTransmission(false)) // Don't release the bus
    return 1; // Error in communication
  Wire.requestFrom(IMUAddress, nbytes,(uint8_t)true); // Send a repeated start and then release the bus after reading
  for(uint8_t i = 0; i < nbytes; i++) {
    if(Wire.available())
      data[i] = Wire.read();
    else {
      timeOutTimer = micros();
      while(((micros() - timeOutTimer) < I2C_TIMEOUT) && !Wire.available());
      if(Wire.available())
        data[i] = Wire.read();
      else
        return 2; // Error in communication
    }
  }
  return 0; // Success
}
 
void setup() {
 
  Serial.begin(9600);
 
  radio.begin();
  radio.openWritingPipe(address);
  radio.stopListening();
 
  Wire.begin();
 
  i2cData[0] = 7; // Set the sample rate to 1000Hz - 8kHz/(7+1) = 1000Hz
 
  i2cData[1] = 0x00; // Disable FSYNC and set 260 Hz Acc filtering, 256 Hz Gyro filtering, 8 KHz sampling
 
 
  i2cData[3] = 0x00; // Set Accelerometer Full Scale Range to ±2g
 
  while(i2cWrite(0x19,i2cData,4,false)); // Write to all four registers at once
 
  while(i2cWrite(0x6B,0x01,true)); // PLL with X axis gyroscope reference and disable sleep mode
 
  while(i2cRead(0x75,i2cData,1));
 
  if(i2cData[0] != 0x68) { // Read "WHO_AM_I" register
 
    Serial.print(F("Error reading sensor"));
 
    while(1);
 
  }
 
 
  delay(100); // Wait for sensor to stabilize
 
  /* Set kalman and gyro starting angle */
 
  while(i2cRead(0x3B,i2cData,6));
 
  timer = micros();
 
 // Mouse.begin();
 
}
 
 
void loop() {
 
  /* Update all the values */
 
  while(i2cRead(0x3B,i2cData,14));
 
  gyroX = ((i2cData[8] << 8) | i2cData[9]);
 
  gyroZ = ((i2cData[12] << 8) | i2cData[13]);
 
 
  gyroX = gyroX / Sensitivity / 1.1  * -1;
 
  gyroZ = gyroZ / Sensitivity  * -1;
 
 
  Serial.print("\t");
 
  Serial.print(gyroX);
 
  Serial.print(gyroZ);
 
  msg1=gyroX;
  msg[0]=msg1;
  
  msg2=gyroZ;
  msg[1]=msg2;
 
  
  radio.write(&msg, sizeof(msg));
 
 
  Serial.print("\r\n");
 
  delay(delayi);
 
}

수신부

#include <SPI.h>
#include <Mouse.h>
#include "RF24.h"
 
int msg[2];
int msg1;
int msg2;
 
byte address[6] = "1Node";
 
RF24 radio(7,8);  // CE, CSN
 
 
void setup(void) {
 
  Serial.begin(9600);
 
  radio.begin();
  Mouse.begin();
 
 
  radio.openReadingPipe(1, address);
 
  radio.startListening();
 
}
 
void loop(void) {
 
  if(radio.available()) {
 
 
    radio.read(&msg, sizeof(msg)); 
   
    Serial.print("Meassage (RX) = ");
 
    Serial.print(msg[0]);
    Serial.println(msg[1]);
 
    Mouse.move(msg[1], -msg[0]);
  
    
  }
 
}

 

사용된 라이브러리는 칼만필터 (센서값의 노이즈를 잡아주는 아주 유명한 프로그램이다.), MPU6050, NRF24L01이다. 라이브러리는 아래 파일로 다운이 가능하다.

 

KalmanFilter-master.zip
다운로드
MPU6050.zip
다운로드
I2Cdev.zip
다운로드
RF24-master.zip
다운로드

 

아래는 테스트 영상이다. 이 글이 에어마우스를 시도하는 많은 사람에게 도움이 되길 바란다. 

 

  

[수정]

아래의 글들이 도움이 될 수있다.

2018/01/12 - [아두이노/프로젝트] - 아두이노 FPS 게임 컨트롤러 (오버워치, 더 하우스 오브 더 데드)

2018/05/20 - [아두이노/프로젝트] - 아두이노 FPS 게임 컨트롤러 2.0

2018/09/22 - [아두이노/프로젝트] - 아두이노 FPS 게임 컨트롤러 수신부 업그레이드 중

2018/09/25 - [아두이노/프로젝트] - 모바일 배틀그라운드 컨트롤러 만들기 [아두이노 FPS 게임컨트롤러 활용]

2018/10/04 - [아두이노/프로젝트] - FPS 게임 컨트롤러 수신기 PCB 발주

2018/10/07 - [분류 전체보기] - 아두이노 FPS 게임 컨트롤러 2.0 게임 테스트

 

 

반응형
    # 테스트용