Обнаружение, когда кто-то начинает ходить, используя данные Core Motion и CMAccelerometer.

Я пытаюсь обнаружить три действия: когда пользователь начинает ходить, бегать или бегать. Я тогда хочу знать, когда остановится. Я успешно обнаружил, когда кто-то ходит, бегает или бегает с помощью следующего кода:

- (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);
    }

Проблема, с которой я сталкиваюсь, имеет две стороны:

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

2) Мне трудно понять, как определить, когда пользователь остановился. Кто-нибудь есть совет о том, как реализовать "Обнаружение остановки"

5 ответов

Решение

Согласно вашим журналам, accelerometerUpdateInterval около 0.02, Обновления могут быть менее частыми, если вы измените указанное свойство CMMotionManager,

Проверка только x-ускорения не очень точна. Я могу положить устройство на стол таким образом (скажем, на левом краю), чтобы x-ускорение было равно 1 или немного наклонило его. Это приведет к тому, что программа будет в режиме ходьбы (x > 0,1) вместо режима ожидания.

Вот ссылка на публикацию ADVANCED PEDOMETER для отслеживания активности на основе SMARTPHONE. Они отслеживают изменения в направлении вектора ускорения. Это косинус угла между двумя последовательными показаниями вектора ускорения.

формула cos (угол

Очевидно, что без движения угол между двумя векторами близок к нулю и cos(0) = 1, Во время других действий d <1. Для фильтрации шума они используют взвешенное скользящее среднее из последних 10 значений d.

WMA10 формула

После реализации ваши значения будут выглядеть следующим образом (красный - ходовой, синий - бегущий):

WMA (г

Теперь вы можете установить порог для каждого действия, чтобы разделить их. Обратите внимание, что средняя частота шага составляет 2-4 Гц. Вы должны ожидать, что текущее значение будет превышать пороговое значение, по крайней мере, несколько раз в секунду, чтобы идентифицировать действие.

Другие полезные публикации:

ОБНОВИТЬ

_acceleration.x, _accelaration.y, _acceleration.z являются координатами одного и того же вектора ускорения. Вы используете каждую из этих координат в формуле d. Для вычисления d также необходимо сохранить вектор ускорения предыдущего обновления (с индексом i-1 в формуле).

WMA просто учитывает 10 последних значений d с разными весами. Последние значения d имеют больший вес, следовательно, больше влияют на результирующее значение. Вам необходимо сохранить 9 предыдущих значений d, чтобы рассчитать текущее. Вам следует сравнить значение WMA с соответствующим порогом.

Если вы используете iOS7 и iPhone5S, я предлагаю вам взглянуть на CMMotionActivityManager, который доступен в iPhone5S благодаря чипу M7. Он также доступен в нескольких других устройствах:

Чип 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);
  }];
}

Я проверил это, и это кажется довольно точным. Единственным недостатком является то, что он не даст вам подтверждения, как только вы начнете действие (например, ходьба). Какой-то алгоритм черного ящика ожидает, что вы действительно гуляете или бегаете. Но тогда вы знаете, что у вас есть подтвержденное действие.

Это лучше, чем возиться с акселерометром. Apple позаботилась об этой детали!

Вы можете использовать эту простую библиотеку, чтобы определить, ходит ли пользователь, бежит, находится на транспортном средстве или не двигается. Работает на всех устройствах iOS и не требует чипа M7.

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

В репо вы можете найти демо-проект

Я следую этой статье( 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)!)
        }
}

После всего классического кода Swifty для iOS для запуска CoreMotion, вот метод вычисления чисел и определения состояния:

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
    }
}

Также я использовал следующее расширение, чтобы упростить значительную настройку фигуры:

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

С необработанными значениями от CoreMotion, алгоритм был haywire.

Надеюсь, это кому-нибудь поможет.

РЕДАКТИРОВАТЬ (4/3/16)

Я забыл предоставить свой roundingPrecision значение. Я определил это как 3. Это просто математика, что эта значительная ценность достаточно прилична. Если вам нравится, вы предоставляете больше.

Еще одна вещь, которую стоит упомянуть, это то, что в данный момент этот алгоритм требует, чтобы iPhone был в ваших руках во время ходьбы. Смотрите картинку ниже. Извините, это был единственный, кого я смог найти.

статус iPhone во время ходьбы

My GitHub Repo хостинг пешеходного статуса

Вы можете использовать последнюю версию Apple CoreML для машинного обучения, чтобы узнать активность пользователей. Для начала нужно собрать размеченные данные и обучить классификатор. Затем вы можете использовать эту модель в своем приложении для классификации активности пользователей. Вы можете следить за этой серией, если вас интересует классификация действий CoreML.

https://medium.com/@tyler.hutcherson/activity-classification-with-create-ml-coreml3-and-skafos-part-1-8f130b5701f6

Другие вопросы по тегам