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,则表明当前设备支持陀螺仪。

  • 相关阅读:
    Vue路由机制
    谷歌浏览器打不开应用商店的解决方法
    Vue报错——Component template should contain exactly one root element. If you are using vif on multiple elements, use velseif to chain them instead.
    Vue.js学习之——安装
    Vue使用axios无法读取data的解决办法
    关于localstorage存储JSON对象的问题
    2013年整体计划
    个人喜欢的警语收集
    Linux防火墙的关闭和开启
    Flex修改title 转载
  • 原文地址:https://www.cnblogs.com/CoderWayne/p/3671101.html
Copyright © 2011-2022 走看看