Core Motion

Core Motion 用以处理加速度计(Accelerometer)、陀螺仪(Gyroscope)、计步器(Pedometer),以及其他环境相关事情。在咱们的运用程序中,能够运用这些数据作为用户交互、健身盯梢等活动的输入。

框架的服务可提供对原始值、处理值,两种运动数据的拜访。原始值反映了来自硬件的未修改数据,而处理值消除了或许对数据运用发生晦气影响的误差。例如,处理后的加速度值仅反映用户引起的加速度,而不反映重力引起的加速度。

框架的某些服务即便在具有所需硬件的设备上也或许不可用。例如,许多 Core Motion 服务可供 visionOS 运用程序运用,但这些服务不适用于其在 iPad 或 iPhone 运用程序上。在测验运用任何与运动相关的服务之前,需求检查这些服务的可用性。

iOS 运用程序必须在其 Info.plist 文件中包括其所需数据类型的运用描绘,否则测验拜访相应的服务时,运用程序会崩溃。 要拜访运动和健身数据,请包括 NSMotionUsageDescription;要拜访跌倒检测服务,请包括 NSFallDetectionUsageDescription

本文将环绕 Core Motion 框架下的 CMHeadphoneMotionManager,解说和实现拜访 AirPods (3rd generation)、AirPods Pro (all generations)、 AirPods Max 的头部盯梢数据。

运用描绘与授权

创立 HeadphoneMotion 项目,并在 Info.plist 文件中新增 Privacy - Motion Usage Description,并增加文字描绘:

经过 Headphone Motion 拜访 AirPods 的头部盯梢数据
经过 Headphone Motion 拜访 AirPods 的头部盯梢数据
经过 Headphone Motion 拜访 AirPods 的头部盯梢数据

稍后,在第一次运用 Core Motion 相关 API 时,将会有对应的提示。咱们能够经过 authorizationStatus() API 获取回来监听耳机运动的授权状况:

open class CMHeadphoneMotionManager : NSObject {
  // ...
  open class func authorizationStatus() -> CMAuthorizationStatus
}

若用户在装置后首次未授权该权限,需求引导用户至设置->对应运用->开启“运动与健身”。能够运用 isDeviceMotionAvailable 特点判断当时设备是否支撑和是否有权限获取头部盯梢数据:

open class CMHeadphoneMotionManager : NSObject {
  // ...
  open var isDeviceMotionAvailable: Bool { get }
}

获取头部盯梢数据

CMHeadphoneMotionManager 提供了两种头部盯梢数据获取办法:

  1. 运用CMHeadphoneMotionManagerstartDeviceMotionUpdates()办法,开始设备运动数据的更新,将在稍后修改 CMHeadphoneMotionManagerdeviceMotion 特点:
open class CMHeadphoneMotionManager : NSObject {
  //...
  open var deviceMotion: CMDeviceMotion? { get }
  open func startDeviceMotionUpdates()
}
  1. 运用CMHeadphoneMotionManagerstartDeviceMotionUpdates(to:withHandler:) 办法,指定行列并流式接纳数据更新回调:
open class CMHeadphoneMotionManager : NSObject {
  //...
  open func startDeviceMotionUpdates(to queue: OperationQueue, withHandler handler: @escaping CMHeadphoneMotionManager.DeviceMotionHandler)
}
  1. CMHeadphoneMotionManagerisDeviceMotionActive 特点标识设备是否处于活动状况,在更新头部盯梢数据数据期间将回来 true
open class CMHeadphoneMotionManager : NSObject {
  //...
  open var isDeviceMotionActive: Bool { get }
}
  1. 相应的,CMHeadphoneMotionManagerstopDeviceMotionUpdates() 办法中止数据接纳的才能:
open class CMHeadphoneMotionManager : NSObject {
  //...
   open func stopDeviceMotionUpdates()
}
  1. CMHeadphoneMotionManager 提供了代理办法 CMHeadphoneMotionManagerDelegate,回调首次设置及后续的衔接和断开耳机的事情:
open class CMHeadphoneMotionManager : NSObject {
  //...
   weak open var delegate: CMHeadphoneMotionManagerDelegate?
}
​
public protocol CMHeadphoneMotionManagerDelegate : NSObjectProtocol {
  // 衔接耳机时调用
  optional func headphoneMotionManagerDidConnect(_ manager: CMHeadphoneMotionManager)
  // 断开耳机时调用
  optional func headphoneMotionManagerDidDisconnect(_ manager: CMHeadphoneMotionManager)
}

以上述办法二为例,咱们能够运用以下代码进行数据获取,:

import CoreMotion
​
class CoreMotionViewController: UIViewController {
  
  let manager = CMHeadphoneMotionManager()
  
  override func viewDidLoad() {
    super.viewDidLoad()
    guard manager.isDeviceMotionAvailable else {
      print("Device Motion is not Available.")
      return
    }
    manager.delegate = self
    manager.startDeviceMotionUpdates(to: OperationQueue.main) { [weak self] deviceMotion, error in
      guard let self, error == nil else {
        print("Start device motion updates failed.")
        return
      }
      self.printData(from: deviceMotion)
    }
  }
 
