2016年11月22日火曜日

今回は前回実装したSpatial Mappingで作成された空間をXbox Oneコントローラーを使ってユニティちゃんを走らせてみたいと思います。


【12/01動画追加】【HoloLens開発】ユニティちゃんとHoloLensで戯れる - ゲームパッド編 -

今回は前回実装したSpatial Mappingで作成された空間をXbox Oneコントローラーを使ってユニティちゃんを走らせてみたいと思います。


2016年11月18日金曜日


今回はステレオカメラです。この機能自体はROSのパッケージを導入すれば実現可能ですが、よい結果を得るためにはキャリブレーション(校正)をしっかりと行うことがステレオ性能を左右する重要な要素となります。

今回はステレオカメラを良好に動作させるためのキャリブレーション方法について紹介いたします。

ROSで始めるロボティクス(9) ー ROSを使ったステレオカメラキャリブレーション


今回はステレオカメラです。この機能自体はROSのパッケージを導入すれば実現可能ですが、よい結果を得るためにはキャリブレーション(校正)をしっかりと行うことがステレオ性能を左右する重要な要素となります。

今回はステレオカメラを良好に動作させるためのキャリブレーション方法について紹介いたします。

2016年11月9日水曜日

今回は表示編で予告していた、HoloLensの「Spatial Mapping(空間認識)」を実装します。


【HoloLens開発】ユニティちゃんとHoloLensで戯れる - 空間認識編 -

今回は表示編で予告していた、HoloLensの「Spatial Mapping(空間認識)」を実装します。


2016年10月31日月曜日

前回はHololensにユニティちゃんを表示させただけでしたが、今回はそのユニティちゃんを音声認識で動かしたいと思います。


【HoloLens開発】ユニティちゃんとHoloLensで戯れる - 音声認識編 -

前回はHololensにユニティちゃんを表示させただけでしたが、今回はそのユニティちゃんを音声認識で動かしたいと思います。


2016年10月17日月曜日


ROSではロボットを目的の位置まで移動させるためのライブラリ群であるNavigationスタックが用意されています。自作のロボットでNavigationスタックが使えるようにしていきたいと思います。



ROSで始めるロボティクス(8) ー ロボットのナビゲーションを行う


ROSではロボットを目的の位置まで移動させるためのライブラリ群であるNavigationスタックが用意されています。自作のロボットでNavigationスタックが使えるようにしていきたいと思います。




前回までの作業でシミュレータ上で動くロボットが準備出来ましたが、今のままでは人が指示を出して動くただのラジコンでしかありません。
ここからは、障害物を避けながら目的の位置まで自立で移動するようにしていきましょう。

まずは地図を用意します。人間でも知らない場所に行く時には事前に地図を確認しますよね。ロボットにも同じように地図が必要になります。

ROSで始めるロボティクス(7) ー ロボットのための二次元mapを作る


前回までの作業でシミュレータ上で動くロボットが準備出来ましたが、今のままでは人が指示を出して動くただのラジコンでしかありません。
ここからは、障害物を避けながら目的の位置まで自立で移動するようにしていきましょう。

まずは地図を用意します。人間でも知らない場所に行く時には事前に地図を確認しますよね。ロボットにも同じように地図が必要になります。

PMD CamBoard pico flexxは3D形状を認識することが可能な非常に小型のToFセンサーです。たまたま別部署用に購入していたものを借りることが出来ましたので、色々試してみました。

このセンサーはとにかく小さいです。ミントケースの半分ぐらいのセンサーで十分な解像度のToFセンサーなので、使い勝手は最高です。早速、ロボットのセンサーに使うため、ROSで使えるように環境を整えていきましょう。



ROSで始めるロボティクス(6) ー ROSでデプスカメラPMD CamBoard pico flexxを使う


PMD CamBoard pico flexxは3D形状を認識することが可能な非常に小型のToFセンサーです。たまたま別部署用に購入していたものを借りることが出来ましたので、色々試してみました。

このセンサーはとにかく小さいです。ミントケースの半分ぐらいのセンサーで十分な解像度のToFセンサーなので、使い勝手は最高です。早速、ロボットのセンサーに使うため、ROSで使えるように環境を整えていきましょう。




ロボットに使用される定番センサーとしてステレオカメラやレーザーレンジファインダーなどがあります。これらを使うことで、ロボットの周囲の環境を判定し、ロボットの動作を決めることができるようになり、ロボットの自立制御の第一歩となります。
センサーのその他の選択として、マイクロソフト社Kinectやインテル社のRealSenseといった、デプスカメラなどが挙げられます。今回はロボットシミュレータにデプスカメラを追加していきます。



ROSで始めるロボティクス(5) ー GazeboでToFセンサーをシミュレーションする


