【Unity】標準以外のセンサー(歩数計や心拍数など)を使う(Android) 
2018/04/05 Thu [edit]
せっかくなので、Android で Unity の標準センサー(Input.acceleration, compass, gyro)以外のセンサーを使う方法を書いておこう。またついでに Android のセンサーの値の仕様も覚えておくと、新しいセンサーが搭載されたときにも役に立つかも知れない。あと、センサーの利用にはその端末がそのセンサーを搭載しているか、パーミッションが与えられているかなどという注意点もあるので覚えておこう。ここでは歩数計や心拍数センサーを例に挙げてるが、他のセンサーでも基本的には変わらない。
|
センサーのデモシーンは「SensorTest」(AssetStore版は「Assets/FantomPlugin/Demo/Scenes/」以下、GoogleDrive版は「Assets/_Test/Scenes/」以下)にまとまっているので、コピペして使うのも良いだろう。プラグイン自体が無い場合は以下から GoogleDrive版をダウンロードしても良い。
プラグインのセットアップから始める場合には以前の記事を参考にして欲しい。AssetStore版を利用してる場合はこちらの記事を、GoogleDrive版を利用している場合はこちらの記事を参照して欲しい。どちらもコード自体は同じなので同じように使えると思う。パスなどの違いは適宜置き換えて考えて欲しい。
■プラグインのセットアップ(AssetStore 版) [※別ページ]
■歩数センサー(Step Counter Sensor)を使う
●プレファブ「StepCounterSensorController」の利用
●スクリプト(StepCounterSensorController)での利用
■心拍数センサー(Heart Rate Sensor)を使う
●プレファブ「HeartRateController」の利用
●スクリプト(HeartRateController)での利用
■センサーの値の仕様など
■更新履歴
(※) Unity 5.6.3p1 - 2017.3.0f3 / Windows10(x64) / Galaxy S7 Edge (Android 7.0) で確認
■歩数センサー(Step Counter Sensor)を使う
歩数センサーは歩く度にカウントアップされるセンサーだ。いわゆる歩数計である。大まかにはあらかじめ用意してあるプレファブを利用する方法とスクリプトを書く方法があるが、両方解説しておこう。基本的にはプレファブとその「~Controller」スクリプトを使う方が簡単だろう。自分で細かく制御したいときには直接スクリプトを書く感じにすれば良いと思う。
ちなみに歩数センサーはある程度の速度で歩かないと検知しないようだ。ゆっくり歩いたり、あまり揺れないように動いたりすると反応しない。端末に搭載されているハードによっても違うらしいので、センサーを扱う場合はある程度値にレンジ幅を持たせた方が良いだろう(例えば照度センサーとか近接センサーなどは結構違うらしいので、きっちりした値で判別などすると、端末によって違う挙動になってしまう)。
●プレファブ「StepCounterSensorController」の利用
AssetStore版は「Assets/FantomPlugin/FantomLib/Prefabs/Sensors/」以下、GoogleDrive版は「Assets/FantomLib/Prefabs/Sensors/」以下にプレファブ「StepCounterSensorController」があるのでヒエラルキーに置こう。
以下はデモシーン「SensorTest」に使っているプレファブのキャプチャだが(掲載時点:ver.1.9)、簡単にパラメータの説明を書いておこう。

