2
votes

I am using the Leap Motion device to get usable data on the position and orientation of my hand. At the moment I am having trouble with the orientation segment of the coding. The Leap API only has code for frame by frame rotation, however, it also provides a normal vector (normal to the palm of the hand) and a pointer vector (pointing in the direction from the palm outwards towards the fingers). These two vectors are perpendicular.

The vectors:

Leap.Vector normal = current.PalmNormal;
Leap.Vector pointer = current.Direction; 

More information can be found on the Leap Hand API: https://developer.leapmotion.com/documentation/Languages/CSharpandUnity/API/class_leap_1_1_hand.html

Converting to Unity Vector3 class:

Vector3 normalU = new Vector3();
normalU.x = normal.x;
normalU.y = normal.y;
normalU.z = normal.z;
Vector3 pointerU = new Vector3();
pointerU.x = pointer.x;
pointerU.y = pointer.y;
pointerU.z = pointer.z;

I use these to vectors to calculate the Euler Angles orientation of my hand (a rotation of theta_x degrees about the x-axis, theta_y degrees about the y-axis, and theta_z degrees about the z-axis) using the code:

float rXn = Mathf.Atan (normalU.y/normalU.z);
rXn *= (180f/Mathf.PI);
if ((normalU.y < 0 && normalU.z < 0) || (normalU.y > 0 && normalU.z < 0))
{
    rXn += 180f;
}
float rZn = Mathf.Atan (normalU.y/normalU.x);
rZn *= (180f/Mathf.PI);
if ((normalU.y < 0 && normal.x > 0) || (normalU.y > 0 && normalU.x > 0))
{
    rZn += 180f;
}
float rYn = Mathf.Atan (pointerU.x/pointerU.z);
rYn *= (180f/Mathf.PI);
if ((pointerU.x > 0 && pointerU.z > 0) || (pointerU.x < 0 && pointerU.z > 0))
{
    rYn += 180f;
}

The Euler Angles are then converted to a Quaternion and implemented using the code:

Quaternion rotation = Quaternion.Euler (-rZn+90, -rYn, rXn+90);
rigidbody.MoveRotation (rotation);

More information on the Unity Quaternion class can be found here: http://docs.unity3d.com/Documentation/ScriptReference/Quaternion.html

As I coded this, I tested each axis of rotation individually, commenting out the others (setting them to 0), and they worked properly. However, when I implemented all three at once, the behaviors of rotations around an individual axis changed, which confuses me. Why would including recognition of rotation about the y-axis change the way rotation about the x-axis occurs?

As each individual axis of rotation worked when the others were commented out (and set to 0), I think the problem lies in the way the Euler Angles are converted to a Quaternion. I do not have a great understanding of the way Quaternions are used to represent rotations, however I am confused as to why changing the value of the angle of rotation about the y-axis would change the angle of rotation about the x-axis.

Thanks for your help.

2
Are you sure you meant to say Quaternion.Euler (-rZn+90, -rYn, rXn+90); and not Quaternion.Euler (-rXn+90, -rYn, rZn+90); or does -rZn+90 properly correlate to degrees of rotation about the x-axis, and -rXn+90 properly correlates to degrees of rotation about z-axis?AndyG
The Unity API for Quaternion.Euler specifies the order of the arguments and it is z, y, x.Tristan Hull
Correct me if I'm wrong, but this documentation seems to say otherwise: docs.unity3d.com/Documentation/ScriptReference/…AndyG
@AndyG I think the key is the last bit "in that order", after defining rotations around Z, then X, then Y. Also, I recommend switching from atan to atan2. If normalU.z or normalyU.x are 0 you'll have division by 0.Jerdak
@Jerdak: Thank you, but I still disagree. The parameter list gives x,y,z order. The description is most likely talking about the order the rotations would be applied (rotation about z applied first, rotation about y applied second, rotation about x applied last). See PMF's answer.AndyG

2 Answers

2
votes

The order of rotation is relevant, and this might be what causes your confusion. Imagine a point on the x-axis at (1, 0, 0). When we now do a rotation of 90° around the x axis, nothing happens. Then we do a rotation of 90° around the y axis, which makes the point lie on the positive z-axis. If we change the order of rotation, the point will end on the y axis. Depending on the way your functions are implemented, they require a certain order of rotation to get the expected results.

0
votes

It's not perfect, but I am getting pretty good results with:

private void UpdateHandNormal( Hand hand, Transform marker )
{

    float y = Mathf.Atan( hand.Direction.x / hand.Direction.z );
    if( float.IsNaN( y ) ) y = 0;
    marker.localRotation = new Quaternion( hand.PalmNormal.z, -y, hand.PalmNormal.x, 1 ) ;  

}

Where hand is the Hand instance from the leap controller and marker is a simple rectangle representing the hand rotation.

I was getting NaN for y so I added the set to 0 check.

ath

J.