从矩阵获得俯仰和滚动而没有奇点

Adr*_*ddy 24 c++ math 3d matrix euler-angles

我正在研究2自由度(俯仰和滚动)的运动模拟器.我正在从游戏中读取变换矩阵,我需要获得角度并发送到硬件来驱动电机.由于欧拉角有奇点,我不能真正使用它们.它的行为如下:

什么时候应该这样:

我准备了在线示例以更好地显示问题:

// 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;
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/qajro0ny/3/

据我了解,这里有两个问题.

  1. 模拟器上没有偏航轴.
  2. 即使有偏航轴,电机也不会像计算机图形那样,即它们需要时间才能达到目标位置.

我已经读过关于万向节锁甚至实现了euler过滤器,但是没有按预期工作.关于万向节锁的大多数建议是使用四元数,但我不能用四元数驱动物理运动(或者我可以?).

轴顺序在这里并不重要,因为更改它只会将奇点从一个轴移动到另一个轴.

我需要以其他方式处理这个问题.

我尝试用矩阵乘以轴向量,然后使用十字和点积来获得角度,但这也失败了.我认为还应该进行轴重投,以实现这一目标,但我无法弄明白.但有些事情告诉我,这是正确的方法.它是这样的:http://jsfiddle.net/qajro0ny/53/

然后我提出了不同的想法.我知道以前的位置,所以可能会做以下事情:

  1. 将矩阵转换为四元数
  2. 计算当前和之前四元数之间的差异
  3. 将生成的四元数转换为欧拉角
  4. 将这些角度添加到静态俯仰,滚动和偏航变量.

所以我试过了......它奏效了!在任何方向上都没有奇点,在俯仰,滚转和偏航方面完美的360度旋转.完美的解决方案!除了......它不是.帧没有同步,所以经过一段时间的角度远离他们应该是什么.我一直在考虑某种同步机制,但我认为这不是正确的方法.

它看起来像这样:http://jsfiddle.net/qajro0ny/52/

和相同的逻辑,但直接与矩阵:http://jsfiddle.net/qajro0ny/54/

我搜索了网页的高低,我已经阅读了几十篇论文和其他问题/帖子,我简直无法相信没有什么能真正起作用.

我可能不理解或遗漏某些东西,所以这里是我发现和尝试的一切:

链接:http://pastebin.com/3G0dYLvu

代码:http://pastebin.com/PiZKwE2t(我把它们放在一起,所以它很乱)

我一定是错过了什么,或者我是从错误的角度看这个.

Nic*_*ler 7

如果您知道矩阵仅包含两个旋转(按给定顺序T = RZ * RX),那么您可以执行以下操作:

局部x轴不受第二次旋转的影响.因此,您只能使用局部x轴计算第一个角度.然后,您可以从矩阵中移除此旋转,并从其他两个轴中的任意一个计算剩余角度:

function calculateAngles() {
    var mat = model.matrix;

    //calculates the angle from the local x-axis
    var pitch = Math.atan2(mat.elements[1], mat.elements[0]);

    //this matrix is used to remove the first rotation
    var invPitch = new THREE.Matrix4();
    invPitch.makeRotationZ(-pitch);

    //this matrix will only contain the roll rotation
    //  rollRot = RZ^-1 * T
    //          = RZ^-1 * RZ * RX
    //          = RX
    var rollRot = new THREE.Matrix4();
    rollRot.multiplyMatrices(invPitch, mat);

    //calculate the remaining angle from the local y-axis
    var roll  = Math.atan2(rollRot.elements[6], rollRot.elements[5]);

    updateSimAngles(pitch, roll);
}
Run Code Online (Sandbox Code Playgroud)

这当然只有在给定的矩阵符合要求时才有效.它不得包含第三个旋转.否则,您可能需要找到非线性最小二乘解.