ロボットに使用される定番センサーとしてステレオカメラやレーザーレンジファインダーなどがあります。これらを使うことで、ロボットの周囲の環境を判定し、ロボットの動作を決めることができるようになり、ロボットの自立制御の第一歩となります。
センサーのその他の選択として、マイクロソフト社Kinectやインテル社のRealSenseといった、デプスカメラなどが挙げられます。今回はロボットシミュレータにデプスカメラを追加していきます。




ロボットシミュレータとしてGazeboを使用します。Gazeboはオープンソースで開発されたロボットアプリケーション開発のための動力学シミュレータです。ROSとも連携しており、モータのみならず、ToFセンサやカメラなどもシミュレーション出来ます。


ROSで始めるロボティクス(4) ー シミュレータ上でロボットを動かしてみる


ロボットシミュレータとしてGazeboを使用します。Gazeboはオープンソースで開発されたロボットアプリケーション開発のための動力学シミュレータです。ROSとも連携しており、モータのみならず、ToFセンサやカメラなどもシミュレーション出来ます。



実際のロボットを動かす前に、シミュレータで動かしてみましょう。
まずは、ロボットのモデリングです。

次のような2つのモーターと2つの車輪で動作する移動ロボットを定義しましょう。




ROSで始めるロボティクス(3) ー 差動二輪ロボットを準備する


実際のロボットを動かす前に、シミュレータで動かしてみましょう。
まずは、ロボットのモデリングです。

次のような2つのモーターと2つの車輪で動作する移動ロボットを定義しましょう。





それではROSの開発環境をインストールしていきます。現在ROSの最新バージョンは「Kinetic Kame」ですが、ここでは「Indigo Igloo」を使用します。というのも、このバージョンはユーザーも多く、サポートする周辺のライブラリも多いため、最初はこのバージョンを選択しておくのが無難だからです。

ROSのサイト。http://www.ros.org/ ROSに関する情報はこのサイトを確認しよう。


ROSで始めるロボティクス(2) ー ROSのインストールとセットアップ


それではROSの開発環境をインストールしていきます。現在ROSの最新バージョンは「Kinetic Kame」ですが、ここでは「Indigo Igloo」を使用します。というのも、このバージョンはユーザーも多く、サポートする周辺のライブラリも多いため、最初はこのバージョンを選択しておくのが無難だからです。

ROSのサイト。http://www.ros.org/ ROSに関する情報はこのサイトを確認しよう。



皆さんは、「ロボット開発」と聞いてどんなイメージをお持ちでしょうか。「難しい」「専門知識が必要」「大量のプログラミングが必要」そんなイメージの方も多いのではないでしょうか。本連載ではROSを使用することで手軽に「ロボット開発」を行います。ROSではロボットの「シミュレータ」環境も充実しており、「動作するロボット」がなくても開発することが可能です。
本連載ではROSを使って差動二輪ロボットを作成し、シミュレータ上でうごかしていきます。連載を通じてROSのイメージを掴んていくことができます。また実際のToFセンサーも扱います。実際に動くロボットも作成していきます。



ROSで始めるロボティクス(1) ー The Robot Operating System


皆さんは、「ロボット開発」と聞いてどんなイメージをお持ちでしょうか。「難しい」「専門知識が必要」「大量のプログラミングが必要」そんなイメージの方も多いのではないでしょうか。本連載ではROSを使用することで手軽に「ロボット開発」を行います。ROSではロボットの「シミュレータ」環境も充実しており、「動作するロボット」がなくても開発することが可能です。
本連載ではROSを使って差動二輪ロボットを作成し、シミュレータ上でうごかしていきます。連載を通じてROSのイメージを掴んていくことができます。また実際のToFセンサーも扱います。実際に動くロボットも作成していきます。



2016年9月6日火曜日

UnityもVisual Studioも触ったことのなかった筆者が、Unity公式キャラクターである『ユニティちゃん』を使ってHololens開発をしてみます。その第1回目としてユニティちゃんをHoloLensで表示してみます。


【HoloLens開発】ユニティちゃんとHololensで戯れる - 表示編 -

UnityもVisual Studioも触ったことのなかった筆者が、Unity公式キャラクターである『ユニティちゃん』を使ってHololens開発をしてみます。その第1回目としてユニティちゃんをHoloLensで表示してみます。


2016年8月29日月曜日


HoloLensの肝であるHPUチップは○○で出来ていた!?

法人向けHoloLens(Commercial Suite)が発売!追加された新機能とは?等の最新情報に加え、HoloLensに関する基本的な知識を今回の記事で書いていきます。次回、Part3の記事では、遂にHoloLens開発の中身を書いていきますのでご期待ください!
連載目次
Part 2: 【HoloLens開発】日本での発売に備える実機開発 - 基礎知識編 - ←本記事
Part 8: 【HoloLens開発】ユニティちゃんとHoloLensで戯れる - シェアリング編2 - (予定)
本記事目次

