16933


iOSアプリ開発で、ジャイロセンサー,加速度センサー(CoreMotion)から取得できる(timestamp,x,y,z)の値を使って端末の移動距離を計算する方法が知りたいです。ここでGPSは使用しない予定です。

[![画像の説明をここに入力](https://i.stack.imgur.com/farSD.png)](https://i.stack.imgur.com/farSD.png)

[code]

    CMMotionManager *manager = [[CMMotionManager alloc] init];
    
    // センサーの更新間隔の指定
    manager.deviceMotionUpdateInterval = 0.01; 
    
    CMDeviceMotionHandler handler = ^(CMDeviceMotion *motion, NSError *error) {
        double timestamp = data.timestamp;
    
        /* 加速度センサー(ローパスフィルタ) */
        double gravityX = motion.gravity.x;
        double gravityY = motion.gravity.y;
        double gravityZ = motion.gravity.z;
    
        /* 加速度センサー(ハイパスフィルタ) */
        double userAccelerationX = motion.userAcceleration.x;
        double userAccelerationY = motion.userAcceleration.y;
        double userAccelerationZ = motion.userAcceleration.z;
    
        /* ジャイロスコープ */
        double x = motion.rotationRate.x;
        double y = motion.rotationRate.y;
        double z = motion.rotationRate.z;
    };
    
    [manager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:handler];
    
[/code]


CC BY-SA 3.0
2015-08-04T12:20:58.650
13033
2015-09-25T19:26:55.337
4369
question
ios swift objective-c iphone
ジャイロセンサー,加速度センサーを用いて端末の移動距離を計算する方法


まず、2つの座標系があります

グローバルとローカルです  
センサーはローカルにあります  
我々が知りたいのはグローバルでの位置です

加速度の軸をグローバルへ前回の回転行列を用いて変換します

その後加速度を積分します

ジャイロからの値を積分し、角度を回転行列に入れます

これの繰り返しによってグローバルのデータを得ます

積分は単純に高校の物理の公式です  
y=at^2+vt+y¬

プログラムは私にはかけません


CC BY-SA 3.0
2015-08-05T05:29:43.740
13058
2015-08-05T05:29:43.740
10807
13033
answer


結論から言いますと、おそらく無理です。

理論上は確かに加速度を2回積分すれば距離が出ますが、しかしその場合、加速度はちゃんとΔtにおける加速度でなければなりません。ところがiPhoneのモーションセンサが取るのは受けた力から計算した瞬間加速度です。  
積分自体は非常に簡単で、y*Δtを足していけば面積になりますから、例えば初速度を0と見なせば、0.01秒ごとに加速度を取るとし、取った加速度を0.01かけて100回足せば1秒後の速度になりますからなんも難しくありません。ところが問題はこの場合はΔt=0.01の場合の加速度が必要であり、瞬間加速度しか取れない以上それを無理やり足しても100Hzじゃあサンプリングレートとしても低すぎて精度が使い物になりません。

一応無理やりにプログラムに書くと単純な書き方ですがおそらく多分下記のようになりますが：

[code]

    import UIKit
    import CoreMotion
    
    class ViewController: UIViewController {
        let cmManager = CMMotionManager()
        override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    
        self.distance()
    
    }
    func distance() {
    
        self.cmManager.deviceMotionUpdateInterval = 0.01
        let dt = self.cmManager.deviceMotionUpdateInterval
        var aData = [0.0]
        var vData = [0.0]
        var s = 0.0
        var loopCount = 0
    
        self.cmManager.startDeviceMotionUpdatesToQueue(NSOperationQueue.currentQueue()!) { (data, error) -> Void in
            defer {
                loopCount++
            }
            let motionData = data!
            let x = motionData.userAcceleration.x
            let y = motionData.userAcceleration.y
            let z = motionData.userAcceleration.z
    
            let pa = aData[loopCount]
            let a = cbrt(x * y * z)
            let dv = (a + pa) * dt * 0.5
            aData.append(a)
    
            let pv = vData[loopCount]
            let v = pv + dv
            let ds = (v + dv) * dt * 0.5
            vData.append(v)
    
            s += ds
        }
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { () -> Void in
            while true {
                NSThread.sleepForTimeInterval(1)
                print("")
                print(aData.last!)
                print(vData.last!)
                print(s)
            }
        }
    
    }
    
[/code]

（積分の計算はちょっと頭の中で曖昧ですので悪しからず）

これで速度を取得して値見てみるとわかりますが、一旦iPhoneを移動したら再びテーブルに置いても速度がなかなか元の値に戻らなかったりします。原因は先ほど言いました、そもそも加速度はdtに置いての加速度ではなく、瞬間加速度だからです。


CC BY-SA 3.0
2015-09-25T19:21:29.713
16933
2015-09-25T19:26:55.337
2015-09-25T19:26:55.337
12449
12449
13033
answer