Sensor Delay | センサーの検出速度定数。具体的な速度は以下のようになっているが、実際には「可能であればより速く」受信される。センサーによっては常に一定のものもある。基本的にセンサー取得は高負荷なので、速度に問題ないなら遅い方が良い(※「Normal」推奨)。 ・Fastest:0ms ・Game:20ms (50fps) ・UI:66.6ms (15fps) ・Normal:200ms (5fps) |
---|---|
Start Listening On Enable | Unity のライフサイクル OnEnable() で自動的に開始される。このオプションに関わらず OnDisable(), OnDestroy(), OnApplicationQuit() では停止される。 |
On Sensor Changed | オリジナルのセンサーの値のコールバック。Android から送られてくる値そのままである。歩数センサーの場合、OS がリブートされてからのカウント数が返される(センサーを稼働している全アプリ共通となる)。詳細は後述を参照。 |
On Error | エラー時のコールバック。起動時(Start())に歩数センサーがサポートされてなかったら、エラーメッセージ「Not Supported: (センサーの種類)」が返される。 |
On Step Counter Sensor Changed | 適宜変換されたセンサーの値のコールバック。歩数センサーの場合、スクリプトが実行されてからの歩数となる。int 型に変換されている。 |
プレファブを利用する場合はヒエラルキーに置いてインスペクターで設定するだけだ。大ざっぱには「Start Listening On Enable」をオンにするか否かとコールバックを登録するくらいだろう。コールバックの値は「On Sensor Changed」「On Step Counter Sensor Changed」のどちらを使っても構わないが、アプリで実行してからの歩数を取得するなら「On Step Counter Sensor Changed」の方が簡単だろう。センサー系のプレファブには必ず2つの値を返すコールバックがあるが、元の値が「On Sensor Changed」、便宜上簡単に扱える値に変換(型なども)したものがもう1つのコールバックと考えて良い。
●スクリプト(StepCounterSensorController)での利用
クラス「StepCounterSensorController」を利用する場合は、おおよそ以下のように使うと考えて良い。簡略したものを書いておくので、適宜修正して手を加えて欲しい。
using FantomLib;
//※実際には FindObjectOfType は負荷の高い関数なので、インスペクタで予め登録できるようにしておくなど工夫した方が良いかも。
StepCounterSensorController stepConter = FindObjectOfType<StepCounterSensorController>();
if (stepConter != null && stepConter.IsSupportedSensor) { //サポートのチェック
stepConter.StartListening(); //取得開始
}
if (stepConter != null && stepConter.IsSupportedSensor) { //サポートのチェック
stepConter.ResetCount(); //0にする(OnStepCounterSensorChanged にのみ反映)
}
if (stepConter != null && stepConter.IsSupportedSensor) { //サポートのチェック
stepConter.StopListening(); //取得停止
}
なお、「~Controller」は一連の機能をまとめただけのものなので、AndroidPlugin を直接使う場合には以下のようになる。それぞれのコードは何らかのメソッドなどに書いてあると考えて欲しい。
using FantomLib;
//取得開始処理
#if !UNITY_EDITOR && UNITY_ANDROID
if (AndroidPlugin.IsSupportedSensor(SensorType.StepCounter)) { //サポートのチェック
AndroidPlugin.SetSensorListener(SensorType.StepCounter, SensorDelay.Normal, gameObject.name, "ReceiveValues");
}
#endif
//取得停止処理
#if !UNITY_EDITOR && UNITY_ANDROID
if (AndroidPlugin.IsSupportedSensor(SensorType.StepCounter)) { //サポートのチェック
AndroidPlugin.RemoveSensorListener(SensorType.StepCounter);
}
#endif
//値の取得(コールバックハンドラ)
void ReceiveValues(string json)
{
if (string.IsNullOrEmpty(json))
return;
SensorInfo info = JsonUtility.FromJson<SensorInfo>(json); //JSONから変換
if (info.type == (int)SensorType.StepCounter) {
//info.values(OS がリブートしてからの歩数:float 型)
//を用いて何らかの処理など
}
}
//センサーの解放
#if !UNITY_EDITOR && UNITY_ANDROID
AndroidPlugin.ReleaseSensors();
#endif
センサーの値は Android から Unity へ JSON の形式で送られる。そのフォーマットはセンサーの種類(int 型)とその値(float 型の配列)となっている。JSON 変換してるために余計負荷は高くなるので、Unity で標準的に使えるセンサー(Input.acceleration, compass, gyro)があったらそちらを使った方が良いだろう。ただし同じセンサーでも値は違ったりするので(型、ベクトルと四元数、符号など)注意して欲しい。詳細は後述の「センサーの値の仕様」や公式のデベロッパーマニュアルを参照して欲しい。
なお、プラグインでのセンサーリスニング(SetSensorListener)のコールバック登録は1つのみとなる。複数登録できないので注意して欲しい(常に上書きになるため、最後のものが有効になる)。複数のメソッドをコールバックハンドラにしたい場合は、インスペクタのコールバック(UnityEvent)に複数のメソッドを登録すれば良い。
■心拍数センサー(Heart Rate Sensor)を使う
心拍数(HeartRate)センサーは端末の裏に指を当てることによって(Galaxy S7 Edge の場合、裏面のカメラの横にあるセンサーに指を近づけると赤く光るので、そこにしばらく指を置く)心拍数(単位:bpm)を計測するセンサーである。他にも「HeartBeat」センサーというものもあるが、こちらは心拍数のピークを検出するものらしい(Galaxy S7 Edge には搭載されてないので未確認。一番高い心拍数を検出?)。
心拍数センサーを使う場合は、端末に搭載しているか否かもだが、それとは別に「バイタルサインの取得」パーミッションも必要になる。パーミッションが必要なものはアプリ起動時に以下のような確認メッセージが出るものがあるので注意しよう。また Google Play などに公開したときにも権限として表示される。アプリと関係ない権限を付けるとインストールを拒否られる確率も高くなるらしいので、最低限にすることを心がけた方が良いだろう。パーミッションの設定や Google Play でのフィルタリングなどは以前の記事に書いておいたので参照して欲しい。
・パーミッションの設定
<uses-permission android:name="android.permission.BODY_SENSORS"/>
・センサー利用時のフィルタリング(Google Play)
<uses-feature android:name="android.hardware.sensor.heart_rate" android:required="true" />