【HoloLens開発】日本での発売に備える実機開発 基礎知識編


HoloLensの肝であるHPUチップは○○で出来ていた!?

法人向けHoloLens(Commercial Suite)が発売!追加された新機能とは?等の最新情報に加え、HoloLensに関する基本的な知識を今回の記事で書いていきます。次回、Part3の記事では、遂にHoloLens開発の中身を書いていきますのでご期待ください!
連載目次
Part 2: 【HoloLens開発】日本での発売に備える実機開発 - 基礎知識編 - ←本記事
Part 8: 【HoloLens開発】ユニティちゃんとHoloLensで戯れる - シェアリング編2 - (予定)
本記事目次

2016年8月19日金曜日

HoloLensは13m先の壁まで認識できる!?


HoloLensの実機を使ったからこそ分かったことを装着感・空間把握・視野・酔い・ジェスチャー操作・HoloLensに向いている用途・向いていない用途という7項目に分けて書いていきます。


連載目次
Part 1: 【HoloLens開発】日本での発売に備える実機開発 - 体験編 - ←本記事
Part 8: 【HoloLens開発】ユニティちゃんとHoloLensで戯れる - シェアリング編2 - (予定)

【HoloLens開発】日本での発売に備える実機開発 体験編

HoloLensは13m先の壁まで認識できる!?


HoloLensの実機を使ったからこそ分かったことを装着感・空間把握・視野・酔い・ジェスチャー操作・HoloLensに向いている用途・向いていない用途という7項目に分けて書いていきます。


連載目次
Part 1: 【HoloLens開発】日本での発売に備える実機開発 - 体験編 - ←本記事
Part 8: 【HoloLens開発】ユニティちゃんとHoloLensで戯れる - シェアリング編2 - (予定)

2016年6月3日金曜日

はじめに

Googleに買収された Firebase が、Googleサービスに統合されより使いやすく強力になりました。またFirebaseの持つリアルタイム性を生かした IoTプロジェクトも現れてきています。今回はI/Oに発表されずにいた小粒ななIoTプロジェクトに焦点を当て、Googleに統合されたFirebaseの設定やIoTとしての活用方法について紹介いたします。


Googleに統合されたFirebaseを使ってIoTとスマホの連携を実践する

はじめに

Googleに買収された Firebase が、Googleサービスに統合されより使いやすく強力になりました。またFirebaseの持つリアルタイム性を生かした IoTプロジェクトも現れてきています。今回はI/Oに発表されずにいた小粒ななIoTプロジェクトに焦点を当て、Googleに統合されたFirebaseの設定やIoTとしての活用方法について紹介いたします。


2016年4月25日月曜日

http://www.grocerycrud.com/より抜粋


CodeigniterのCRUD画面を自動生成してくれる便利なライブラリGrocery CRUDにチェックボックスで選択した項目を一括削除する機能を追加しましたので、その方法をブログにまとめました。
  エラーチェックをしていなかったりなどそのまま使うには不完全なところもありますので、適宜付け加えて使ってみてください。

CodeIgniterとGrocery CRUDに選択一括削除機能を付ける方法

http://www.grocerycrud.com/より抜粋


CodeigniterのCRUD画面を自動生成してくれる便利なライブラリGrocery CRUDにチェックボックスで選択した項目を一括削除する機能を追加しましたので、その方法をブログにまとめました。
  エラーチェックをしていなかったりなどそのまま使うには不完全なところもありますので、適宜付け加えて使ってみてください。

2016年3月23日水曜日



はじめに


Linkingが発表されてからおよそ3か月が経過して、Linkingを利用したいくつかのアプリがプレイストアにアップされています。その中には弊社がリリースした「忘れ物防止」や「迷子防止」、「お天気予報通知」アプリもあります。今回の記事では、Linkingを利用してどのように「忘れ物防止」や「迷子防止」、「お天気予報通知」のアプリが実現されているかの説明を行っていきたいと思います。

Linkingを利用したアプリの実装方法について



はじめに


Linkingが発表されてからおよそ3か月が経過して、Linkingを利用したいくつかのアプリがプレイストアにアップされています。その中には弊社がリリースした「忘れ物防止」や「迷子防止」、「お天気予報通知」アプリもあります。今回の記事では、Linkingを利用してどのように「忘れ物防止」や「迷子防止」、「お天気予報通知」のアプリが実現されているかの説明を行っていきたいと思います。

2015年12月10日木曜日


https://www.youtube.com/watch?v=vUbFB1Qypg8 より抜粋

本記事は以下の記事の続きになります。

