デコシノニッキ

ホロレンジャーの戦いの記録

外部デバイスを使わずHoloLensで位置情報取得を試みる【ダメだった話】

はい、ダメだったはなしです。

皆さんご存知の通り、HoloLensはGPSのってないので迷子に優しくないデバイスです。
ナビゲーションだけじゃなくて、GPSが使えると何が嬉しいかというと、開発でいつも頭を悩ませる位置合わせがオブジェクトそのものにリアル座標を設定してあげることで楽になる・・・かもしれない。

(この記事とか面白いですよ)
www.moguravr.com


今回挑戦したのは、Google Maps Geolocation APIを使ってHoloLensの位置情報をとってみるという試み。
developers.google.com

Geolocation APIではWifiのAccessPointを2点以上与えてあげると、現在地を返してくれるそうです。

最新のアプリ - UWP での Wi-Fi スキャナーのビルドでは、APIに必要なアクセスポイントの情報を取得する方法について書かれています。
まずはサンプルを実行してみましょう。以下からクローンして実行してみます。
github.com

f:id:haikage1755:20171218013225p:plain:w300
(写真には出さないけど、MacアドレスSSID、信号強度などがずらっと表示されます)

では、次にUnity側へ実装してみます。
今回の開発環境は、

  • Unity2017.1.2
  • VS2017

になります。

レポジトリから、

  • WiFiPointData.cs
  • WiFiScanner.cs
  • WiFiSignal.cs

をUnityProjectに引っ張ってきます。そのままだとwifi-scannerはビルドに引っかかるので#if UNITY_UWP ~ #endifで囲ってあげてください。

using System;
using System.Threading.Tasks;
#if UNITY_UWP
using Windows.Devices.Enumeration;
using Windows.Devices.WiFi;
#endif

namespace WiFiScannerUWP {
    public class WiFiScanner {
#if UNITY_UWP
        ~~~~~~
#endif

    }
}

それでは、MainPage.xaml.csを元にAPIを呼んでみます。

using System;
using System.Text;
using System.Collections.Generic;
using Newtonsoft.Json;
using UnityEngine;

#if UNITY_UWP
using System.Threading.Tasks;
using WiFiScannerUWP;
using System.Net.Http;
using Windows.Devices.WiFi;
using Windows.Devices.Geolocation;
#endif


public class Rootobject {
    public WifiAccessPoints[] wifiAccessPoints { get; set; }
}
public class WifiAccessPoints {
    public string macAddress { get; set; }
}


public class Response {
    public Location location { get; set; }
    public float accuracy { get; set; }
}

public class Location {
    public float lat { get; set; }
    public float lng { get; set; }
}

public class WiFiScanViewer : MonoBehaviour {

#if UNITY_UWP
    private WiFiScanner wifiScanner;
    private HttpClient httpClient = new HttpClient();
    List<WifiAccessPoints> wifiPoints;
#endif
    string msg;
    private readonly string url = "https://www.googleapis.com/geolocation/v1/geolocate?key=";
    public string apiKey = "********";

#if UNITY_UWP
    void Start() {
        wifiScanner = new WiFiScanner();
        InitializeScanner();

        //3秒後から5秒おきにスキャン
        InvokeRepeating("GetPositionInformation", 3f, 5f);
    }

    /// <summary>
    /// Scan及び位置情報の取得
    /// </summary>
    private async void GetPositionInformation() {
        try {
            string info = await RunWifiScan();
            var jsonString = JsonConvert.DeserializeObject<Response>(info);

            msg =
                "LAT: " + jsonString.location.lat + "\r\n" +
                "LNG: " + jsonString.location.lng + "\r\n" +
                "Accuracy: " + jsonString.accuracy;

        }
        catch (Exception e) {
            msg = e.ToString();
        }
    }

    /// <summary>
    /// Scannerの初期化
    /// </summary>
    private async void InitializeScanner() {
        await this.wifiScanner.InitializeScanner();
    }

    /// <summary>
    /// Scanの実行
    /// </summary>
    /// <returns></returns>
    private async Task<String> RunWifiScan() {

        await this.wifiScanner.ScanForNetworks();

        Geolocator geolocator = new Geolocator();
        Geoposition position  = await geolocator.GetGeopositionAsync();

        WiFiNetworkReport report = this.wifiScanner.WiFiAdapter.NetworkReport;

        wifiPoints = new List<WifiAccessPoints>();

        //アクセスポイントの情報取得
        foreach (var availableNetwork in report.AvailableNetworks) {
            var wifiaccessPoint = new WifiAccessPoints();
            wifiaccessPoint.macAddress = availableNetwork.Bssid;
            wifiPoints.Add(wifiaccessPoint);
        }

        //送信データのシリアライズ
        var postData = JsonConvert.SerializeObject(wifiPoints.ToArray());
        var resMsg = "";

        //Geolocation apiの呼び出し
        using (var client = new HttpClient()) {
            var content = new StringContent(postData, Encoding.UTF8, "application/json");
            var response = await client.PostAsync(url + apiKey, content);
            resMsg = await response.Content.ReadAsStringAsync();
        }
        return resMsg;
    }
#endif

}

f:id:haikage1755:20171218015517p:plain:w300
wifiAccessPoints では複数のパラメータを指定できるのですが、使用したパラメータはMACアドレスのみです。
信号強度のパラメータが有用という情報は見かけたのですが、残念ながらUWPで使用できるのは0-5の値のみで必要なデシベル値がとれないようです。
信号強度のパラメータはavailableNetwork.NetworkRssiInDecibelMilliwattsで取得できます。
データはJSON.Netを使ってシリアライズ/デシリアライズしています。

CapabilityからInternet Clientを有効にし、ビルド後にPackage.appxmanager から画像にある2つのCapabilityを有効にします。
f:id:haikage1755:20171218021436p:plain:w300

配置後、うまく位置データが表示されない場合はHoloLensのSettings->Privacy->Locationから対象のアプリの位置情報をONにしてください。

ご存知の結果になります。

[デコシノニッキ]は、Amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、Amazonアソシエイト・プログラムの参加者です。」