移动开发(IOS) –传感器

来源:互联网 发布:淘宝大学哪个老师最好 编辑:程序博客网 时间:2024/05/21 14:06

移动开发(IOS) – 传感器

Bydocoder in 博客, 学习on 2014/07/12

ios-sensor

1.iOS中的主要传感器

 加速度传感器电子罗盘陀螺仪接近传感器功能 通过测量三个轴的加速度大小来判断人体运动 通过测量设备周围地磁场的强度和方向来判断朝向 通过测量三个轴的旋转速率来判断朝向 无须物理接触就判断附近物体的存在主要局限性 受重力干扰大,瞬时误差大 误差大,容易受其他磁场和金属物体影响。主要用于校正其他设备误差会累积,长时间读数的准确性差不通用,大多数只针对几种材质应用 活动测量 导航 导航 智能省电

2.加速度传感器,又称加速计

2.1.通过iOS设备提供的内置的加速计,可以确定设备什么时候移动、移动了多少距离以及设备的方向

2.2.在应用程序中,使用 UIAccelerometer 类来接收加速计数据,通过类方法 sharedAccelerometer 可以获得该类的实例

2.3.使用加速计需要设置其更新间隔和代理,此后,在指定的时间间隔,会收到代理方法 accelerometer:didAccelerate: 的回调

2.4.该代理方法收到一个指向加速计的指针和一个指向 UIAcceleration 对象的指针

2.5.该加速对象包含: x , y , z 和 timestamp 四个属性,其中 x , y , z是设备在这三个方向上的重力加速度,单位 g

MainViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#import "MainViewController.h"
#import <QuartzCore/QuartzCore.h>
 
@interfaceMainViewController () <UIAccelerometerDelegate>
{
    // 小球图像
    UIImageView *_ball;
    // 小球速度
    CGPoint _ballVelocity;
    // 游戏时钟
    CADisplayLink *_gameTimer;
}
 
@end
 
@implementationMainViewController
/*
 加速剂默认是不工作,因为工作会耗电,当设置了采样频率,加速剂开始工作,同时将采样获得的数据
 通过代理方法,发送给调用方
 
 UIAcceleration的说明
 * timestamp 数据采样发生的时间
 * x x 方向的加速度
 * y y 方向的加速度
 * z z 方向的加速度
 */
- (void)viewDidLoad
{
    [superviewDidLoad];
 
    UIImage *image = [UIImage imageNamed:@"black.png"];
    _ball = [[UIImageView alloc]initWithImage:image];
    [_ball setCenter:self.view.center];
  
    [self.view addSubview:_ball];
  
    // 小球初始静止
    _ballVelocity = CGPointZero;
  
    // 加速计
    // 1. 实例化加速计,因为在手机上有且仅有一个芯片,因此使用单例来访问加速剂
    UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer];
    // 2. 设置更新频率(采样频率)
    [accelerometer setUpdateInterval:1 / 30.0];
    // 3. 设置代理
    [accelerometer setDelegate:self];
  
    // 游戏时钟
    // 1. 实例化
    _gameTimer = [CADisplayLink displayLinkWithTarget:selfselector:@selector(step)];
    // 2. 主运行循环
    [_gameTimer addToRunLoop:[NSRunLoopmainRunLoop] forMode:NSDefaultRunLoopMode];
}
 
#pragma mark - 时钟监听方法
- (void)step
{
    [selfupdateBallLocation];
}
 
#pragma mark - 更新小球位置
- (void)updateBallLocation
{
    // 根据小球位置调整中心点位置
    CGPoint center = _ball.center;
    // 判断小球的位置是否超出边界,如果超出边界,将小球的方向求反
    // 1) 水平方向
    // 如果小球的最小x值,小于0,表示左边出界
    // 如果小球的最大x值,大于viewW,表示右边边出界
    if(CGRectGetMinX(_ball.frame) < 0 || CGRectGetMaxX(_ball.frame) >self.view.bounds.size.width) {
        _ballVelocity.x *= -0.8;
  
        // 修复小球位置
        if(CGRectGetMinX(_ball.frame) < 0) {
            center.x = _ball.bounds.size.width / 2;
        }else {
            center.x =self.view.bounds.size.width - _ball.bounds.size.width / 2;
        }
    }
  
    // 2)垂直方向
    if(CGRectGetMinY(_ball.frame) < 0 || CGRectGetMaxY(_ball.frame) >self.view.bounds.size.height) {
        _ballVelocity.y *= -0.8;
  
        // 修复小球位置
        if(CGRectGetMinY(_ball.frame) < 0) {
            center.y = _ball.bounds.size.height / 2;
        }else {
            center.y =self.view.bounds.size.height - _ball.bounds.size.height / 2;
        }
    }
  
    center.x += _ballVelocity.x;
    center.y += _ballVelocity.y;
    [_ball setCenter:center];
}
 
#pragma mark - 加速计代理方法
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
    // 使用加速度调整小球速度
    _ballVelocity.x += acceleration.x;
    _ballVelocity.y -= acceleration.y;
  
    // 让加速剂仅负责采样数据,更新速度
    // [self updateBallLocation];
}
@end

3.CoreMotion

3.1.Core Motion 不仅能够提供实时的加速度值和旋转速度值,更重要的是,苹果在其中集成了很多算法,可以直接输出把重力加速度分量剥离的加速度,省去你的高通滤波操作,以及提供给你一个专门的设备的三维 attitude 信息

3.2.Core Motion 框架结构示意图:

ios-coremotion

 

3.3.Core Motion 获取数据的两种方式: Push 和 Pull

ios-coremotion-push-pull

