文章目录
简介
目前市面上的iOS设备都配备了运动传感器,能够获取设备的加速度以及角速度,而运动传感器的引入,也为用户交互带来了新的体验,比如很多游戏(如赛车类游戏)就是与iOS设备的运动传感器结合起来,从而实现很多新奇的玩法。为了更加方便开发者使用设备上的传感器,苹果带来了CoreMotion框架,基于该框架,可以非常快捷的获取设备当前传感器的各个数值。
运动传感器的常见用途
iOS设备中的运动传感器被广泛应用于游戏类应用以及导航类应用中,例如,在地图类应用中,选择步行模式,就可以通过手机当前的方向来判断行走的方向。又如我们常见的赛车类游戏以及跑酷类游戏中,也可以通过摇动手机来改变汽车以及游戏人物的运动方向。
iOS设备中的运动传感器
在iOS设备中,存在3种传感器:加速计(Accelerometer)、陀螺仪(Gyroscope)以及磁力计(magnetometer)。
- 陀螺仪(Gyroscope、GYRO-Sensor): 也叫地感器,传统结构是内部有个三轴陀螺,如下图所示。三轴陀螺仪的工作原理是通过测量三维坐标系内陀螺转子的垂直轴与设备之间的夹角,并计算角速度,通过夹角和角速度来判别物体在三维空间的运动状态。三轴陀螺仪可以同时测定上、下、左、右、前、后等6个方向(合成方向同样可分解为三轴坐标),最终可判断出设备的移动轨迹和加速度。
- 加速计(Accelerometer、G-Sensor): 也叫重力感应器,实际上是可以感知任意方向上的加速度(重力加速度则只是地表垂直方向加速度)。加速计通过测量组件在某个轴向的受力情况来得到结果,表现形式为轴向的加速度大小和方向(XYZ),这一点又有点类似于陀螺仪,但陀螺仪的更多关注自身旋转情况(原位运动),加速计则主要是测量设备的受力情况,也就是三轴运动情况,尽管加速计也可以在某个小范围换算出角速度,但设计原理决定似乎更适合于空间运动判断。
- 磁力计(Magnetic、M-Sensor): 也叫地磁、磁感器,可用于测试磁场强度和方向,定位设备的方位,磁力计的原理跟指南针原理类似,可以测量出当前设备与东南西北四个方向上的夹角。
综上所述,陀螺仪知道“我们转了个身”,加速计知道“我们又向前走了几米”,而磁力计则知道“我们是向西方向”的。
CoreMotion框架简介
为了更加方便开发者获得iOS设备运动传感器的数值,苹果提供了CoreMotion框架。通过CoreMotion框架,开发者不仅可以直接获取陀螺仪、加速计以及磁力计的数值,并且还对这些传感器的数值进行了一些加工,主要体现在对传感器数值进行了数学方面的处理。加工后的数据对于开发者来说,更加具有使用价值。
Core Motion框架包含有一个专门的CMMotionManager类,由这个manager去管理和运动相关的数据封装类。一个app可以接收4种设备的运动数据:
加速计数据
陀螺仪数据
磁力计数据
DeviceMotion数据(处理后的数据)
Pull模式与Push模式
CoreMotionManager类能够获取到设备的所有运动数据(motion data),Core Motion框架提供了两种对motion数据的操作方式,一个是”pull”,另一个是”push”。其中”pull”方式能够以CoreMotionManager的只读方式获取当前任何传感器状态或是组合数据。”push”方式则是以块或者闭包的形式收集到开发者希望得到的数据并且会在特定周期内得到实时的更新。
苹果官方也对Pull模式以及Push模式进行了对比,并且对于各自的使用场景给了一些建议。其中,Push模式更加适合需要实时采集传感器数据的应用,例如:数据采集类应用,而Pull模式适合绝大多数应用,一般来说,推荐用Pull模式。
获取运动传感器的裸数据
iOS设备中的运动传感器,可以借助陀螺仪、加速计以及磁力计来获取设备的运动数据,我们可以使用CoreMotion框架来分别获取3种传感器当前采样的数据,此时获取的数据可以认为是传感器的裸数据。但是,裸数据通常不能直接应用于实际的App开发,而是需要对裸数据采用数学方法进行综合计算,得到CMDeviceMotion数据后,才更加具有实际使用价值。介绍如何使用Push以及Pull方式分别获取传感器的裸数据。
加速计的裸数据
push模式
- Push模式:在Push模式下,通过accelerometerUpdateInterval属性来设置加速计的数据采样间隔. 然后调用 startAccelerometerUpdatesToQueue:withHandler: 方法即可获取加速计的裸数据。 在该方法中提供一个回调block,即采样获取数据成功后,采样到的数据即CMAccelerometerData对象,把该采样数据作为参数传递到block中,可以对数据进行后续处理。
//
// ViewController.m
// CoreMotion框架
//
// Created by on 2019/8/5.
// Copyright © 2019 Shae. All rights reserved.
//
#import "ViewController.h"
#import <CoreMotion/CoreMotion.h>
@interface ViewController ()
@property (nonatomic,strong) CMMotionManager *motionMgr;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)start:(UIButton *)sender {
[self startAccPush];
}
- (IBAction)stop:(UIButton *)sender {
[self stopAccPush];
}
//加速计的裸数据Push模式
- (CMMotionManager *)motionMgr{
if (_motionMgr==nil) {
_motionMgr=[[CMMotionManager alloc]init];
}
return _motionMgr;
}
-(void)startAccPush{
//设置采样间隔
self.motionMgr.accelerometerUpdateInterval=1.0;
//开始采样
[self.motionMgr startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) {
NSLog(@"x:%f,y:%f,z:%f",accelerometerData.acceleration.x,accelerometerData.acceleration.y,accelerometerData.acceleration.z);
}];
}
-(void)stopAccPush{
[self.motionMgr stopAccelerometerUpdates];
}
@end
Pull模式
在Pull模式下,首先推荐检查一下加速计是否可用,如果可用,则调用startAccelerometerUpdates方法启动。当需要获取当前加速计数据的时候,可以通过CMMotionManager的accelerometerData属性获取。
-(void)startAccPull{
//pull模式--加速计Accelerometer
if (self.motionMgr.isAccelerometerAvailable) {
// 启动采样
[self.motionMgr startAccelerometerUpdates];
}else{
NSLog(@"加速计Accelerometer不可用");
}
//获取加速计当前状态
CMAcceleration acceleration=self.motionMgr.accelerometerData.acceleration;
NSLog(@"accelerometer current state:x:%f, y:%f, z:%f",acceleration.x,acceleration.y,acceleration.z);
}
陀螺仪的裸数据
Push模式
在Push模式下,通过gyroUpdateInterval属性来设置陀螺仪的数据采样间隔,然后调用startGyroUpdatesToQueue:withHandler: 方法获取陀螺仪的裸数据。 在该方法中具有一个回调block,即采样获取数据成功后,采样到的数据即CMGyroData对象,把该采样数据作为参数传递到block中,可以对数据进行后续处理。
-(void)startGyroPush{
//设置采样间隔
self.motionMgr.gyroUpdateInterval = 1.0;
//开始采样
[self.motionMgr startGyroUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMGyroData * _Nullable gyroData, NSError * _Nullable error) {
NSLog(@"x:%f, y:%f, z:%f", gyroData.rotationRate.x, gyroData.rotationRate.y, gyroData.rotationRate.z);
}];
}
-(void)stopGyroPush{
[self.motionMgr stopGyroUpdates];
}
pull模式
在Pull模式下,首先推荐检查一下陀螺仪是否可用,如果可用,则调用startGyroUpdates方法启动。当需要获取当前陀螺仪数据的时候,可以通过CMMotionManager的gyroData属性获取。
-(void)startGyroPull{
//Pull模式--陀螺仪
if (self.motionMgr.isGyroAvailable) {
[self.motionMgr startGyroUpdates];
}else {
NSLog(@"陀螺仪GyroScope不可用");
}
//获取陀螺仪当前状态
CMRotationRate rationRate = self.motionMgr.gyroData.rotationRate;
NSLog(@"gyroscope current state: x:%f, y:%f, z:%f", rationRate.x, rationRate.y, rationRate.z);
}
磁力计的裸数据
Push模式
在Push模式下,通过magnetometerUpdateInterval属性来设置磁力计的数据采样间隔. 然后调用startMagnetometerUpdatesToQueue::withHandler: 方法获取磁力计的裸数据。 在该方法中具有一个回调block,即采样获取数据成功后,采样到的数据即CMMagnetometerData对象,把该采样数据作为参数传递到block中,可以对数据进行后续处理。
-(void)startMagnetoPush{
//设置采样间隔
self.motionMgr.magnetometerUpdateInterval = 1.0;
//开始采样
[self.motionMgr startMagnetometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMMagnetometerData * _Nullable magnetometerData, NSError * _Nullable error) {
NSLog(@"x:%f, y:%f, z:%f", magnetometerData.magneticField.x, magnetometerData.magneticField.y, magnetometerData.magneticField.z);
}];
}
-(void)stopMagetoPush{
[self.motionMgr stopMagnetometerUpdates];
}
Pull模式
在Pull模式下,首先推荐检查一下磁力计是否可用,如果可用,则调用startMagnetometerUpdates方法启动。当需要获取当前磁力计数据的时候,可以通过CMMotionManager的magnetometerData属性获取。
-(void)startMagnetoPull{
//Pull模式--磁力计
if (self.motionMgr.isMagnetometerAvailable) {
[self.motionMgr startMagnetometerUpdates];
}else {
NSLog(@"磁力计Magnetometer不可用");
}
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//获取磁力计当前状态
CMMagneticField magneticField = self.motionMgr.magnetometerData.magneticField;
NSLog(@"magnetometer current state: x:%f, y:%f, z:%f", magneticField.x,magneticField.y,magneticField.z);
}
CMDeviceMotion
CoreMotionManager对象,不仅仅能够分别提供加速计、陀螺仪和磁力计的裸数据,并且还能够把获取到的以上三种传感器的数据进行综合计算以及偏差调整,得到更加具有实际使用价值的数据,加工后的数据可以通过CoreMotionManager的deviceMotion属性获得。
简介
CMDeviceMotion类介绍
在CMDeviceMotion类中,可以获取设备当前的加速计、陀螺仪以及磁力计的裸数据,但与传感器的裸数据相比,CMDeviceMotion类中的数据已经经过了进一步的处理,这个处理过程由CoreMotion框架自动完成,主要包括对于裸数据的偏差纠正以及综合计算。总之,CMDeviceMotion类中获取的传感器数据,更加具有使用价值。
获取设备方向/朝向的数据
@property(readonly, nonatomic) CMAttitude *attitude;
获取陀螺仪相关数据
@property(readonly, nonatomic) CMRotationRate rotationRate;
获取加速计相关数据。其中,总加速度=重力加速度+用户产生的加速度
@property(readonly, nonatomic) CMAcceleration gravity; //重力加速度
@property(readonly, nonatomic) CMAcceleration userAcceleration; //用户产生的加速度
磁力计相关数据。其中,CMCalibratedMagneticField是一个结构体,包括两个成员变量field以及accuracy;
@property(readonly, nonatomic) CMCalibratedMagneticField magneticField ;
举例
通过deviceMotion获取的陀螺仪数据与直接获取陀螺仪的裸数据有差别,即数据进行了处理。
/*4.2 deviceMotion 陀螺仪的Pull模式 */
-(void)rotationRateDeviceMotionPull{
//Pull模式--device motion
if (self.motionMgr.isDeviceMotionAvailable) {
[self.motionMgr startDeviceMotionUpdates];
}else {
NSLog(@"device motion不可用");
}
//通过deviceMotion获取陀螺仪当前状态
CMDeviceMotion * deviceMotion = self.motionMgr.deviceMotion;
NSLog(@"device motion rationRate: x:%f, y:%f, z:%f",deviceMotion.rotationRate.x, deviceMotion.rotationRate.y,deviceMotion.rotationRate.z);
}
/*4.1 deviceMotion 陀螺仪的Push模式 */
-(void)startRotationRateDeviceMotionPush{
//设置采样间隔
self.motionMgr.deviceMotionUpdateInterval = 1.0;
//开始采样
[self.motionMgr startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
NSLog(@"x:%f, y:%f, z:%f", motion.rotationRate.x, motion.rotationRate.y, motion.rotationRate.z);
}];
}
-(void)stopRotationRateDeviceMotionPush{
[self.motionMgr stopDeviceMotionUpdates];
}
代码
https://github.com/ShaeZhuJiu/CoreMotion_base.git