これぞ、完全タッチレスエントリー
17日目の記事です。
WebエンジニアのBunです。主にiOSアプリの開発を担当しています。
ドアに貼り付けるだけでスマホ、ICカード、社員証、遠隔から施錠解錠可能な弊社のスマートロックAkerunについて、もっと楽な施錠解錠方法がないか日々考えています。
新型コロナウイルスが広がっている中、ドアすら触れたくないですね。そこで、Apple Watchと弊社の「タッチレスエントリー・ソリューション」を組み合わせて、完全タッチレスでより快適な解錠を実現してみたいと思います。
13日目の記事(LINE Botから施錠解錠する)も書いたので、こちらも読んでみてください。
大分前にApple Watch Series 2を購入しましたが、その時はまだWatchOSのバージョンが2か3になっていて、色々機能制限があったので、結局何も作らずにただの腕時計として使ってきました。 その後、だんだん制限が解除され、特にWatchOS 6から独立したアプリも作成できるようになったので、Apple Watchだけで解錠できるアプリを作ってみました。
※最新のSeries 6を購入しようと思いましたが、今持っているSeires 2でもWatchOS 6までアップデートできたので、新たに購入せず済みました。ラッキ~
基本的にWatchOSのCMDeviceMotionから取得した姿勢データとBLEを使って実現可能なので、試してみたら、予想より簡単にできてしまいました。
WatchOSアプリのプロジェクト作成
プロジェクト新規作成から以下の「Watch App」を選択します。
適宜内容を記載し、プロジェクトを作成します。
以下のフォルダ構成フォルダ構成になります。
今回は特にUIも必要ないので、主にExtensionの方を実装していきます。 ただ、最初はMotionセンサーとBLE処理をデバッグしながら作るので、WatchKit AppのUIにテスト用ボタンなど追加してデバッグを行います。 また、毎回ビルドしてApple Watchにバイナリを転送すると結構時間がかかるので、Akerun本体とのBLE通信を確認するためのiPhoneアプリ(BLETester)も作ります。
Akerun本体とのBLE疎通確認
AkerunはPeripheralとして動作するので、Apple WatchをCentralとして動作させます。 iOS同様WatchOSからも直接BLE通信ができるので、CBCentralManagerを使って、Scan、Connect、Write(解錠コマンド書き込み)処理を実装します。 解錠用BLEコマンドは独自の暗号化処理になっているので、詳細は割愛します。
Motionデータ取得
WatchOSのCoreMotionからattitude(姿勢)、rotationRate(角速度)、gravity(重力加速度)、userAcceleration(加速度)が取れますが、今回はシンプルにattitude(姿勢)を使います。
Attitudeはpitch(ビッチ)、roll(ロール)、yaw(ヨー)の姿勢角があります。 手の動きについて何パターンか考えましたが、ドアノブを回す動きが自然かなと思ったので、pitchの変化タイミングを検知し、適切な閾値を設定して、解錠判定を行います。 ちなみにpitchは以下の定義になります。
具体的に、腕を上げてpitchの値が0前後(+/-0.1)になったら、判定をスタートし、腕を一瞬反時計回りに回した時、pitchの値が-π/3前後で解錠コマンドを送信するようにしています。
Apple Watchは、腕を下げると画面がDeactiveになるので、センサー情報の取得とBLE通信ができなくなります。バックグランドで実行するタスクを作れば、一定時間動作しますが、今回はDeactiveにならないように腕を反時計回りに回した後すぐ戻すことで回避しました。
画面がActiveになった場合、以下でMotionデータ取得開始します。パフォーマンスも考慮して、データ取得Intervalは1/30以下で十分だと思います。
private var motionMan = CMMotionManager() func start() { if self.motionMan.isDeviceMotionAvailable { self.motionMan.deviceMotionUpdateInterval = 1.0 / 30.0 self.motionMan.startDeviceMotionUpdates(to: OperationQueue.current!) { (motion, error) in if let m = motion { let data = MotionData( attiPitch: m.attitude.pitch, attiRoll: m.attitude.roll, attiYaw: m.attitude.yaw ) self.delegate.motionMamanger(self, data) } } } } func stop() { self.motionMan.stopDeviceMotionUpdates() }
Motionデータが定期的に通知されるので、pitchがπ / 20以内になったら解錠判定をスタートし、その後のpitchが反時計回りにπ / 3以上回ったら、Akerunに接続し、解錠コマンドを送信します。
extension InterfaceController: MotionManagerDelegate { func motionMamanger(_ motionManager: MotionManager, _ data: MotionData) { if fabs(data.attiPitch) < Double.pi / 20 { self.isActive = true } if self.isActive { if data.attiPitch < -Double.pi / 3 { self.isActive = false self.akerunMan.connect(to: testUuid) } } } }
動作
ちょうど出社する日があったので、Officeのドアで試してみました。ドアには電気錠/電磁錠に対応したAkerunコントローラーが設置され、半年前にタッチレスエントリーも導入しました。
普段は社員カードをかざして入退室していますが、下記のようにほぼ完全タッチレスが実現できました。
※動画撮るために腕を前に出していますが、手首の部分を少し上げてから回しても問題なく動作します。
まとめ
久しぶりにWatchOSを触りましたが、やっぱりIoT製品との相性も良く面白いですね。WatchOSのMotionセンサー、BLEなど基本的な機能だけで簡単にアイデアを具体化できるので、今後も色々試して見たくなります。
ただし、iOSと違ってまだまだ色々制限があるので、工夫しないといけないところもあります。
- バックグランド処理
画面がDeactiveになって、バックグラウンドに入った時は処理が実行されません。 今回は、腕を早く回すことで何とか回避できましたが、下記の拡張セッションを使えば、完全ではないですが、バックグラウンドでの処理が実行できそうです。
https://developer.apple.com/documentation/watchkit/using_extended_runtime_sessions
WatchOS 8以降でバックグラウンドでも簡単に処理が実行できるようになるかもしれませんが、早めにこういう制限を解除して欲しいですね。
- NW通信
WiFiモデルの場合、結局iPhone経由でNetwork通信を行うので、独立したWatchアプリではなく、「iOS App with Watch App」でも十分かもしれません。Cellularモデルであればもっと快適になるかと思います。
取り敢えず動作するかどうか試してみただけなので、精度についてはそこまで考えていません。 以下のモーション動作を分類するActivity Classificationを使ってモデル構築し、機械学習すれば、色んな解錠ジェスチャーが実現できて、精度がもっと上がると思います。誤動作も少なくなるはずです。
https://developer.apple.com/videos/play/wwdc2019/426/
また別の機会で試してみたいと思います。
株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co
Akerun Proの購入はこちらから akerun.com