Nefryで使えるGrove加速度センサがNefry BTだとうまく使えなかった(けど使えるようにした)話

[Nefry Advent Calendar 2017](https://qiita.com/advent-calendar/2017/nefry) の16日目です。よろしくお願いします。

今夏、[Nefry BTのクラウドファンディング](https://kibidango.com/513)を支援してNefry BTをゲットし、Nefry BTにはGroveの端子が4つあるので、せっかくだからGroveのセンサを使ってみようと思いました。
[のびすけ](https://twitter.com/n0bisuke)さんの[NefryでGrove加速度センサを触るメモ](https://qiita.com/n0bisuke/items/3ec65674696f94bc1e96)という記事を見て、Nefry BTで加速度センサを使ってみようとしましたが、見事にハマってしまったというお話です。

# 使用したもの
* Nefry BT
* Grove - 3-Axis Digital Accelerometer(±1.5g)
    * http://wiki.seeed.cc/Grove-3-Axis_Digital_Accelerometer-1.5g/

センサとNefry BTのI2C(D0)ソケットをGroveケーブルで接続します。

![PC160788.jpg](https://qiita-image-store.s3.amazonaws.com/0/137045/b799a88a-ba22-cf18-47cc-bbd73aeac963.jpeg)

# Nefry BTにサンプルのスケッチを書いてみた
のびすけさんの記事に書いてある通り、センサを扱うためにSeeedのリポジトリからAccelerometer_MMA7660ライブラリをダウンロード(Download ZIP)し、Arduino IDE上で「ライブラリをインクルード > .ZIP形式のライブラリをインストール」でライブラリをインストールします。

https://github.com/Seeed-Studio/Accelerometer_MMA7660
(Nefry BTを利用する際、こちらのリポジトリからZIPファイルをダウンロードすることはおすすめできません)

Arduino IDEのスケッチの例に「Accelerometer_MMA7660 > MMA7660FC_Demo」があるので、こちらのスケッチをNefry BTに書き込んでみました。

<img width="771" alt="スクリーンショット 2017-12-16 8.09.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/137045/1351fb6c-d98a-c9fd-a4a0-3cd35a7c5ebb.png">

シリアルモニタを見てみるとこんな感じでした。
センサは静止した状態でスクリーンショットを撮りましたが、3軸の加速度の2乗和平方根(つまりノルムの値)が `3.18g` くらいになってしまっています。地球上にいるのならだいたい `1g` になるはずなので、明らかにおかしな状態です。[Seeedのページ](http://wiki.seeed.cc/Grove-3-Axis_Digital_Accelerometer-1.5g/)を見ても、やはり仕様通りではありません。

# Arduino Unoにサンプルのスケッチを書いてみた
センサの初期不良を疑いましたが、いったんArduino Unoで問題なく動作するか確認してみることにしました。

![PC160786.jpg](https://qiita-image-store.s3.amazonaws.com/0/137045/feb5135a-c96b-b1d8-f212-db5985b5845a.jpeg)
この写真のようにGroveケーブルにジャンパワイヤーを差し込んで、センサをGroveのベースシールドがないArduino Unoに接続できるようにしました。A4とSDA, A5とSCL, GND, 5Vを接続します。

Nefry BTと同様にスケッチの例「Accelerometer_MMA7660 > MMA7660FC_Demo」をArduino Unoに書き込んでみました。

<img width="771" alt="スクリーンショット 2017-12-16 8.47.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/137045/91f0e07d-4519-be98-4c57-912259b6fe0e.png">

おそらく正しい値が取れており、センサの初期不良ではなさそうです。

# ライブラリのコードを見て修正してみた
となると、ライブラリがおかしいと思われたので、C++の知識はあまりないですが[ライブラリのコード](https://github.com/Seeed-Studio/Accelerometer_MMA7660/blob/master/MMA7660.cpp)を見てみることにしました。
すると、 `MMA7660::getXYZ` の引数が`bool MMA7660::getXYZ(int8_t *x,int8_t *y,int8_t *z)` なのにも関わらず、最後に `char` でキャストして4で割って `*x`, `*y`, `*z` に代入していることに気づきました。

> <img width="219" alt="スクリーンショット 2017-12-16 9.13.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/137045/97ee69e9-de97-9f27-3643-11b58f4537e9.png">

キャストの部分に怪しさを感じ、試しに `char` でキャストの部分を `int8_t` でキャストに変更したところ、Nefry BTでもArduino Unoでも問題なく動作するようになりました。

# つぶやいてみた
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">byte型の値をchar型のキャストして4で割ってint8_t型の変数に入れるときの挙動がArduino UnoとESP32で違うっぽい🤔 <a href="https://t.co/IFoE3g0NqM">pic.twitter.com/IFoE3g0NqM</a></p>&mdash; mascii (@mascii_k) <a href="https://twitter.com/mascii_k/status/896712941457645568?ref_src=twsrc%5Etfw">2017年8月13日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
キャストの動作がArduino UnoとNefry BT(ESP32)とで異なることについて、Twitterでつぶやいたところ、「charがsignedかどうかは処理系依存」ではないか、というご意見をいただきました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">なんかESP32の方、charがunsigned charになってるっぽい挙動。コンパイル時にオプション入ってるんちゃうかな。 <a href="https://t.co/uJHbz0LVt7">https://t.co/uJHbz0LVt7</a></p>&mdash; Kenta IDA (@ciniml) <a href="https://twitter.com/ciniml/status/896746571743739906?ref_src=twsrc%5Etfw">2017年8月13日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ああ、charがsignedかどうかは処理系依存なのか。Espressifが提供するxtensa用ツールチェインのgccはunsignedなんかな。ARMもunsignedらしい。<a href="https://t.co/CSNYEWH40S">https://t.co/CSNYEWH40S</a></p>&mdash; Kenta IDA (@ciniml) <a href="https://twitter.com/ciniml/status/896766135126839297?ref_src=twsrc%5Etfw">2017年8月13日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 学んだこと
* NefryはESP8266、Nefry BTはESP32を使っている以上、Nefryで使えるライブラリがNefry BTでそのまま使えると限らないこと
    * 初心者の方は「Nefry BTで」使えることがわかっているセンサ・ライブラリの組み合わせを使うと良さそうです
* 今回のケースのように、Arduino用として公開されているセンサのライブラリをArduinoで使ってみることで問題の切り分け(センサの初期不良なのか、ライブラリの不備なのか、など)ができること
* 「charがsignedかどうかは処理系依存」であること

# ちなみに、この加速度センサの使い道は？
8月に開催された[Maker Faire Tokyo 2017](http://makezine.jp/event/mft2017/)で、Seeedさんが同種のセンサで「ゴミ箱のフタの開閉」を検知していたので、そういった使い方があると思われます。加速度センサというより、重力方向センサだと思った方が良さそうです。
![ファイル 2017-12-16 9 42 52.jpg](https://qiita-image-store.s3.amazonaws.com/0/137045/f403722c-109f-294c-b35e-6c459744d875.jpeg)

# 修正版ライブラリの公開
SeeedのリポジトリをForkし、修正版を公開していますので、お困りの方はこちらをご利用ください。
https://github.com/mascii/Accelerometer_MMA7660

(20180319追記)
[のびすけ](https://twitter.com/n0bisuke)さんからESP32用サンプルスケッチの[Pull Request](https://github.com/mascii/Accelerometer_MMA7660/pull/1)をいただき、マージいたしました。
https://github.com/mascii/Accelerometer_MMA7660/blob/master/examples/MMA7660_for_ESP32/MMA7660_for_ESP32.ino