固定Beaconを使って現在位置を測位するアプリをDelphi/C++BuilderとBeaconFenceで作る

これは [Delphi Advent Calendar 2016](http://qiita.com/advent-calendar/2016/delphi) 17日目の記事です。

また、前回の記事 [ビーコンの距離測定精度を上げるためのキャリブレーションを行うアプリをDelphiで作る](http://qiita.com/kazinoue/items/fefe996df6e39d6f0381) の続きでもあります。

# 前回の内容のフォローアップ
前回の記事の投稿時点では Beacon の RSSI を取得するだけのカンタンなアプリを作るところまでを書いていましたが、これだけでは使い勝手がイマイチです。

そのため「RSSIの値から TxPower の最適値を自動で算出するアプリ」というものを作ってみました。[このアプリのソースコードへのリポジトリを前回の記事に追記しています](http://qiita.com/kazinoue/items/fefe996df6e39d6f0381#%E3%82%82%E3%81%86%E3%81%A1%E3%82%87%E3%81%A3%E3%81%A8%E3%81%BE%E3%81%A8%E3%82%82%E3%81%AA%E6%B8%AC%E5%AE%9A%E3%82%92%E8%A1%8C%E3%81%86%E3%81%AB%E3%81%AF)。実際のキャリブレーションではそちらをお使い頂くと良いでしょう。

# BeaconFence とは何か？ そしてライセンスはどうなっているのか？

## BeaconFence = iBeacon を用いた屋内測位のためのコンポーネント

[BeaconFence](https://www.embarcadero.com/jp/products/beaconfence) は、Delphi/C++Builder で iBeacon を用いた屋内測位のためのコンポーネントです。

BeaconFence の特徴は

- 専用のマップエディタで使用場所の縦横の長さを設定し、
- マップ上にビーコンを配置するだけで
- スマートフォンやタブレットで屋内の現在位置を示すアプリを作ることができる
- しかも測位のための計算はすべてコンポーネント側にお任せ

という点にあります。

## ライセンスはどうなってんの？

RAD Studio/Delphi/C++Builder 10.2 Tokyo Release 2 以降の Enterprise では、BeaconFence １拠点（ビーコン数上限なし、面積制限なし）のライセンスが付帯します。

これは正確にいうと、以下のようになります。

- 10.2 Update 2 Enterprise からは RAD Server Single Site License １ライセンスが付帯する
- RAD Server Single Site License には BeaconFence の運用ライセンスも含まれている

このような理由により、10.2.2 以降なら BeaconFence も使えます。


これより前のバージョンや、Enterprise ではないエディションをご利用の場合は、次の２つの選択肢があります。

- BeaconFence はライセンスを購入していなくても、 150m<sup>2</sup>（約12.24m四方）までの面積にビーコン3つを配置しての試用が可能です。
- 本番向けに利用する場合は、RAD Server Single Site License を購入することができます。


そこで、この記事でもビーコン３つを使った試用を行ってみます。ビーコンの現物がない場合は、このシリーズの過去記事を参照してスマートフォンやタブレットをビーコンにすることができます。

# 事前準備

予め行っておく作業は以下のとおりです。

+ エリアの縦横の長さを測る
+ エリアの見取り図を作る
+ 使用する Beacon の UUID, Major, Minor を確認しておく

これらは特別な作業は含みませんので説明を省略します。

# 位置測位を作るために必要なこと（BeaconFenceを使わない場合）
BeaconFenceの話を進める前に、めんどくさい話をあえて書きます。
## 三辺測量の知識が必要
平面（２次元）での位置測位のためには、３つの基準点からの距離が正確に分かっていることが必要です。

+ １つの基準点からの距離 r<sub>1</sub>が分かっていると、その基準点から半径 r<sub>1</sub> の円の円周上のどこかにいるはずです。この円を "円r<sub>1</sub>" と表記することにします。
+ ２つの基準点からの距離 r<sub>1</sub> と r<sub>2</sub> が分かっていると、"円r<sub>1</sub> と 円r<sub>2</sub>" の円周が重なり合う交点のどこかにいるはずです。通常なら、この交点は２つ存在します。例外なのは "円r<sub>1</sub> と 円r<sub>2</sub>" が１箇所で接している場合です。
+ ３つの基準点からの距離 r<sub>1</sub>, r<sub>2</sub>, r<sub>3</sub> が分かっていると、３つの円の円周の交点にいるはずです。これは１箇所しか存在し得ません。

このように、３つの基準点からの距離が正確に分かっていれば位置が決まります。ここまでの話は中学生や高校生の数学でも出てきそうな話ですね。

ちなみに余談ではありますが、カーナビでの位置測位では４つのGPS衛星を使います。カーナビは空間（３次元）の位置決めをせねばならないからです。

## 電波強度から距離を計算する方法の知識が必要
「フリスの伝達公式」について調べてください。そして、ビーコンの TxPower と RSSI から実際に距離を計算してみると実感できると思うのですが、機器を安定的な状態に置いていても RSSI が変動することがわかります。そして RSSI から算出できる距離も当然のように変動しています。

## 確率統計の知識が必要
ビーコンを使った位置決めでは、そもそもビーコンからの距離計算自体が常時変動しています。だから理論上の計算とは違って、正確に位置測位を行うことは不可能です。３つの円の交わった場所は１点に収束せず、一定の面積のエリアを示していることでしょう。

したがって「３つの円が交わったエリアに対して時間軸の変化を重ねた時に、重なりが最も多い場所にいた可能性が高い」などのロジックで場所を推測せねばなりません。

このような位置決めでは確率統計の知識が不可欠です。さて、そろそろうんざりしていませんか？

# 位置測位を作るために必要なこと（BeaconFenceを使う場合）
BeaconFenceを使えば、三辺測量とか、フリスの伝達公式とか、確率統計の話は出てきません。BeaconFenceがこれらを全てやってくれます。必要なことは、固定ビーコンを使いたいエリアの見取り図を用意して、ビーコンの配置を決めるだけです。

# BeaconFence で位置測位アプリを作る
## BeaconFenceをインストールする
BeaconFenceはDelphi/C++Builder/RAD Studioを普通にインストールしただけでは含まれていません。GetItパッケージマネージャーから追加する必要があります。IDE起動後の画面で「GetItからアドオンを取得」を選ぶか、または [ツール]=>[GetItパッケージマネージャー]を選択します。
![image](https://qiita-image-store.s3.amazonaws.com/0/149350/4275a3b8-5011-6b69-2e1d-f14f9586127d.png)

GetItパッケージマネージャーで、カテゴリーより [Internet Of Things] を選ぶと以下のような表示となっていることでしょう。
![image](https://qiita-image-store.s3.amazonaws.com/0/149350/5264d402-5640-960f-400e-e4765a80fb69.png)

ここで[BeaconFence]の[インストール]をクリックするとダウンロードとインストールが行われます。

GetItパッケージマネージャーに BeaconFence が出てこない方は、大変申し訳ないのですが、ここで終了です……。Delphi/C++Builderではエディションにより BeaconFence の利用の可否が異なります。

ですが、以下の内容をご一読いただければ、BeaconFence による測位アプリがとても簡単に作れることがわかると思いますので、ぜひお目通しを。

## 新規プロジェクトを開く
新規プロジェクトは「マルチデバイスアプリケーションの新規作成」を選びます。「マルチデバイスアプリケーション」ではWindows/macOS/iOS/Android向けのプログラムを単一のソースコードから生成できます。このときのフレームワークは FireMonkey というものが用いられます。これはXamarin.Forms みたいなものだと思ってもらえればよいのかも（Xamarin使ったことないけど）。ここでは Delphi をベースに説明しますが、C++で作成することもできます。
![image](https://qiita-image-store.s3.amazonaws.com/0/149350/b373e51b-b5f7-2447-c90a-ddff557c6757.png)

マルチデバイスアプリケーションを選ぶと、さらにいくつかのテンプレートが選択できます。ここでは「空のアプリケーション」を選んでみます。
![image](https://qiita-image-store.s3.amazonaws.com/0/149350/7427384b-5986-87d1-bc84-7250ddb87ccd.png)

そうすると、IDEの画面はこのようになります。それでは作業を始めてみましょう。
![image](https://qiita-image-store.s3.amazonaws.com/0/149350/cb3b9e9f-a49c-7b24-75fc-79f4303653ef.png)

## コンポーネントをフォームに配置する
さて、フォームに対して以下の４種類のコンポーネントを載せていきます。コンポーネントは右下のツールパレットから選んでダブルクリックするか、またはドラッグ＆ドロップします。
![image](https://qiita-image-store.s3.amazonaws.com/0/149350/8fff982c-d88a-94d4-6cca-f8c3b10f7abe.png)

これらのコンポーネントの配置を３次元的に図にすると、こういう感じです。
![image](https://qiita-image-store.s3.amazonaws.com/0/149350/652536e9-552c-597b-2c1b-c56fe016c4e0.png)

### TRectangle を配置する。
Form の上に Rectangle を配置します。Rectangle はナビアプリの描画領域として使いますので、できるだけ大きく表示させたいです。この場合はプロパティの Align = Client と設定しておきます。

![image](https://qiita-image-store.s3.amazonaws.com/0/149350/82efe979-3739-c374-c96c-f7d3595e11f5.png)


### TLayout を配置する
TLayout はアプリの下部のフッタ領域として使用します。画面の下部に配置する場合は Align = Bottom と設定します。
![image](https://qiita-image-store.s3.amazonaws.com/0/149350/873cc69c-e175-851b-c48a-e1c13146bfc8.png)

### TMemo を配置する
さらに TMemo を TLayout の上に載せます。TMemo は動作に関するメッセージの表示領域として使います。TLayout を選んだ状態で載せます。

TMemo は Align = Client にします。
![image](https://qiita-image-store.s3.amazonaws.com/0/149350/feaeabb4-24d4-79d8-e206-5d132d5ea3ad.png)

また、編集機能を無効にするために Locked = True にします。
![image](https://qiita-image-store.s3.amazonaws.com/0/149350/26cb249b-fb10-6996-84af-fd5221202160.png)


### BeaconMapFencing を配置する
ここまでの作業で表示用のコンポーネントの配置ができましたので、最後に BeaconFence (BeaconMapFencing) を配置します。BeaconFence のコンポーネント自体は描画の機能を持たない「非ビジュアルコンポーネント」ですので、フォーム上のどこに配置しても構いませんが、ツールパレットで選んでダブルクリックするとフォームの中央に配置されます。

![image](https://qiita-image-store.s3.amazonaws.com/0/149350/1e24d985-f230-eedb-eabd-1bd5e3b9460e.png)

そして BeaconMapFencing については、下記３つのプロパティを調整します。

+ PaintContol
+ Enabled
+ MapOptions

Enabled = True にしておくと、アプリ起動時から BeaconFence が有効になります。また、MapOptions はすべての項目を True にしておくと動作が分かりやすくなります。PaintControlはBeaconFenceの描画を受けるコンポーネントを指定します。ここではRectangleを指定しておきます。

![image](https://qiita-image-store.s3.amazonaws.com/0/149350/1797feec-60ec-9c54-dcf5-55e7bc64bcea.png)

### BeaconMapFencing のマップを編集する
フォーム上の BeaconMapFencing のコンポーネントをダブルクリックすると、マップエディタが開きます。

![image](https://qiita-image-store.s3.amazonaws.com/0/149350/ba99eddf-2f5c-0185-ca86-5fad27095524.png)

ここでメニューアイコンの一番左をクリックすると、新規のマップが作られます。新規マップが開いたら「エリアの見取り図の画像」を指定し、「幅と高さの長さ」を設定します。

これらの作業が終わると、マップエディタはこのような画面になっていることでしょう。
![image](https://qiita-image-store.s3.amazonaws.com/0/149350/0bd4a7e8-211f-71dc-2473-f6f1f84d2866.png)

それではいよいよビーコンを配置します。メニューから Create Beacon を選ぶとビーコンを配置できます。マウスでビーコンの位置を決めてクリックすると配置されます。配置が終了したら ESC を押すと配置作業は完了です。
![image](https://qiita-image-store.s3.amazonaws.com/0/149350/96d0aeb2-ab7f-15a2-cde4-4a5a0056284f.png)
配置したビーコンは UUID, Major, Minor が未設定の状態ですので、実際に配置するビーコンの情報を設定してください。

ここまで終わったら、念のために３つのビーコンに識別用の情報が適切に設定されているかどうかを再度確認の上で、マップエディタを閉じます。ウィンドウ右上の[閉じる]ボタンを押すと作成したマップを保存するかどうかを聞いてきますので[はい]を選びます。
![image](https://qiita-image-store.s3.amazonaws.com/0/149350/87a120df-fa05-e060-72ee-9bc0a8ed01a7.png)

## 実機にデプロイする。

この状態でコードは１行も書いていませんが、位置測位のアプリはこれで最低限のものは完成した状態です。これを実機にデプロイしてみましょう。

なお、Android 向けにデプロイする場合は「使用する権限の設定」が必要です。[プロジェクト]の[オプション]より、ビルドターゲット Android を選択し、[使用する権限]で「Bluetooth」と「Bluetooth管理」を True にします。
![image](https://qiita-image-store.s3.amazonaws.com/0/149350/aa98d5a8-1218-1005-e6d7-c6c6beb0a22f.png)

さて、これを実際にデプロイして実行してみます。IDEの画面でターゲットを選んで[実行]ボタンを押すだけです。

Androidの場合はUSBデバッグを有効にした機材をUSBケーブルでIDE実行中の機材に直接接続します。

![image](https://qiita-image-store.s3.amazonaws.com/0/149350/046f1275-d115-4737-eaf3-60ac9457b92d.png)

なお、iOSでは「XCodeをインストールしたmac」に「PAServer」をインストールして「IDEとPAServerが通信できる状態」に設定しておくことが必要です。また原則として iOS 向けの実機デプロイでは Apple Developer Network への加入等が必要です。これらの説明はここでは省略しています。

また、iOS 向けにデプロイする場合には1点だけ注意があります。Delphi/C++Builder 10.1 Berlin の Update 1 と Update 2 を利用中の場合は iOS 64bit 向けのビルドが失敗します。これは Update 1 と Update 2 のパッケージングが腐っているようなので、利用者側での対処方法ができません。この問題はR&D側に報告済みですので、R&D側の対応待ちです。幸いなことに（？）BeaconFenceはGetItからインストールするコンポーネントですから、本件の対応はおそらくはR&D側の対処が完了したらGetItでの入れ直しで済むと思われます。 


さて、実機へのデプロイを行うと、このような画面でアプリが動きます。

![image](https://qiita-image-store.s3.amazonaws.com/0/149350/1a0a5423-c556-3172-390b-2d08b42f5a77.png)

色の判例はざっくり書くとこんな感じです。

+ 黒丸は計算上の位置です。（10.1 Berlin以降では色をプロパティで変更可能）
+ 紫色は補正後の位置です。（10.1 Berlin以降では色をプロパティで変更可能）
+ ビーコンは電波の受信状況によって色が変わります。白丸なら電波を受けていません。黄色や緑なら電波を受信できています。
+ ビーコンの周りの赤丸（塗りなし）は、電波を受信している雰囲気を描画しています。実際の動作ではビーコンの周囲に赤い円が広がっていくような動きをつけて描画しています。

これらを描画する、しないの設定は BeaconMapFencing のプロパティのうち [MapOptions] で変更可能です。初期値ではこれらを描画しませんが、今回は全てを True に変更しましたので、全て描画されています。本番運用では位置だけを表示するのが良いのですが、開発時は必要に応じて表示する項目を増やした方が良いかと思います。

また補正は近くのビーコンまたは「パス」に対して寄せるように補正が掛かります。今回は「パス」を設定していないのでビーコンに対しての補正だけが行われています。

## 出来上がった後に必要なこと
ビーコンを使った位置測位では、ビーコンの電波を反射吸収するような障害物の影響を減らすように配置を工夫することが必要です。また、その他の電波との干渉についても留意せねばなりません。これに関する説明だけで記事が１つ作れるくらいなので詳細は省略しますが、実際の利用では十分にキャリブレーションされたビーコンを用いたとしても現場でのビーコン配置の微調整は必須と考えておくべきです。

# 次回予告？
思ったよりも今回の内容はボリュームが大きくなってしまったので、いくつかの取りこぼしがあります。

せっかく配置した Memo を活用していなかったり、あるいは「パス」の機能も使えていませんので、次回は Memo に対して情報を出力したり、あるいは「パス」を定義して位置の補正を積極的に行う話をしつつ、位置情報のログをクラウド側に送信してデータロギングする話もしたいと考えています。

⇒ Delphi Advent Calendar 2016 24日目に「[IoTデバイスの計測値やiBeaconを利用した位置測位結果をGoogle Spreadsheetでリアルタイムに分析するためにGoogle Formを使う](http://qiita.com/kazinoue/items/55131d81ee75533bd1c4)」を書きました。