MyMotionManager.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#import "MyMotionManager.h"
staticMyMotionManager *sharedInstace;
@implementationMyMotionManager
//使用单例
+ (id)allocWithZone:(NSZone*)zone
{
    staticdispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstace = [superallocWithZone:zone];
    });
  
    returnsharedInstace;
}
 
+ (MyMotionManager *)sharedMontionManager
{
    staticdispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstace = [[superalloc]init];
    });
  
    returnsharedInstace;
}
 
@end
MainViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#import "MainViewController.h"
#import <CoreMotion/CoreMotion.h>
#import <QuartzCore/QuartzCore.h>
#import "MyMotionManager.h"
 
@interfaceMainViewController ()
{
    UIImageView *_ball;// 小球
    CGPoint _ballVelocity;// 小球速度
    CMMotionManager *_montionManager;// 运动管理器(单例)
    NSOperationQueue*_queue; // 操作队列
    CADisplayLink *_gameTimer;// 游戏时钟
}
@end
 
@implementationMainViewController
/*
 * accelerometerAvailable      加速计计是否可用
 * accelerometerUpdateInterval 加速计采样频率
 * accelerometerActive         加速计是否正在采样数据
 
 * accelerometerData           取回末次采样数据,pull方法使用
 * startAccelerometerUpdates   开始加速计更新
  
 * startAccelerometerUpdatesToQueue:(NSOperationQueue *)queue withHandler:(CMAccelerometerHandler)handler
 * 使用多线程的加速计采样数据,push方法
 
 * stopAccelerometerUpdates    停止采样
 */
- (void)viewDidLoad
{
    [superviewDidLoad];
 
    // 实例化小球
    UIImage *image = [UIImage imageNamed:@"black.png"];
    _ball = [[UIImageView alloc]initWithImage:image];
    [_ball setCenter:self.view.center];
    [self.view addSubview:_ball];
  
    _queue = [[NSOperationQueuealloc]init];
    [selfloadAccelerometerData];
  
    // 游戏时钟
    _gameTimer = [CADisplayLink displayLinkWithTarget:selfselector:@selector(step)];
    [_gameTimer addToRunLoop:[NSRunLoopmainRunLoop] forMode:NSDefaultRunLoopMode];
}
 
#pragma mark - 更新小球位置
- (void)step
{
    // 根据小球位置调整中心点位置
    CGPoint center = _ball.center;
  
    // 判断小球的位置是否超出边界,如果超出边界,将小球的方向求反
    // 1) 水平方向
    // 如果小球的最小x值,小于0,表示左边出界
    // 如果小球的最大x值,大于viewW,表示右边边出界
    if(CGRectGetMinX(_ball.frame) < 0 || CGRectGetMaxX(_ball.frame) >self.view.bounds.size.width) {
        _ballVelocity.x *= -0.8;
  
        // 修复小球位置
        if(CGRectGetMinX(_ball.frame) < 0) {
            center.x = _ball.bounds.size.width / 2;
        }else {
            center.x =self.view.bounds.size.width - _ball.bounds.size.width / 2;
        }
    }
  
    // 2)垂直方向
    if(CGRectGetMinY(_ball.frame) < 0 || CGRectGetMaxY(_ball.frame) >self.view.bounds.size.height) {
        _ballVelocity.y *= -0.8;
  
        // 修复小球位置
        if(CGRectGetMinY(_ball.frame) < 0) {
            center.y = _ball.bounds.size.height / 2;
        }else {
            center.y =self.view.bounds.size.height - _ball.bounds.size.height / 2;
        }
    }
  
    center.x += _ballVelocity.x;
    center.y += _ballVelocity.y;
  
    [_ball setCenter:center];
}
 
#pragma mark - 加速计采样数据
- (void)loadAccelerometerData
{
    //从MyMotionManager中获取运动管理器的单例
    _montionManager = [MyMotionManager sharedMontionManager];
  
    // 采样过程
    // 1) 判断加速计是否可用
    if([_montionManager isAccelerometerAvailable]) {
        // 2) 指定加速计采样频率
        [_montionManager setAccelerometerUpdateInterval:1 / 30.0];
  
        [selfaccelerometerUpdatesData];
    }else {
        NSLog(@"加速计不可用");
    }
}
#pragma mark - 开始采样数据
// 加速计更新数据
- (void)accelerometerUpdatesData
{
    // 3) 使用push方法,采样数据
    [_montionManager startAccelerometerUpdatesToQueue:_queue withHandler:^(CMAccelerometerData *accelerometerData,NSError *error) {
        // 仅负责更新小球的速度
        _ballVelocity.x += accelerometerData.acceleration.x;
        _ballVelocity.y -= accelerometerData.acceleration.y;
    }];
}
#pragma mark - 触摸事件
// 点按屏幕停止数据更新,游戏中有暂停的需求
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event
{
    // 加速计负责采样数据,游戏时钟负责更新界面
    // 因此,暂停游戏时,需要将二者同时暂停或启动
    // 根据加速计是否正在采样数据,停止或者开始采样数据
    if([_montionManager isAccelerometerActive]) {
        // 停止采样
        [_montionManager stopAccelerometerUpdates];
  
        // 停止游戏时钟
        // invalidate方法会销毁游戏时钟,下次启动时,需要重新实例化
        // [_gameTimer invalidate];
        // 将游戏时钟从运行循环中清除,下次启动时,无需实例化gameTimer
        [_gameTimer removeFromRunLoop:[NSRunLoopmainRunLoop] forMode:NSDefaultRunLoopMode];
    }else {
        // 开始采样
        [selfaccelerometerUpdatesData];
 
        // 重新开启游戏时钟
        // _gameTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(step)];
        [_gameTimer addToRunLoop:[NSRunLoopmainRunLoop] forMode:NSDefaultRunLoopMode];
    }
}

0 0