将G力数据转换为旋转?
我最近在玩一个三轴加速度计,它有X、Y和Z三个方向。供应商的网站上说这个加速度计可以测量重力。
我把这些数据发送到Blender游戏引擎里,根据加速度计传来的数据实时旋转一个立方体。不过,传来的数值似乎不太对劲。
加速度计在每个轴上输出的值范围是从-700到700,我需要把这些值转换成Blender可以用的格式。我的数学知识不太好,所以不知道该从哪里入手。
如果有人能帮我解答一下,那就太好了。
非常感谢
Will
编辑 目前我在用一些Python代码把旋转值转换成一个矩阵:
def reorient(alpha, beta, gamma):
a = math.cos(alpha)
b = math.sin(alpha)
c = math.cos(beta)
d = math.sin(beta)
e = math.cos(gamma)
f = math.sin(gamma)
ad = a*d
bd = b*d
matrix = [[c*e, -a*f+b*d*e, b*f+a*d*e], [c*f, a*e+b*d*f, -b*e+a*d*f], [-d, b*c, a*c]]
return matrix
然后我用setOrientation(matrix)来影响立方体的旋转。不过我现在把错误的值传给了矩阵的reorient()函数。
2 个回答
假设你可以通过加速度计准确判断哪个方向是“上”。我们可以把这个方向称为N。看起来你想让立方体的“上”方向和N对齐。正如之前提到的,这样会让立方体自由旋转,但你仍然可以找到一个旋转矩阵来实现你的目标,不过你需要考虑两种不同的情况,否则解决方案会出现问题。我假设立方体的“Z”方向是“上”。
如果你把三个加速度计的值当作一个向量并进行归一化(也就是调整它的长度),你就得到了旋转矩阵的新“Z”轴部分,这样指向Z方向的向量就会和“上”向量对齐。
| a d N.x | |0| |N.x|
| b e N.y | * |0| = |N.y|
| c f N.z | |1| |N.z|
所以我们需要决定如何处理a-f。一个常见的做法是:如果N大部分指向原来的“Z”轴,那么就让矩阵的新“Y”轴部分为M = N与X的叉乘:
d = 0
e = N.z
f = -N.y
接着对M进行归一化,然后找到矩阵的“X”轴部分:L = M与N的叉乘。然后对L进行归一化。
如果N并不主要指向“Z”轴(也就是N.z < .707),那么你需要找到新的“Y”轴部分,计算方式是M = N与Z的叉乘。然后对M进行归一化,接着找到L = M与N的叉乘,最后对L进行归一化。
编辑:
现在我们有了三个加速度计的值:A.x, A.y, A.z。第一步是对它们进行归一化:
a = sqrt(A.x*A.x + A.y*Ay + A.z*A.z); and then
N.x = A.x/a; N.y = A.y/a; N.z = A.z/a;
我们假设如果N == [0, 0, 1]
,那么正确的旋转矩阵就是单位矩阵。如果N没有直接指向z轴,那么我们想要形成一个矩阵,将立方体的z轴旋转,使其与N对齐。
我猜你是在用测量到的加速度来找出重力的方向(也就是向下)。如果你在移动加速度计,除了只是转动它,还会有一些额外的力;可以想象加速度计上挂着一个摆锤,当你移动它时,摆锤会摇摆(虽然在这种情况下,它的摆动会很短且反应很快)。你可以尝试做一些运动补偿,但可能更简单的方法是保持传感器在一个固定的位置。
编辑:好吧,看起来我完全误解了问题——你想知道怎么在脚本中进行旋转吗?
看起来每个Blender对象都有三个属性(.RotX, .RotY, .RotZ),这些属性包含当前的值(以弧度为单位),还有一个方法(.rot(new_rotx, new_roty, new_rotz))可以执行旋转(具体可以查看文档,链接在这里:http://www.blender.org/documentation/249PythonDoc/Object.Object-class.html)。我现在正在研究这些旋转是如何应用的,稍后会有更多信息。
编辑2:看起来这些角度是用欧拉角来表示的(http://en.wikipedia.org/wiki/Euler_angles);它们提供了一些转换矩阵。还看起来你的加速度计数据是欠约束的(你需要一个额外的约束,指定关于“向下”方向的旋转——也许某种惯性“与之前位置的最小距离”计算?)
编辑3:有一个示例脚本可能会对你有帮助;在我的电脑上,它位于 C:\Users\Me\AppData\Roaming\Blender Foundation\Blender.blender\scripts\object_random_loc_sz_rot.py。它展示了如何获取当前选中的对象并调整它的旋转。希望这对你有帮助!
编辑4:为了讨论,这里有一些示例代码;可能有点冗余(我之前没有在Blender中工作过),而且它并没有解决问题,但至少可以为我们进一步讨论提供一个共同的基础;-)
#!BPY
"""
Name: 'Set rotation by accelerometer'
Blender: 249
Group: 'Object'
Tooltip: 'Set the selected objects rotation by accelerometer'
"""
__bpydoc__=\
'''
This script sets the selected objects rotation by accelerometer.
'''
from Blender import Draw, Scene
import math
def reorient(alpha, beta, gamma):
a = math.cos(alpha)
b = math.sin(alpha)
c = math.cos(beta)
d = math.sin(beta)
e = math.cos(gamma)
f = math.sin(gamma)
ad = a*d
bd = b*d
return = [
[c*e, -a*f+b*d*e, b*f+a*d*e],
[c*f, a*e+b*d*f, -b*e+a*d*f],
[-d, b*c, a*c ]
]
def getAccel():
# test stub -
# need to get actual values from accelerometer here
dx = -700
dy = 100
dz = 250
return (dx,dy,dz)
def normalize(vec):
"Return scaled unit vector"
x,y,z = vec
mag = (x*x + y*y + z*z)**0.5
return (x/mag, y/mag, z/mag)
def main():
scn = Scene.GetCurrent()
try:
obj = scn.objects.context
euler = (obj.RotX, obj.RotY, obj.RotZ)
except AttributeError:
return
down = normalize(getAccel())
matrix = None
# do something here to find new rotation-matrix
# based on euler and down
# then
if matrix:
obj.setOrientation(matrix)
else:
# test value:
# if reorient() is working properly, the
# object's rotation should not change!
obj.setOrientation(reorient(*euler))
if __name__=="__main__":
main()