LoginSignup
19
9

More than 1 year has passed since last update.

iOSのUWB通信用フレームワーク「Nearby Interaction」の基礎

Last updated at Posted at 2022-12-16

はじめに

スマートフォンの近距離無線通信といえば、みなさん Bluetooth, Wi-Fi, NFC あたりを思い浮かべるでしょう。実はiPhoneでは、UWB(超広帯域無線)というもう一つの無線通信があることをご存知でしょうか。
iPhone11 から iPhone に標準搭載されるようになった Apple U1チップ。Apple製デバイスをUWBに対応させる専用チップで、一般向け製品に UWB が搭載された初のケースです。特に近距離の正確な位置測位に強く、他にはないポテンシャルを秘めています。
しかし、LiDARスキャナの話題性に比べ、こちらはあまり使われているアプリを見ることがありません(Apple公式の「探す」アプリくらい?)。今回はそんな UWB と、Apple の UWB 技術を簡単に使える開発者向けフレームワーク「NearbyInteraction」についてご紹介いたします。

目次

UWBについて

UWBとは?

UWB(Ultra Wide Band)
  • 距離と方向が正確に取得できる、近距離の屋内位置測位技術。
    通信距離は10m程度の近距離通信
    距離と方向が正確に取得できる(誤差数十cm)

  • 超広帯域の周波数幅にわたって、低電力密度の無線電波を用いて無線通信を行う技術 (500MHz ~ 数GHz)
    屋外利用は7.25-9.0 GHz, 24.25-29 GHz に限られる(2019年5月20日の総務省令)

  • 標準規格 IEEE 802.15.4z(2019年)

  • 消費電力が極めて少ない(2.4 mW)

  • データ伝送の通信量 100 Mbps以上

  • 三点測位によるリアルタイム位置測位システム(Real Time Location System:RTLS)に使われる

  • AirTagにも対応。「探す」アプリで正確な位置を特定することができる。

Bluetoothとの比較

同じく近距離無線通信で広く活躍している Bluetooth (BLE) との違いは以下の通りです。

UWB (Ultra Wide Band) Bluetooth Bluetooth (5.1~)
消費電力 少ない 少ない(特にBLE) 少ない(特にBLE)
通信距離 ~10m程度 ~10m程度 ~10m程度
測距の誤差 10cm程度 1~5m程度 1~5m程度
方向の取得 不可 可(AoA)
測距・測位方法 ToF (Time of Flight) RSSI (Received Signal Strength Indicator) RSSI,AoA (Angle of Arrival)
対障害物 比較的強い 弱い 弱い
通信速度 100 Mbps以上 1 Mbps (4.0) 2 Mbps (5.0以降)
対応機種 iPhone 11~ 全てのiPhone iPhone 11~
周波数 500MHz ~ 数GHz。屋外利用は7.25-9.0 GHz, 24.25-29 GHz に限られる(2019年5月20日の総務省令) 2.4GHz帯 2.4GHz帯(日本の屋外利用)

Nearby Interaction

Apple で UWB 通信をするために iOS14で導入されたフレームワーク。

これまでの Nearby Interaction

WWDC2020での登場以来、毎年新情報が更新されています。
WWDC2020 Meet Nearby Interaction
・iPhone to iPhone
WWDC2021 Explore Nearby Interaction with third-party accessories
・iPhone to Apple Watch
・Third-party Accessories
WWDC2022 What's new in Nearby Interaction
・Enhanced NI with ARKit
・Background Sessions, Third-party Hardware

実際の動作のイメージなども、ここから動画で確認できます。

フレームワークの概要

今回は最も簡単なiPhone to iPhone をベースに説明します。

接続のステップ

iPhone to iPhone のUWB接続は、大きく分けて以下の6ステップで実行されます。

  1. NISession の生成
  2. delegate のセット
  3. Peerデバイスと NI discovery token を共有
    *tokenの共有方法はNearbyInteractionは提供していないため、bluetooth接続など他の方法で共有する必要がある
    例:Multipeer Connectivity, Core Bluetooth
  4. Peerデバイスから NI discovery token を受信
  5. session configration の作成
  6. 上記 configration でセッションを実行
Summary.swift
// 1.NISession の生成
let session = NISession()

// 2.delegate のセット
session.delegate = self

// 3.Peerデバイスと NI discovery token を共有
let myDiscoveryToken = session.discoveryToken
sendDiscoveryTokenToMyPeer(peer, myDiscoveryToken) // YOUR app's method

// 4.Peerデバイスから NI discovery token を受信
let peerDiscoveryToken = ...

// 5.session configration の作成
let config = NINearbyPeerConfigration(peerToken: peerDiscoveryToken)