[第一回] 生活で使えるBLEデバイス
[第二回] 生活で使えるBLEデバイス~ペアリング編~
[第三回] 生活で使えるBLE~アプリ間通信編~

はじめに

私事ですが、最近携帯をGalaxy S6に変更しました。(とても気に入っています)
しかしGalaxy S6は電池の容量が少ないらしく、日常的に使っていても少し電池の減りが早い気がします。
なんとか出来ないかと電池の消費などについて少し調べてみると、充電回数を減らすことや過充電を行わないことが電池の寿命を延ばすことに繋がるようです。

ということで、今回はBLEデバイスを使って少しでも携帯の電池寿命の延命を行いたいと思います。

環境
  • 端末
    • Nexus 5(Android 6.0)
BLEデバイスは鳴動可能で、物理ボタンがあるモノにしました。今後もいろいろ遊べそうです。

やりたいこと

1. 過充電を防いで電池の寿命を長く保ちたい。
2. 家の中で携帯をすぐ無くすので、居場所を特定したい。

イメージとしては以下のよう感じです。

1. 過充電防止

図1 過充電防止

2. 携帯の位置通知
図2 携帯の位置通知

BLEデバイスのサービスの確認
まず、購入したBLEデバイスを実際に接続してサービスを確認しましょう。
以下のようなサービスがあるようです。
サービス名
UUID
説明
Generic Access
1800
 デバイス名などの情報取得
Immediate Alert
1802
アラームを鳴らす
Link Loss
1803
接続が切れたときの挙動を設定する
Tx Power
1804
BLEの送信のパワー
Battery Service
180f
バッテリーの状態
Battery ServiceとImmediate Alertのサービスがあるので、やりたいことは実現出来そうです。
では、実際に作ってみましょう。

実際に作ってみる

1. 過充電防止

充電状態が90%を超えたら、BLEデバイスへ通知を送るようにしたい。
ただし、電源接続している時だけ通知が欲しいので、ACTION_POWER_CONNECTEDを契機に、バッテリーの状態を監視するサービスを常駐させるようにしたいと思います。

構成としては以下の通りです。

図3 過充電防止-構成

では次に、Android側の実装に移ります。

使用するUUID
サービスのImmediate Alertを使用します。
Alert Levelに値(0 or 1or 2)を設定することで通知を行えるようです。

public static final UUID ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
public static final UUID ALERT_LEVEL_UUID = UUID.fromString("00002a06-0000-1000-8000-00805f9b34fb");
AndroidManifestに宣言
<service android:name=".power.BatteryMonitorService" android:enabled="true"/>
<service android:name=".ble.BluetoothLeService" android:enabled="true"/>

<receiver android:name=".power.PowerConnectedReceiver" android:enabled="true" android:exported="false">
    <intent-filter>
            <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
            <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
    </intent-filter>
</receiver>
PowerConnectedReciverの実装
電源の接続/切断を受けるレシーバーで、電源接続を契機にバッテリーの監視を行い、電源の切断を契機にバッテリーの監視を終了します。
public class PowerConnectedReceiver extends BroadcastReceiver {

    private static final String TAG = "BleNotify.PowerConnectedReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "onReceive : " + intent.getAction());

        if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
            Intent serviceIntent = new Intent(context, BatteryMonitorService.class);
            context.startService(serviceIntent);
        } else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
            Intent serviceIntent = new Intent(context, BatteryMonitorService.class);
            context.stopService(serviceIntent);
        }
    }
}
BatteryMonitorServiceの実装
起動時にバッテリーの状態変化を監視するサービスで、バッテリーが90%以上になるとブロードキャストを送信します。
public class BatteryMonitorService extends Service {

    private static final String TAG = "BleNotify.BatteryMonitorService";
    private ChargingOnReceiver mChargingOnReceiver;
    private boolean isRegisteredChargingReceiver = false;

    class ChargingOnReceiver extends BroadcastReceiver {
        public void onReceive(Context context, Intent intent) {
            int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
            int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
            float batteryPct = level / (float)scale;
            Log.d(TAG, "change battery state : " + batteryPct*100 + "%");
            if (batteryPct > 0.9) {
                Intent notify = new Intent(BluetoothLeService.ACTION_CALL_BATTERY_NOTIFY);
                LocalBroadcastManager.getInstance(context).sendBroadcast(notify);
                Log.d(TAG, "send broadcast Notify");
            }
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
        mChargingOnReceiver = new ChargingOnReceiver();
        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        registerReceiver(mChargingOnReceiver, filter);
        isRegisteredChargingReceiver = true;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "starting the BatteryMonitorService.");
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "terminate the BatteryMonitorService.");
        // close process
        if (isRegisteredChargingReceiver) {
            unregisterReceiver(mChargingOnReceiver);
        }
        super.onDestroy();
    }
}
BLEデバイスへ通知
BattryMonitorServiceからの通知を受けて、BLEデバイスへアラームの鳴動要求を通知します。
public class BluetoothLeService  extends Service {

