##これまでのあらすじ
WWDC.next にて。
watchOS 3 で「アレ」は本当にできるようになったのか? - Qiita
##これまでのあらすじ
CMDeviceMotionでジャイロセンサの値、およびそれを利用した姿勢情報を取れるようになった!
→ ⌚️を利用したモーション認識が可能に!
##今日お話しすること
テニスのスウィングを検出して「フォアハンド」か「バックハンド」かを識別するアルゴリズムを紐解きつつ、モーション検出に必要な基礎知識について解説します。
今日お話しすることは、Apple Watchに限らず、
- iPhone
- Android
- Android Wear
- バンド型ウェアラブルデバイス
等々、加速度センサやジャイロセンサの値を取り扱えるデバイス一般に共通する話です。
#watchOS 3 に興味がなくてもぜひ聞いてください!
##テニスのスウィング検出のアルゴリズム
- 角速度と重力加速度のベクトルの内積を計算する
- 1の移動平均と、ピーク値を求める
- 2で求めた値を閾値処理する
- 2の値の符号と、手首の方向からフォアハンドかバックハンドかを判定する
##1. 角速度と重力加速度のベクトルの内積を計算する
欲しい情報: 重力方向の軸に対する角速度
##CMDeviceMotion
- watchOS 3 から取得できるようになった
- デバイスのモーションに関するいろんな情報が入っている
##rotationRate: 角速度
/*
* rotationRate
*
* Discussion:
* Returns the rotation rate of the device for devices with a gyro.
*
*/
open var rotationRate: CMRotationRate { get }
struct CMRotationRate {
var x: Double
var y: Double
var z: Double
}
- 各軸の単位はラジアン/秒
##gravity: 重力加速度
/*
* gravity
*
* Discussion:
* Returns the gravity vector expressed in the device's reference frame. Note
* that the total acceleration of the device is equal to gravity plus
* userAcceleration.
*
*/
open var gravity: CMAcceleration { get }
struct CMAcceleration {
var x: Double
var y: Double
var z: Double
}
欲しい情報: 重力方向の軸に対する角速度
##ベクトルの内積
{\bf a}\cdot{\bf b} = \|{\bf a}\|\|{\bf b}\|\ \cos\theta
(出展:【数学】「内積」の意味をグラフィカルに理解すると色々見えてくる その1)
欲しい情報: 重力方向の軸に対する角速度
→ ⌚️の角速度ベクトルと重力ベクトルの内積で得られる!
##内積の計算方法
${\bf a}=(a_1,\cdots,a_n), {\bf b}=(b_1,\cdots,b_n)$
{\bf a} \cdot {\bf b} = a_1b_1+\cdots+a_nb_n = \sum_{i=1}^n a_ib_i
##実装
⌚️の角速度と、重力加速度の内積を計算
let gravity = deviceMotion.gravity
let rotationRate = deviceMotion.rotationRate
let rateAlongGravity = rotationRate.x * gravity.x
+ rotationRate.y * gravity.y
+ rotationRate.z * gravity.z
これが得られた
##2. 1の移動平均と、ピーク値を求める
- 50サンプル(1秒)分を貯める
rateAlongGravityBuffer.addSample(rateAlongGravity)
- 50サンプル中での平均値を計算
let accumulatedYawRot = rateAlongGravityBuffer.sum() * sampleInterval
- 50サンプル中で絶対値が最も大きいものを抽出
let peakRate = accumulatedYawRot > 0 ?
rateAlongGravityBuffer.max() : rateAlongGravityBuffer.min()
##accumulatedYawRot
という変数名について
- accumulate: 蓄積する
- Rot: Rotation
###→ Yaw(ヨー) って?
##オイラー角
- 3次元空間での姿勢を表す角度
- ロール・ピッチ・ヨーの3つの回転角で表現される
##ロール・ピッチ・ヨー
#全然覚えられない・・・
##最高の解説
##スウィング検出のアルゴリズムに戻ります
##これまでのおさらい
- 角速度と重力加速度のベクトルの内積を計算する
- 1の移動平均と、ピーク値を求める
→ 求めた移動平均が accumulatedYawRot
、ピーク値がpeakRate
##3. 2で求めた値を閾値処理する
if (accumulatedYawRot < -yawThreshold && peakRate < -rateThreshold) {
// 4へ
} else if (accumulatedYawRot > yawThreshold && peakRate > rateThreshold) {
// 4へ
}
##平均値とピーク両方について閾値処理する理由(推測)
- ピーク値だけだと、ホンの一瞬速く動いただけで反応してしまう
- 平均値だけだと、その間一定以上の速さで動かし続けないといけない
##4. 2の値の符号と、手首の方向からフォアハンドかバックハンドかを判定する
##⌚️をどちらの手首に付けているか?
var wristLocation: WKInterfaceDeviceWristLocation { get }
enum WKInterfaceDeviceWristLocation : Int {
case left
case right
}
- watchOS 3 で追加された新API
- 自動検出ではなく、ユーザーが手動設定した値
if (accumulatedYawRot < -yawThreshold && peakRate < -rateThreshold) {
// 反時計回り
if (wristLocationIsLeft) {
// バックハンド
} else {
// フォアハンド
}
} else if (accumulatedYawRot > yawThreshold && peakRate > rateThreshold) {
// 時計回り
if (wristLocationIsLeft) {
// フォアハンド
} else {
// バックハンド
}
}
##(デモ)
めっちゃいい顔してるw#iosdcrc pic.twitter.com/XUguXfIlp2
— Kohei Tabata (@nerd0geek1) 2016年8月30日
\fore hand/ オオー \back hand/ オオー #iOSDCRC
— 長谷川智希 / とむぞう (@tomzoh) 2016年8月30日
##まとめ
話したこと
- CMDeviceMotionで取れる値いろいろ
- 角速度
- 重力加速度
- ベクトルの内積
- オイラー角
- ・・・を利用したモーション検出アルゴリズム
##ご清聴ありがとうございました!
本記事は、2016.8.30に開催された iOSDC Reject Conference days1 - connpass での発表資料です。