使用Core Motion和CMAccelerometer数据检测某人何时开始行走

Apo*_*llo 19 objective-c ios core-motion apple-m7

我正在尝试检测三种动作:当用户开始步行,慢跑或跑步时.然后我想知道何时停止.我成功地检测到有人在走路,慢跑或跑步时使用以下代码:

- (void)update:(CMAccelerometerData *)accelData {

    [(id) self setAcceleration:accelData.acceleration];

    NSTimeInterval secondsSinceLastUpdate = -([self.lastUpdateTime timeIntervalSinceNow]);

    if (labs(_acceleration.x) >= 0.10000) {
        NSLog(@"walking: %f",_acceleration.x);
    }
    else if (labs(_acceleration.x) > 2.0) {
        NSLog(@"jogging: %f",_acceleration.x);
    }
    else if (labs(_acceleration.x) > 4.0) {
        NSLog(@"sprinting: %f",_acceleration.x);
    }
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是双重的:

1)每次有动作时都会多次调用更新,这可能是因为它经常检查当用户开始行走时(即_acceleration.x> = .1000)它再次调用更新时仍然> = .1000.

示例日志:

    2014-02-22 12:14:20.728 myApp[5039:60b] walking: 1.029846
    2014-02-22 12:14:20.748 myApp[5039:60b] walking: 1.071777
    2014-02-22 12:14:20.768 myApp[5039:60b] walking: 1.067749
Run Code Online (Sandbox Code Playgroud)

2)我很难弄清楚如何检测用户何时停止.有没有人就如何实施"停止检测"提出建议

vok*_*lam 23

根据你的日志,accelerometerUpdateInterval是关于0.02.如果更改上面提到的属性,更新可能会更少CMMotionManager.

仅检查x加速度不是很准确.我可以用这样的方式将一个设备放在桌子上(比如说在左边缘),x加速度将等于1,或倾斜一点.这将导致程序处于步行模式(x> 0.1)而不是空闲.

这是一个链接到基于智能手机的基于活动跟踪的ADVANCED PEDOMETER出版物.它们跟踪加速度矢量方向的变化.这是两个连续加速度矢量读数之间角度的余弦值.

cos(角度)公式

显然,没有任何运动,两个矢量之间的角度接近于零cos(0) = 1.在其他活动中,d <1.为了滤除噪声,他们使用d的最后10个值的加权移动平均值.

WMA10配方

实现之后,您的值将如下所示(红色 - 行走,蓝色 - 运行):

WMA(d)

现在,您可以为每个活动设置阈值以将它们分开.请注意,平均步进频率为2-4Hz.您应该期望当前值在一秒钟内超过阈值至少几次以识别操作.

其他有用的出版物

UPDATE

_acceleration.x,_accelaration.y,_acceleration.z是相同的加速度矢量的坐标.您可以在d公式中使用这些坐标中的每一个.为了计算d,您还需要存储先前更新的加速度矢量(在公式中使用i-1索引).

WMA只考虑具有不同权重的10个最后d值.最近的d值具有更大的权重,因此对结果值的影响更大.您需要存储9个先前的d值才能计算当前的值.您应该将WMA值与相应的阈值进行比较.


Kha*_*azi 16

如果你使用的是iOS7和iPhone5S,我建议你研究一下因为M7芯片而在iPhone5S中可用的CMMotionActivityManager.它还可以在其他几种设备中使用:

M7芯片

这是我在学习的时候整理的代码片段.

#import <CoreMotion/CoreMotion.h>

@property (nonatomic,strong) CMMotionActivityManager *motionActivityManager;

-(void) inSomeMethod
{
  self.motionActivityManager=[[CMMotionActivityManager alloc]init];

  //register for Coremotion notifications
  [self.motionActivityManager startActivityUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMMotionActivity *activity) 
  {
    NSLog(@"Got a core motion update");
    NSLog(@"Current activity date is %f",activity.timestamp);
    NSLog(@"Current activity confidence from a scale of 0 to 2 - 2 being best- is: %ld",activity.confidence);
    NSLog(@"Current activity type is unknown: %i",activity.unknown);
    NSLog(@"Current activity type is stationary: %i",activity.stationary);
    NSLog(@"Current activity type is walking: %i",activity.walking);
    NSLog(@"Current activity type is running: %i",activity.running);
    NSLog(@"Current activity type is automotive: %i",activity.automotive);
  }];
}
Run Code Online (Sandbox Code Playgroud)

我测试了它,它似乎非常准确.唯一的缺点是,一旦你开始行动(例如走路)它就不会给你确认.一些黑盒算法等待确保您真正走路或跑步.但是你知道你已经确认了行动.

这加速了加速度计.Apple负责这个细节!


art*_*dev 7

您可以使用此简单库来检测用户是在步行,跑步,在车上还是不在移动.适用于所有iOS设备,无需M7芯片.

https://github.com/SocialObjects-Software/SOMotionDetector

在回购中,您可以找到演示项目


Can*_*Can 5

我正在我的室内导航项目中关注这篇论文(PDF通过RG),仅通过加速度计数据来确定用户动态(静态,慢行,快走),以帮助确定位置.

这是项目中提出的算法:

在此输入图像描述

这是我在Swift 2.0中的实现:

import CoreMotion
let motionManager = CMMotionManager()
motionManager.accelerometerUpdateInterval = 0.1
motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue.mainQueue()) { (accelerometerData: CMAccelerometerData?, error: NSError?) -> Void in
        if((error) != nil) {
            print(error)
        } else {
            self.estimatePedestrianStatus((accelerometerData?.acceleration)!)
        }
}
Run Code Online (Sandbox Code Playgroud)

在启动CoreMotion的所有经典Swifty iOS代码之后,这里是处理数字和确定状态的方法:

func estimatePedestrianStatus(acceleration: CMAcceleration) {
    // Obtain the Euclidian Norm of the accelerometer data
    accelerometerDataInEuclidianNorm = sqrt((acceleration.x.roundTo(roundingPrecision) * acceleration.x.roundTo(roundingPrecision)) + (acceleration.y.roundTo(roundingPrecision) * acceleration.y.roundTo(roundingPrecision)) + (acceleration.z.roundTo(roundingPrecision) * acceleration.z.roundTo(roundingPrecision)))

    // Significant figure setting
    accelerometerDataInEuclidianNorm = accelerometerDataInEuclidianNorm.roundTo(roundingPrecision)

    // record 10 values
    // meaning values in a second
    // accUpdateInterval(0.1s) * 10 = 1s
    while accelerometerDataCount < 1 {
        accelerometerDataCount += 0.1

        accelerometerDataInASecond.append(accelerometerDataInEuclidianNorm)
        totalAcceleration += accelerometerDataInEuclidianNorm

        break   // required since we want to obtain data every acc cycle
    }

    // when acc values recorded
    // interpret them
    if accelerometerDataCount >= 1 {
        accelerometerDataCount = 0  // reset for the next round

        // Calculating the variance of the Euclidian Norm of the accelerometer data
        let accelerationMean = (totalAcceleration / 10).roundTo(roundingPrecision)
        var total: Double = 0.0

        for data in accelerometerDataInASecond {
            total += ((data-accelerationMean) * (data-accelerationMean)).roundTo(roundingPrecision)
        }

        total = total.roundTo(roundingPrecision)

        let result = (total / 10).roundTo(roundingPrecision)
        print("Result: \(result)")

        if (result < staticThreshold) {
            pedestrianStatus = "Static"
        } else if ((staticThreshold < result) && (result <= slowWalkingThreshold)) {
            pedestrianStatus = "Slow Walking"
        } else if (slowWalkingThreshold < result) {
            pedestrianStatus = "Fast Walking"
        }

        print("Pedestrian Status: \(pedestrianStatus)\n---\n\n")

        // reset for the next round
        accelerometerDataInASecond = []
        totalAcceleration = 0.0
    }
}
Run Code Online (Sandbox Code Playgroud)

我还使用了以下扩展来简化有意义的图形设置:

extension Double {
    func roundTo(precision: Int) -> Double {
        let divisor = pow(10.0, Double(precision))
        return round(self * divisor) / divisor
    }
}
Run Code Online (Sandbox Code Playgroud)

使用CoreMotion的原始值,算法是乱七八糟的.

希望这有助于某人.

编辑(4/3/16)

我忘了提供我的roundingPrecision价值.我把它定义为3.只是简单的数学,这个非常重要的价值就足够了.如果您愿意,可以提供更多.

还有一点要提的是,目前,这种算法要求iPhone在行走时随身携带.见下图.对不起,这是我能找到的唯一一个.

走路时的iPhone状态

我的GitHub Repo托管行人状态