    private BluetoothGatt mBluetoothGatt;

    public final static String ACTION_CALL_BATTERY_NOTIFY =
            "com.brilliant.blenotify.ble.le.ACTION_CALL_BATTERY_NOTIFY";

〜中略〜
    class GattRequestReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d(TAG, "onReceive : " + intent.getAction());
            if (mBluetoothGatt == null) {
                Log.e(TAG, "GattService is not connected...");
                return;
            }

            if (ACTION_CALL_BATTERY_NOTIFY.equals(intent.getAction())) {
                BluetoothGattCharacteristic c =
                        getCharacteristic(GattAttributes.ALERT_SERVICE_UUID,
                                GattAttributes.ALERT_LEVEL_UUID);
                if (c != null) {
                    // 1 : vibrator
                    // 2 : sound 
                    int level = 2;
                    c.setValue(new byte[]{(byte) level});
                    mBluetoothGatt.writeCharacteristic(c);
                }
            }
        }
    }

    public BluetoothGattCharacteristic getCharacteristic(UUID sid, UUID cid) {
        BluetoothGattService s = mBluetoothGatt.getService(sid);
        if (s == null) {
            Log.w(TAG, "Service NOT found :" + sid.toString());
            return null;
        }
        BluetoothGattCharacteristic c = s.getCharacteristic(cid);
        if (c == null) {
            Log.w(TAG, "Characteristic NOT found :" + cid.toString());
            return null;
        }
        return c;
    }
このようにすることで、充電中で90パーセントを超えると音を鳴らして通知してくれます。
過充電を防ぐことで、電池の寿命を長持ちさせましょう。

2. 携帯の位置通知
次携帯の位置通知は、BLEデバイス側に物理ボタンがあるので、押された場合に端末側にて鳴動等で位置を知らせます。
今回は端末がバイブレーションするところまで作ります。

構成としては以下の通り。
図4 携帯の位置通知-構成


NotificationをONに設定
まずはBLEデバイスからの通知を受け取る為に設定を行います。
サービス内のキャラクタリスティックスにNotification設定をONにすることで、BLEデバイスからの通知を受けることが出来ます。
調べてみると、Battery Service内にある「00002a1b」から始まるキャラクタリスティックスがどうやらNotificationのプロパティを持っているようです。
このキャラクタリスティックスを利用すれば、BLEデバイスからの通知を受けることが出来そうです。
※取得したキャラクタリスティックスはBluetoothGattCharacteristic#getProperties()で確認出来ます。
Blutooth SIGで定義されているBattery ServiceにはBattery Levelしかいないようなので、カスタムで追加されているようです。

「Power State Lebel(00002a1b)」の参考:
https://groups.google.com/d/msg/android-group-japan/8PffzGRfMms/0gtEcPdjQY8J

public static final UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb");
public static final UUID BATTERY_LEVEL_STATE_UUID = UUID.fromString("00002a1b-0000-1000-8000-00805f9b34fb");
通知を受ける準備(NotificationをON)
BluetoothGattCharacteristic c =
        getCharacteristic(GattAttributes.BATTERY_SERVICE_UUID,
        GattAttributes.BATTERY_LEVEL_STATE_UUID);

if (c != null) {
    final int charaProp = c.getProperties();
    if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
        Log.d(TAG, "has PROPERTY_NOTIFY");
    }
    mBluetoothGatt.setCharacteristicNotification(c, true);
}
BLEデバイスから通知を受ける
通知はボタンを押された時だけに限定します。
通知されたデータの1byte目でボタンの状態がわかります。
public class BluetoothLeService  extends Service {

    public final static String ACTION_FINDME_NOTIFY =
            "com.brilliant.blenotify.ble.le.ACTION_FINDME_NOTIFY";

〜中略〜

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic) {
            UUID uuid = characteristic.getUuid();
            Log.e(TAG, "onCharacteristicChanged : " + characteristic.getUuid());
            if (GattAttributes.BATTERY_LEVEL_STATE_UUID.equals(uuid)) {
                // For all other profiles, writes the data formatted in HEX.
                final byte[] data = characteristic.getValue();
                Log.d(TAG, "BATTERY_LEVEL_STATE_UUID received : " + new String(data));
                if (data != null && data.length > 0) {
                    // if button pressed.
                    if (data[0] == 1) {
                        Intent intent = new Intent(ACTION_FINDME_NOTIFY);
                        sendBroadcast(intent);
                        Log.d(TAG, "send broadcast ACTION_FINDME_NOTIFY.");
                     } else {
                        Log.d(TAG, "Button is not pressed.");
                    }
                }
            } else {
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            }
        }
