손으로 하는 테트리스 만들기 (1) 자이로센서는 어려워

2021. 1. 19. 23:11뚝딱뚝딱 만들기 Devlog/프로젝트 Devlog

이번에 해볼 프로젝트는 손으로 하는 테트리스 만들기입니다.

 

최근에 아두이노를 처음 해보면서 되게 재밌다고 느껴져서 게임 컨트롤러를 만들기로 했습니다.

장갑에 자이로센서를 부착해서 손을 휘휘 흔들면서 테트리스를 할 수 있도록 만들 겁니다.

블록이 좌우로 움직이는 건 참참참 할 때 같은 동작으로 하고,

돌리는 건 병뚜껑 닫듯이 손을 돌리면 되게 할 겁니다.

 

이를 하기 위해 넘어야 할 산은

 

1. 자이로스코프 센서로 모션 인식하기

2. 인식한 데이터를 컴퓨터(Unity)로 옮기기

3. 자이로스코프를 손에 붙일 도구 만들기

4. 옮겨진 데이터를 제스쳐 (왼쪽, 오른쪽, 회전 등)으로 변환하기

5. 테트리스 만들기

 

가 있겠습니다.

 

1. 자이로스코프 예제 해석하기

사용한 아두이노는 아두이노 uno 보드와 MPU6050(6축자이로) 센서를 사용했습니다.

아두이노 기초편 공부하면서 다른 센서는 예제코드가 10줄 내외였는데

이 자이로센서만 코드가 엄청 길더라구요.

예제코드는 MPU6050 라이브러리 예제 중 MPU6050_DMP6을 이용했습니다.

난독증이 있지만 꾹 참고 그 긴 코드를 다 읽어보며 검색을 해본 결과

뭔지 다 알 순 없었지만 나온 용어들이 뭔지 정도는 알 수 있었습니다.

 

MPU6050_DMP6예제를 처음 해석할 때 미리 알았더라면 좋은 내용들입니다.

 

-I2C / Wire

이게 I to C 이렇게 읽는 줄 알았는데 알고 보니 I제곱 C였습니다.

I2C 통신을 Wire라는 라이브러리로 사용하는 것 같은데 핵심은 I2C 같습니다.

I2C는 부수 기기들이 master와 slave의 관계로 데이터를 통신하는 거로 이해했습니다.

저는 어차피 센서 하나니까 별 신경 안 쓰고 넘겼습니다.

