iOS 传感器编程


iOS 传感器编程

内容概述

  • 传感器编程的准备工作
  • 加速度传感器(Accelerometer)
  • 陀螺仪传感器(Gyroscope)
  • 磁力传感器(Magnetometer)
  • 设备移动(Device motion)
  • 通过加速度传感器控制小球运动

设备传感器使我们的程序变得更加生动有趣,尤其体现在游戏开发中,例如,一些飞车类游戏可通过设备传感器来控制方向。iOS SDK 中提供了四种设备传感器,他们分别是,加速度传感器(Accelerometer)、陀螺仪(Gyroscope)、磁力传感器(Magnetometer)和设备移动传感器(Device motion)。传感器编程API框架是CoreMotion.framework,使用时必须添加该框架。传感器编程的核心类是CMMotionManager,可以调用startXXX和stopXXX方法对不同传感器开始更新和停止更新。

下面是本章核心类一览:

表1.1 本章核心类一览

类名称 类说明
CMMotionManager 传感器管理类,用来启动和停止服务及获得当前传感器数据
CMAccelerometerData 加速度传感器数据封装类
CMAcceleration 是CMAccelerometerData的一个属性,类型是一个结构体,用x、y、z三个变量表示三个方向的重力加速度
CMMagnetometerData 磁力传感器数据封装类
CMMagneticField 是CMMagnetometerData的一个属性,类型是一个结构体,用x、y、z三个变量表示三个方向的磁力
CMGyroData 陀螺仪数据封装类
CMRotationRate 是CMGyroData的一个属性,类型是一个结构体,用x、y、z三个变量表示三个方向的角速度旋转量
CMDeviceMotion 检测设备移动的属性的封装类,可以测量设备的加速度,角速度和设备当前姿势等
CMAttitude 设备当前方向的测量值,分别使用roll、pitch和yaw来表示设备的旋转量、左右倾斜量和上下偏移量

1.1 传感器编程的准备工作

传感器编程的首要任务是添加CoreMotion.framework到项目中,并添加头文件到当前项目。另外,我们需要检测当前传感器是否可利用,是否被激活。下面的案例用来检测传感器是否可利用、是否被激活。实现步骤如下:

  1. 创建项目,并添加CoreMotion.framework到项目中。
  2. 在界面添加一个按钮,并添加点击事件方法,并声明CMMotionManager属性。
#import <UIKit/UIKit.h>

#import <CoreMotion/CoreMotion.h>

@interface AmakerViewController : UIViewController

@property(nonatomic,strong)CMMotionManager *mm;

- (IBAction)check:(id)sender;

@end
  1. 在viewDidLoad方法中实例化CMMotionManager。
- (void)viewDidLoad

{

    [super viewDidLoad];

 self.mm = [[CMMotionManager alloc]init];

}
  1. 按钮单击事件方法实现。
- (IBAction)check:(id)sender {

    // 检测重力加速度传感器是否可利用,已经激活

    if (self.mm.isAccelerometerAvailable) {

        NSLog(@"Accelerometer Available...");

        if (self.mm.isAccelerometerActive) {

             NSLog(@"Accelerometer Active...");

        }else{

            NSLog(@"Accelerometer not Active...");

        }

    }else{

        NSLog(@"Accelerometer not Available...");

    }

    // 检测陀螺仪传感器是否可利用,已经激活

    if (self.mm.isGyroAvailable) {

        NSLog(@"Gyro Available...");

        if (self.mm.isGyroActive) {

            NSLog(@"Gyro Active...");

        }else{

             NSLog(@"Gyro not Active...");

        }

    }else{

        NSLog(@"Gyro not Available...");

    }

    // 检测磁力传感器是否可利用,已经激活

    if (self.mm.isMagnetometerAvailable) {

        NSLog(@"Magnetometer Available...");

        if (self.mm.isMagnetometerActive) {

            NSLog(@"Magnetometer Active...");

        }else{

            NSLog(@"Magnetometer not Active...");

        }

    }else{

        NSLog(@"Magnetometer not Available...");

    }

    // 检测设备移动传感器是否可利用,已经激活

    if (self.mm.isDeviceMotionAvailable) {

        NSLog(@"DeviceMotion Available...");

        if (self.mm.isDeviceMotionActive) {

            NSLog(@"DeviceMotion Active...");

        }else{

            NSLog(@"DeviceMotion not Active...");

        }

    }else{

        NSLog(@"DeviceMotion not Available...");

    }

}
  1. 程序运行结果如下所示。

