如何使用加速度计检测iPhone在空间中的运动?

13

我正在尝试制作一个应用程序,使用iPhone的加速度计可以检测您用手所做的形状。例如,如果您用手拿着iPhone画圆形,则该应用程序将能够在屏幕上重新绘制它。 这也可以适用于正方形,甚至更复杂的形状。 我看过唯一做这种事情的应用程序是AirPaint (http://vimeo.com/2276713),但它似乎不能实时完成。

我的第一次尝试是在加速度计的X和Y参数上应用低通滤波器,并使指针朝向这些值移动,与屏幕大小成比例。 但这显然还不够,我的准确度非常低,如果我摇晃设备也会使指针移动...

有关此事的任何想法吗? 您认为加速度计数据足够吗?或者应该考虑使用其他数据,例如指南针?

提前致谢!

4个回答

10

好的,我找到了似乎有效的方法,但我仍然有一些问题。 这是我的步骤(假设设备垂直放置):

1 - 我有我的默认 x、y 和 z 值。
2 - 我使用低通滤波器从这些数据中提取重力向量。
3 - 我从每个 x、y 和 z 中减去标准化的重力向量,得到运动加速度。
4 - 然后,我将这个加速度值与时间积分,得到速度。
5 - 我再次将这个速度与时间积分,得到位置。

下面的所有代码都在我的控制器的 accelerometer:didAccelerate: 代理中。 我正在尝试根据我找到的位置让球移动。 这是我的代码:

NSTimeInterval interval = 0;
NSDate *now = [NSDate date];
if (previousDate != nil)
{
    interval = [now timeIntervalSinceDate:previousDate];
}
previousDate = now;

//Isolating gravity vector
gravity.x = currentAcceleration.x * kFileringFactor + gravity.x * (1.0 - kFileringFactor);
gravity.y = currentAcceleration.y * kFileringFactor + gravity.y * (1.0 - kFileringFactor);
gravity.z = currentAcceleration.z * kFileringFactor + gravity.z * (1.0 - kFileringFactor);
float gravityNorm = sqrt(gravity.x * gravity.x + gravity.y * gravity.y + gravity.z * gravity.z);

//Removing gravity vector from initial acceleration
filteredAcceleration.x = acceleration.x - gravity.x / gravityNorm;
filteredAcceleration.y = acceleration.y - gravity.y / gravityNorm;
filteredAcceleration.z = acceleration.z - gravity.z / gravityNorm;

//Calculating velocity related to time interval
velocity.x = velocity.x + filteredAcceleration.x * interval;
velocity.y = velocity.y + filteredAcceleration.y * interval;
velocity.z = velocity.z + filteredAcceleration.z * interval;

//Finding position
position.x = position.x + velocity.x * interval * 160;
position.y = position.y + velocity.y * interval * 230;
如果我执行这个程序,我会得到相当不错的值,我的意思是,根据我做出的动作,我可以看到加速度进入正值或负值。 但是当我尝试将该位置应用于我的球视图时,我可以看到它在移动,但倾向于朝一个方向而不是另一个方向。这意味着,例如,如果我在我的设备上画圆圈,我会看到球描述出向屏幕左上角的曲线。 类似于此:http://img685.imageshack.us/i/capturedcran20100422133.png/ 你有任何关于发生了什么的想法吗? 提前感谢!

7
问题在于你不能通过两次积分加速度来得到位置。除非你知道初始位置和速度。还记得在学习积分时添加的+C项吗?到了位置这个阶段,它是一个ct+k项。而且它是很重要的。更不用说你获取的加速度数据是量化和平均的,所以你实际上并没有积分设备的实际加速度。当你两次积分时,这些误差会变得很大。
仔细观看AirPaint演示,你就会看到这种情况发生,渲染的形状与移动的形状有很大的区别。
即使是一些具有一定位置和速度感知能力的设备(例如Wiimote),也难以进行手势识别。这是一个棘手的问题,人们会为此花费大量资金(例如向AILive等公司)解决。
话虽如此,如果它们的大规模特征不同,你可能可以很容易地区分某些类型的手势。例如,如果设备在六个角度范围内接收到加速度,则可以检测出圆形。你可以区分在空中滑动iPhone和摇晃它之间的区别。
要区分圆形和正方形将会更加困难。

在开始整合加速度计数值之前,我需要知道设备的初始位置和速度?该设备的初始速度和位置大约为0。这可能不是一个好主意,但即使我让我的iPhone平放在桌子上,我仍然会得到一些运动信息。通过这个微积分,我对用户绘制的形状有了一个大致的想法,这已经足够我所要做的事情了。我只是想知道如何过滤加速度计数值,以便摆脱这种“默认运动行为”,并始终保持我找到的位置居中。 - Thomas Desert
这就是我的意思。你不能通过过滤加速度计中的“默认运动”来摆脱它,因为你无法知道那是什么。AirPaint假设运动将在其起始点结束,因此可以通过这种方式进行一些误差校正。但是,对于加速度数据,问题的一般解决方案根本不可能实现。当设备静止时,您得到的运动也是由加速度计的不准确性贡献的。当您来两次积分时,这些不准确性非常大。 - Ian
您还会遇到由于手机在运动过程中轻微扭曲而引起的错误。因为您将低频加速度视为重力,所以倾斜的变化会被注册为加速度的剧烈变化。如果我倾斜,然后再倾斜回来,这相当于一个大摆动。 - Ian

2
你需要查阅加速度与速度以及速度与位置的关系。我现在有些困惑,但我确定这是积分...你需要将加速度关于时间进行积分。维基百科应该可以帮助你解决数学问题,而且我相信一定有一个好的库可以帮助你。

请记住,加速度计并不完美,也不会被快速轮询。非常突然的动作可能无法被很好地捕捉到。但对于轻轻在空中画画来说,它应该可以正常工作。


你需要进行两次积分才能从加速度得出位移。 - Paul R

2
似乎你在减去瞬时加速度之前对重力向量进行了归一化处理。这将保持相对方向但移除任何相对比例。我测试的最新设备(诚然不是I设备)返回大约-9.8的重力,可能校准为m/s。假设没有其他加速度,如果您将其归一化,然后从过滤后的通道中减去它,您将得到当前加速度为-8.8而不是0.0f;
两个选项: -您可以在过滤通道后直接减去重力向量 -捕获初始加速度向量长度,规范化加速度和重力向量,通过加速度和重力法线的点来缩放加速度向量。
还值得记住考虑设备的方向。

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