FindMeRecieverの実装
BLEデバイスから通知を受けたときの動作を実装します。
public class FindMeReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
        long[] pattern = {3000, 1000, 3000, 1000};
        vibrator.vibrate(pattern, -1);
    }
}
AndrodManifestにも以下を追加しておきます。
<uses-permission android:name="android.permission.VIBRATE"/>
<receiver android:name=".findme.FindMeReceiver" android:enabled="true" android:exported="false"/>
     <intent-filter/>
        <action android:name="com.brilliant.blenotify.ble.le.ACTION_FINDME_NOTIFY" />
     </intent-filter/>
</receiver/>

これで、BLEデバイスから通知があったら端末がブルブルと震えてくれるのでどこに置いたかわかるようになりました。

さいごに

以上で「生活で使えるBLEデバイス」シリーズは終了となります。
いかがでしたでしょうか。

BLEの接続方法から実際のデータ通信までの方法を紹介してきましたが、BLEを利用するにあたって多少の苦労がありました。
BLEデバイスの持っているプロファイルに関して、独自に追加されているサービスやキャラクタリスティックスは情報がなかったり、デバイス毎にどのサービスをどの機能に利用しているか等が不明だったりします。(今回で言うところのPower State Lebel)
BluetoothやBLEでの通信のとっつきにくさはこのあたりも関係しているような気がします。

しかし、コツさえ掴んでしまえばアイデア次第で自由なモノ作りが可能な為、様々な分野で活躍できる技術であると思います。
今回までの記事が、そのコツを掴むまでのお手伝いになれば幸いです。

[第四回] 生活で使えるBLEデバイス~実用編~


https://www.youtube.com/watch?v=vUbFB1Qypg8 より抜粋

本記事は以下の記事の続きになります。

[第一回] 生活で使えるBLEデバイス
[第二回] 生活で使えるBLEデバイス~ペアリング編~
[第三回] 生活で使えるBLE~アプリ間通信編~

はじめに

私事ですが、最近携帯をGalaxy S6に変更しました。(とても気に入っています)
しかしGalaxy S6は電池の容量が少ないらしく、日常的に使っていても少し電池の減りが早い気がします。
なんとか出来ないかと電池の消費などについて少し調べてみると、充電回数を減らすことや過充電を行わないことが電池の寿命を延ばすことに繋がるようです。

ということで、今回はBLEデバイスを使って少しでも携帯の電池寿命の延命を行いたいと思います。

環境
  • 端末
    • Nexus 5(Android 6.0)
BLEデバイスは鳴動可能で、物理ボタンがあるモノにしました。今後もいろいろ遊べそうです。

やりたいこと

1. 過充電を防いで電池の寿命を長く保ちたい。
2. 家の中で携帯をすぐ無くすので、居場所を特定したい。

イメージとしては以下のよう感じです。

1. 過充電防止

図1 過充電防止

2. 携帯の位置通知
図2 携帯の位置通知

BLEデバイスのサービスの確認
まず、購入したBLEデバイスを実際に接続してサービスを確認しましょう。
以下のようなサービスがあるようです。
サービス名
UUID
説明
Generic Access
1800
 デバイス名などの情報取得
Immediate Alert
1802
アラームを鳴らす
Link Loss
1803
接続が切れたときの挙動を設定する
Tx Power
1804
BLEの送信のパワー
Battery Service
180f
バッテリーの状態
Battery ServiceとImmediate Alertのサービスがあるので、やりたいことは実現出来そうです。
では、実際に作ってみましょう。

実際に作ってみる

1. 過充電防止

充電状態が90%を超えたら、BLEデバイスへ通知を送るようにしたい。
ただし、電源接続している時だけ通知が欲しいので、ACTION_POWER_CONNECTEDを契機に、バッテリーの状態を監視するサービスを常駐させるようにしたいと思います。

構成としては以下の通りです。

図3 過充電防止-構成

では次に、Android側の実装に移ります。

使用するUUID
サービスのImmediate Alertを使用します。
Alert Levelに値(0 or 1or 2)を設定することで通知を行えるようです。

public static final UUID ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
public static final UUID ALERT_LEVEL_UUID = UUID.fromString("00002a06-0000-1000-8000-00805f9b34fb");
AndroidManifestに宣言
<service android:name=".power.BatteryMonitorService" android:enabled="true"/>
<service android:name=".ble.BluetoothLeService" android:enabled="true"/>

<receiver android:name=".power.PowerConnectedReceiver" android:enabled="true" android:exported="false">
    <intent-filter>
            <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
            <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
    </intent-filter>