图28.1  检测传感器当前状态

1.2 加速度传感器(Accelerometer)

通过减速度传感,可以获得设备当前x、y、z轴三个方向的加速度坐标值,坐标系统如下图所示。

图28.2 加速度传感器坐标系统

下面我们通过一个实例来演示加速度传感器的用法,该案例在界面上添加两个按钮分别开启和停止当前传感器,一个UILabel来显示三个方向上的加速度值。实现步骤如下所示:

  1. 创建一个项目添加CoreMotion.framework框架。
  2. 在界面上添加两个按钮和一个UILabel标签,为按钮创建点击事件方法,为标签添加属性,并声明CMMotionManager属性。
#import <UIKit/UIKit.h>

#import <CoreMotion/CoreMotion.h>

@interface AmakerViewController : UIViewController

// 开启方法

- (IBAction)start:(id)sender;

// 停止方法

- (IBAction)stop:(id)sender;

// 显示坐标数据的标签

@property (strong, nonatomic) IBOutlet UILabel *myData;

// 移动管理器

@property(strong,nonatomic) CMMotionManager *mm;

@end
  1. 在viewDidLoad方法中,实例化CMMotionManager
- (void)viewDidLoad

{

    [super viewDidLoad];

    // 实例化CMMotionManager

        self.mm = [[CMMotionManager alloc]init];

}
  1. 在开启方法中开启传感器服务,在Block方法中获得当前传感器数据。
- (IBAction)start:(id)sender {

    // 检测传感器是否可利用

    if (self.mm.isAccelerometerAvailable) {

        // 实例化操作队列

        NSOperationQueue *queue = [[NSOperationQueue alloc]init];

        // 开启传感器服务,在Block方法中获得当前传感器数据

        [self.mm startAccelerometerUpdatesToQueue:queue withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {

            // 属性

            CMAcceleration data =  accelerometerData.acceleration;

            // 三个坐标值

            double x = data.x;

            double y = data.y;

            double z = data.z;

            // NSLog打印

            NSString *str = [NSString stringWithFormat:@"[%f,%f,%f]",x,y,z];

            NSLog(@"%@",str);

            // 使用UILabel显示

           dispatch\_async(dispatch\_get\_main\_queue(), ^{

                self.myData.text = str;

           });

        }];

    }else{

        NSLog(@"Accelerometer not Available");

    }

}
  1. 在停止方法中停止传感器。
- (IBAction)stop:(id)sender {

    // 停止传感器

    if (self.mm.isAccelerometerAvailable) {

        [self.mm stopAccelerometerUpdates];

    }else{

        NSLog(@"Accelerometer not Available");

    }

}
  1. 程序运行结果如下图所示。

图28.3 加速度传感器数据

1.3 陀螺仪传感器(Gyroscope)

陀螺仪传感器,也称为角速度传感器,是测量设备在x、y、z三个方向上的旋转角度的,旋转坐标系统如下图所示。

图28.3 陀螺仪传感器坐标系统

下面我们也是通过一个实例来演示如何获得,陀螺仪传感器角速度数据,该实例在界面上添加两个按钮来开启和停止陀螺仪传感器,使用NSLog打印数据。实现步骤如下所示。

  1. 创建项目并添加CoreMotion.framework框架。
  2. 在界面上添加两个按钮,并添加点击事件方法,声明CMMotionManager属性。
#import <UIKit/UIKit.h>

#import <CoreMotion/CoreMotion.h>

@interface AmakerViewController : UIViewController

// 开启方法

- (IBAction)start:(id)sender;

// 停止方法

- (IBAction)stop:(id)sender;

// 显示数据信息

@property (strong, nonatomic) IBOutlet UILabel *myLabel;

// 移动管理器属性

@property (strong,nonatomic) CMMotionManager *mm;

@end
  1. 在viewDidLoad方法中实例化CMMotionManager。
