将G力数据转换为旋转?

1 投票
2 回答
1984 浏览
提问于 2025-04-16 14:20


我最近在玩一个三轴加速度计,它有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 个回答

1

假设你可以通过加速度计准确判断哪个方向是“上”。我们可以把这个方向称为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 = NX的叉乘:

d =  0
e =  N.z
f = -N.y

接着对M进行归一化,然后找到矩阵的“X”轴部分:L = MN的叉乘。然后对L进行归一化。

如果N并不主要指向“Z”轴(也就是N.z < .707),那么你需要找到新的“Y”轴部分,计算方式是M = NZ的叉乘。然后对M进行归一化,接着找到L = MN的叉乘,最后对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对齐。

1

我猜你是在用测量到的加速度来找出重力的方向(也就是向下)。如果你在移动加速度计,除了只是转动它,还会有一些额外的力;可以想象加速度计上挂着一个摆锤,当你移动它时,摆锤会摇摆(虽然在这种情况下,它的摆动会很短且反应很快)。你可以尝试做一些运动补偿,但可能更简单的方法是保持传感器在一个固定的位置。

编辑:好吧,看起来我完全误解了问题——你想知道怎么在脚本中进行旋转吗?

看起来每个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()

撰写回答