c++ - 从没有奇点的矩阵中获取俯仰和滚动

标签 c++ math matrix 3d euler-angles

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


(来源:gfycat.com)

什么时候应该是这样的:


(来源:gfycat.com)

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

// 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/

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

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

我已经阅读了有关万向节锁定的信息,甚至实现了欧拉过滤器,但这并没有按预期工作。 大多数关于云台锁定的建议是使用四元数,但我不能用四元数驱动物理电机(或者我可以吗?)。

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

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

我尝试将轴 vector 乘以矩阵,然后使用叉积和点积来获得角度,但这也失败了。我认为还应该涉及到轴重投影才能做到这一点,但我无法弄清楚。但有件事告诉我,这是正确的做法。是这样的:http://jsfiddle.net/qajro0ny/53/

然后我想出了不同的想法。我知道以前的职位,所以也许做以下事情:

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

所以我尝试了,并且......它成功了!任何方向都没有奇点,俯仰、滚动和偏航的完美 360 度旋转。完美的解决方案!除了......它不是。帧没有同步,所以过了一会儿,角度偏离了它们应该的样子。我一直在考虑某种同步机制,但我认为这不是正确的方法。

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

同样的逻辑,但直接使用矩阵:http://jsfiddle.net/qajro0ny/54/

我在网上搜索过很多次,我已经阅读了几十篇论文和其他问题/帖子,我简直不敢相信没有什么真正适合我的案例。

我可能不明白或错过了什么,所以这里是我找到并尝试过的所有内容:

Links: http://pastebin.com/3G0dYLvu

Code: http://pastebin.com/PiZKwE2t (I've put it all together so it's messy)

我一定是遗漏了什么,或者我从错误的角度看这个。

最佳答案

如果你知道矩阵只包含两个旋转(按照给定的顺序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);
}

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

关于c++ - 从没有奇点的矩阵中获取俯仰和滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31088440/

相关文章:

python - 如何找到二维矩阵的两条对角线?

r - 将上半部分矩阵与下半部分矩阵进行比较

html - 尝试使用带有表格的 div 元素创建带括号的(数学)矩阵。表格不在 div 内

c - OpenCL 转置内核如何使用 get_local_id

c++ - boost asio steady_timer 上的多个递归 async_wait

c++ - 以编程方式检查数字签名

algorithm - AP GP clrs 系列总和附录 A.1-4

c++ - 什么是用于连接音频文件的好库?

c++ - 枚举位域和聚合初始化

algorithm - 我可以实现什么样的酷图形算法?