●プレファブ「HeartRateController」の利用
基本的には歩数センサーのプレファブとあまり変わらないので、設定パラメータはそちらを参照して欲しい。違いは「On Heart Rate Sensor Changed」コールバックくらいで、それだけ解説を載せておこう。なお、こちらもデモシーン「SensorTest」に置いてあるプレファブをキャプチャしたものである(掲載時点:ver.1.9)。

On Heart Rate Sensor Changed | 適宜変換されたセンサーの値のコールバック。心拍センサーの場合、1分間の心拍数[bpm] になる(float 型)。「On Sensor Changed」の values[0] と同じもの。 |
---|
●スクリプト(HeartRateController)での利用
考え方は「StepCounterSensor」の場合とほとんど変わらない。「HeartRateController」を利用する場合は、サポートに加えてパーミッションもチェックも加えているだけだ(※実際には心拍数センサーの場合、パーミッションが与えられてないとサポートも不可になる)。簡略したものを書いておくので、適宜手を加えて利用して欲しい。
using FantomLib;
//※実際には FindObjectOfType は負荷の高い関数なので、インスペクタで予め登録できるようにしておくなど工夫した方が良いかも。
HeartRateController heartRate = FindObjectOfType<HeartRateController>();
if (heartRate != null && heartRate.IsSupportedSensor && heartRate.IsPermissionGranted) { //サポートとパーミッションのチェック
heartRate.StartListening(); //取得開始
}
if (heartRate != null && heartRate.IsSupportedSensor && heartRate.IsPermissionGranted) { //サポートとパーミッションのチェック
heartRate.StopListening(); //取得停止
}
なお、「~Controller」は一連の機能をまとめただけのものなので、AndroidPlugin を直接使う場合には以下のようになる。それぞれのコードは何らかのメソッドなどに書いてあると考えて欲しい。
using FantomLib;
//取得開始処理
#if !UNITY_EDITOR && UNITY_ANDROID
if (AndroidPlugin.IsSupportedSensor(SensorType.HeartRate)
&& AndroidPlugin.CheckPermission("android.permission.BODY_SENSORS")) { //サポートとパーミッションのチェック
AndroidPlugin.SetSensorListener(SensorType.HeartRate, SensorDelay.Normal, gameObject.name, "ReceiveValues");
}
#endif
//取得停止処理
#if !UNITY_EDITOR && UNITY_ANDROID
if (AndroidPlugin.IsSupportedSensor(SensorType.HeartRate)
&& AndroidPlugin.CheckPermission("android.permission.BODY_SENSORS")) { //サポートとパーミッションのチェック
AndroidPlugin.RemoveSensorListener(SensorType.HeartRate);
}
#endif
//値の取得(コールバックハンドラ)
void ReceiveValues(string json)
{
if (string.IsNullOrEmpty(json))
return;
SensorInfo info = JsonUtility.FromJson<SensorInfo>(json); //JSONから変換
if (info.type == (int)SensorType.HeartRate) {
//info.values を用いて何らかの処理など
}
}
//センサーの解放
#if !UNITY_EDITOR && UNITY_ANDROID
AndroidPlugin.ReleaseSensors();
#endif
他のセンサーでも返ってくる値が違うだけで、やり方は同じようなものなので、色々使ってみると良いだろう。
以降にはセンサーを利用する際の共通な仕様を書いておくので、一読しておけば自分でスクリプトを組んだり、改造するときなどにも理解しやすいと思う。
■センサーの値の仕様など
詳細は公式のデベロッパーマニュアルを見て欲しいが、このプラグインでは基本的にセンサーの種類定数(ID:int 型)と取得したセンサーの値の配列(float[] 型)の2つになる。センサーの値に関してはその配列の長さはまちまちで、1つのものもあれば 15個あるものもある。値もトリガー系(だいたい名前が「~Detect」となっている)のものはトリガされたら「1.0」が送られるのみで、待機している間は何も送ってこないものもある。また、端末に搭載されているハードによっても値は異なるので、センサーを扱う場合はある程度値にレンジ幅を持たせた方が良いだろう(例えば照度センサーとか近接センサーなどは結構違うらしいので、きっちりした値で判別などすると、端末によって違う挙動になってしまう → 例えば照度センサーの場合「LIGHT_~」(Constant Value を使う)のように目安が定義されている)。自分で実装するときには注意しよう。
他にプレファブにもそれぞれのセンサー専用 Controller 以外にも「AndroidSensorController」「AndroidSensorIntController」というものが用意されている(~/FantomLib/Prefabs/Sensors/ 以下)。これらのプレファブも含めて「On Sensor Changed」コールバックの引数はセンサーの値をそのまま返すと考えて良い。「AndroidSensorIntController」の方はセンサーの種類定数が int 型になっているだけで内容は同じだ。SensorType にはデベロッパーマニュアルの値(Constant Value)をそのまま使っているが、例えばウェアラブルデバイスやタブレットなどで特殊なセンサーを搭載している場合には int値で指定すれば取得できることがある(通常のスマホでもデベロッパーマニュアルに載ってない ID のセンサーがいくつか搭載されている。ただしこれらは他のデバイスでは利用できないと考えた方が良い)。
(デベロッパーマニュアル)
・各センサーの定数値
・各センサーの取得値(values 配列に入る値)
それ以外にも「AndroidManifest.xml でのパーミッションの設定」や「Google Play に公開する際に、センサー利用のフィルタリング」も合わせて考えておいた方が良いだろう。そのあたりは以前の記事を参照して欲しい。
・パーミッションの設定
・センサー利用時のフィルタリング(Google Play)
※とりあえず試してみたい方は、最新版をビルドした apk デモをダウンロードできます。動作確認にもどうぞ。


Android 4.2以上
※「提供元不明アプリのインストール」許可が必要です。
(関連記事)
【Unity】AssetStore版 FantomPlugin のセットアップ
【Unity】Androidのトーストやダイアログ、通知、音声認識、ハード音量操作など基本的な機能を使えるプラグインを作ってみた
- 関連記事
トラックバック
トラックバックURL
→http://fantom1x.blog130.fc2.com/tb.php/294-b429d5ed
この記事にトラックバックする(FC2ブログユーザー)
| h o m e |