加速計與陀螺儀


設備靜止時受到的地球引力為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,則表明當前設備支持陀螺儀。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM