CoreMotion
Core Motion可以让开发者从各个内置传感器那里获取未经修改的传感数据,并观测或响应设备各种运动和角度变化。这些传感器包括陀螺仪、加速器和磁力仪(罗盘)。
加速器和陀螺仪数据以iOS设备上3维坐标来展示。当手机呈水平放置的时候(如下图),X轴从左(负值)到右(正值),Y周从下(负值)到上(正值),还有就是Z轴垂直方向上从背屏(负值)到屏幕(正值)。
CoreMotionManager
CoreMotionManager类能够使用到设备的所有移动数据(motion data),Core Motion框架提供了两种对motion数据的操作方式,一个是"pull",另一个是"push",其中"pull"方式能够以CoreMotionManager的只读方式获取当前任何传感器状态或是组合数据。"push"方式则是以块或者闭包的形式收集到你想要得到的数据并且会在特定周期内得到实时的更新。
CoreMotionManager为四种motion数据类型的每一个都提供了统一的接口:accelerometer,gyro,magnetometer和deviceMotion。
//创建 CoreMotionManager
_motionManager = [[CMMotionManager alloc] init];
加速计
//Push方式,获取加速度
- (void)startAccelerometerUpdatePush {
if ([self.motionManager isDeviceMotionAvailable] && ![self.motionManager isDeviceMotionActive]) {
_motionManager.accelerometerUpdateInterval = 1.0;
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[_motionManager startAccelerometerUpdatesToQueue:queue withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) {
if (error) {
[self.motionManager stopAccelerometerUpdates];
NSLog(@"There is something error for accelerometer update");
}else {
NSLog(@"\n加速度:\nX: %f\nY: %f\nZ: %f", accelerometerData.acceleration.x, accelerometerData.acceleration.y, accelerometerData.acceleration.z);
}
}];
}
}
//Pull方式,获取加速度数据
- (void)startAccelerometerUpdatePull {
if ([self.motionManager isAccelerometerAvailable] && ![self.motionManager isAccelerometerActive]) {
[self.motionManager startAccelerometerUpdates];
}
NSLog(@"\n加速度:\nX: %f\nY: %f\nZ: %f", self.motionManager.accelerometerData.acceleration.x, self.motionManager.accelerometerData.acceleration.y, self.motionManager.accelerometerData.acceleration.z);
}
//停止获取加速度
- (void)stopAccelerometerUpdate {
if ([_motionManager isAccelerometerActive]) {
[_motionManager stopAccelerometerUpdates];
}
}
陀螺仪
//Push方式,获取陀螺仪数据
- (void)startGyroUpdatePush {
if ([_motionManager isGyroAvailable] && ![_motionManager isGyroActive]) {
_motionManager.gyroUpdateInterval = 1.0;
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[_motionManager startGyroUpdatesToQueue:queue withHandler:^(CMGyroData * _Nullable gyroData, NSError * _Nullable error) {
if (error) {
[self stopGyroUpdate];
NSLog(@"There is something error for accelerometer update");
}else {
NSLog(@"\n旋转速度:\nX: %f\nY: %f\nZ: %f", gyroData.rotationRate.x, gyroData.rotationRate.y, gyroData.rotationRate.z);
}
}];
}
}
//Pull方式,获取陀螺仪数据
- (void)startGyroUpdatePull {
if ([self.motionManager isGyroAvailable] && ![self.motionManager isGyroActive]) {
[self.motionManager startGyroUpdates];
}
NSLog(@"\n陀螺仪:\nX: %f\nY: %f\nZ: %f", self.motionManager.gyroData.rotationRate.x, self.motionManager.gyroData.rotationRate.y, self.motionManager.gyroData.rotationRate.z);
}
//停止获取陀螺仪数据
- (void)stopGyroUpdate {
if ([_motionManager isGyroActive]) {
[_motionManager stopGyroUpdates];
}
}
磁力计
//Pull方式,获取磁力计数据
- (void)startMagnetometerUpdatePull {
if ([self.motionManager isMagnetometerAvailable] && ![self.motionManager isMagnetometerActive]) {
[self.motionManager startMagnetometerUpdates];
}
NSLog(@"\n磁力计:\nX: %f\nY: %f\nZ: %f", self.motionManager.magnetometerData.magneticField.x, self.motionManager.magnetometerData.magneticField.y, self.motionManager.magnetometerData.magneticField.z);
}
//Push方式,获取磁力计数据
- (void)startMagnetometerUpdatePush {
if ([_motionManager isMagnetometerAvailable] && ![_motionManager isMagnetometerActive]) {
_motionManager.magnetometerUpdateInterval = 1.0;
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[_motionManager startMagnetometerUpdatesToQueue:queue withHandler:^(CMMagnetometerData * _Nullable magnetometerData, NSError * _Nullable error) {
if (error) {
[self stopMagnetometerUpdate];
NSLog(@"There is something error for magnetometer update");
}else {
NSLog(@"\n磁力计:\nX: %f\nY: %f\nZ: %f", magnetometerData.magneticField.x, magnetometerData.magneticField.y, magnetometerData.magneticField.z);
}
}];
}
}
//停止获取磁力计数据
- (void)stopMagnetometerUpdate {
if ([_motionManager isMagnetometerActive]) {
[_motionManager stopMagnetometerUpdates];
}
}
Device Motion
//Push方式,获取deviceMotion数据
- (void)startDeviceMotionUpdatePush {
// __weak __typeof__(self) weakself = self;
if ([self.motionManager isDeviceMotionAvailable] && ![self.motionManager isDeviceMotionActive]) {
[self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue]
withHandler:^(CMDeviceMotion * _Nullable motion,
NSError * _Nullable error) {
//2. Gravity 获取手机的重力值在各个方向上的分量,根据这个就可以获得手机的空间位置,倾斜角度等
//重力加速度在各个方向的分量
double gravityX = motion.gravity.x;
double gravityY = motion.gravity.y;
double gravityZ = motion.gravity.z;
NSLog(@"\n重力:\nX:%f\nY:%f\nZ:%f", gravityX, gravityY, gravityZ);
//获取手机的倾斜角度(zTheta是手机与水平面的夹角, xyTheta是手机绕自身旋转的角度):
double zTheta = atan2(gravityZ,sqrtf(gravityX*gravityX+gravityY*gravityY))/M_PI*180.0;
double xyTheta = atan2(gravityX,gravityY)/M_PI*180.0;
NSLog(@"\n与水平夹角: %f\n自身旋转角度:%f", zTheta, xyTheta);
}];
}
}
//Pull方式,获取deviceMotion数据
- (void)startDeviceMotionUpdatePull {
if ([self.motionManager isDeviceMotionAvailable] && ![self.motionManager isDeviceMotionActive]) {
[self.motionManager startDeviceMotionUpdates];
CMDeviceMotion *deviceMotion = self.motionManager.deviceMotion;
double gravityX = deviceMotion.gravity.x;
double gravityY = deviceMotion.gravity.y;
double gravityZ = deviceMotion.gravity.z;
NSLog(@"\n重力:\nX:%f\nY:%f\nZ:%f", gravityX, gravityY, gravityZ);
}
}
//停止获取deviceMotion数据
- (void)stopDeviceMotionUpdate {
if ([self.motionManager isDeviceMotionActive]) {
[self.motionManager stopDeviceMotionUpdates];
}
}
欧拉角
空间位置的欧拉角,通过欧拉角可以算得手机两个时刻之间的夹角,比用角速度计算精确地多
double roll = motionManager.deviceMotion.attitude.roll;
double pitch = motionManager.deviceMotion.attitude.pitch;
double yaw = motionManager.deviceMotion.attitude.yaw;
四元数
空间位置的四元数(与欧拉角类似,但解决了万向结死锁问题)
double w = motionManager.deviceMotion.attitude.quaternion.w;
double wx = motionManager.deviceMotion.attitude.quaternion.x;
double wy = motionManager.deviceMotion.attitude.quaternion.y;
double wz = motionManager.deviceMotion.attitude.quaternion.z;