加速度センサーで遊ぶ

## 加速度センサーの使い道
ちょっとした興味本位で加速度センサーを買ったのですが、あまり使わなくて古くから眠っていたものを最近掘り起こしたのでちょっと遊んでみました。

### 使用機器
MMA8452Qモジュールキットを使いました。秋月電子で買いましたが今はもう売ってないらしいです。

https://www.nxp.jp/products/sensors/accelerometers/2g-4g-8g-low-g-12-bit-digital-accelerometer:MMA8452Q

RaspberryPi Zeroとつないで動かしています

### 何をしたか
Pythonから加速度データを整形し、pythonのcursesモジュールを用いて<b>傾けるとカーソルの位置も変わる</b>というちょっとしたものを作って遊びました。

動作画面：（実際の映像は最後にあります）
![c.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624852/444db413-b696-c7ae-58fc-9c30f7505bad.png)


ちなみに軸の取り方はこんな感じです(公式データシートより)

![s.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624852/74f51a2a-a807-ecf3-536f-cbeeedc40d70.png)

## プログラムと動作

### 加速度センサーを操るプログラム

加速度センサーとはI2Cで通信します。その際にsmbusというモジュールを使います。




```python:sensor.py
#MMA8452Q加速度センサーモジュール

import smbus
import time
import math

#I2C設定
i2c = smbus.SMBus(1)
address = 0x1D

#センサー設定
ret = i2c.write_byte_data(address,0x0E,0x00)
ret = i2c.write_byte_data(address,0x2A,0x01)

def get_data():
	#データ読み込み
	dat = i2c.read_i2c_block_data(address,0x01,0x06)
	#print(dat)
	#データ変換
	dat_x = (dat[0] << 8 | dat[1]) >> 4
	dat_y = (dat[2] << 8 | dat[3]) >> 4
	dat_z = (dat[4] << 8 | dat[5]) >> 4

	#極性診断
	if dat_x >= 2048:
		dat_x -= 4096
	if dat_y >= 2048:
		dat_y -= 4096
	if dat_z >= 2048:
		dat_z -= 4096
	#物理量(加速度)に変換
	out_x = dat_x / 1024.0
	out_y = dat_y / 1024.0
	out_z = dat_z / 1024.0
 
	return (out_x, out_y, out_z)
```

### 表示するプログラム
cursesモジュールを使いました。詳しいことは過去記事をご覧ください。

https://qiita.com/iiirukaaa/items/6d3f49ccde1a34ae3c54

ちなみに、センサーが返す値は重力加速度=1となる値として帰ってきます。


```python:pointer_moving.py
#!usr/bin/ python
# -*- coding: utf-8 -*-

import sys,os,time
import curses
#前述プログラム
import sensor

def pointer(stdscr):
    #初期化
    cursor_x = 0
    cursor_y = 0
    x,y,z = 0,0,0

    #画面の初期化
    stdscr.clear()
    stdscr.refresh()

    #カラー定義
    curses.start_color()
    curses.init_pair(1, curses.COLOR_CYAN, curses.COLOR_BLACK)    # カラー１は、文字色をシアン、背景色を黒

    while 1:
        #画面初期化
        stdscr.clear()
        #画面の最大値を取得
        height, width = stdscr.getmaxyx()

        #加速度データ取得(zは使わない)
        x,y,z = new_3dsensor.get_data()
        x = round((-1)*x,6)
        y = round(y,6)
        #カーソル中心を取得
        center_x, center_y = width // 2, height // 2
        cursor_x = center_x + int(center_x * x)
        cursor_y = center_y + int(center_y * y)


        #カーソル枠の補正
        cursor_x = max(0, cursor_x)
        cursor_x = min(width-1, cursor_x)

        cursor_y = max(0, cursor_y)
        cursor_y = min(height-1, cursor_y)

        # カーソル位置の表示
        whstr = "W:{},H:{} , x:{},y:{} , cursor x:{} / y:{}".format(width, height,x,y,cursor_x,cursor_y)
        stdscr.addstr(0, 0, whstr, curses.color_pair(1))    #　文字列whstrを（0,0）にカラー１で表示する

        #カーソル
        stdscr.move(cursor_y, cursor_x)

        #リフレッシュ
        stdscr.refresh()

        #待機
        time.sleep(0.1)
    #元に戻す
    curses.nocbreak()
    stdscr.keypad(False)
    curses.echo()
    curses.endwin()

def main():
    curses.wrapper(pointer)

if __name__ == "__main__":
    main()

```

 元に戻すという部分がありますが、breakするポイントがないので意味はないです。(Ctrl-Cブッチ)
 また、加速度データを読み込む際のround関数あたりでx軸だけ正負反転させていますが、操作上直感的なものになるようにしているだけです。（左に傾けたら左にカーソルがいくようにした）
 カーソルも基本的に中心になるようちょっと工夫があります。

### 実際の挙動

 ![Videotogif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624852/7beb8e28-f836-c5a9-9a66-0d5be7b747f2.gif)

 実際動かすとちらつきが半端ないですが、一応完成しました！

#### 直したいとこ
 通常の世界で静止しているときの重力加速度は真下にしか働かず、ななめにするとx:0.5,y:0.5と分散されるのは当たり前ですが、このプログラムだと隅っこにカーソルが動かないという問題があります。
 片方が1に近づくともう片方の加速度も1になるよう調整できたらいいかなと思いました。


 ...まあ遊びなのでとりあえず動いたのでヨシ！！