// 6.上記 configration でセッションを実行
session.run(config)

NI discovery token: ランダムに生成された一時的なセッションID。セッションが存続する間は有効。
NISessionクラスのインスタンスプロパティとして呼び出せる。

セッション実行の流れ
  1. NISessionでデリゲートを取得
  2. 実行すると、デリゲートが近傍オブジェクトの更新データを取得
    image.png
    余談ですが、1vsN で multiple session をする場合は、NISession までの流れを複数用意して、同一のdelegateを取得します。
NISessionクラス のよく使うインスタンスメソッド

NISession: 2 つのpeer devicies 間の一意の接続を識別する。
以下に、よく使うインスタンスメソッドの名前と引数、使用例を記載する。

open class NISession : NSObject {
    // NI discovery token
    @NSCopying var discoveryToken: NIDiscoveryToken? { get }
    // セッションで実行される構成
    @NSCopying var configuration: NIConfiguration? { get }
    // セッションの操作
    func run(_ configuration: NIConfiguration)
    func pause()
    func invalidate()
}
使用例.swift
let session = NISession()

// セッションの実行
session.run(config)
// セッションのポーズ
session.pause()
// セッションの再開
session.run(session.config)
// セッションの停止
session.invalidate()
NISessionDelegate のよく使うインスタンスメソッド

NISessionDelegate: セッションの更新を監視して対応するオブジェクト。
以下に、よく使うインスタンスメソッドの名前と引数を記載する。

// NearbyInteraction の session delegate
public protocol NISessionDelegate : NSObjectProtocol {
    // セッションが近傍オブジェクトを更新したときに通知
    optional func session(
        _ session: NISession,
        didUpdate nearbyObjects: [NINearbyObject]
    )

    // セッションが1つ以上の近傍オブジェクトを削除したときに通知
    optional func session(
        _ session: NISession,
        didRemove nearbyObjects: [NINearbyObject],
        reason: NINearbyObject.RemovalReason
    )

    // 中断されたセッションを通知
    optional func sessionWasSuspended(_ session: NISession)

    // セッションの再開を通知
    optional func sessionSuspensionEnded(_ session: NISession)

    // 無効化されたセッションを通知
    optional func session(
        _ session: NISession,
        didInvalidateWith error: Error
    )
}
NINearbyObjectクラス から取得できる情報
open class NINearbyObject : NSObject, NSCopying, NSSecureCoding {
    // discovery Token
    @NSCopying var discoveryToken: NIDiscoveryToken { get }
    // 相対距離の取得
    public var distance: Float? { get }
    // 角度の取得
    public var direction: simd_float3? { get }
}

使用例

以下に、NearbyInteraction を開始するための簡単なメソッドの例を記載します。

sample.swift
    func startup() {
        // ① NISessionの生成
        session = NISession()
        
        // ② delegate のセット
        session?.delegate = self
        
        // トークン共有フラグのリセット(新規セッション開始のため)
        sharedTokenWithPeer = false

        // `connectedPeer`が存在する場合(P2P接続できている場合)、必要に応じて discovery トークンを共有
        if connectedPeer != nil && mpc != nil {
            // 接続済みの場合
            // ③ Peerデバイスと discovery token を共有
            if let myToken = session?.discoveryToken {
                updateInformationLabel(description: "Initializing ...")
                if !sharedTokenWithPeer {
                    shareMyDiscoveryToken(token: myToken)
                }
                // ④ Peerデバイスから discovery token を受信
                guard let peerToken = peerDiscoveryToken else {
                    return
                }
                // ⑤ session configration の作成
                let config = NINearbyPeerConfiguration(peerToken: peerToken)
                // ⑥ 上記 configration でセッションを実行
                session?.run(config)
            } else {
                fatalError("Unable to get self discovery token, is this session invalidated?")
            }
        } else {
            // 接続できていない場合
            updateInformationLabel(description: "Discovering Peer ...") // UIに文字列を設定
            
            // P2P通信スタートアップ(P2P通信の開始トリガー)
            // * Multipeer Connectivity フレームワークを使用 *
            startupMPC()
            
            // 距離・方向ステータスにunknownをセット
            currentDistanceDirectionState = .unknown
        }
    }

おわりに

実際にアプリを作って動かしてみて、以下のような感想を持ちました。
・距離は10m以内であれば、どのように持っていても非常に正確な値が取れる。
・角度はiPhoneの背面同士を向け合わないと、取得が難しい。

すぐに使えるサンプルコードもあるので、ぜひお手元のiPhoneにビルドして動かしてみてください。

参考

Apple公式 https://developer.apple.com/documentation/nearbyinteraction
NearbyInteractionで周囲の端末の位置を測定する

19
9
1

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
19
9