How to programmatically move limbs of 3d model in unity according to gyroscope orientation?

486 Views Asked by At

I have a number of gyroscopes(in real life) attached to my body on my arms, legs, head and spine. Each gyroscope has a unique id, which I map to a body part on the 3d model.

The gyroscope data for each sensor is a quaternion.

I basically just want to animate my 3d model based on this data.

So if I rotate my head to the right, the 3d model should rotate its head similarly. If I stand on one leg, the 3d model should do the same.

When using 2d physics engines like Box2d, this is as simple as applying a transform. What is the equivalent way to do this in Unity ?

EDIT: In Godot its really simple.

https://docs.godotengine.org/en/3.0/tutorials/3d/working_with_3d_skeletons.html

extends Spatial
var skel
var id

func _ready():
    skel = get_node("skel")
    id = skel.find_bone("upperarm")
    print("bone id:", id)
    var parent = skel.get_bone_parent(id)
    print("bone parent id:", id)
    var t = skel.get_bone_pose(id)
    print("bone transform: ", t)
    set_process(true)

func _process(delta):
    var t = skel.get_bone_pose(id)
    t = t.rotated(Vector3(0.0, 1.0, 0.0), 0.1 * delta)
    skel.set_bone_pose(id, t)
1

There are 1 best solutions below

0
Ruzihm On

In Unity, you can apply a quaternion rotation to a transform (overwriting its previous rotation) like this:

float quatX,quatY,quatZ,quatW;

Quaternion quat = new Quaternion(quatX,quatY,quatZ,quatW);
transform.rotation = quat;

If the problem then is that your arduino outputs right-handed quaternions, and that you need to convert them to the left-handed quaternions that unity uses, then this answer by stackexchange user DMGregory by may help you make the conversion in Unity:

A quaternion can be thought of as an angle-axis representation:

quaternion.xyz = sin(angle/2) * axis.xyz
quaternion.w = cos(angle/2)

So, converting them between two coordinate systems can be broken down into two steps:

  1. Map the axis into the new coordinate system.
  2. If changing between left & right hand coordinates (eg. if there's an odd number of axis negations or axis exchanges between the two), negate the angle.

    Since cos(-angle) = cos(angle) and sin(-angle) = -sin(angle) this is the same as flipping the axis of rotation, negating the x, y, and z parts.

Taking your specific example:

         sensor   unity
forward    x        z
up         z        y
right     -y        x

We can combine these steps into:

Quaternion ConvertToUnity(Quaternion input) {
    return new Quaternion(
         input.y,   // -(  right = -left  )
        -input.z,   // -(     up =  up     )
        -input.x,   // -(forward =  forward)
         input.w
    );
}