在平面上检测iPhone的运动

6
我是一个coremotion初学者。
我需要检测iPhone在像桌子这样的平面上的运动 - 到目前为止,我通过访问陀螺仪的偏航来检测其侧向运动,但我想不到一种方法来检测上下变化。我尝试使用加速度计,但它检测到的更多是设备的倾斜而不是运动。此外,当运动停止时会有一个反作用力。
你有任何想法吗?这样可以以相对精度获得运动数据吗?我需要它用于类似空气曲棍球游戏的东西。
4个回答

7
为了从设备运动中确定水平位置并不是可行的。要使用的水平传感器是加速度计,但它们测量的是速度变化。因此,要从中找到位置,您需要对传感器数据进行两次积分。一次获取速度,然后再一次获取位置。
这意味着即使加速度数据中最小的不准确性也会导致速度结果出现误差,这意味着您的程序认为手机正在以恒定的速度移动,而实际上它是静止的。
如果您不需要精度(例如,当您不需要在将其来回移动时将其返回到相同的位置时),则可以在加速度计数据安静且接近于零的情况下将速度强制设置为零,这样您可能会获得可以接受的结果。
如果您真的想尝试这个功能,则卡尔曼滤波器可能是从加速度计数据中推导速度和位置的最佳选择。
这意味着您的代码最终将类似于以下内容,其中 acceleration speed position 是您保留的三个变量,而 acc 是来自加速度计的数据样本。
// correction step:
double delta = (acc - acceleration);
acceleration += FACTOR1 * delta;
speed += FACTOR2 * delta;
position += FACTOR3 * delta;

// prediction step:
position = position + speed * DT + 0.5 * acceleration * DT * DT;
speed = speed + acceleration * DT;

其中DT是数据样本之间的时间,FACTOR1..3的合适值需要您自行找出。

顺便说一下,偏航角不会给您水平运动,而是旋转。


编辑:现在,您可以通过ARKit的运动跟踪获得良好的结果,它将加速计输入与相机的图像分析相结合。 它会为您完成所有艰苦的工作。


顺便提一下:如果使用前置摄像头并使用一些图像分析来推导天花板图片的移动,可能会获得更好的结果... - fishinear
我考虑使用后置摄像头,但这会强制用户使用iPhone保护套(否则镜头会太靠近)。谢谢你的帖子。昨天我了解到了双重积分,我会试一试。对我来说,这似乎是最有价值的答案。我会告诉你效果的。谢谢! - Michał Siwek

6
我也对CoreMotion不太了解。我会尽力解释为什么你所要求的无法实现,至少不能准确地实现。
根据我阅读的苹果文档,iOS有三个运动处理程序:
加速度计
陀螺仪
磁力计
(我相信最新的设备有高度计)
根据我对物理学的理解,我认为加速度计对你的场景最有用,因为陀螺仪和磁力计更专注于旋转。我做了一些研究,并找到了this book。特别是第9.5章。从书中得知:
虽然加速度计可以测量x、y和z轴上的力,但它无法测量旋转。另一方面,陀螺仪是一个变化率设备;当手机绕着一个轴旋转时,它允许您测量这种旋转的变化。
按照他们在图9-5下的代码来实现一个简单的应用程序来观察加速度:
#import <UIKit/UIKit.h>
#import <CoreMotion/CoreMotion.h>

@interface ViewController : UIViewController {

    CMMotionManager *motionManager;
    NSOperationQueue *queue;
}


@property (weak, nonatomic) IBOutlet UILabel *xLabel;
@property (weak, nonatomic) IBOutlet UILabel *yLabel;
@property (weak, nonatomic) IBOutlet UILabel *zLabel;

@property (weak, nonatomic) IBOutlet UIProgressView *xBar;
@property (weak, nonatomic) IBOutlet UIProgressView *yBar;
@property (weak, nonatomic) IBOutlet UIProgressView *zBar;

@end

然后在.m文件的viewDidLoad中

- (void)viewDidLoad {
    [super viewDidLoad];

    motionManager = [[CMMotionManager alloc] init];
    motionManager.accelerometerUpdateInterval  = 1.0/10.0; // Update at 10Hz
    if (motionManager.accelerometerAvailable) {
        NSLog(@"Accelerometer avaliable");
        queue = [NSOperationQueue currentQueue];
        [motionManager startAccelerometerUpdatesToQueue:queue
          withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
            CMAcceleration acceleration = accelerometerData.acceleration;
            xLabel.text = [NSString stringWithFormat:@"%f", acceleration.x];
            xBar.progress = ABS(acceleration.x);

            yLabel.text = [NSString stringWithFormat:@"%f", acceleration.y];
            yBar.progress = ABS(acceleration.y);

            zLabel.text = [NSString stringWithFormat:@"%f", acceleration.z];
            zBar.progress = ABS(acceleration.z);
        }];

    }
}

在将一切连接起来并在手机上运行之后,我发现加速度计正在测量我的手机在平坦桌面上移动时加速和减速的变化。现在我们有了加速度,但要从中得到位置变化(这就是你所问的),需要进行双重积分(即有趣的微积分)。虽然可行,但我查阅了arduino上的专家们对此的看法here,结果是令人沮丧的消息。(他们没有讨论iPhone加速度计,但我推断这些信息也适用于这个问题)。
我在这里发布了相关部分:
从加速度中获取位置是双重积分,因此误差堆积非常严重。使用固定IMU(你正在尝试做的事情)获得良好的位置数据是一个真正困难的问题;实现它所需的加速度计非常昂贵。
以及
你所说的是双重积分,在这种硬件上单个加速度计的精度太低,甚至单次积分每单位时间的误差都会增加,因为这个设置缺乏准确性。

所有这些研究都导致我的结论是,在iPhone上做你要求的事情是不可行的。尽管我说过,我也是个初学者!很抱歉这不是你想听到的答案。


3
设备无法检测运动。沿着桌面进行直线恒定运动是绝对无法检测到的,因为没有产生任何

该设备仅能检测姿态(在空间中的方向和变化)和力量(速度的增加或减少)。

因此,您需要根据这些能力形成您的期望。


1
好的,我当前正在做的是 var ax: Double = data.userAcceleration.x; var ay: Double = data.userAcceleration.y; if((abs(ax) > 0.05) || (abs(ay) > 0.05)) { //使用数据 } ,而且它出乎意料地做到了我想要的。然而,关于惯性反应存在一个很大的问题,如果设备突然停止移动,它会将玩家放回到之前没有进行任何移动的位置。你能否想到任何解决这个问题的方法? - Michał Siwek
我所能想到的唯一方法就是继续追踪,从设备明显在移动的事实中推断出这种突然减速很可能是设备停止,而不是加速将设备移回原来的位置。即使如此,你也只能猜测。 - matt
我们能否通过核心运动检测表面的水平测量?或者您能否建议任何替代方法? - Prashant Tukadiya

1
这个链接或许可以更好地解释一些事情:http://blog.denivip.ru/index.php/2013/07/the-art-of-core-motion-in-ios/?lang=en 不过似乎你需要了解Y轴加速度。苹果文档中已经很好地涵盖了这一点:https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/motion_event_basics/motion_event_basics.html 使用运动处理方法来检测运动变化,然后访问y位置的变化。如果您愿意,我也可以尝试提供一些代码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接