Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ヘッドジェスチャを検知して Vibe Cooking - iOSDC Japan 2025

Avatar for Kanta Oikawa Kanta Oikawa
September 20, 2025
210

ヘッドジェスチャを検知して Vibe Cooking - iOSDC Japan 2025

Avatar for Kanta Oikawa

Kanta Oikawa

September 20, 2025
Tweet

Transcript

  1. Vibe Cooking x ϔουδΣενϟ • Ի੠ಡΈ্͛ɾίϯτϩʔϧͰ͸؀ڥͷӨڹΛड͚΍͍͢ • ྉཧத͸ AirPods Λ૷ண

    • Core Motion Λ࢖ͬͯ AirPods ͷϞʔγϣϯσʔλΛऔಘՄೳ • ਐΉɾ໭Δૢ࡞ΛϔουδΣενϟͰ 4
  2. AirPods ͰϔουδΣενϟΛݕ஌͢Δྫ (2024/09) ϔουδΣενϟΛ࢖༻ͯ͠ Siri ʹԠ౴͢Δ • AirPods Pro 2·ͨ͸AirPods

    4ʢ྆ϞσϧʣΛ͓࣋ͪͰɺʮԻ੠Ͱண৴Λ஌ ΒͤΔʯͱʮ௨஌ͷಡΈ্͛ʯΛΦϯʹ͍ͯ͠Δ৔߹͸ɺ੠·ͨ͸खΛ࢖Θ ͣʹɺϔουδΣενϟΛ࢖༻ͯ͠ɺ௨࿩Λड͚ͨΓڋ൱ͨ͠Γɺ௨஌Λ։͍ ͨΓดͨ͡Γ͢Δ͜ͱ΋Ͱ͖·͢ɻ • ϔουδΣενϟΛ࢖༻ͯ͠SiriʹԠ౴͢Δ • ి࿩ʹग़Δɺ·ͨ͸௨஌ͱϝοηʔδʹฦ৴͢Δ: ᰐ͖·͢ɻ • ి࿩Λڋ൱͢Δɺ·ͨ͸௨஌ͱϝοηʔδΛด͡Δ: टΛࠨӈʹৼΓ·͢ɻ 5 AirPodsͰίϯτϩʔϧͱδΣενϟΛ࢖༻͢Δ - Apple αϙʔτʢ೔ຊʣ https://support.apple.com/ja-jp/guide/airpods/devb2c431317 (Accessed on 2025/09/12)
  3. ޲͍͍ͯΔํ޲Λݕ஌͢Δ final class HeadphoneMotionRepository: NSObject, CMHeadphoneMotionManagerDelegate, Sendable { private let

    manager: CMHeadphoneMotionManager override init() { ... } func startTracking(queue: OperationQueue? = .current) throws -> AsyncStream<CMDeviceMotion> { guard manager.isDeviceMotionAvailable else { throw HeadphoneMotionRepositoryError.deviceMotionNotAvailable } return AsyncStream { continuation in manager.startDeviceMotionUpdates(to: queue ?? .main) { motion, error in guard let motion else { return } continuation.yield(motion) } } } ... } 7
  4. ޲͍͍ͯΔํ޲Λݕ஌͢Δ for await motion in try motionService.startTracking() { state.motion =

    motion } ... if abs(state.motion?.attitude.yaw ?? 0) > .pi / 12 { // π / 12 = 15° ... } 8 yaw | Apple Developer Documentation https://developer.apple.com/documentation/coremotion/cmattitude/yaw (Accessed on 2025/09/20)
  5. ͏ͳ͖ͣδΣενϟΛݕ஌͢Δ 1. ͏ͳ͖ͣδΣενϟͷϞʔγϣϯσʔλΛऩू͢Δ • ͏ͳͣ͘δΣενϟ ͱ ͦΕҎ֎ͷδΣενϟ ͷ 2 Ϋϥε

    • CMDeviceMotion ʹؚ·ΕΔ஋Λ CSV ϑΝΠϧʹॻ͖ࠐΈ • attitude_roll, attitude_pitch, attitude_yaw, gravity_x, gravity_y, gravity_z, quaternion_x, quaternion_y, quaternion_z, quaternion_w, rotation_rate_x, rotation_rate_y, rotation_rate_z, user_acceleration_x, user_acceleration_y, user_acceleration_z • ͻͨ͢Β͏ͳͣ͘ 10
  6. ͏ͳ͖ͣδΣενϟΛݕ஌͢Δ 3. ϞσϧΛ࢖ͬͯ͏ͳ͖ͣδΣενϟΛݕ஌͢Δ let configuration = MLModelConfiguration() let model =

    try HeadGestureClassifier(configuration: configuration) let input = HeadGestureClassifierInput( rotation_rate_x: try MLMultiArray(motions.map { $0.rotationRate.x }), stateIn: try MLMultiArray(shape: [400], dataType: .double) ) let output = try model.prediction(input: input) return Gesture(rawValue: output.label) ?? .idle ... enum Gesture: String { case idle case nod ... } 13
  7. ࣮૷ͯ͠Έͨײ૝ • Core Motion ͱ Core ML Λ૊Έ߹ΘͤͯδΣενϟݕ஌͕؆୯ʹ࣮૷Ͱ͖ͨ • ML

    ʹؔ͢Δߴ౓ͳ஌͕ࣝͳͯ͘΋؆୯ʹϞσϧΛ࡞Δ͜ͱ͕Ͱ͖Δ • ஌͕ࣝ͋Ε͹ਫ਼౓্͕͕Γͦ͏ • CMDeviceMotionͷͦΕͧΕͷ஋͕ҙຯ͢Δ͜ͱΛཧղ͢Δ͜ͱ͕ॏཁ 16