美文网首页iOS干货ios框架iOS 实用
iOS学习笔记34-加速计和陀螺仪

iOS学习笔记34-加速计和陀螺仪

作者: 执着丶执念 | 来源:发表于2016-04-16 11:39 被阅读9177次

一、CoreMotion框架介绍

我们知道有一些iOS的应用,会有一些特殊的要求,比如:

  1. 电子罗盘指南针之类的应用:让我们知道方向。
  2. 运动类型软件:让我们知道我们跑步多少公里。
  3. 社交软件中的摇一摇功能。
  4. 游戏中扮演角色类中根据设备的晃动等进行操作。

其实,他们多半是使用了iOS中的一个核心运动框架CoreMotion.framework

  • 使用iOS提供给我们的CoreMotion框架,主要是为了访问加速度计陀螺仪的相关数据。
  • 它不仅仅提供给你获得实时的加速度值和旋转速度值,更重要的是,苹果在其中集成了很多算法,可以直接给你输出把重力加速度分量剥离的加速度,省去你的高通滤波操作,以及提供给你一个专门的设备的三维位置信息。
传感器介绍:
  1. 加速度计:
    加速度计的原理很简单,现在手机里面基本配备的都是3维线传感器,也就是说,用来测量x,y,z三个轴上的加速力。加速力就是当物体在加速过程中作用在物体上的力,就好比地球引力,也就是重力。


  2. 陀螺仪:
    陀螺仪的主要作用,是基于角动量守恒的理论,沿着某个特定的坐标轴测量旋转速率。在使用中,陀螺仪的转子在高速旋转时,始终指向一个固定的方向,当运动物体的运动方向偏离预定方向时,陀螺仪就可以感受出来。


二、CoreMotion使用

CoreMotion主要负责三种数据:
  • 加速度值CMAccelerometerData
  • 陀螺仪值CMGyroData
  • 设备motion值CMDeviceMotion

实际上,这个设备motion值就是通过加速度和旋转速度进行变换算出来的


CMDeviceMotion属性介绍:
  1. attitude:通俗来讲,就是告诉你手机在当前空间的位置和姿势
  2. gravity:重力信息,其本质是重力加速度矢量在当前设备的参考坐标系中的表达
  3. userAcceleration:加速度信息
  4. rotationRate:即时的旋转速率,是陀螺仪的输出
使用CoreMotion的步骤:
  1. 初始化CMMotionManager管理对象
  2. 调用管理对象的对象方法获取数据,有2种方式
  3. 处理数据
  4. 当你不需要使用的时候,停止获取数据
-(void)stopAccelerometerUpdates;//停止获取加速度计数据
-(void)stopGyroUpdates;//停止获取陀螺仪数据
-(void)stopDeviceMotionUpdates;//停止获取设备motion数据
在CoreMotion中有2种获取数据方式:
  1. Push方式:
    提供一个线程管理器NSOperationQueue和一个回调BlockCoreMotion自动在每一个采样数据到来的时候回调这个Block,进行处理。在这种情况下,Block中的操作会在你自己的主线程内执行。
  2. Pull方式:
    你必须主动去向CMMotionManager要数据,这个数据就是最近一次的采样数据。你不去要,CMMotionManager就不会给你。