</receiver>
PowerConnectedReciverの実装
電源の接続/切断を受けるレシーバーで、電源接続を契機にバッテリーの監視を行い、電源の切断を契機にバッテリーの監視を終了します。
public class PowerConnectedReceiver extends BroadcastReceiver {

    private static final String TAG = "BleNotify.PowerConnectedReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "onReceive : " + intent.getAction());

        if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
            Intent serviceIntent = new Intent(context, BatteryMonitorService.class);
            context.startService(serviceIntent);
        } else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
            Intent serviceIntent = new Intent(context, BatteryMonitorService.class);
            context.stopService(serviceIntent);
        }
    }
}
BatteryMonitorServiceの実装
起動時にバッテリーの状態変化を監視するサービスで、バッテリーが90%以上になるとブロードキャストを送信します。
public class BatteryMonitorService extends Service {

    private static final String TAG = "BleNotify.BatteryMonitorService";
    private ChargingOnReceiver mChargingOnReceiver;
    private boolean isRegisteredChargingReceiver = false;

    class ChargingOnReceiver extends BroadcastReceiver {
        public void onReceive(Context context, Intent intent) {
            int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
            int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
            float batteryPct = level / (float)scale;
            Log.d(TAG, "change battery state : " + batteryPct*100 + "%");
            if (batteryPct > 0.9) {
                Intent notify = new Intent(BluetoothLeService.ACTION_CALL_BATTERY_NOTIFY);
                LocalBroadcastManager.getInstance(context).sendBroadcast(notify);
                Log.d(TAG, "send broadcast Notify");
            }
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
        mChargingOnReceiver = new ChargingOnReceiver();
        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        registerReceiver(mChargingOnReceiver, filter);
        isRegisteredChargingReceiver = true;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "starting the BatteryMonitorService.");
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "terminate the BatteryMonitorService.");
        // close process
        if (isRegisteredChargingReceiver) {
            unregisterReceiver(mChargingOnReceiver);
        }
        super.onDestroy();
    }
}
BLEデバイスへ通知
BattryMonitorServiceからの通知を受けて、BLEデバイスへアラームの鳴動要求を通知します。
public class BluetoothLeService  extends Service {

    private BluetoothGatt mBluetoothGatt;

    public final static String ACTION_CALL_BATTERY_NOTIFY =
            "com.brilliant.blenotify.ble.le.ACTION_CALL_BATTERY_NOTIFY";

〜中略〜
    class GattRequestReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d(TAG, "onReceive : " + intent.getAction());
            if (mBluetoothGatt == null) {
                Log.e(TAG, "GattService is not connected...");
                return;
            }

            if (ACTION_CALL_BATTERY_NOTIFY.equals(intent.getAction())) {
                BluetoothGattCharacteristic c =
                        getCharacteristic(GattAttributes.ALERT_SERVICE_UUID,
                                GattAttributes.ALERT_LEVEL_UUID);
                if (c != null) {
                    // 1 : vibrator
                    // 2 : sound 
                    int level = 2;
                    c.setValue(new byte[]{(byte) level});
                    mBluetoothGatt.writeCharacteristic(c);
                }
            }
        }
    }

    public BluetoothGattCharacteristic getCharacteristic(UUID sid, UUID cid) {
        BluetoothGattService s = mBluetoothGatt.getService(sid);
        if (s == null) {
            Log.w(TAG, "Service NOT found :" + sid.toString());
            return null;
        }
        BluetoothGattCharacteristic c = s.getCharacteristic(cid);
        if (c == null) {
            Log.w(TAG, "Characteristic NOT found :" + cid.toString());
            return null;
        }
        return c;
    }
このようにすることで、充電中で90パーセントを超えると音を鳴らして通知してくれます。
過充電を防ぐことで、電池の寿命を長持ちさせましょう。

2. 携帯の位置通知
次携帯の位置通知は、BLEデバイス側に物理ボタンがあるので、押された場合に端末側にて鳴動等で位置を知らせます。
今回は端末がバイブレーションするところまで作ります。

構成としては以下の通り。
図4 携帯の位置通知-構成


NotificationをONに設定
まずはBLEデバイスからの通知を受け取る為に設定を行います。
サービス内のキャラクタリスティックスにNotification設定をONにすることで、BLEデバイスからの通知を受けることが出来ます。
調べてみると、Battery Service内にある「00002a1b」から始まるキャラクタリスティックスがどうやらNotificationのプロパティを持っているようです。
このキャラクタリスティックスを利用すれば、BLEデバイスからの通知を受けることが出来そうです。
※取得したキャラクタリスティックスはBluetoothGattCharacteristic#getProperties()で確認出来ます。
Blutooth SIGで定義されているBattery ServiceにはBattery Levelしかいないようなので、カスタムで追加されているようです。

