Imagine this scenario: An object is laying flat on a horizontal surface, from this an original rotation is determined. Then the object is moved, and at some point flipped upside down and put back down on the table, throughout this a second rotation is continuously updated.

I need a way to determine if the rotation is now pointing downwards compared to the first rotation. This rotation is updated using data from a gyroscope and an accelerometer.

  • \$\begingroup\$ Doesn't the accelerometer give you values for 3 axes? After the flip, your Y axis is now negative of what it was. \$\endgroup\$ – MichaelHouse Oct 2 '13 at 14:57
  • \$\begingroup\$ @Byte56: Yes, both the gyroscope and the accelerometer provide information on 3 axes(afaik). After the object has been flipped and is standing still in the horizontal position, the accelerometer will be measuring no acceleration in any direction. I might not know very much about this, but I don't know how that could be of any use, other than for calculating a new rotation while it is measuring movements, which is currently done. \$\endgroup\$ – Atheuz Oct 2 '13 at 15:43
  • \$\begingroup\$ Actually, the accelerometer will be measuring gravity (interestingly acceleration and gravity are frequently indistinguishable, this situation doesn't stray from that). \$\endgroup\$ – MichaelHouse Oct 2 '13 at 15:46

As Byte56 noted in a comment, you should just be able to read the object's current orientation (i.e., its rotation matrix) off of the gyroscope, and the problem is much easier to solve that way. Regardless of how you have the object's orientation, the key is to find the 'transformed' version of whichever axis (presumably Y or Z) corresponds to your upwards direction and to determine whether it points in the opposite direction from the original axis; the condition for the latter is just that the dot product between the two is less than zero. Since the axis is generally a basis vector, you don't even need to look at a full dot product; just the appropriate component. So, for instance, assuming that your vertical axis is Z, if the device's current rotational transformation is stored in a quaternion q then the pseudocode might look something like:

Vector vNewZAxis = q.rotateVector(Vector(0,0,1));
bool bIsFlipped = (vNewZAxis[2] < 0);

If you have your transformation encoded as a matrix, then this simplifies even further (since then the rotation is simply a column extraction), and the code ends up looking something like:

bool bIsFlipped = (mOrientationMatrix[2][2] < 0);
  • \$\begingroup\$ Thanks! A lot of this stuff is over my head and it isn't helping that I'm working in C. I tried making an orientation matrix from the quaternion and I'll see if it works(primarily because I don't know how to rotate a vector around my quaternion in C). \$\endgroup\$ – Atheuz Oct 2 '13 at 17:49
  • \$\begingroup\$ Just to test what you did, even though it's not necessary, I tried making the value at index 2,2 in the orientation matrix using this formula, that I found on wikipedia see here: 1 - 2 * pow(x, 2) - 2 * pow(y, 2) But it didn't really work all that well. As there were upside down orientations that were achieved by flipping the device differently that didn't result in a negative value, and some orientations that were up that did result in a negative value. Did I do something wrong? \$\endgroup\$ – Atheuz Oct 5 '13 at 22:47
  • \$\begingroup\$ Well, you shouldn't be using 'pow' - especially not for 'pow(n,2)' which can better be written as just n*n! But more to the point, I'm not sure what your 'x' and 'y' are referring to there; They're supposed to be two of the 'imaginary' components of the quaternion (whether your 'real' component is q0 or q3 varies with convention). But based on your answer you must have done something wrong along the way, because 1-2*q1^2-2*q2^2 (to use your answer's notation) should be the same as q0^2-q1^2-q2^2+q3^2! \$\endgroup\$ – Steven Stadnicki Oct 7 '13 at 7:07
  • \$\begingroup\$ This is because q should be a unit quaternion : q0^2+q1^2+q2^2+q3^2=1. Subtracting (q1^2+q2^2) from both sides of this gives q0^2+q3^2=1-q1^2-q2^2; subtracting (q1^2+q2^2) again gives q0^2-q1^2-q2^2+q3^2 = 1-2q1^2-2q2^2 - but the left hand side of this is exactly the formula your answer gives for gz, and the right hand side is exactly the formula you list from Wikipedia. \$\endgroup\$ – Steven Stadnicki Oct 7 '13 at 7:09
  • \$\begingroup\$ The quaternion is normalized. I agree the quaternion component names were poorly chosen, that is rectified now: q0 is w, q1 is x, q2 is y, q3 is z. I'll have to test it again, because looking at your math I can't see anything wrong. \$\endgroup\$ – Atheuz Oct 7 '13 at 16:18

I resolved it I think - I will however accept Steven Stadnicki's answer but here's how I did it for posterity:

Using the quaternion, with its parts called q0 q1 q2 q3.

Calculate the direction of gravity, gx gy gz using this:

gx = 2 * (q1*q3 - q0*q2);
gy = 2 * (q0*q1 + q2*q3);
gz = q0*q0 - q1*q1 - q2*q2 + q3*q3;

gz will then be positive if in the upright position, and negative if facing upside down.

  • \$\begingroup\$ Worth noting: what you did amounts to building the rotation matrix from the quaternion and transforming the unit Z vector by that rotation matrix (i.e., extracting the matrix's 'Z' column). \$\endgroup\$ – Steven Stadnicki Oct 2 '13 at 22:01
  • 2
    \$\begingroup\$ Note that since your quaternion has unit length, gz can be calculated as 2.0 * (q0*q0 + q3*q3) - 1.0, and since you only care about the sign, your test can be if (q0*q0 + q3*q3 > 0.5). \$\endgroup\$ – sam hocevar Oct 3 '13 at 13:19
  • \$\begingroup\$ Where did you get this formula from? Or in other words why does this formula work? Can you explain a little more how this equations do work? Thank you \$\endgroup\$ – Soccertrash Sep 27 '17 at 8:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.