zoukankan      html  css  js  c++  java
  • 加速计与陀螺仪

     

    设备静止时受到的地球引力为1g,1g是物体在地球的海平面上受到的下拉力(9.8米/秒²)。假如设备从高处掉落,其加速计测量到的加速度将为0g。假如设备水平放在桌面上,则加速计测量出的加速度为1g,且方向朝上。

    加速计测量3个轴(x、y和z)上的值,如图所示:

    这个轴在方向上有些不同于传统坐标轴,考虑以下实际情况:

    1g重力的分布情况是:y=-1.0

     

    1g重力的分布情况是:x=1.0

     

    1g重力的分布情况是:z=-1.0

     

    1g重力的分布情况是:x=0.5,y=-0.5

     

    1g重力的分布情况是:y=-0.5,z=0.5

     

    仅当设备的朝向相对于重力的方向发生变化时,加速计才能检测到;要同时检测设备的朝向和运动数据,就需要用到陀螺仪了。当查询设备的陀螺仪时,它将报告设备绕x, y, z轴的旋转速度,单位为弧度/秒;2弧度相当于一整圈,因此陀螺仪返回读数2表示设备绕相应的轴每秒转一圈。

    有两种方式访问设备的朝向和运动数据,一种是通过UIDevice请求朝向通知,另一种是利用框架Core Motion定期地直接访问加速计和陀螺仪数据。

    通过UIDevice请求朝向通知

    虽然可直接查询加速计并使用它返回的值判断设备的朝向,但Apple为开发人员简化了这项工作。单例UIDevice表示当前设备,它包含方法beginGeneratingDeviceOrientationNotifications,该方法命令iOS将朝向通知发送到通知中心(NSNotificationCenter)。启动通知后,就可以注册一个NSNotificationCenter实例,以便设备的朝向发生变化时自动调用指定的方法。

    通过访问UIDevice的属性orientation来获得设备当前朝向,该属性的类型为枚举值UIDeviceOrientation,有6个预定义值:

    UIDeviceOrientationFaceUp — 设备正面朝上

    UIDeviceOrientationFaceDown — 设备正面朝下

    UIDeviceOrientationPortrait — 纵向(Home键在下)

    UIDeviceOrientationPortraitUpsideDown — 纵向倒转(Home键在上)

    UIDeviceOrientationLandscapeLeft — Home键在左边的横向

    UIDeviceOrientationLandscapeRight — Home键在右边的横向

    复制代码
    - (void)viewDidLoad
    {
        [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    
        [[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(orientationChanged:) name:@"UIDeviceOrientationDidChangeNotification"object:nil];
    
        [super viewDidLoad];
    }
    
    - (void)orientationChanged:(NSNotification *)notification
    {
      UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
      NSLog(@"当前朝向枚举数字值:%d",orientation);
    
      switch (orientation) {
        case UIDeviceOrientationPortrait:
          self.lblOriention.text = @"Portrait";
          break;
        case UIDeviceOrientationPortraitUpsideDown:
          self.lblOriention.text = @"Portrait Upside Down";
          break;
        case UIDeviceOrientationLandscapeLeft:
          self.lblOriention.text = @"Landscape Left";
          break;
        case UIDeviceOrientationLandscapeRight:
          self.lblOriention.text = @"Landscape Right";
          break;
        case UIDeviceOrientationFaceUp:
          self.lblOriention.text = @"Face Up";
          break;
        case UIDeviceOrientationFaceDown:
          self.lblOriention.text = @"Face Down";
          break;
        default:
          self.lblOriention.text = @"Unknown";
          break;
        }
    }
    复制代码

    代码解释:

    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

    beginGeneratingDeviceOrientationNotifications从字面来理解是:开始产生设备朝向通知。实际作用是,通过调用该方法通知设备:如果用户改变了iPhone或iPad的朝向,我们想获悉这一点。

    [[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(orientationChanged:) name:@"UIDeviceOrientationDidChangeNotification"object:nil];

    [NSNotificationCenter defaultCenter]调用默认的消息中心,然后向默认的消息中心添加

    addObserver — 观察者,即处理通知的类,如果是当前类,则设置为self。

    selector — 收到通知后调用何种方法。

    name — 通知的名字,上面的"UIDeviceOrientationDidChangeNotification"来自于UIDevice.h:

    UIKIT_EXTERNNSString *constUIDeviceOrientationDidChangeNotification;

    使用Core Motion读取加速计和陀螺仪数据

    利用UIDevice只能判断极端朝向,应用程序经常要获悉这些朝向之间的过渡状态,如设备处于某个倾斜位置。Core Motion运动管理器让您能够指定从加速计和陀螺仪那里接收更新的频率(单位为秒),还让您能够直接指定一个处理程序块(handle block),每当更新就绪时都将执行该处理程序块。

    实际加速度在Core Motion里被分解成了两部分:Gravity和UserAcceleration。Gravity代表重力1g在设备的分布情况,UserAcceleration代表设备运动中的加速度分布情况。将这两者相加就等于实际加速度。Gravity的三个轴所受的重力加起来始终等于1g,而UserAcceleration取决于单位时间内动作的幅度大小。

    CMRotationRate的X,Y,Z分别代表三个轴上的旋转速率,单位为弧度/秒。旋转速度为1弧度/秒,意味着设备每秒旋转半圈。这里复习一下弧度与角度的转换:

    1角度 = π/180 弧度

    1弧度 = 180/π角度

    360角度 = 360 * π/180 = 2π弧度 = 一整圈

    CMAttitude的三个属性Yaw,Pitch和Roll分别代表左右摆动、俯仰以及滚动。可以将设备想象成一架飞机,下面的gif图演示了各种运动状态:

    Yaw的运动状态:

    Pitch的运动状态:

    Roll的运动状态:

    让应用程序使用CMMotionManager需要3个步骤:分配并初始化运动管理器→设置更新频率→使用startDeviceMotionUpdatesToQueue:withHandler请求开始更新并将更新发送给一个处理程序块。

    首先需要将框架Core Motion添加到项目中:

    下面的代码实现了这样一个界面,通过CMMotionManager返回了设备的各个状态值:

    复制代码
    #import "ViewController.h"
    
    
    @interface ViewController ()
    
    @property (strong, nonatomic) IBOutlet UILabel *lblYaw;
    @property (strong, nonatomic) IBOutlet UILabel *lblPitch;
    @property (strong, nonatomic) IBOutlet UILabel *lblRoll;
    
    @property (strong, nonatomic) IBOutlet UILabel *lblAccelerometerX;
    @property (strong, nonatomic) IBOutlet UILabel *lblAccelerometerY;
    @property (strong, nonatomic) IBOutlet UILabel *lblAccelerometerZ;
    
    @property (strong, nonatomic) IBOutlet UILabel *lblGravityX;
    @property (strong, nonatomic) IBOutlet UILabel *lblGravityY;
    @property (strong, nonatomic) IBOutlet UILabel *lblGravityZ;
    
    @property (strong, nonatomic) IBOutlet UILabel *lblRotationRateX;
    @property (strong, nonatomic) IBOutlet UILabel *lblRotationRateY;
    @property (strong, nonatomic) IBOutlet UILabel *lblRotationRateZ;
    
    @property (strong, nonatomic) CMMotionManager *motionManager;
    
    - (IBAction)motionSwitchHandler:(id)sender;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        self.motionManager = [[CMMotionManager alloc] init];
        self.motionManager.deviceMotionUpdateInterval = 1.0f/10.0f; //1秒10次
    }
    
    - (void)controlHardware
    {
        [self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMDeviceMotion *motion, NSError *error) {
            //Acceleration
            if(fabs(motion.userAcceleration.x)>1.3f)
                self.lblAccelerometerX.text = [NSString stringWithFormat:@"%.2f",motion.userAcceleration.x];
            if(fabs(motion.userAcceleration.y)>1.3f)
                self.lblAccelerometerY.text = [NSString stringWithFormat:@"%.2f",motion.userAcceleration.y];
            if(fabs(motion.userAcceleration.z)>1.3f)
                self.lblAccelerometerZ.text = [NSString stringWithFormat:@"%.2f",motion.userAcceleration.z];
            //Gravity
            self.lblGravityX.text = [NSString stringWithFormat:@"%.2f",motion.gravity.x];
            self.lblGravityY.text = [NSString stringWithFormat:@"%.2f",motion.gravity.y];
            self.lblGravityZ.text = [NSString stringWithFormat:@"%.2f",motion.gravity.z];
            //yaw,pitch,roll
            self.lblYaw.text = [NSString stringWithFormat:@"%.2f",motion.attitude.yaw];
            self.lblPitch.text = [NSString stringWithFormat:@"%.2f",motion.attitude.pitch];
            self.lblRoll.text = [NSString stringWithFormat:@"%.2f",motion.attitude.roll];
            //Gyroscope's rotationRate(CMRotationRate)
            self.lblRotationRateX.text = [NSString stringWithFormat:@"%.2f",motion.rotationRate.x];
            self.lblRotationRateY.text = [NSString stringWithFormat:@"%.2f",motion.rotationRate.y];
            self.lblRotationRateZ.text = [NSString stringWithFormat:@"%.2f",motion.rotationRate.z];
        }];
    }
    
    - (IBAction)motionSwitchHandler:(id)sender
    {
        UISwitch *motionSwitch = (UISwitch *)sender;
        if(motionSwitch.on)
        {
            [self controlHardware];
        }
        else
        {
            [self.motionManager stopDeviceMotionUpdates];
        }
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    @end
    复制代码

    P.s. 只有2010年后的设备支持陀螺仪。要检查设备是否提供了这种支持,可使用CMMotionManager的布尔属性gyroAvailable,如果其值为YES,则表明当前设备支持陀螺仪。

  • 相关阅读:
    【重构笔记02】重新组织函数
    【重构笔记01】第一个案例/补齐插件
    仿iphone日历插件(beta)
    都别说工资低了,我们来一起写简单的dom选择器吧!
    【单页应用】一起来单页应用吧,实现简单微博功能!(总结)
    【单页应用】一起来单页应用吧,实现简单微博功能!(下)
    【单页应用】一起来单页应用吧,实现简单微博功能!(上)
    RequireJS与Backbone简单整合
    初探Backbone
    RequireJS学习笔记
  • 原文地址:https://www.cnblogs.com/cyyljw/p/7093043.html
Copyright © 2011-2022 走看看