LoginSignup
21
22

More than 5 years have passed since last update.

Edisonのセンサ

 Edisonにはセンサがついてないので,様々なセンサを外付けしないと外界の情報を拾えません.
 ・・拾えません?

  Wifiの情報取れるじゃーーーん!!

ジオロケーション

 ジオロケーションというのは,地図上の位置推定のことです.GPSなんかが有名ですね.GPSは地球の周り遥か遠くを回っている静止衛星から送られて来る時刻情報を元に,一般相対性理論により位置推定を行う技術です.でも,今回は関係ない.
 今回ターゲットにするのは,世の中にたくさん散らばっているWifiアクセスポイント(AP)の情報です.多くのAPは,あまり動かされることなく一地点でずっと電波を発し続けています.Wifi等で利用される電波は周波数が高いため,すぐに減衰してあまり遠くまで飛んでいきません.また,電波はその性質が距離に応じて強さが減衰することが知られています.
 このあたりの性質を見て,Wifiの電波の強さによって,受信した機器の地図上の位置を特定できるんじゃないかと考えて人がいました.
 そして,それを地球規模でやってしまったのがGoogleです.そしてなんと,私たちも,そのAPIを利用することができます.それが,Google MapのGeolocation API.APIのURLにJSONで固めた周辺のAP情報を送ると,すぐに推定位置の情報が返って来ます.

コード

 Googleに開発者登録をして,Google MapのAPIキーを取得しておいてください.以下のコードのGAPI_KEYがそれにあたります.1000リクエスト/日,1リクエスト/秒以内なら,無償で使用可能だそうです.
 以下のコードの.ELI_MACとなっているところには,位置推定から除外するAPのMACアドレスを入れます.私の場合は,Edisonの通信用に利用しているテザリング携帯のMACアドレスを入れています.

geo.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import commands, datetime, time
import re
import json, requests

GAPI_KEY = "fa1iuEe32hw4iusiWKgrwFEheERfieunGeWW"
ELI_MAC = ["12:34:56:78:9A:BC"]

re_mac = re.compile("\s+Cell \d{2} - Address: (\w{2}:\w{2}:\w{2}:\w{2}:\w{2}:\w{2})")
re_ch = re.compile("\s+Channel:(\d+)")
re_freq = re.compile("\s+Frequency:(\S+) GHz")
re_qual = re.compile("\s+Quality=(\S+)  Signal level=(\S+) dBm")
re_essid = re.compile("\s+ESSID:\"([^\"]+)\"")

class AP:
    def __init__(self, _mac, _channel, _frequency, _quality, _signal, _essid=""):
        self.mac = _mac
        self.channel = _channel
        self.frequency = _frequency
        self.quality = _quality
        self.signal = _signal
        self.essid = _essid
        self.time = datetime.datetime.now()
    def show(self):
        print("%s, %s, %s, %s, %s, %s" % (self.essid, self.mac, self.channel, self.frequency, self.quality, self.signal))
    def getVal(self):
        t = datetime.datetime.now() - self.time
        age = t.seconds * 1000 + t.microseconds / 1000
        return {"macAddress":self.mac, "signalStrength":self.signal, "age":age, "channel":self.channel}

def getAPList():
    aplist = []
    res = commands.getoutput("/sbin/iwlist wlan0 scan")

    essid = ""
    mac = ""
    channel = ""
    frequency = ""
    quality = ""
    signal = ""

    for t in res.splitlines():
        m = re_mac.match(t)
        if m:
            mac = m.group(1)
            continue
        m = re_ch.match(t)
        if m:
            channel = m.group(1)
            continue
        m = re_freq.match(t)
        if m:
            frequency = m.group(1)
            continue
        m = re_qual.match(t)
        if m:
            quality = m.group(1)
            signal = m.group(2)

            if mac not in ELI_MAC:
                aplist.append(AP(mac, channel, frequency, quality, signal, essid))

            continue
        m = re_essid.match(t)
        if m:
            essid = m.group(1)
            continue

    return aplist

def getLocationFromWifi(wifilist):
    url = "https://www.googleapis.com/geolocation/v1/geolocate?key=%s" % GAPI_KEY
    headers = {"Content-Type": "application/json"}
    data = json.dumps({"wifiAccessPoints":wifilist})

    r = requests.post(url, data=data, headers=headers)
    geo = r.json()

    return {"Latitude":geo['location']['lat'], "Longitude":geo['location']['lng'], "Accuracy":geo['accuracy']}



if __name__ == '__main__':
    aps = {}

    while True:
        naps = getAPList()

        lapsk = aps.keys()
        napsk = []

        # add new APs to AP list.
        for ap in naps:
            if ap.mac not in lapsk:
                aps[ap.mac] = ap
            # make new AP names list
            napsk.append(ap.mac)

        # search missed APs to delete from AP list
        for ap in lapsk:
            if ap not in napsk:
                aps.pop(ap)

        loc = getLocationFromWifi([d.getVal() for d in aps.values()])

        print("Latitude: %f, Longitude: %f, Accuracy; %f" % (loc['Latitude'], loc['Longitude'], loc['Accuracy']))
        print("https://www.google.co.jp/maps/@%s,%s,21z?hl=ja" % (loc["Latitude"], loc["Longitude"]))

        time.sleep(30)

 このコードを,管理者権限で実行してください.
 テストのつもりで自宅で実行してみたら,部屋番号まで分かるんじゃないかってくらいなレベルで特定されて,ちょっと怖かったです.

実験

 秋葉原-御茶の水間を徒歩で移動した際の位置推定の結果を以下に示します.赤点になっているのが,推定された位置です.なお,この実験は,APIの時間単位の制限を回避するため,APの情報だけ取得しておいて,位置推定のほうは帰宅してから行いました.
Wifi位置推定

 Edisonで周辺のWifi情報を収集しながら歩いていた際のGPSのデータは以下のようになっています.こちらも,そんなに精度が良いわけではないので,参考程度に.
Wifi位置推定

考察

 いきなり御茶の水駅前に赤点が現れたりしているところには笑ってしまいますが,びっくりするくらいドンピシャな位置を推定しているところもありますね.常識的な移動速度でフィルタをかければ,あるいは?

 えぇ.実験場所に秋葉原を選んだのは,サンプルとなるWifi APの数が大量にあるだろうと踏んだからです.場所によっては60近くもAPが見えるところもあり,期待以上でした.

まとめ

  • Edison単体でも地図上の位置推定はある程度可能.
  • Big brother is watching YOU !!
21
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
22