1. 加速度计使用Pull方式获取:
- (void)useAccelerometerPull{
    //初始化全局管理对象
    CMMotionManager *manager = [[CMMotionManager alloc] init];
    self.motionManager = manager;
    //判断加速度计可不可用,判断加速度计是否开启
    if ([manager isAccelerometerAvailable] && ![manager isAccelerometerActive]){
        //告诉manager,更新频率是100Hz
        manager.accelerometerUpdateInterval = 0.01;
        //开始更新,后台线程开始运行。这是Pull方式。
        [manager startAccelerometerUpdates];
    }
    //获取并处理加速度计数据
    CMAccelerometerData *newestAccel = self.motionManager.accelerometerData;
    NSLog(@"X = %.04f",newestAccel.acceleration.x);
    NSLog(@"Y = %.04f",newestAccel.acceleration.y);
    NSLog(@"Z = %.04f",newestAccel.acceleration.z);
}
2. 加速度计使用Push方式获取:
- (void)useAccelerometerPush{
    //初始化全局管理对象
    CMMotionManager *manager = [[CMMotionManager alloc] init];
    self.motionManager = manager;
    //判断加速度计可不可用,判断加速度计是否开启
    if ([manager isAccelerometerAvailable] && ![manager isAccelerometerActive]){
        //告诉manager,更新频率是100Hz
        manager.accelerometerUpdateInterval = 0.01;
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        //Push方式获取和处理数据
        [manager startAccelerometerUpdatesToQueue:queue
                 withHandler:^(CMAccelerometerData *accelerometerData, NSError *error)
         {
             NSLog(@"X = %.04f",accelerometerData.acceleration.x);
             NSLog(@"Y = %.04f",accelerometerData.acceleration.y);
             NSLog(@"Z = %.04f",accelerometerData.acceleration.z);
         }];
    }
}
3. 陀螺仪使用Push方式获取,Pull方式就不列出来了,和加速度计使用相似:
- (void)useGyroPush{
    //初始化全局管理对象
    CMMotionManager *manager = [[CMMotionManager alloc] init];
    self.motionManager = manager;
    //判断陀螺仪可不可以,判断陀螺仪是不是开启
    if ([manager isGyroAvailable] && ![manager isGyroActive]){
        
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        //告诉manager,更新频率是100Hz
        manager.gyroUpdateInterval = 0.01;
        //Push方式获取和处理数据
        [manager startGyroUpdatesToQueue:queue
                             withHandler:^(CMGyroData *gyroData, NSError *error)
        {
            NSLog(@"Gyro Rotation x = %.04f", gyroData.rotationRate.x);
            NSLog(@"Gyro Rotation y = %.04f", gyroData.rotationRate.y);
            NSLog(@"Gyro Rotation z = %.04f", gyroData.rotationRate.z);
        }];
    }
}

以上代码必须是真机上才能正常运行,利用上面的知识我们可以做类似于这样的效果:

- (void)keepBalance {
    if (self.manager.isDeviceMotionAvailable) {
        //设置加速计采样频率
        self.manager.deviceMotionUpdateInterval = 0.05f;
        [self.manager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
            double rotation = atan2(motion.gravity.x, motion.gravity.y) - M_PI;
            self.imageView.transform = CGAffineTransformMakeRotation(rotation);
        }];
    }
}
有什么建议可以在下方评论区中提出!

相关文章

网友评论

  • 48d063e3b39b:我就是要做出你第一张图片的效果。但是根据你那个陀螺仪方法获取出来的角度始终不对啊。不管手机怎么偏都没用。。。。。我之前用的是这个方法,- (void)startDeviceMotionUpdatesToQueue:(NSOperationQueue *)queue withHandler:(CMDeviceMotionHandler)handler __TVOS_PROHIBITED;能获取到。但是有个数据总是乱跳。比如返回 100 100 100 ,,然后陡然一个负值。这个是怎么回事啊。。求教
  • 郭苒:你确定这段代码正确 if ([manager isAccelerometerAvailable] && [manager isAccelerometerActive])?你确定[manager isAccelerometerActive]不是![manager isAccelerometerActive]?
    Eden大虾:你说的是正确的, 我跑程序的时候还纳闷为何程序所有的X,Y,Z输出一直都是0,想着评论一下,没想到你已经说啦
  • 不进则退:手机左右摇晃,图片跟着左右平移,这个怎么弄啊
    d428c82fffac:图片是平移还是左右晃动,左右晃动的用指南针可以。平移应该是改变frame吧
    阿噗阿噗阿:请问你这个效果弄出来了么?
  • OrangesChen:能问一下更新频率最大值有限制的么?不同的手机型号有影响么?
  • 叔简:[App] if we're in the real pre-commit handler we can't actually add any new fences due to CA restriction,我使用的时候出现了这个错误。从网上搜的OS_ACTIVITY_MODE设置为disable也不能用,不知道楼主有没有遇到
    蔡林林:这个问题解决了吗?可以说下怎么解决的吗?
  • Song1025:赞一个
  • 我的时代我开创:问下指针的指向怎么实现? 就是导航箭头的方向
    梁同桌:@我的时代我开创 指南针是另外的,我记得
    VR http://www.jianshu.com/p/94bf8916645d
    我的时代我开创:@执着_执念 好的 谢谢
    执着丶执念: @我的时代我开创 应该是用陀螺仪,获取x,y,z的旋转度数,更新指针方向
  • 701749d3a13b:这个图片的是怎么做到的,能不能发个Demo啊
    小_蜡笔:这个有demo吗
    701749d3a13b:@执着_执念 好的 ,谢谢 做了好久都没写出来 :joy:
    执着丶执念:@倪Orz 那个动态图是从网上扣的,旋转那个图应该是有个大于手机屏幕的图片,根据陀螺仪计算旋转角度进行旋转

本文标题:iOS学习笔记34-加速计和陀螺仪

本文链接:https://www.haomeiwen.com/subject/rmonlttx.html