   deinit {
    manager.stopDeviceMotionUpdates()
  }
}
​
extension CoreMotionViewController: CMHeadphoneMotionManagerDelegate {
  
  func headphoneMotionManagerDidConnect(_ manager: CMHeadphoneMotionManager) {
    print("Headphone motion manager did connect")
  }
    
  func headphoneMotionManagerDidDisconnect(_ manager: CMHeadphoneMotionManager) {
    print("Headphone motion manager did dis connect")
  }
  
  private func printData(from deviceMotion: CMDeviceMotion?) {
       // 将在下部分进行解析
  }
}

解析头部盯梢数据

咱们将经过 CMDeviceMotion 来解析头部盯梢数据。CMDeviceMotion 是设备姿势、旋转速率和加速度的封装测量。

class CMDeviceMotion : CMLogItem

要解说姿势数据,咱们需求知道设备坐标轴的方向,下图显示了 Airpods 的正 x 轴、正 y 轴和正 z 轴:

经过 Headphone Motion 拜访 AirPods 的头部盯梢数据

CMDeviceMotion 的声明如下,咱们依次来看:

@available(iOS 4.0, *)
open class CMDeviceMotion : CMLogItem {
    // 回来设备的姿势。
  open var attitude: CMAttitude { get }
  // 对于带有陀螺仪的设备,回来设备的旋转速率。
  open var rotationRate: CMRotationRate { get }
  // 回来设备参阅系下的重力矢量。
  open var gravity: CMAcceleration { get }
  // 回来用户给予设备的加速度。
  open var userAcceleration: CMAcceleration { get }
  // 对于带有磁力计的设备,回来相对于设备的磁场矢量。
  @available(iOS 5.0, *)
  open var magneticField: CMCalibratedMagneticField { get }
  // 回来相对于 CMAttitude 参阅系的航向角度,规模为 [0,360) 度。
  @available(iOS 11.0, *)
  open var heading: Double { get }
  // 回来用于核算设备运动数据的传感器的方位。
  open var sensorLocation: CMDeviceMotion.SensorLocation { get }
}
  1. attitude 是设备相对于已知参阅系的方向。rollpitchyaw 特点取得弧度为单位的欧拉角:

经过 Headphone Motion 拜访 AirPods 的头部盯梢数据

能够经过数学核算,将其简单转换为度数为单位:

let rollValue = (180 / Double.pi) * deviceMotion.attitude.roll
let pitchValue = (180 / Double.pi) * deviceMotion.attitude.pitch
let yawValue  = (180 / Double.pi) * deviceMotion.attitude.yaw

以上图为例,若咱们向下垂头 45 度,则核算得到的 pitchValue 为 -45,若咱们向上昂首 45 度,则核算得到的 pitchValue 为 45,以此类推。

CMAttitude 中,咱们除了运用 rollpitchyaw 特点取得弧度为单位的欧拉角表明,还能够运用 rotationMatrix 取得其旋转矩阵表明、能够运用 quaternion 取得其四元数表明。这里不做详细展开。

  1. rotationRate 是设备的旋转速率,CMRotationRate 结构中包括指定设备绕三个轴的旋转速率的数据 xyz。其单位为弧度/秒。
  2. gravity,回来以设备参阅系表明的重力矢量,包括 xyz 三个方向。设备的总加速度等于重力加上用户施加到设备的加速度。单位是 m/s,或是 N/kg。
  3. userAcceleration 是用户给予设备的加速度,包括 xyz 三个方向。单位是 m/s,或是 N/kg。
  4. magneticField 回来相对于设备的磁场矢量。 其特点 field 是包括 3 轴校准磁场数据的结构。accuracy 是指示磁场估量准确性的枚举常量值。
  5. heading 是相对于当时参阅系的航向角,以度为单位。该特点只在 VisionOS 体系上收效。
  6. sensorLocation 界说设备的传感器方位。回来枚举类型默许传感器方位、传感器坐落左边耳机中、传感器坐落右侧耳机中。

总结

CMHeadphoneMotionManager 是 Apple 在 iOS 14 及今后的版本中提供的一个 API,它允许运用程序检测和响应耳机的运动和姿势。这个 API 能够检测到耳机的歪斜、旋转和移动等动作,并将这些信息传递给运用程序。对于增强现实和虚拟现实运用程序、运动和健身运用程序等,为开发人员提供了一种新的用户交互的办法,带来用户带来更丰富、更个性化的体验。

笔者的 GitHub Headphone Motion 项目根据上述描绘,经过 CoreMotion 和 SceneKit 实现了头部盯梢数据的获取与可视化,以及实现运用头部盯梢数据进行视频流滑动的 Demo:

经过 Headphone Motion 拜访 AirPods 的头部盯梢数据
经过 Headphone Motion 拜访 AirPods 的头部盯梢数据
头部盯梢数据的获取与可视化 运用头部盯梢数据进行视频流滑动

其他参阅内容