使用核心动作计算倾斜角度

7
我有一个应用程序的记录会话。当用户开始记录会话时,我从设备的CMMotionManager对象收集数据并将其存储在CoreData中以供稍后处理和呈现。我收集的数据包括GPS数据、加速度计数据和陀螺仪数据。数据的频率为10Hz。
目前,我正在努力计算设备的倾斜角度。使用重力数据可以计算设备的哪一侧是地面,但我想计算用户与地面之间的左右角度,而不考虑行进方向。
这个问题需要一些线性代数知识来解决。例如,在某个点上进行计算时,我必须计算所计算平面上的3D线的方程。我已经花了一天的时间在这个问题上,它变得更加复杂了。我对数学一点也不擅长。欢迎提供与该问题相关的数学示例。

1
你使用任何姿态参考框架吗?你想要测量的角度是相对于什么参考物呢?例如,假设用户一开始站立,然后躺在地上,即将设备倾斜90度,那么你认为右角和左角是什么,转向运动还是倾斜? - Kay
@关键用户在记录会话期间将携带设备放在口袋里。因此,我们没有参考框架。我认为可以通过检查重力加速度来计算设备位置。你觉得呢?这不可能吗? - Cemal Eker
2个回答

11
这取决于您希望如何使用收集的数据以及用户将如何携带记录iPhone。原因是欧拉角不是安全的,特别是不是唯一表示旋转的方式。考虑这样一种情况,用户将手机竖直放入牛仔裤后口袋,然后向左旋转90度。因为CMAttitude与设备平放在桌子上有关,所以根据此picture,您需要两个连续的旋转(pitch=x, roll=y, yaw=z)来表示:

  • pitch +90°,使手机竖立 => (90, 0, 0)
  • roll +90°,向左旋转 => (90, 90, 0)

但是您也可以通过以下方式获得相同的位置:

  • yaw +90°,向左旋转手机 (0, 0, 90)
  • pitch -90°,使手机竖立 (-90, 0, 90)
你会看到两种不同的表示方法 (90, 90, 0) 和 (-90, 0, 90) 来实现相同的旋转,还有更多。所以当你按下开始按钮,进行一些花哨的旋转将手机放入口袋时,你可能会遇到麻烦,因为在进行更复杂的运动时不能依靠欧拉角(参见万向节锁以获得更多头痛;-))。
现在好消息是:你说得对,线性代数可以完成这项工作。你可以强制用户将手机放在相同的位置,例如右后口袋内垂直固定,并通过构建点积CMDeviceMotiong = (x, y, z)中计算相对于地面的角度和位置向量p,即竖直位置下的-Y轴(0,-1,0):

g • x = x*0 + y*(-1) + z*0 = -y = ||g||*1*cos (alpha)

=> alpha = arccos (-y/9.81) 作为总角度。请注意,重力加速度g恒定约为9.81

要获取左右倾斜角度和前后角度,我们使用正切函数:

alphaLR = arctan (x/y)

alphaFB = arctan (z/y)


[更新:]

如果您不能依赖于在上述方程中预定义的位置(0,-1,0),则只能计算总角度而不是特定的alphaLR和alphaFB。原因是您只有一个新坐标系的轴,您需要其中两个。新的Y轴y'将被定义为平均重力向量,但您不知道新的X轴,因为与y'垂直的每个向量都是有效的。

因此,您必须提供进一步的信息,例如让用户朝一个方向行走更长的距离,而不偏离,并使用GPS和磁力计数据来获取第二个轴z'。在实践中,这听起来相当容易出错。

总角度没有问题,因为我们可以用平均重力向量(pX,pY,pZ)替换(0,-1,0):

g•p = xpX + ypY + zpZ = ||g||||p||*cos(alpha) = ||g||^2*cos(alpha)

alpha = arccos ((xpX + ypY + z*pZ) / 9.81^2)


还有两件事情需要记住:

  • 不同的人穿着不同的裤子,带有不同的口袋。因此,即使是同一个人穿其他衣服,重力向量也会有所不同,您可能需要一些归一化处理。
  • CMMotionManager不在后台工作,即用户不能按下待机按钮。

感谢您提供的出色答案。它确实帮助我更好地了解了情况。不幸的是,我无法强制用户在录制过程中保持手机的相同位置。但我相信设备在录制过程中会保持“几乎”相同的状态。可以计算设备的平均位置。我认为,如果使用重力数据的点积计算相对坐标系,并通过记录会话期间设备的平均位置计算角度,就可以近似计算倾斜角度。有什么想法如何计算相对坐标系吗? - Cemal Eker
@CemalEker 很抱歉要说,这并不那么容易。请看我的更新答案。 - Kay