MPU6050 생김새 (https://www.elementzonline.com/mpu6050-gy-521-3-axis-analog-gyro-sensors-accelerometer-module)

SCL이 클럭(clock)정보, SDA가 데이터(data)정보를 담당하는 칸입니다.

 

-DMP

dmp는 칩 자체에 있는 어떤 프레임웍인듯합니다.

센서가 읽어온 정보를 센서 단에서 예쁘게 계산해서 보내주는 기능을 합니다.

 

-interrupt / fifo

계속 가만히 있다가 interrupt를 받아서 어떤 interrupt냐에 따라 다르게 동작하게 할 수 있습니다.

인터럽트는 일종의 신호고, fifo는 버퍼입니다.

예제의 loop() 함수 앞부분이 이것들로 범벅이 돼 있는데,

인터럽트 신호를 기다렸다가 데이터를 보냈다는 뜻의 인터럽트가 오면 fifo 버퍼를 확인하는 식입니다.

 

-Yaw / Pitch / Roll

그다음 밑에 ifdef들은 전부 출력 포맷을 정하는 건데,

Quaternion방식, Euler방식은 뭔지 알겠는데 yaw pitch roll이라는걸 처음 봤습니다.

그래서 그게 뭔지 찾아봤는데 아주 잘 정리된 글이 있었습니다.

 

roll: y축에 대한 회전 (머리 갸웃갸웃) 

pitch: x축에 대한 회전 (머리 끄덕끄덕) 

yaw: z축에 대한 회전 (머리 도리도리)

입니다. (m.blog.naver.com/ccaa09/220704142932) 

 

여기서 x,y,z축은 유니티와 달리, 위를 향하는 방향이 z축이고, 전방을 향하는 방향이 y축 입니다.

 

2. 자이로스코프 센서 이해하기

제가 쓴 센서 MPU6050은 3축 가속도 센서와 3축 자이로 센서가 같이 있습니다.

가속도 센서는 센서가 움직이면서 변하는 가속도 (중력 포함)을 측정하는 거고,

자이로 센서는 코리올리힘?을 측정해서 각속도를 측정하는 겁니다.

 

-가속도 센서

이 가속도 센서로 각도를 알아내는 방식이 뭐냐면

x축과 y축 방향에 중력이 얼마나 작용했는지로 판단합니다.

예를 들어 x축 방향으로 중력이 작용하고 있다면 그쪽으로 기울었다는 겁니다. (제대로 이해 못한 것 같습니다)

그래서 roll이나 pitch를 구하는 방식을 보면

roll = atan(yacc/zacc) * 180/pi 입니다.

 

가속도 센서의 단점은 굉장히 예민하기 때문에 노이즈가 많다는 겁니다.

그리고 z축 회전을 인식할 수 없습니다. 센서가 아무리 돌아봤자 z축(바닥과 수직)으로 받는 중력가속도에는 차이가 없기 때문입니다.

게다가 조사하면서 알았는데 충격적이게도 가속도 센서로는 움직임을 측정할 수가 없습니다.

원래 이걸로 테트리스 만들고 마법진을 그리면서 싸우는 마법사 게임을 만들려했는데 움직임을 측정할 수 없어서 기각됐습니다.

가속도 센서로 위치를 알려면 가속도를 적분을 두 번 해야되는데(가속도>속도>위치), 사실 적분이라는 게

속도 = 속도 + (이번 프레임 가속도 * deltaTime) 형식입니다.

이걸 한번 더하면 위치가 나오는데, 그러면 가속도 센서에서 인식된 그 오차가 엄청 뻥튀기 돼서 제대로 나오질 않습니다.

 

-자이로 센서

자이로센서는 원리는 이해를 못 했습니다. 그냥 되는 것 같아요.

어쨌든 자이로센서는 직접적으로 어떤 축에 대한 회전 속도를 알려주기 때문에,

한번 적분하면 각이 나옵니다. 그래서

x회전 = x회전 + (이번 프레임 각속도 * deltaTime) 을 하면 됩니다.

 

자이로센서의 단점은 드리프트 현상이 생긴다는 겁니다.

이건 대단한 게 아니라 적분 과정에서 생기는 오차가 누적돼서 쌓이는겁니다.

그래서 가만히 놔둬도 값이 자꾸 올라가거나 내려갑니다.

 

***별표 3개***

가속도 센서는 노이즈가 많지만 오차가 적고 (장기간 관측 시 유용)

자이로 센서는 오차가 누적되는 방식이지만 노이즈가 적습니다. (단기간 관측 시 유용)

 

이 두 가지를 합쳐버리는 필터가 있는데, 칼만 필터와 상보 필터에 대해 검색해 봤습니다.

정말 오랜시간 봤는데 이해를 못했습니다.

 -칼만 필터 : 결과값을 미리 예측하고, 실제 측정값과 비교하고 잘 버무려서 다음 결과값 예측 때 씁니다. (이해 못 했습니다.)

 -상보 필터 : 두 값을 n:m의 비율로 잘 섞는 방식입니다.

요정도로 이해를 했는데,

 

검색을 계속하다 보니 이렇게 두 측정값 모두 사용하는 과정을 dmp에서 해주는 거였다는걸 알게 됐습니다.

그래서 결론적으로는 그냥 내장된 dmp로 계산된 값을 사용하기로 했습니다.

 

 

결국 코드는 직접 쓴 부분은 없고 원래 예제에서 주석들 다 지우고, 쓸모없는 부분은 다 뺐습니다.

예를 들면 계속 initializing..을 출력하는 부분이나 (나중에 게임을 돌릴 땐 필요 없는 출력이라서)

키를 눌러야 값을 읽어오는 부분을 뻈습니다.

(스포일러)

그리고 출력 포맷을 살짝 바꿨는데 이건 나중에 유니티에서 읽기 편하게 하려고 바꿨습니다.

 

소스코드 : github.com/HappyFaceFriend/TetrisWithHand/blob/master/gyrotest2/gyrotest2.ino

반응형