Question

How do you represent quaternion rotations in 2 dimensions?

I'm developing in Android Studio Java with two Bluetooth IMUs that give quaternions. The sensors are oriented in the following way to start: "Zero" position for sensors

In the image shown, this is considered the “zero” position. NOTE: XYZ is displayed on the sensors. This position should be represented on the phone screen like this: "Zero" position on the phone screen

The green circle represents the angular difference between the two sensors. This circle moves based on the orientation of the sensors. The orange circle is meant to be a target and therefore the distance between the two circles is the distance from being in line as shown in the zero position.

With these sensors I’m only concerned with two rotations for each of them. The red sensor rotates about Y and Z, whereas the blue sensor rotates about X and Y. Both of these sensors can rotate about the third axis, but I’m just not really concerned with it. If it’s absolutely necessary, these rotations could be represented by the black notch shown in the image above.

My question is how do I take the quaternions given by the sensors and represent them in 2 dimensions? So for example, a rotation like:

Same as image 1 with the red sensor rotated about Z and Y

would be represented:

Phone screen display for a rotation on Z and Y

What I've tried: With the assistance of ChatGPT (since I’m somewhat new to quaternions still), I got this method, which moved the blue circle above the orange in it's zero. I’m not really sure of where CGPT got these conversions, but it’s what I have so far.

private PointF quaternionTo2D(Quaternion q) { 
   float angleX = (float) Math.atan2(2.0f * (q.w() * q.x() + q.y() * q.z()), 1.0f - 2.0f * (q.x() * q.x() + q.y() * q.y())); 
   float angleY = (float) Math.asin(2.0f * (q.w() * q.y() - q.z() * q.x())); // Mapping angles to screen coordinates 
   float x = (float) Math.sin(angleX); float y = (float) Math.sin(angleY); 
   Log.i("QuaternionTo2D", "Quaternion: " + q + " -> PointF: x=" + x + ", y=" + y); 
   return new PointF(x, y); 
}

I'm feeding this method the relative rotation quaternion calculated by multiplying the conjugate of the red sensors quaternion by the blue sensors quaternion.

Any recommendations/tips are appreciated! I can also clarify any further details.

 3  165  3
1 Jan 1970

Solution

 2

We need to know more about the coordinate system for the quaternions. But assuming a typical i is the x-axis, j is the y-axis and k is the z-axis, you can figure out which rotation each axis represents from the right hand rule. Namely that i is the y-z rotation, j is the z-x rotation, and k is the x-y rotation.

From what you've said, you want the k coordinate for the blue sensor and the i coordinate for the red sensor. This gives you your two numbers, and then it is up to you to display them in your UI.


After discussion in the comments, I have a guess about what the sensor means. This is something that should be tested by playing around with small, controlled, angles.

The identity is W=1. The X, Y, and Z components give you the axis around which it rotated. sin(θ) = sqrt(X^2 + Y^2 + Z^2). The angle that you want is asin(X / sqrt(W^2 + X^2). Replace X with whatever coordinate that you're interested in.

You'll have to play around to figure out how to handle the intended difference in orientation between the red and blue sensors. My guess is that if u is the starting orientation of red, and v is the actual orientation, you want to look at u^(-1) v. Where u^(-1) = (u_w - i*u_x - j*u_y - k*u_z)/(u_w^2 + u_x^2 + u_y^2 + y_z^2). Note that multiplication is noncommutative, so the order matters. But that's only a best guess - you may find that something different works better.

2024-07-08
btilly