4
如果我理解你的问题,我想你对获取设备的姿态很感兴趣。您可以使用从CMMotionManager对象的deviceMotion属性获取的CMDeviceMotion对象的attitude属性来执行此操作。
您可能会对CMAttitude类中的两个不同角度感兴趣:roll和pitch。如果您将设备想象为具有螺旋桨置于顶部(耳机插孔位置)的飞机,则pitch是飞机/设备与地面在攀升或下潜时所做的角度。同时,roll是在飞机进行银行或中级滚动时“翅膀”与地面所成的角度。
(顺便说一句,我认为与您的问题无关的第三个角度称为yaw。)
角度将以弧度给出,但如果您需要,可以轻松将它们转换为度数(通过乘以180然后除以pi)。
假设我理解您想要什么,好消息是您可能不需要了解任何线性代数来捕获和使用这些角度。(如果我遗漏了什么,请澄清,我很乐意提供更多帮助。)
更新(基于评论):
CMAttitude对象中的姿态值相对于地面(即默认参考框架的Z轴垂直,指向与重力相反的方向),因此您不必担心取消重力。因此,例如,如果您将设备放在平坦的桌面上,然后将其侧翻,CMAttitude对象的roll属性将从0更改为正负90度(+ - .5pi弧度),具体取决于您将其滚动到哪一侧。同时,如果您开始将其平躺并逐渐将其竖起来,则pitch属性也会发生相同的变化。
虽然您可以直接使用俯仰,横滚和偏航角度,但您也可以设置不同的参考框架(例如,“向上”的不同方向)。要执行此操作,请在“校准”步骤中捕获该方向的姿态,然后使用CMAttitude的multiplyByInverseOfAttitude:方法将您的姿态数据转换为新的参考框架。
尽管您的问题只涉及捕捉“倾斜角”(与地面接触),但您可能希望至少捕捉3个姿态角中的2个(例如,俯仰和滚转或偏航,取决于它们的运动方式),如果设备将放在人的口袋中,则可能需要捕捉所有三个。 (如果口袋很松,例如,设备可能会以各种方式旋转。)但是,大多数情况下,我认为您可能只能依靠其中两个(除非您在记录会话期间看到偏航有根本性的变化)。 因此,例如,在我的牛仔裤口袋中,手机通常几乎垂直。 因此,对我来说,当我走路,坐下或奔跑时,俯仰会有很大的变化。 每当我改变面对的方向时,滚转都会发生变化。 同时,偏航不会有太大的变化(除非我做卡丘翻,这是我做不到的!)。 因此,对我来说,可以忽略偏航。
总结主要观点:要使用这些姿态角,您无需进行任何线性代数,也无需担心重力(当然,您可能还想出于其他目的使用它)。
基于Kay的新帖子,更新2:
Kay刚刚回复并展示了如何使用重力和线性代数确保您的角度是唯一的。 (顺便说一句,我认为您应该将赏金给那篇文章。)根据您想要做什么,您可能需要使用这种数学方法。 如果您需要一种标准化的方式来“谈论”和/或比较记录会话期间的态度,则需要使用线性代数和重力。 如果您只想可视化它们,您可能仍然可以逃避不使用增加的复杂性。 (例如,可视化(俯仰= 90,滚转= 0,偏航= 0)应与可视化(俯仰= 0,滚转= 90,偏航= 90)相同。)在我上面的方法中,虽然您可以有多种方式引用“相同”的态度,但它们都不是实际上错误的。 它们仍将向您提供相对于地面的角度。
但是,陀螺仪可以从一个有效的姿态描述切换到另一个意味着我上面关于只需捕获3个组件中的2个就可以摆脱的事实需要进行更正:因为这样,无论如何,您都需要捕获所有三个组件。 对不起。

实际上,我确实收集了态度数据,就像我在问题中所指示的那样。实际的问题不在于收集和转换数据,而在于计算设备的角度。我认为 CMDeviceMotion 对象的重力参数可以解决这个问题。然后比较这些角度并将差异呈现给用户。 - Cemal Eker
1
姿态数据可以提供设备的角度。我猜我需要更好地理解的是角度是相对于什么的。你想要相对于用户还是相对于地面? - Turix
我们需要计算相对于地面的角度。 - Cemal Eker
@Cernal_Eker 噢,那很好,因为这意味着你几乎可以直接使用姿态角。我会更新我的答案以反映这一点。 - Turix
@Kay 谢谢。但我认为你的解释更好!我试图避免使用线性代数,尽管我认为他可能会做到,但你的解释可能是他想要的。我将再更新一次我的帖子,以提及您的解释。 - Turix

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