- (void)viewDidLoad

{

    [super viewDidLoad];

    // 实例化CMMotionManager

    self.mm = [[CMMotionManager alloc]init];

}
  1. 在start方法中开启传感器并获得数据。
- (IBAction)start:(id)sender {

    if (self.mm.isGyroAvailable) {

        // 开启传感器

        [self.mm startGyroUpdatesToQueue:[[NSOperationQueue alloc]init] withHandler:^(CMGyroData *gyroData, NSError *error) {

            // 获得角速度数据

            CMRotationRate data = gyroData.rotationRate;

            double x = data.x;

            double y = data.y;

            double z = data.z;

            // 打印输出

            NSString *str = [NSString stringWithFormat:@"[%f,%f,%f]",x,y,z];

            NSLog(@"%@",str);

            // 在标签上显示

            dispatch\_async(dispatch\_get\_main\_queue(), ^{

                self.myLabel.text = str;

            });

        }];

    }

}
  1. 在stop方法中停止传感器。
- (IBAction)stop:(id)sender {

    // 停止传感器

    if (self.mm.isGyroAvailable) {

        [self.mm stopGyroUpdates];

    }

}
  1. 程序运行结果如下图所示。

图28.4 陀螺仪传感器数据输出结果

1.4 磁力传感器(Magnetometer)

磁力传感器可以检测当前设备周围磁场强度值,磁力传感器的典型应用是指南针,下面通过案例还是演示如何获得磁力传感器x、y、z三个坐标轴方向的磁场数据,实现步骤如下所示。

  1. 创建项目并添加CoreMotion.framework框架。
  2. 在界面上添加两个按钮和一个UILabel。
  3. 在.h文件中声明两个点击事件方法和CMMotionManager属性和UILabel属性。
#import <UIKit/UIKit.h>

#import <CoreMotion/CoreMotion.h>

@interface AmakerViewController : UIViewController

// 开启

- (IBAction)start:(id)sender;

// 停止

- (IBAction)stop:(id)sender;

// 移动管理器

@property(nonatomic,strong)CMMotionManager *mm;

// 显示当前数据信息

@property (strong, nonatomic) IBOutlet UILabel *myLabel;

@end
  1. 在viewDidLoad方法中实例化CMMotionManager。
- (void)viewDidLoad

{

    [super viewDidLoad];

    // 实例化CMMotionManager

    self.mm = [[CMMotionManager alloc]init];

}
  1. 在按钮的开启事件方法中开启磁力传感器,并获取数据。
- (IBAction)start:(id)sender {

    if (self.mm.isMagnetometerAvailable) {

        // 开启

        [self.mm startMagnetometerUpdatesToQueue:[[NSOperationQueue alloc]init] withHandler:^(CMMagnetometerData *magnetometerData, NSError *error) {

            // 获取实时数据

            CMMagneticField data = magnetometerData.magneticField;

            double x = data.x;

            double y = data.y;

            double z = data.z;

            // 打印数据

            NSString *str = [NSString stringWithFormat:@"[%f,%f,%f]",x,y,z];

            NSLog(@"%@",str);

            // 在UILabel上显示数据

            dispatch\_async(dispatch\_get\_main\_queue(), ^{

                self.myLabel.text = str;

            });

        }];

    }

}
  1. 在按钮的停止事件方法中停止磁力传感器。
- (IBAction)stop:(id)sender {

    if (self.mm.isMagnetometerAvailable) {

        [self.mm stopMagnetometerUpdates];

    }

}
  1. 程序运行结果如下图所示。

图28.5 磁力传感器数据输出结果

1.5 设备移动(Device motion)

如果设备有加速度传感器和角速度传感器,那么通过这个两个传感器可以检测出当前设备的运动情况,并获得运动数据。获得设备移动数据方法和获得其他传感器数据的方法一致,下面我们通过实例来演示如何获得移动数据。操作步骤如下所示:

  1. 创建项目并添加CoreMotion.framework框架。
  2. 在界面上添加两个按钮和一个UILabel标签。
  3. 在.h文件中声明两个按钮的事件方法,并声明标签属性和CMMotionManager属性。
#import <UIKit/UIKit.h>

#import <CoreMotion/CoreMotion.h>

@interface AmakerViewController : UIViewController

// 开启方法

- (IBAction)start:(id)sender;

// 停止方法

- (IBAction)stop:(id)sender;

// UILabel 属性

@property (strong, nonatomic) IBOutlet UILabel *myLabel;

// CMMotionManager属性

@property(strong,nonatomic) CMMotionManager *mm;

@end
  1. 在viewDidLoad方法中实例化CMMotionManager。
- (void)viewDidLoad

{

    [super viewDidLoad];

    // 实例化CMMotionManager

    self.mm = [[CMMotionManager alloc]init];

    // 更新频率

    self.mm.deviceMotionUpdateInterval= 1;

}
  1. 在开启按钮事件方法中开启,并获得数据。
- (IBAction)start:(id)sender {

    if (self.mm.isDeviceMotionAvailable) {

        // 开启

        [self.mm startDeviceMotionUpdatesToQueue:[[NSOperationQueue alloc]init] withHandler:^(CMDeviceMotion *motion, NSError *error) {

            // 获得数据

            CMAttitude *attr = motion.attitude;

            double roll = attr.roll;

            double pitch = attr.pitch;

            double raw = attr.yaw;

            // 打印数据

            NSString *str = [NSString stringWithFormat:@"[%f,%f,%f]",roll,pitch,raw];

            NSLog(@"str = %@",str);

            // 显示数据

            dispatch\_async(dispatch\_get\_main\_queue(), ^{

                self.myLabel.text = str;

            });

        }];

    }

}
  1. 在停止按钮事件方法中停止。
- (IBAction)stop:(id)sender {

    if (self.mm.isDeviceMotionAvailable) {

        [self.mm stopDeviceMotionUpdates];

    }

}
  1. 程序运行结果如下图所示。

图28.6 移动传感器数据输出结果

1.6 通过加速度传感器控制小球运动

本节通过加速度传感器小球运动的游戏模型,该案例首先获得加速度传感器x、y坐标数值,通过该数值动态改变小球图片的frame属性的x、y坐标。实现步骤如下所示:

  1. 创建项目,并添加CoreMotion.framework框架。
  2. 在界面上添加UIImageView和UIButton。
  3. 在.h文件中添加按钮点击事件方法、图片属性和CMMotionManager属性。
#import <CoreMotion/CoreMotion.h>

@interface AmakerViewController : UIViewController

// CMMotionManager属性

@property(nonatomic,strong)CMMotionManager *mm;

// 图片属性

@property (strong, nonatomic) IBOutlet UIImageView *img;

// 点击方法

- (IBAction)start:(id)sender;

@end
  1. 在viewDidLoad方法中实例化CMMotionManager。
- (void)viewDidLoad

{

    [super viewDidLoad];

    self.mm = [[CMMotionManager alloc]init];

    //self.mm.accelerometerUpdateInterval=0.2;

}
  1. 在按钮的点击方法中,开启加速度传感器,异步获取数据,并更新图片的frame属性。
- (IBAction)start:(id)sender {

    // 开启加速度传感器,异步获取数据

    [self.mm startAccelerometerUpdatesToQueue:[[NSOperationQueue alloc] init] withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {

        dispatch\_sync(dispatch\_get\_main\_queue(), ^(void) {

            // 获得当前图片的frame属性

            CGRect imgFrame = self.img.frame;

            // 将当前传感器x属性赋值给图片x

            imgFrame.origin.x += accelerometerData.acceleration.x;

            // 判断图片是否x越界

            if(!CGRectContainsRect(self.view.bounds, imgFrame))

                // 如果x越界不变

                imgFrame.origin.x = self.img.frame.origin.x;

            // 将当前传感器y属性赋值给图片y

            imgFrame.origin.y -= accelerometerData.acceleration.y;

            // 判断图片是否y越界

            if(!CGRectContainsRect(self.view.bounds, imgFrame))

                // 如果y越界不变

                imgFrame.origin.y = self.img.frame.origin.y;

            // 更改frame属性

            self.img.frame = imgFrame;

        });

    }];

}
  1. 程序运行结果如下图所示。

图28.7 通过传感器控制小球运动