「Power State Lebel(00002a1b)」の参考:
https://groups.google.com/d/msg/android-group-japan/8PffzGRfMms/0gtEcPdjQY8J

public static final UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb");
public static final UUID BATTERY_LEVEL_STATE_UUID = UUID.fromString("00002a1b-0000-1000-8000-00805f9b34fb");
通知を受ける準備(NotificationをON)
BluetoothGattCharacteristic c =
        getCharacteristic(GattAttributes.BATTERY_SERVICE_UUID,
        GattAttributes.BATTERY_LEVEL_STATE_UUID);

if (c != null) {
    final int charaProp = c.getProperties();
    if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
        Log.d(TAG, "has PROPERTY_NOTIFY");
    }
    mBluetoothGatt.setCharacteristicNotification(c, true);
}
BLEデバイスから通知を受ける
通知はボタンを押された時だけに限定します。
通知されたデータの1byte目でボタンの状態がわかります。
public class BluetoothLeService  extends Service {

    public final static String ACTION_FINDME_NOTIFY =
            "com.brilliant.blenotify.ble.le.ACTION_FINDME_NOTIFY";

〜中略〜

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic) {
            UUID uuid = characteristic.getUuid();
            Log.e(TAG, "onCharacteristicChanged : " + characteristic.getUuid());
            if (GattAttributes.BATTERY_LEVEL_STATE_UUID.equals(uuid)) {
                // For all other profiles, writes the data formatted in HEX.
                final byte[] data = characteristic.getValue();
                Log.d(TAG, "BATTERY_LEVEL_STATE_UUID received : " + new String(data));
                if (data != null && data.length > 0) {
                    // if button pressed.
                    if (data[0] == 1) {
                        Intent intent = new Intent(ACTION_FINDME_NOTIFY);
                        sendBroadcast(intent);
                        Log.d(TAG, "send broadcast ACTION_FINDME_NOTIFY.");
                     } else {
                        Log.d(TAG, "Button is not pressed.");
                    }
                }
            } else {
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            }
        }
FindMeRecieverの実装
BLEデバイスから通知を受けたときの動作を実装します。
public class FindMeReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
        long[] pattern = {3000, 1000, 3000, 1000};
        vibrator.vibrate(pattern, -1);
    }
}
AndrodManifestにも以下を追加しておきます。
<uses-permission android:name="android.permission.VIBRATE"/>
<receiver android:name=".findme.FindMeReceiver" android:enabled="true" android:exported="false"/>
     <intent-filter/>
        <action android:name="com.brilliant.blenotify.ble.le.ACTION_FINDME_NOTIFY" />
     </intent-filter/>
</receiver/>

これで、BLEデバイスから通知があったら端末がブルブルと震えてくれるのでどこに置いたかわかるようになりました。

さいごに

以上で「生活で使えるBLEデバイス」シリーズは終了となります。
いかがでしたでしょうか。

BLEの接続方法から実際のデータ通信までの方法を紹介してきましたが、BLEを利用するにあたって多少の苦労がありました。
BLEデバイスの持っているプロファイルに関して、独自に追加されているサービスやキャラクタリスティックスは情報がなかったり、デバイス毎にどのサービスをどの機能に利用しているか等が不明だったりします。(今回で言うところのPower State Lebel)
BluetoothやBLEでの通信のとっつきにくさはこのあたりも関係しているような気がします。

しかし、コツさえ掴んでしまえばアイデア次第で自由なモノ作りが可能な為、様々な分野で活躍できる技術であると思います。
今回までの記事が、そのコツを掴むまでのお手伝いになれば幸いです。

2015年11月27日金曜日

https://linkingiot.com/developer/#developers より引用
はじめに

NTTドコモ等の複数の国内企業が連携して「Linking」というプラットフォームが発表されました。

公開されたサイトを見てみると、どうやらLinkingとはIoT(Internet of Things)に関係するらしいフレーズが散りばめられています。
  • すべてのモノが、ネットでつながる
  • デバイス開発者も、アプリ開発者も、そしてユーザーも。
  • Linkingプラットフォームが、つくるをつなぐ。
さて、Linkingとは一体どういったものなのでしょうか。

すべてがつながる「Linking」とは

https://linkingiot.com/developer/#developers より引用
はじめに

NTTドコモ等の複数の国内企業が連携して「Linking」というプラットフォームが発表されました。

公開されたサイトを見てみると、どうやらLinkingとはIoT(Internet of Things)に関係するらしいフレーズが散りばめられています。
  • すべてのモノが、ネットでつながる
  • デバイス開発者も、アプリ開発者も、そしてユーザーも。
  • Linkingプラットフォームが、つくるをつなぐ。
さて、Linkingとは一体どういったものなのでしょうか。

Related Posts Plugin for WordPress, Blogger...