简体   繁体   English

将3x3矩阵转换为Euler / Tait Bryan角度(俯仰偏航滚动)

[英]Converting a 3x3 matrix to Euler/Tait Bryan angles (pitch yaw roll)

I have the Razer Hydra SDK here, and I want to transform the rotation matrix I get from the hardware, into pitch, yaw and roll. 我在这里有Razer Hydra SDK,我希望将我从硬件获得的旋转矩阵转换为俯仰,偏航和滚动。

The documentation states: 文件说明:

rot_mat - A 3x3 matrix describing the rotation of the controller.

My code is currently: 我的代码目前是:

roll = atan2(rot_mat[2][0], rot_mat[2][1]);
pitch = acos(rot_mat[2][2]);
yaw = -atan2(rot_mat[0][2], rot_mat[1][2]);

Yet this seems to give me wrong results. 然而,这似乎给我错误的结果。

Would somebody know how I can easily translate this, and what I am doing wrong? 有人会知道我怎么能轻易地翻译这个,以及我做错了什么?

You can calculate pitch, roll and yaw like this . 你可以像这样计算俯仰,滚转和偏航。 Based on that: 基于此:

#include <array>
#include <limits>

typedef std::array<float, 3> float3;
typedef std::array<float3, 3> float3x3;

const float PI = 3.14159265358979323846264f;

bool closeEnough(const float& a, const float& b, const float& epsilon = std::numeric_limits<float>::epsilon()) {
    return (epsilon > std::abs(a - b));
}

float3 eulerAngles(const float3x3& R) {

    //check for gimbal lock
    if (closeEnough(R[0][2], -1.0f)) {
        float x = 0; //gimbal lock, value of x doesn't matter
        float y = PI / 2;
        float z = x + atan2(R[1][0], R[2][0]);
        return { x, y, z };
    } else if (closeEnough(R[0][2], 1.0f)) {
        float x = 0;
        float y = -PI / 2;
        float z = -x + atan2(-R[1][0], -R[2][0]);
        return { x, y, z };
    } else { //two solutions exist
        float x1 = -asin(R[0][2]);
        float x2 = PI - x1;

        float y1 = atan2(R[1][2] / cos(x1), R[2][2] / cos(x1));
        float y2 = atan2(R[1][2] / cos(x2), R[2][2] / cos(x2));

        float z1 = atan2(R[0][1] / cos(x1), R[0][0] / cos(x1));
        float z2 = atan2(R[0][1] / cos(x2), R[0][0] / cos(x2));

        //choose one solution to return
        //for example the "shortest" rotation
        if ((std::abs(x1) + std::abs(y1) + std::abs(z1)) <= (std::abs(x2) + std::abs(y2) + std::abs(z2))) {
            return { x1, y1, z1 };
        } else {
            return { x2, y2, z2 };
        }
    }
}

If you still get wrong angles with this, you may be using a row-major matrix as opposed to column-major, or vice versa - in that case you'll need to flip all R[i][j] instances to R[j][i] . 如果你仍然得到错误的角度,你可能使用行主矩阵而不是列主要,反之亦然 - 在这种情况下你需要将所有R[i][j]实例翻转到R[j][i]

Depending on the coordinate system used (left handed, right handed) x,y,z may not correspond to the same axes, but once you start getting the right numbers, figuring out which axis is which should be easy :) 根据所使用的坐标系(左手,右手)x,y,z可能不对应相同的轴,但是一旦你开始得到正确的数字,找出哪个轴应该是容易的:)

Alternatively, to convert from a Quaternion to euler angles like shown here : 或者,从四元数转换为欧拉角,如下所示

float3 eulerAngles(float q0, float q1, float q2, float q3)
{
    return
    {
        atan2(2 * (q0*q1 + q2*q3), 1 - 2 * (q1*q1 + q2*q2)),
        asin( 2 * (q0*q2 - q3*q1)),
        atan2(2 * (q0*q3 + q1*q2), 1 - 2 * (q2*q2 + q3*q3))
    };
}

This is the an formula that will do, keep in mind that the higher the precision the more variables in the rotation matrix are important: 这是一个公式,请记住,精度越高,旋转矩阵中的变量越多越重要:

roll = atan2(rot_mat[2][1], rot_mat[2][2]);
pitch = asin(rot_mat[2][0]);
yaw = -atan2(rot_mat[1][0], rot_mat[0][0]);

http://nghiaho.com/?page_id=846 http://nghiaho.com/?page_id=846

This is also used in the point cloud library, function : pcl::getEulerAngles 这也用在点云库中,函数:pcl :: getEulerAngles

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM