どうもこんばんわ。
シークレットラブ(仮) 攻略しました。涼しそうな制服ですねって言おうとしたらもう寒い時期。
それはそれとして今作の HOOK 結構おもしろかった。セーブ枠が足りない。あとえちえちだった。
今作は特にみんなかわいい、しかもきれい。買う前と共通やった後で誰から攻略するか変わった。
ハルちゃんのここのシナリオすき、>< かわいい
顔が良すぎる
こちら後輩ちゃんです。売り文句どおりえちえちだった。。
楓ちゃんルートが一番おもしろいかもしれん!
でもやっぱちあきちゃんが一番良かったかも
!?!?
ん~
それはそれとして、他のヒロイン選んだときに真っ先にちあきちゃん飛んでくるのが心に来る
だから最後にするといいのかな、ヨカッタ
あとはオープンルートのが掛け合いがあるので面白かったけどクローズドの方にも好きなシナリオあるから一概に言えない!!
↑ここすき
いい!!とてもいいです。おすすすすめです
本題
Pixel 6 Pro
以降のPro
モデルにはUWB アンテナ
が搭載されていて?、API
も用意されているわけですがあんまり情報がないので、
今回は試しにUWB
のAPI
を使ってお互いの位置を見れるアプリを作ってみようと思います。
なんならUWB
あるのが忘れられている可能性・・・?
公式
まじでこれしか無い。
なんなら2つ目のYouTube
の動画のほうが詳しく話してる。
UWB とは
近くの端末と通信する技術で、他のそれと違ってかなり正確な位置検出が出来る。位置測定に関してはセンチメートルの単位で報告される。(体感10cm
前後くらいの誤差)
あとは高速通信があるらしいですが、今のところAndroid
のUWB
にはデータ通信のAPI
は無さそう?
ドキュメントを見る限り位置情報に関してしか無い。
UWB どこで使ってるの
ニアバイシェア
の際に共有する端末に近付けると勝手に転送が始まる。端末を選ぶ作業がスキップされる。
あとは・・・
UWB 誰もやってない
しかしUWB
を試すには地味にハードルが高い。
UWB 対応端末を2台用意する必要がある
https://developer.android.com/develop/connectivity/uwb#uwb-enabled_mobile_devices
多分これのせい。
今のところPixel
のPro
シリーズとGalaxy
には搭載されているそう。
・・・高い。
UWB は通信する機能しかなく、発見する別の仕組みが必要
どういうことかというと携帯電話を持っていても相手の電話番号が分からなければ電話をかけることが出来ない。
UWB
も同じで、UWB
通信を開始するためのパラメーターを何らかの方法でお互いに送受信する必要があり、これも地味にハードルが高い。
それこそ例えば、前回の記事でやったBluetooth Low Energy
のキャラクタリスティック
で読み書きしパラメーターを交換する必要がある。
UWB
のパラメーターも多分そんな複雑じゃないからキーボードで打ち込んでもらうでも最悪いいはず。
環境
今回はPixel 6 Pro
とPixel 8 Pro
があるのでそれを使います。
あとUWB
のライブラリがKotlin Coroutines Flow
を使っているのでKotlin
です。Jetpack Compose
使いたいのでそれはそう。
UWB
自体はFlow
かRx
のどっちか選べるらしい。Flow
しかわからん無いのでそっちで。
| |
---|
端末 | Pixel 6 Pro / Pixel 8 Pro |
Android Studio | Android Studio Ladybug 2024.2.1 Patch 2 |
targetSdk | 31 ? |
そのほか | Jetpack Compose + Navigation Compose |
言語 | Kotlin |
今回の作戦
UWB
でお互いに交換する必要があるパラメーターはdata class
に詰めてSerializable
にした後BLE
経由で交換します。
BLE
でやり取りする話は前回の記事でやったので今回は手短にします。
https://takusan.negitoro.dev/posts/android_ble_peripheral_central/
ちなみにGoogle
が書いたUWB
サンプルコードはNearby API
で交換してるっぽい。
ただ、Nearby API
にはAPI キー
の払い出しが必要なはずでそれはそれで面倒。
https://github.com/android/connectivity-samples/tree/main/UwbRanging
流れ
なので、流れとしては、
- 2台のうちどっちかが
Controller
になり、もう片方がControlee
になる
UWB
接続に必要なパラメーターを受け取り、BLE
のキャラクタリスティック
に読み書きして交換する
- お互い相手の情報を知ったうえで
UWB
を開始する
後述しますが、親→子は複数の値を渡す必要がある、逆に子→親は自分のアドレス(ByteArray
)を渡すだけなので楽。
つくる
Jetpack Compose
で適当にプロジェクトを作ってください。
必要なライブラリを入れる
app/build.gradle.kts
にUWB
のライブラリとnavigation-compose
を入れてね。バージョンカタログ入ってるならそっちに書くべきです。
何故かUWB
はAndroid Jetpack
からの提供になります。普通にgetSystemService()
するもんだと思ってたら違った。
権限を書く
まじで情報がさっきのYouTube
とサンプルコードくらいしか無いんですが、多分android.permission.UWB_RANGING
ってのが必要。
後はBLE
のための権限が続きます。
MainActivity
でNavigation Compose
のアレコレをします。
各画面はまだ作ってないのでエラーになると思います。
最初の権限ください画面
BLE
のそれと同じなので解説はコードのコメントくらいしか無いです。
Controller側
(親機側)になるか、Controlee側
(子機側)になるかを選べる画面です。
BLE 周りを作る
さて、先にBLE
でUWB
開始に必要なパラメーター交換周りを作ります。
詳しくは前回のBLE
でペリフェラル、セントラル
を試す記事を読んでください。
再掲:
https://takusan.negitoro.dev/posts/android_ble_peripheral_central/
GATT のサービスとキャラクタリスティックの UUID
を適当に作ったのでそれを使います。
BLE ペリフェラル側のコード
これも前回の記事でやったので。。
BLE セントラル側のコード
これも前回のようなコードを書きます。
BLE で実際にやり取りするデータのデータクラス
さて、UWB
を開始するために必要なパラメーターなのですが、Controller(親)→Controlee(子)
へ送る必要がある値が複数個あるんですね。
ちなみにControlee(子)→Controller(親)
は1つのバイト配列を投げれば終わり。
というわけで何らかの方法で1つのバイト配列に変換しちゃいたいわけです。
今ならprotobuf
なんでしょうが、私は使ったことがないので大人しくJava
のSerializable
でdata class
をバイト配列に変換しようと思います。。。
実際に UWB の部分を書いていく
ついに来ました。まずはController
(ホスト)側から!
UWB Controller(ホスト) 側の画面
ついにドキュメントが役に立ちそうなところまで進んできました。
まずは実際にUI
で表示するためRangingPosition
をremember { mutableStateOf }
で作っておきます。
で、LaunchedEffect
の中でBLE
からのUWB
をやっています。
Controller
側になるにはUwbManager#controllerSessionScope
を呼び出します。あ、まずUWB
があるかの確認をしたほうが良さそうですね。めんどいのでやりません。
Controlee側
(ゲスト側)に送らないといけない値は以下で、
controllerSession()
から取得できるlocalAddress.address
、uwbComplexChannel.channel
、uwbComplexChannel.preambleIndex
、
それからsessionId
とsessionKeyInfo
を適当に作る必要があるらしいです。サンプルコードでも適当に作ってたので適当に作りました。
この値たちをデータクラスにした後、Serializable
なのでバイト配列に変換し、BLE
のキャラクタリスティック
のread要求
でこのバイト配列を送るようにします。
また、Controlee
側をまだ作っていないのであれですが、Controlee
側からもByteArray
のアドレスを受け取る必要があるので、write要求
されるまで待ちます。
Controlee
側からのアドレスが受信できればRangingParameters()
の値が全て揃います。
詳しい引数はよくわからずで、とりあえずコレで動きました。
最後にControllerSession#prepareSession
にRangingParameters
を入れてFlow
をcollect { }
するとControlee
側の位置の情報が取得できるようになります。
適当に受け取った位置情報はText()
で表示するようにしました。
UWB Controlee(ゲスト) 側の画面
こちらも同様、RangingPosition
をremember stateof
で持っておきます。
で、Controlee側
はUwbManager#controleeSessionScope
で作れます。
つぎに、BLE
を使い、Controller側
のペリフェラルへ接続し、キャラクタリスティックへread
することでUWB
に必要なパラメーターを受信します。Serializable
なByteArray
なのでデータクラスの状態戻します。
Controller側
で話しましたが、こっちはlocalAddress.address
1つをController
側へ送るだけなので楽です。
そしたらRangingParameters
が作成できるので、あとは同じです。
UWB 使ってみる!!!
アプリを実行してみます。
UWB 注意事項
ドキュメントには書いてないのですが、注意事項がいくつかあります。iPhone
のドキュメントをチラ見しましたが多分Android
もそうです。
ドキュメントに書いてないけど多分そういう仕様。
- 端末を縦持ちにする
- 2台の端末を背中合わせにする形で配置する
- つまり、画面が同じ方向を向いていると正しい値にならなそうです
- 手で持ってない方(机においている方)は自分側に外カメが来るようにする必要があります
動かない時
logcat
でUwbBackend
でTAG
を探して見てみるといいかも。ちなみに私は権限が付与されてないことに30分くらい気付かなかった。。。
こんな感じ
こんな感じ。手元で見る感じ誤差はざっくりプラマイ10cm
くらいかな?
すごい
アクセサリの位置を探す矢印みたいなやつは?
YouTube
の動画を見た感じ、距離に加えてazimuth
ってので角度を取得できるらしい。
ところで試したところ、なんかドキュメントだと90, -90
の範囲って書いてあって、
でも画面に表示されてるのは-148
で普通に超えてる気がするんだけどどういうことなの?
https://developer.android.com/reference/androidx/core/uwb/RangingPosition#getAzimuth()
というわけで矢印コンポーネントを用意しました。
矢印の記号をrotationZ
しています。
あとはControllerScreen / ControleeScreen
で呼び出せばいいはず!
こんな感じに矢印が出て、この矢印がまっすぐになった方向に歩くと見つかります。
結構正確です。
相手の位置を表示する Canvas
サンプルアプリでは、自分の位置を中心に、どのへんにUWB
接続相手がいるかをレーダーみたいに表示するUI
があるっぽいです。
これをパクってみます。
元ネタはこの辺です。
https://github.com/android/connectivity-samples/blob/main/UwbRanging/app/src/main/java/com/google/apps/hellouwb/ui/home/HomeScreen.kt
Apache-2.0 license
まずはCanvas
を用意し、UWB
デバイスの位置を表す点を書きます。
これをControllerScreen / ControleeScreen
で呼び出せばよいです。
もう一方の端末ではisInvert
をtrue
にして自分と相手を入れ替える必要がある。多分。
こんな感じに自分と相手の位置が点で表示される。上から見た図ですね。
Jetpack Compose
数年使ってる気がするけど始めてCanvas
使ったかもしれない。
おまけ UWB デバイスを動かして軌跡を描く
点の動きを記録して、線を書いてみる。数が多くなるので適当に捨てます。
さっきのCanvas
に書いてたやつを転用し、引数の値を配列に記録するように改造し、点を描画する際にはその配列から取り出すようにします。
開始、終了ボタン、リセットボタンをおきました。
あとは片方の端末で記録ボタンを押し、もう一方のUWB
端末に動いてもらえばいいはず。
でもあんまりうまく取れてない。
そーすこーど
どーぞ
UWB
対応の2台の端末にビルドしたアプリを入れて、片方でController
を開始したあともう片方をControlee
にしてしばらく待ってると位置とかが表示されるようになるはず。
https://github.com/takusan23/AndroidBleAndUwbSample
おわりに
2台それぞれにインストールするのが大変でした。
以上です。88888888