micro:bit / MicroPython & Mbed / オンボード加速度センサーのさまざまな読み出しかた

#概要  
micro:bit は I2C バスに加速度センサー [MMA8653FC](https://www.nxp.com/products/sensors/motion-sensors/accelerometers-for-iot/2g-4g-8g-low-g-10-bit-digital-accelerometer:MMA8653FC?lang=en&lang_cd=en&) が接続されている。この加速度センサーからさまざまな方法で加速度を読み出してみる。

#(1) 一番簡単な方法 (MicroPython)  
microbit.accelerometer オブジェクトから ```get_ ～ ()``` メソッドで読み出す。単位は約 mg (ミリ・ジー)。

```python
from microbit import *

while True:
    # 軸ごとに読み出す。
    x = accelerometer.get_x()
    y = accelerometer.get_y()
    z = accelerometer.get_z()
    print("%d, %d, %d" % (x, y, z))
    
    # 3 軸を一遍に tuple として読み出すこともできる。
    xyz = accelerometer.get_values()
    print(xyz)

    sleep(500)
```

実行結果:
<img src="https://qiita-image-store.s3.amazonaws.com/0/193936/8de6850e-eb20-a66b-24c1-0cbb2de35a15.png" width=150>
  
検知方向:
<img src="https://qiita-image-store.s3.amazonaws.com/0/193936/50ab665d-ad80-1bab-b2e5-96b12796be30.png" width=400>


#(2) I2C バスから読み出す方法 (MicroPython)
10 ビットの測定データが OUT_X(Y,Z)_MSB と OUT_X(Y,Z)_LSB とに分けてに格納される。
<img src="https://qiita-image-store.s3.amazonaws.com/0/193936/53236dca-0af7-08aa-df90-e52c2af1ee5b.png" width=600>

```python
from microbit import *

# 10 ビットの生データを ± 2 g に変換するための函数
def raw2g(raw):
    if 0b1000000000 == (0b1000000000 & raw): # 最上位ビットに 1 が立っていたら負数なので
        raw -= 2**10                         # -0d1 ～ -0d512 に変換する。
    
    return 4/(2**10) * raw                   # 1 LSB = 4 / 2**10 = 0.00390625g
    
while True:
    # 0x1d がディバイスアドレス。レジスタアドレス 0x00 から 7 バイトを読み出す。
    # (もちろんレジスタアドレス 0x01 から 6 バイトを読み出すことにしてもよい)
    raw = i2c.read(0x1d, 7)
    
    # 2 つの 8 ビットデータを 10 ビットデータに並べ換える。
    raw_x = raw[1]<<2 | raw[2]>>6
    raw_y = raw[3]<<2 | raw[4]>>6
    raw_z = raw[5]<<2 | raw[6]>>6
    
    g_x = raw2g(raw_x)
    g_y = raw2g(raw_y)
    g_z = raw2g(raw_z)
    
    print("x: %.8f, y: %.8f, z: %.8f" % (g_x, g_y, g_z))
    sleep(500)
```

実行結果:
<img src="https://qiita-image-store.s3.amazonaws.com/0/193936/1b30de9a-8f5a-bfec-3562-c286e814847e.png" width=300>
  
検知方向:
<img src="https://qiita-image-store.s3.amazonaws.com/0/193936/7516f05a-04da-d2f8-5d5c-bd87972c9645.png" width=400>  
  
#(3) MicroBitAccelerometer オブジェクトから読み出す方法 (mbed)
mbed でコンパイルする。加速度だけでなくピッチ、ロールを取得するためのメソッドも用意されている。

```cpp
#include "MicroBit.h"
MicroBit              uBit;
MicroBitI2C           i2c           = MicroBitI2C(I2C_SDA0, I2C_SCL0);
MicroBitAccelerometer accelerometer = MicroBitAccelerometer(i2c);

int main(void){
    uBit.init();
    //accelerometer.setPeriod(100);
    
    while(1){
        // 3 軸の加速度を取得する (単位は約 mg)。
        int g_x = accelerometer.getX();
        int g_y = accelerometer.getY();
        int g_z = accelerometer.getZ();
        
        // ピッチを角度単位、ラジアン単位で取得する。
        int   pitch    = accelerometer.getPitch();
        float pitchRad = accelerometer.getPitchRadians();
        
        // ロールを角度単位、ラジアン単位で取得する。
        int   roll    = accelerometer.getRoll();
        float rollRad = accelerometer.getRollRadians();

        printf("x: %d, y: %d, z: %d\n", g_x, g_y, g_z);
        printf("pitch(deg): %d, pitchRad(rad): %.3f\n", pitch, pitchRad);
        printf("roll(deg) : %d, rollRad(rad) : %.3f\n", roll, rollRad);
        printf("\n");
        
        wait_ms(500);
    }
    
    release_fiber();
    return 0;
}
```

実行結果:
<img src="https://qiita-image-store.s3.amazonaws.com/0/193936/4bb53573-062b-a046-7fce-815a39a99746.png" width=280>

検知方向:
<img src="https://qiita-image-store.s3.amazonaws.com/0/193936/50ab665d-ad80-1bab-b2e5-96b12796be30.png" width=400>
<img src="https://qiita-image-store.s3.amazonaws.com/0/193936/ba7bb69a-5e3f-99e1-cca0-28b949b96d4f.png" width=250>

#(4) I2C バスから読み出す方法 (mbed)
mbed でコンパイルする。  
ディバイスアドレス (7 ビットアドレッシング) は 0x1d (0b 001 1101) であるが 8 ビット幅の Bit7-1 として送信されるので ```0x1d<<1``` のようにして左に 1 ビットシフトする (0b 0011 101?)。Bit0 には R/!W のどちらかが入る。  
レジスタアドレス 0x01 から 6 バイトを読み出す。
<img src="https://qiita-image-store.s3.amazonaws.com/0/193936/ba139b06-53b6-eded-d347-9fdb5452cbaa.png" width=500>

```cpp
#include "MicroBit.h"
MicroBit uBit;

float raw2g(int raw){
    if(0x200 == (0x200 & raw)){     // 0x200 = 0b 10 0000 0000
        raw -= 1024;                // 1024 = 2^10
    }
    return 0.00390625 * (float)raw; // 1 LSB = 0.00390625 = 4/(2^10)
}

int main(void){
    uBit.init();
 
    char buf1[] = {0x01};
    char buf2[6];
       
    while(1){
        uBit.i2c.write(0x1d<<1, buf1, 1, true); // true を指定して repeated START にする。
        uBit.i2c.read(0x1d<<1, buf2, 6);
        
        int raw_x = buf2[0]<<2 | buf2[1]>>6;
        int raw_y = buf2[2]<<2 | buf2[3]>>6;
        int raw_z = buf2[4]<<2 | buf2[5]>>6;

        float x = raw2g(raw_x);
        float y = raw2g(raw_y);
        float z = raw2g(raw_z);

        printf("x: %.8f, y: %.8f, z: %.8f\n", x, y, z);
        wait_ms(500);
    }
    
    release_fiber();
    return 0;
}
```

実行結果:
<img src="https://qiita-image-store.s3.amazonaws.com/0/193936/fc2c6e0b-89f3-b01e-1006-7c5ada01f64d.png" width=350>
  
検知方向:
<img src="https://qiita-image-store.s3.amazonaws.com/0/193936/7516f05a-04da-d2f8-5d5c-bd87972c9645.png" width=400>

#参考
- [_micro:bit IoT in C_](https://www.amazon.co.jp/Micro-Bit-Iot-Harry-Fairhead/dp/1871962455/ref=sr_1_1?ie=UTF8&qid=1527664047&sr=8-1&keywords=press+iot+micro%3Abit), pp.81-90
- [_Beginning BBC micro:bit_](https://www.amazon.co.jp/s/ref=nb_sb_noss?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&url=search-alias%3Denglish-books&field-keywords=beginning+bbc+micro%3Abit+apress), pp.90-95
- [MMA8653FC 3-Axis, 10-bit Digital
Accelerometer Data Sheet (.pdf)](https://www.nxp.com/docs/en/data-sheet/MMA8653FC.pdf)
- https://lancaster-university.github.io/microbit-docs/ubit/accelerometer/


#関連  
[micro:bit I2C バス / オンボード加速度計](http://ti-nspire.hatenablog.com/archive/category/micro%3Abit%20I2C%20%E3%83%90%E3%82%B9%20%2F%20%E3%82%AA%E3%83%B3%E3%83%9C%E3%83%BC%E3%83%89%E5%8A%A0%E9%80%9F%E5%BA%A6%E8%A8%88)