Reset position to center using quaternion (myo)

Hi
I’m trying to reset the myo position of a cube to the center when a person is pointing to the screen wearing the myo on the right hand.
I’m using ofNode with two objects, one is “myArm” as a generic object and “geometry” that is the cube that appears in the screen. Myo rotates “geometry”. I’m trying to center “geometry” by multiply myArm quaternion by the inverse quaterion of “geometry” called “center”, buuuut it doesn’t work.
Any suggestion?

            void Arm::reset(ofQuaternion inRotation){
                ofQuaternion center = inRotation.inverse();
                myArm.rotate(myArm.getGlobalOrientation() * center);
            }

I got something more close to the idea, but it has problems with Roll, when it too different from origin it never goes to cero. Any idea?

void Arm::reset(ofQuaternion inRotation){
	ofQuaternion origin = ofQuaternion(0, 0, 0, 1);
	ofQuaternion orientation_quaternion = geometry.getOrientationQuat();
	ofQuaternion point = inRotation.inverse();
	ofQuaternion result = origin + (orientation_quaternion * (point - origin));
	geometry.setOrientation(result);
}

Hi, what do you mean when you say “center”?.
of which coordinate system it is the center ?

Hi
with “center” I mean the box object pointing to the front, like (0,0,0,1) in quaternions rotation. If you have practice with Myo, is exactly what the Unity3d example does when you click "r. My point is that I don’t find a direct translation from C# Unity to C++.

Here the piece of code from Unity:

    _antiYaw = Quaternion.FromToRotation (
    new Vector3 (myo.transform.forward.x, 0, myo.transform.forward.z),
    new Vector3 (0, 0, 1)
    );
    // _referenceRoll represents how many degrees the Myo armband is rotated clockwise
    // about its forward axis (when looking down the wearer's arm towards their hand) from the reference zero
    // roll direction. This direction is calculated and explained below. When this reference is
    // taken, the joint will be rotated about its forward axis such that it faces upwards when
    // the roll value matches the reference.
    Vector3 referenceZeroRoll = computeZeroRollVector (myo.transform.forward);
    _referenceRoll = rollFromZero (referenceZeroRoll, myo.transform.forward, myo.transform.up);

hi, from that code you pasted, what are the computeZeroRollVector and rollFromZero functions?
Is your Arm class inheriting from an OF class? You should make it inherit from ofNode, as it has a lot of handy functions to make what you want. Check its documentation from here.

Hi Roy,
Yes I’m working with ofNode. I paste the functions below:
Right now I’m just trying to find all the correlative code from Unity to Of. Some things are just coded differently, like Quaternion.FromToRotation that seems to be ofQuaternion::invert()

Vector3 computeZeroRollVector (Vector3 forward)
{
    Vector3 antigravity = Vector3.up;
    Vector3 m = Vector3.Cross (myo.transform.forward, antigravity);
    Vector3 roll = Vector3.Cross (m, myo.transform.forward);

    return roll.normalized;
}

float rollFromZero (Vector3 zeroRoll, Vector3 forward, Vector3 up)
{
    // The cosine of the angle between the up vector and the zero roll vector. Since both are
    // orthogonal to the forward vector, this tells us how far the Myo has been turned around the
    // forward axis relative to the zero roll vector, but we need to determine separately whether the
    // Myo has been rolled clockwise or counterclockwise.
    float cosine = Vector3.Dot (up, zeroRoll);

    // To determine the sign of the roll, we take the cross product of the up vector and the zero
    // roll vector. This cross product will either be the same or opposite direction as the forward
    // vector depending on whether up is clockwise or counter-clockwise from zero roll.
    // Thus the sign of the dot product of forward and it yields the sign of our roll value.
    Vector3 cp = Vector3.Cross (up, zeroRoll);
    float directionCosine = Vector3.Dot (forward, cp);
    float sign = directionCosine < 0.0f ? 1.0f : -1.0f;

    // Return the angle of roll (in degrees) from the cosine and the sign.
    return sign * Mathf.Rad2Deg * Mathf.Acos (cosine);
}

i believe quaternion fromToRotation is the same as ofQuaternion::makeRorate(vec1, vec2) which creates a quaternion that rotates vec1 to transform it into vec2

Arturo stole my words. :slight_smile:
all the rest seems quite straight forwards.
Actually it looks much more like glm.

Anyhow,
something like

Vector3 m = Vector3.Cross (myo.transform.forward, antigravity);

should translate to

ofVec3f m = myo.transform.forward.cross(antigravity);

This is assuming that you already converted myo.transform.forward to an ofVec3

best

ok
I started to traduce the code, but not totally sure how to convert myo.transform.forward, it is a ofVec3f but how to obtain it from the quaternion? I have an ofNode that is moved by the myo quaternion. myo.transform.forward is a vector that points forward, then, I have to store the position of the myo in two frames using deque and takes the difference?

I don’t really understand transform.forward :kissing_closed_eyes:

Ok. so I made a fast research and figured out your problem.
The myo.transform object is analogous to ofNode in the sense that it stores the transformation of an object.
https://docs.unity3d.com/ScriptReference/Transform.html
The myo is a Unity GameObject instance.
https://docs.unity3d.com/ScriptReference/GameObject.html
So, you only need to get the transform matrix from myo.transform and use it to set the matrix of your ofNode instance.
the myo.transform.forward gives you back the direction of the “blue” axis as the documentations says, which probably is the Z axis. It gives the transformation local axis in global coordinates.
ofNode has getZAxis() which should be the same as myo.transform.forward.

hope this helps.

Hey,
Thanks a lot for the help. How to translate this lines? I have more doubts about the second one.

return sign * Mathf.Rad2Deg * Mathf.Acos (cosine); 
return sign * ofRadToDeg(acos(cosine));

Quaternion antiRoll = Quaternion.AngleAxis (relativeRoll, myo.transform.forward);
antiRoll.makeRotate(relativeRoll, myArm.getZAxis());

the first part seems to be correct.
the second one should be

ofQuaternion antiRoll (relativeRoll, myArm.getZAxis());

best!

I see! well at the end I resolve it with only this two lines. :sweat_smile:

void Arm::reset(ofQuaternion inRotation){
    ofQuaternion result = inRotation.inverse();
    geometry.setOrientation(result);
}

good to know.
it would be good if you can make an addon for the Myo.
all the best

yes, absolutely! I will upload it when it is ready: I have a version working on mac and windows but still need to clean it to make the addon.
Thanks for the help!

1 Like

Hi Dazzid_of !
I would be really interested in your code if you don’t mind to share it. Did you create an addon already… ?

Thanks