开发者

Converting G Force data to rotation?

I've been playing around with an accelerometer with 3 axis: X, Y and Z. It says on the supplier's site that it measures gravitational force.

I'm sending this data to the blender games engine where I am rotating a cube in real time depending on the data values coming from the accelerometer. However the values coming through don't seem to match up.

On each axis the accelerometer spits out values from -700 to 700 on each axis and I need to convert these values to something I can use in Blender. My maths knowledge is not up to scratch so I don't know where to start with this one.

If anybody could shed some light on this, that would be great.

Many thanks

Will

EDIT Currently I'm using a bit of python code to convert the rotation values to a matrix:

def reorient(alpha, beta, gamma):
  a = math.cos(alpha) 
  b = math.sin(alpha) 
  c = mat开发者_如何学Pythonh.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 

I am then using setOrientation(matrix) to affect the rotation of the cube. However I am currently throwing the wrong values into the matrix reorient() function


I guess you are using the measured acceleration to find the direction of gravitational pull (ie, down). If you are moving the accelerometer, apart from just turning it, there will be some additional force; think of the accelerometer having a pendulum weight handing from it, as you move it the pendulum sways (although in this case it would be a very short, fast-reacting pendulum?). You could try doing some sort of movement compensation, but it might be simpler to just try to keep the sensor in a fixed location.

Edit: ok, it looks like I totally misread the question - you want to know how to do the rotation in a script?

It looks like each Blender object has three properties (.RotX, .RotY, .RotZ) which contain the current values (in radians) and a method (.rot(new_rotx, new_roty, new_rotz)) which performs a rotation (see documentation at http://www.blender.org/documentation/249PythonDoc/Object.Object-class.html). I am currently looking at how the rotations are applied; more shortly.

Edit2: it looks like the angles are specified as Euler angles (http://en.wikipedia.org/wiki/Euler_angles); they give some conversion matrices. It also looks like your accelerometer data is underconstrained (you need one more constraint, specifying rotation about the 'down' direction - maybe some sort of inertial 'least distance from previous position' calculation?)

Edit3: there is a sample script which may be helpful; on my machine it is at C:\Users\Me\AppData\Roaming\Blender Foundation\Blender.blender\scripts\object_random_loc_sz_rot.py It shows how to get the currently selected object and tweak its rotation. Hope that helps!

Edit4: for sake of discussion, here is some sample code; it may be a bit redundant (I haven't worked in Blender before) and it doesn't solve the problem, but it will at least give us a common basis for further discussion ;-)

#!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()


Let's assume that you can use the accelerometers to correctly determine which way is 'up'. We can call that vector N. It seems to me that you want the 'up' direction of your cube to align with N. As already mentioned, that leaves the cube free to spin, but you can still find a rotation matrix that might accomplish what you're going for, but you need to account for two separate cases or else you'll have a singularity in the solution. I'll assume that 'Z' is 'up' on the cube.

If you treat the three accelerometer values as a vector and normalize it (to get N), you've got the new 'Z' axis portion of your rotation matrix so that a vector pointed in the z direction will now align with the 'up' vector.

| a d N.x |   |0|   |N.x|
| b e N.y | * |0| = |N.y|
| c f N.z |   |1|   |N.z|

So we need to decide what to do with a-f. One common thing to do is this: if N is pointing mostly along the original 'Z' axis, then make the new 'Y' axis portion of the matrix be M = N cross X:

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

Normalize M and then find the 'X' axis portion of the matrix: L = M cross N. Normalize L.

If N is not pointing mostly along the 'Z' axis (N.z < .707), then you find the new 'Y' axis portion as M = N cross Z. Normalize M and find L = M cross N and, finally, normalize L.


Edit:

So we have our three accelerometer values: A.x, A.y, A.z. First step is to normalize them:

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;

We assume that if N == [0, 0, 1] then the correct rotation matrix is the identity matrix. If N doesn't point directly along the z-axis, then we want to form a matrix that will rotate the z-axis of the cube so that it lines up with N.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