github地址:[感知设备移动数据](https://github.com/EmyWong/PersonalUITech/tree/master/CMAttitudeDemo)

07/22/2022 21:01 下午

前言

上一篇我和大家一起学习了CMMotionManager获取加速度数据、陀螺仪数据、磁场数据的方式。

今天我们一起学习感知设备移动数据,与上述方式完全相同。

程序也可通过如下两种方式来感知设备移动数据:

> 使用基于代码块的方式获取设备移动数据。

> 使用周期性主动请求的方式获取设备移动数据。

正文

获取设备移动数据时,CMMotionManager将会返回一个CMDeviceMotion对象,该对象包含如下属性:

> attitude:该属性返回该设备的方位信息。该属性的返回值是一个CMAttitude类型的对象,该对象包含roll、pitch、yaw3个欧拉角的值。

欧拉角:用来确定定点转动刚体位置的3个一组独立角参量,由章动角θ、旋进角(即进动角)ψ和自转角j组成,为欧拉首先提出而得名。

不了解欧拉角的同学可以去百度一下。

> rotationRate:该属性返回原始的陀螺仪信息,该属性值为CMRotationRate结构体变量。基本等同于前面介绍的陀螺仪数据。

> gravity:该属性返回地球重力对该设备在X、Y、Z轴上施加的重力加速度。

> userAcceleration:该属性返回用户外力对该设备在X、Y、Z轴上施加的重力加速度。

> magneticField:该属性返回校准后的磁场信息。该属性值是一个CMCalibratedMagneticField结构体变量。CMCalibratedMagneticField类型的变量包括field和accuracy两个字段,其中field代表X、YZ、轴上的磁场强度,accuracy则代表磁场强度的精度。

因为CMAttitude类型的变量用于表示该设备的控件方位。其中roll、pitch、yaw这3个角度的意义如下。

> yaw角度:表示手机顶部转过的夹角。当手机绕着Z轴旋转时,该角度值发生改变。

例如,当该角度为0时,表明手机并未发生旋转,该角度为π/2时,代表手机逆时针转过90°。

> pitch角度:表示手机顶部或尾部翘起的角度。当手机绕着X轴倾斜时,该角度值发生变化。该角度的取值范围是-π~π。

假设将手机屏幕朝上水平放在桌子上,如果桌子是完全水平的。该角度应该是0。

假如从手机顶部开始抬起。直到将手机沿X轴旋转180°(屏幕向下水平放在桌面上),在这个旋转过程中,该角度值会从0变化到π。也就是说,从手机顶部抬起时,该角度值会逐渐增大,直到等于π。

如果从手机底部开始抬起,直到将手机沿X轴旋转180°(屏幕向下水平放在桌面上),该角度值会从0变化到-π。也就是说,从手机底部抬起时,该角度值会逐渐减小,直到等于-π。

> roll角度:表示手机左侧或右侧翘起的角度。当手机绕着Y轴倾斜时,该角度值发生变化。该角度的取值范围在-π/2~π/2。

假设将手机屏幕朝上水平放在桌面上,如果桌面是完全水平的,该角度值应为0。

假如将手机左侧逐渐抬起,直到将手机沿Y轴旋转90°(手机与桌面垂直),在这个旋转过程中,该角度值会从0变化到π/2。也就是说,从手机左侧抬起时,该角度值会逐渐增大,直到等于π/2。

如果从手机右侧开始抬起,直到将手机沿Y轴旋转90°(手机与桌面垂直),该角度值会从0变化到-π/2。也就是说,从手机左侧抬起时,该角度值会逐渐减少,直到等于-π/2。

代码

主要的属性我已介绍完毕,下面我们开始实战演练。

#import "ViewController.h"
#import <CoreMotion/CoreMotion.h>
 
@interface ViewController ()
{
    NSTimer *updateTimer;
}
@property (strong, nonatomic) CMMotionManager *motionManager;
@property (weak, nonatomic) IBOutlet UILabel *showField;
@end
 
@implementation ViewController
 
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    //创建CMMotionManager对象
    self.motionManager = [[CMMotionManager alloc] init];
    //如果可以获取设备的动作信息
    if (self.motionManager.deviceMotionAvailable) {
        //开始更新设备的动作信息
        [self.motionManager startDeviceMotionUpdates];
    } else {
        NSLog(@"该设备的deviceMotion不可用");
    }
}
 
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    //使用定时器周期性获取设备移动信息
    updateTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateDisplay) userInfo:nil repeats:YES];
    [updateTimer fire];
}
 
- (void)updateDisplay {
    if (self.motionManager.deviceMotionAvailable) {
        //获取设备移动信息
        CMDeviceMotion *deviceMotion = self.motionManager.deviceMotion;
        NSMutableString *str = [NSMutableString stringWithFormat:@"devuceMotion信息为:\n"];
        
        [str appendString:@"---attitude信息---\n"];
        [str appendFormat:@"attitude的yaw:%+.2f\n",deviceMotion.attitude.yaw];
        [str appendFormat:@"attitude的pitch:%+.2f\n",deviceMotion.attitude.pitch];
        [str appendFormat:@"attitude的roll:%+.2f\n",deviceMotion.attitude.roll];
        
        [str appendFormat:@"---rotationRate信息---\n"];
        [str appendFormat:@"rotationRate的X:%+.2f\n",deviceMotion.rotationRate.x];
        [str appendFormat:@"rotationRate的Y:%+.2f\n",deviceMotion.rotationRate.y];
        [str appendFormat:@"rotationRate的Z:%+.2f\n",deviceMotion.rotationRate.z];
        
        [str appendFormat:@"---gravity信息---\n"];
        [str appendFormat:@"gravity的X:%+.2f\n",deviceMotion.gravity.x];
        [str appendFormat:@"gravity的Y:%+.2f\n",deviceMotion.gravity.y];
        [str appendFormat:@"gravity的Z:%+.2f\n",deviceMotion.gravity.z];
        
        [str appendString:@"---magneticField信息---\n"];
        [str appendFormat:@"magneticField的X:%+.2f\n",deviceMotion.magneticField.field.x];
        [str appendFormat:@"magneticField的Y:%+.2f\n",deviceMotion.magneticField.field.y];
        [str appendFormat:@"magneticField的Z:%+.2f\n",deviceMotion.magneticField.field.z];
        self.showField.text = str;
    }
}
 
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
 
@end

运行效果:

很简单,大家快动手试一试吧~