I'm working on motion simulator with 2 DOF (pitch & roll). I'm reading transformation matrix from game and I need to get the angles and send to hardware to drive motors. Since Euler angles have singularities, I can't really use them. It behaves like this:
(source: gfycat.com)
when it should like this:
(source: gfycat.com)
I prepared online example to better show the issue:
// Get euler angles from model matrix
var mat = model.matrix;
mat.transpose();
var e = new THREE.Euler();
e.setFromRotationMatrix(mat, 'XZY');
var v = e.toVector3();
var pitch = -v.z;
var roll = -v.x;
http://jsfiddle.net/qajro0ny/3/
As far as I understand, there are two problems here.
- There is no yaw axis on simulator.
- Even if there were yaw axis, motors just don't behave like computer graphics, i.e. they need time to get to target position.
I've read about gimbal lock and even implemented euler filter, but that didn't work as expected. Most advices about gimbal lock were to use quaternions, but I can't drive physical motor with quaternion (or can I?).
Axis order doesn't really matter here, because changing it will only move singularity from one axis to another.
I need to handle this some other way.
I tried multiplying axis vectors by matrix and then using cross and dot product to get angles, but that failed too. I think there should be also axis reprojection involved to get this right, but I couldn't figure it out. But something tells me that this is the right way to do this. It was something like this: http://jsfiddle.net/qajro0ny/53/
Then I came up with different idea. I know previous position, so maybe do the following:
- Convert matrix to quaternion
- Compute difference between current and previous quaternion
- Convert resulting quaternion to euler angles
- Add those angles to static pitch, roll and yaw variables.
So I tried that and... it worked! No singularities in any of the directions, perfect 360 degree rotation in pitch, roll and yaw. The perfect solution! Except... it is not. The frames did not synchronize, so after a while angles were way off from what they should be. I've been thinking about some sort of synchronization mechanism, but I figured this is not the right way.
It looked like this: http://jsfiddle.net/qajro0ny/52/
And the same logic, but directly with matrices: http://jsfiddle.net/qajro0ny/54/
I've searched web high and low, I've read dozens of papers and other questions/posts and I just can't believe nothing really works for my case.
I might not understand or miss something, so here is everything I found and tried:
Links: http://pastebin.com/3G0dYLvu
Code: http://pastebin.com/PiZKwE2t (I've put it all together so it's messy)
I must be missing something, or I'm looking at this from the wrong angle.