精华内容
下载资源
问答
  • 欧拉角

    千次阅读 2019-05-29 14:44:17
    3D图形的旋转,有三种表示方法:矩阵,欧拉角和四元数。 本文将重点介绍欧拉角heading-pitch-bank(又名roll - pitch - yaw)。 1.heading角 绕y轴转动一定的角度。 2.pitch角 绕x轴转动一定的角度。 3....

        3D图形的旋转,有三种表示方法:矩阵,欧拉角和四元数。

        本文将重点介绍欧拉角heading-pitch-bank(又名roll - pitch - yaw)。

    1.heading角

        绕y轴转动一定的角度。

    2.pitch角

      绕x轴转动一定的角度。

    3.bank角

      绕z轴转动一定的角度。

        欧拉角表示旋转直观简洁(旋转矩阵表示需要9个数字,四元数需要4个数字,欧拉角需要3个角度即可)。但是欧拉角会产生万向锁问题。

    万向锁

        一旦选择pitch角为正负90度,就被限制只能绕垂直轴旋转。欧拉角在插值过程中可能会碰到万向锁问题。

     

    展开全文
  • Matrix3f m; m = AngleAxisf(angle1, Vector3f::UnitZ()) * AngleAxisf(angle2, Vector3f::UnitY()) * AngleAxisf(angle3, Vector3f::UnitZ());
  • 四元数与欧拉角(Yaw、Pitch、Roll)的转换

    万次阅读 多人点赞 2018-01-17 10:52:31
    二、欧拉角到四元数的转换 2.1 公式: 2.2 code: 三、四元数到欧拉角的转换 3.1 公式 3.2 code: 3.3四元素到旋转矩阵转换 四.奇点 五. 矢量旋转 证明: 六 . 其他参考 0、简介 四元数与欧拉角之间的转换...

    目录

    0、简介

    一、四元数的定义

    二、欧拉角到四元数的转换

    2.1 公式:

    2.2 code:

    三、四元数到欧拉角的转换

    3.1 公式

    3.2 code:

    3.3 四元素到旋转矩阵转换

    四. 奇点

    五. 矢量旋转

    证明:

    六 . 其他参考

    七 python 四元素欧拉角互相转换

    旋转矩阵<->欧拉角 py

    8 Eigen transform

    欧拉角到四元素

    四元素得到yaw

    四元素到旋转向量

    旋转轴向量到四元素

     



    0、简介

    四元数与欧拉角之间的转换

    百度百科四元素

    在3D图形学中,最常用的旋转表示方法便是四元数和欧拉角,比起矩阵来具有节省存储空间和方便插值的优点。

    本文主要归纳了两种表达方式的转换,计算公式采用3D笛卡尔坐标系:

    定义\psi\theta\phi分别为绕Z轴、Y轴、X轴的旋转角度,如果用Tait-Bryan angle表示,分别为Yaw、Pitch、Roll。

    一、四元数的定义

    q=[w,x,y,z]^T

    \left | q \right |^2 = w^2+x^2+y^2+z^2 =1

    • 通过旋转轴和绕该轴旋转的角度可以构造一个四元数:

    w=cos(\alpha/2)

    x=sin(\alpha/2)cos(\beta_x)

    y=sin(\alpha/2)cos(\beta_y)

    z=sin(\alpha/2)cos(\beta_z)

    • 其中α是一个简单的旋转角(旋转角的弧度值),而cos(\beta _x),cos(\beta _y),cos(\beta _z)是定位旋转轴的“方向余弦”(欧拉旋转定理)。

    利用欧拉角也可以实现一个物体在空间的旋转,它按照既定的顺序,如依次绕z,y,x分别旋转一个固定角度,使用yaw,pitch,roll分别表示物体绕,x,y,z的旋转角度,记为\psi\theta\phi,可以利用三个四元数依次表示这三次旋转,即:

    Q_1=cos(\psi /2 ) +sin(\psi /2) k

    Q_2=cos(\theta /2 ) +sin(\theta /2) j

    Q_3=cos(\phi /2 ) +sin(\phi /2) i

    二、欧拉角到四元数的转换

    2.1 公式:

    2.2 code:

    struct Quaternion
    {
        double w, x, y, z;
    };
    
    Quaternion ToQuaternion(double yaw, double pitch, double roll) // yaw (Z), pitch (Y), roll (X)
    {
        // Abbreviations for the various angular functions
        double cy = cos(yaw * 0.5);
        double sy = sin(yaw * 0.5);
        double cp = cos(pitch * 0.5);
        double sp = sin(pitch * 0.5);
        double cr = cos(roll * 0.5);
        double sr = sin(roll * 0.5);
    
        Quaternion q;
        q.w = cy * cp * cr + sy * sp * sr;
        q.x = cy * cp * sr - sy * sp * cr;
        q.y = sy * cp * sr + cy * sp * cr;
        q.z = sy * cp * cr - cy * sp * sr;
    
        return q;
    }

    三、四元数到欧拉角的转换

    3.1 公式

    可以从四元数通过以下关系式获得欧拉角:

    • arctan和arcsin的结果是[-\frac{\pi}{2},\frac{\pi}{2}],这并不能覆盖所有朝向(对于\theta[-\frac{\pi}{2},\frac{\pi}{2}]的取值范围已经满足),因此需要用atan2来代替arctan。

    3.2 code:

    #define _USE_MATH_DEFINES
    #include <cmath>
    
    struct Quaternion {
        double w, x, y, z;
    };
    
    struct EulerAngles {
        double roll, pitch, yaw;
    };
    
    EulerAngles ToEulerAngles(Quaternion q) {
        EulerAngles angles;
    
        // roll (x-axis rotation)
        double sinr_cosp = 2 * (q.w * q.x + q.y * q.z);
        double cosr_cosp = 1 - 2 * (q.x * q.x + q.y * q.y);
        angles.roll = std::atan2(sinr_cosp, cosr_cosp);
    
        // pitch (y-axis rotation)
        double sinp = 2 * (q.w * q.y - q.z * q.x);
        if (std::abs(sinp) >= 1)
            angles.pitch = std::copysign(M_PI / 2, sinp); // use 90 degrees if out of range
        else
            angles.pitch = std::asin(sinp);
    
        // yaw (z-axis rotation)
        double siny_cosp = 2 * (q.w * q.z + q.x * q.y);
        double cosy_cosp = 1 - 2 * (q.y * q.y + q.z * q.z);
        angles.yaw = std::atan2(siny_cosp, cosy_cosp);
    
        return angles;
    }

     

    3.3 四元素到旋转矩阵转换

    或等效地,通过齐次表达式:

    四. 奇点

    当螺距接近±90°(南北极)时,必须意识到欧拉角参数化的奇异性。这些情况必须特别处理。这种情况的通用名称是万向节锁。

    处理奇异点的代码可从以下网站获取:www.euclideanspace.com

    五. 矢量旋转

    定义四元素的尺度q_0 和向量 \overrightarrow{q},有{\displaystyle \mathbf {q} =(q_{0},{\vec {q}})=q_{0}+iq_{1}+jq_{2}+kq_{3}}.

    请注意,通过定义欧拉旋转的四元数{\displaystyle q}来旋转三维矢量{\vec{v}}的规范方法是通过公式:

    {\displaystyle \mathbf {p} ^{\,\prime }=\mathbf {qpq} ^{\ast }}

    这儿:{\displaystyle \mathbf {p} =(0,{\vec {v}})=0+iv_{1}+jv_{2}+kv_{3}}是包含嵌入向量{\vec{v}}的四元数,{\displaystyle \mathbf {q} ^{\ast }=(q_{0},-{\vec {q}})} {\displaystyle \mathbf {q} ^{\ast }=(q_{0},-{\vec {q}})}共轭四元数

    在计算实现中,这需要两个四元数乘法。一种替代方法是应用一对关系:

    {\displaystyle {\vec {t}}=2{\vec {q}}\times {\vec {v}}}

    {\displaystyle {\vec {v}}^{\,\prime }={\vec {v}}+q_{0}{\vec {t}}+{\vec {q}}\times {\vec {t}}}

    \times:表示三维矢量叉积。这涉及较少的乘法,因此计算速度更快。数值测试表明,对于矢量旋转,后一种方法可能比原始方法快30%[4]。

    证明:

    标量和矢量部分的四元数乘法的一般规则由下式给出:

    {\displaystyle {\begin{aligned}\mathbf {q_{1}q_{2}} &=(r_{1},{\vec {v}}_{1})(r_{2},{\vec {v}}_{2})\\&=(r_{1}r_{2}-{\vec {v}}_{1}\cdot {\vec {v}}_{2},r_{1}{\vec {v}}_{2}+r_{2}{\vec {v}}_{1}+{\vec {v}}_{1}\times {\vec {v}}_{2})\\\end{aligned}}}

    利用这种关系{\displaystyle \mathbf {p} =(0,{\vec {v}})}可以找到:

    {\displaystyle {\begin{aligned}\mathbf {pq^{\ast }} &=(0,{\vec {v}})(q_{0},-{\vec {q}})\\&=({\vec {v}}\cdot {\vec {q}},q_{0}{\vec {v}}-{\vec {v}}\times {\vec {q}})\\\end{aligned}}}

    并替换为三乘积:

    {\displaystyle {\begin{aligned}\mathbf {qpq^{\ast }} &=(q_{0},{\vec {q}})({\vec {v}}\cdot {\vec {q}},q_{0}{\vec {v}}-{\vec {v}}\times {\vec {q}})\\&=(0,q_{0}^{2}{\vec {v}}+q_{0}{\vec {q}}\times {\vec {v}}+({\vec {v}}\cdot {\vec {q}}){\vec {q}}+q_{0}{\vec {q}}\times {\vec {v}}+{\vec {q}}\times ({\vec {q}}\times {\vec {v}}))\\\end{aligned}}}

    {\displaystyle q_{0}^{2}=1-{\vec {q}}\cdot {\vec {q}}} {\displaystyle q_{0}^{2}=1-{\vec {q}}\cdot {\vec {q}}}

    {\displaystyle {\vec {q}}\times ({\vec {q}}\times {\vec {v}})=({\vec {q}}\cdot {\vec {v}}){\vec {q}}-({\vec {q}}\cdot {\vec {q}}){\vec {v}}}

    可得到:

    {\displaystyle {\begin{aligned}\mathbf {p} ^{\prime }&=\mathbf {qpq^{\ast }} =(0,{\vec {v}}+2q_{0}{\vec {q}}\times {\vec {v}}+2{\vec {q}}\times ({\vec {q}}\times {\vec {v}}))\\\end{aligned}}}

    在定义{\displaystyle {\vec {t}} = 2 {\vec {q}} \times {\vec {v}}}时,可以按标量和矢量部分来表示:

    {\displaystyle (0,{\vec {v}}^{\,\prime })=(0,{\vec {v}}+q_{0}{\vec {t}}+{\vec {q}}\times {\vec {t}}).}

    六 . 其他参考

    七 python 四元素欧拉角互相转换

    def EulerAndQuaternionTransform( intput_data):
        """
            四元素与欧拉角互换
        """
        data_len = len(intput_data)
        angle_is_not_rad = False
     
        if data_len == 3:
            r = 0
            p = 0
            y = 0
            if angle_is_not_rad: # 180 ->pi
                r = math.radians(intput_data[0]) 
                p = math.radians(intput_data[1])
                y = math.radians(intput_data[2])
            else:
                r = intput_data[0] 
                p = intput_data[1]
                y = intput_data[2]
     
            sinp = math.sin(p/2)
            siny = math.sin(y/2)
            sinr = math.sin(r/2)
     
            cosp = math.cos(p/2)
            cosy = math.cos(y/2)
            cosr = math.cos(r/2)
     
            w = cosr*cosp*cosy + sinr*sinp*siny
            x = sinr*cosp*cosy - cosr*sinp*siny
            y = cosr*sinp*cosy + sinr*cosp*siny
            z = cosr*cosp*siny - sinr*sinp*cosy
            return [w,x,y,z]
     
        elif data_len == 4:
     
            w = intput_data[0] 
            x = intput_data[1]
            y = intput_data[2]
            z = intput_data[3]
     
            r = math.atan2(2 * (w * x + y * z), 1 - 2 * (x * x + y * y))
            p = math.asin(2 * (w * y - z * x))
            y = math.atan2(2 * (w * z + x * y), 1 - 2 * (y * y + z * z))
     
            if angle_is_not_rad : # pi -> 180
                r = math.degrees(r)
                p = math.degrees(p)
                y = math.degrees(y)
            return [r,p,y]

    旋转矩阵<->欧拉角 py

    import numpy as np
    import math
    import random
     
    def isRotationMatrix(R) :
        Rt = np.transpose(R)
        shouldBeIdentity = np.dot(Rt, R)
        I = np.identity(3, dtype = R.dtype)
        n = np.linalg.norm(I - shouldBeIdentity)
        return n < 1e-6
    
    def rotationMatrixToEulerAngles(R) :
    
        assert(isRotationMatrix(R))
        sy = math.sqrt(R[0,0] * R[0,0] + R[1,0] * R[1,0])
        singular = sy < 1e-6
    
        if not singular :
            x = math.atan2(R[2,1] , R[2,2])
            y = math.atan2(-R[2,0], sy)
            z = math.atan2(R[1,0], R[0,0])
        else :
            x = math.atan2(-R[1,2], R[1,1])
            y = math.atan2(-R[2,0], sy)
            z = 0
    
        return np.array([x, y, z])
    
    def eulerAnglesToRotationMatrix(theta) :
    
        R_x = np.array([[1,     0,         0          ],
        [0,     math.cos(theta[0]), -math.sin(theta[0]) ],
        [0,     math.sin(theta[0]), math.cos(theta[0]) ]
        ])
    
        R_y = np.array([[math.cos(theta[1]),  0,   math.sin(theta[1]) ],
        [0,           1,   0          ],
        [-math.sin(theta[1]),  0,   math.cos(theta[1]) ]
        ])
    
        R_z = np.array([[math.cos(theta[2]),  -math.sin(theta[2]),  0],
        [math.sin(theta[2]),  math.cos(theta[2]),   0],
        [0,           0,           1]
        ])
    
    
        R = np.dot(R_z, np.dot( R_y, R_x ))
    
        return R

    8 Eigen transform

    欧拉角到四元素

          Eigen::Quaterniond RollPitchYaw(const double roll, const double pitch,
                                          const double yaw) {
            const Eigen::AngleAxisd roll_angle(roll, Eigen::Vector3d::UnitX());
            const Eigen::AngleAxisd pitch_angle(pitch, Eigen::Vector3d::UnitY());
            const Eigen::AngleAxisd yaw_angle(yaw, Eigen::Vector3d::UnitZ());
            return yaw_angle * pitch_angle * roll_angle;
          }

    四元素得到yaw

        template <typename T>
          T GetYaw(const Eigen::Quaternion<T>& rotation) {
            const Eigen::Matrix<T, 3, 1> direction =
              rotation * Eigen::Matrix<T, 3, 1>::UnitX();
            return atan2(direction.y(), direction.x());
          }

    四元素到旋转向量

        template <typename T>
          Eigen::Matrix<T, 3, 1> RotationQuaternionToAngleAxisVector(
            const Eigen::Quaternion<T>& quaternion) {
            Eigen::Quaternion<T> normalized_quaternion = quaternion.normalized();
            // We choose the quaternion with positive 'w', i.e., the one with a smaller
            // angle that represents this orientation.
            if (normalized_quaternion.w() < 0.) {
              // Multiply by -1. http://eigen.tuxfamily.org/bz/show_bug.cgi?id=560
              normalized_quaternion.w() = -1. * normalized_quaternion.w();
              normalized_quaternion.x() = -1. * normalized_quaternion.x();
              normalized_quaternion.y() = -1. * normalized_quaternion.y();
              normalized_quaternion.z() = -1. * normalized_quaternion.z();
            }
            // We convert the normalized_quaternion into a vector along the rotation axis
            // with length of the rotation angle.
            const T angle =
              2. * atan2(normalized_quaternion.vec().norm(), normalized_quaternion.w());
            constexpr double kCutoffAngle = 1e-7;  // We linearize below this angle.
            const T scale = angle < kCutoffAngle ? T(2.) : angle / sin(angle / 2.);
            return Eigen::Matrix<T, 3, 1>(scale * normalized_quaternion.x(),
                                          scale * normalized_quaternion.y(),
                                          scale * normalized_quaternion.z());
          }

    旋转轴向量到四元素

        template <typename T>
          Eigen::Quaternion<T> AngleAxisVectorToRotationQuaternion(
            const Eigen::Matrix<T, 3, 1>& angle_axis) {
            T scale = T(0.5);
            T w = T(1.);
            constexpr double kCutoffAngle = 1e-8;  // We linearize below this angle.
            if (angle_axis.squaredNorm() > kCutoffAngle) {
              const T norm = angle_axis.norm();
              scale = sin(norm / 2.) / norm;
              w = cos(norm / 2.);
            }
            const Eigen::Matrix<T, 3, 1> quaternion_xyz = scale * angle_axis;
            return Eigen::Quaternion<T>(w, quaternion_xyz.x(), quaternion_xyz.y(),
                                        quaternion_xyz.z());
          }

     

    展开全文
  • 欧拉角四元数

    2018-05-08 09:51:41
    C++编程欧拉角和四元数的相互转换,以及根据相关参数求取旋转矩阵
  • 已知: 1.机体坐标系的角速度 gyro_x, gyro_y,gyro_z; 2.欧拉角,pitch,roll,yaw,参考我的上一章节姿态解算知识点1——四元数互滤波 求解:地理坐标系的角速度
  • eigin 欧拉角转换

    2021-01-08 01:37:35
    欧拉角转其他 初始化欧拉角(Z-Y-X,即RPY, 先绕x轴roll,再绕y轴pitch,最后绕z轴yaw) Eigen::Vector3d ea(0.785398, -0, 0);  欧拉角转换为旋转矩阵  Eigen::Matrix3d rotation_matrix3;  rotation_matrix3 = ...
  • 四元数转换欧拉角

    2020-04-27 05:00:31
    全角度欧拉角与四元数转换研究,对于四元数转换为欧拉角算法,普通的参考文献上都局限在 ±90° 内,或是俯仰角局限在内其它两角局限于内。本文利用前一时刻的角度信息对当前角度进行修正,成功地实现了 内的欧拉角...
  • 四元数转欧拉角

    2018-12-10 11:13:31
    四元数转欧拉角
  • 欧拉角旋转矩阵

    2019-03-04 23:49:04
    根据欧拉角计算相应的旋转矩阵,输入欧拉角,可选择旋转轴的次序
  • 欧拉角旋转

    2020-08-23 18:54:31
    欧拉角是一种表示三维旋转的描述方法,欧拉角的计算需要借助旋转矩阵,关于旋转矩阵的知识可先参考之前的文章:3维旋转矩阵推导与助记 欧拉角旋转 静态定义 对于在三维空间里的一个参考系,任何坐标系的取向,都可以...

    欧拉角是一种表示三维旋转的描述方法,欧拉角的计算需要借助旋转矩阵,关于旋转矩阵的知识可先参考之前的文章:3维旋转矩阵推导与助记

    欧拉角旋转

    静态定义

    对于在三维空间里的一个参考系,任何坐标系的取向,都可以用三个欧拉角来表现。

    • 参考系又称为实验室参考系,是静止不动的,可以先简单的理解理解为大地坐标系,也称惯性坐标系
    • 坐标系则固定于刚体,随著刚体的旋转而旋转,比如飞行器自身的坐标系,也称载体坐标系

    如上图为一种ZYZ顺序旋转的欧拉角示意图:

    • 设蓝色的xyz-轴为惯性系的参考轴,即大地坐标系的3个轴。
    • 设红色的XYZ轴为载体系的参考轴,即飞行器坐标系的3个轴。
    • xy-平面XY-平面的相交为交点线,用英文字母N表示。

    图中的角度符号:

    • α是x-轴与交点线的夹角,载体坐标系先绕Z轴旋转了α角度(范围0~2Pi弧度)。
    • β是z-轴与Z-轴的夹角,载体坐标系又绕当前的Y轴旋转了β角度(范围0~Pi弧度)。
    • γ是交点线与X-轴的夹角,载体坐标系又绕当前的Z轴旋转了γ角度(范围0~2Pi弧度)。
    • 这里角度的正负是按照右手定则,如右手大拇指指向z-轴,四指弯曲的旋转方向为α正方向。

    其旋转动画为:

    实际上,对于夹角的顺序和标记,夹角的两个轴的指定,并没有明确的规定。因此当用到欧拉角时,需要明确地表示出夹角的顺序,指定其参考轴。合法的欧拉角组中,唯一的限制是,任何两个连续的旋转,必须绕着不同的转动轴旋转。因此,一共有12种表示。

    • 6种绕三条轴的旋转(Tait-Bryan Angle):XYZ, XZY, YXZ, YZX, ZXY, ZYX
    • 6种只绕两条轴的旋转(Proper Euler Angle):XYX, YXY, XZX, ZXZ, YZY, ZYZ

    动态定义

    我们也可以给予欧拉角两种不同的动态定义。一种是绕固定于载体的坐标轴的三个旋转的复合;另外一种是绕大地坐标系参考轴的三个旋转的复合。

    用动态的定义,我们能更了解,欧拉角在物理上的含义与应用。

    注意,以下的描述, 大写字母XYZ坐标轴是旋转的载体坐标轴;小写字母xyz坐标轴是静止不动的大地参考轴。

    现在以旋转顺序依次是Z、Y、X的方式来描述欧拉角的两种动态定义。

    • 定义A:绕着XYZ坐标轴旋转(载体坐标轴):

      • 最初,两个坐标系统xyz与XYZ的坐标轴都是重叠的。
      • 开始,绕着Z-轴旋转α角度。
      • 然后,绕着Y-轴旋转β角度。
      • 最后,绕着X-轴旋转γ角度。

      设任何一点P1在xyz与XYZ坐标系统的坐标分别为r1与R1。定义Z(α)为绕着Z-轴旋转α角度,Y(β)为绕着Y-轴旋转β角度,X(γ)为绕着X-轴旋转γ角度。则定义A可以表述如下:

      注意这里又有矩阵左乘与右乘的概念,绕载体坐标系旋转是矩阵依次左乘,即X <- Y <- Z

    • 定义B:绕着xyz坐标轴旋转(大地坐标轴):

      • 最初,两个坐标系统xyz与XYZ的坐标轴都是重叠的。
      • 开始,绕着z-轴旋转α角度。
      • 然后,绕着y-轴旋转β角度。
      • 最后,绕着x-轴旋转γ角度。

      设任何一点P2在xyz与XYZ坐标系统的坐标分别为r2与R2。定义z(α)为绕着z-轴旋转α角度,y(β)为绕着y-轴旋转β角度,x(γ)为绕着x-轴旋转γ角度。则定义B可以表述如下:

      注意绕大地坐标系旋转是矩阵依次右乘,即z -> y -> x

      定义A与静态定义的相等,这可以直接用几何制图方法来核对。

      定义A与定义B的相等可以用旋转矩阵来证明:

    展开全文
  • 欧拉角计算

    2013-07-05 15:15:01
    工业机器人需要各种欧拉角,本文档包括了各种欧拉角的计算,还有编程代码。挺不错的资料。
  • 欧拉角研究

    2019-04-22 21:55:00
    对于在三维空间里的一个参考系,任何其它坐标系的取向,都可以用三个欧拉角来表现。参考系又称为实验室参考系,是静止不动的。而坐标系则固定于刚体,随着刚体的旋转而旋转。 欧拉角是用来表示三维坐标系中方向和...

      对于在三维空间里的一个参考系,任何其它坐标系的取向,都可以用三个欧拉角来表现。参考系又称为实验室参考系,是静止不动的。而坐标系则固定于刚体,随着刚体的旋转而旋转。
      欧拉角是用来表示三维坐标系中方向和方向变换的。我们平时说的欧拉角其实还可以细分为欧拉角(Euler-angles)和泰特布莱恩角(Tait-Bryan-angles),这两种方法都利用了笛卡尔坐标系的三轴作为旋转轴,主要区别在于选取顺序。欧拉角的选取顺序有 (x, y, x), (x, z, x), (y, x, y), (y, z, y), (z, x, z), (z, y, z) 这6种,可见选取顺序是a,b,a这样的顺序,也就是绕a轴旋转某角度后,绕新生成的b轴旋转一个角度,最后绕两次旋转以后的a轴再旋转一个角度,以此表示最终的方向。泰特布莱恩角的旋转轴选取有 (x, y, z), (x, z, y), (y, x, z), (y, z, x), (z, x, y), (z, y, x) 这6种,也就是历遍笛卡尔坐标系的三轴,比如我们最常见到的Roll-Pitch-Yaw角就是其中 (x,y,z) 的情况。但这两种方法,其实都是在空间中用最直观的方式和最少的参数表示任意方向的通用方法。

    (一)zxz顺序欧拉角

    如下图所示。设定xyz-轴为参考系的参考轴XYZ-轴为物体上的坐标系轴。称xy-平面与XY-平面的相交为交点线,用英文字母(N)代表。zxz顺规的欧拉角可以静态地这样定义

     

    α 是x-轴与交点线的夹角,

    β 是z-轴与Z-轴的夹角,

    γ 是交点线与X-轴的夹角。

    (可以证明Z,z轴与N是垂直的)

    对于夹角的顺序和标记,夹角的两个轴的指定,并没有任何常规。不同的作者会用不同组合的欧拉角来描述,或用不同的名字表示同样的欧拉角。因此,使用欧拉角前,必须先做好明确的定义。

    这个过程中新生成的坐标系 \left(\begin{matrix}X \\Y \\Z\end{matrix}\right) 可以通过运算由原坐标系 \left(\begin{matrix}x \\y \\z\end{matrix}\right) 得到:

    \left(\begin{matrix}X \\Y \\Z\end{matrix}\right) = M\left(\begin{matrix}x \\y \\z\end{matrix}\right)

    其中,矩阵M表示了上面三次旋转的总过程。我们简单推一下:

    M = Rot(z,\alpha)\cdot Rot(x,\beta)\cdot Rot(z,\gamma) = \left( \begin{matrix}cos\gamma&sin\gamma&0\\-sin\gamma&cos\gamma&0 \\0&0&1\end{matrix}\right)\left(\begin{matrix}1&0&0\\0&cos\beta&sin\beta \\0&-sin\beta&cos\beta\end{matrix}\right)\left( \begin{matrix}cos\alpha&sin\alpha&0\\-sin\alpha&cos\alpha&0 \\0&0&1\end{matrix}\right)

    M = \left(\begin{matrix} cos\alpha cos\gamma-sin\alpha cos\beta sin\gamma &sin\alpha cos\gamma+cos\alpha cos\beta sin\gamma & sin\beta sin\gamma\\ -cos\alpha sin\gamma-sin\alpha cos\beta cos\gamma &-sin\alpha sin\gamma+cos\alpha cos\beta cos\gamma& sin\beta cos\gamma\\ sin\alpha sin\beta & -cos\alpha sin\beta& cos\beta \end{matrix}\right)


    以上欧拉角 (z,x,z) 的情况。
      用欧拉角表示方向(或者说,方向变换)只需要用到三个参数,即三个旋转角度(因为坐标轴是旋转轴,所以不用增加特别的参数描述旋转轴),这样做有一个非常大的优点,就是表述清晰易懂。但随之而来的有一个很重要的问题,简单来说就是,当给定了欧拉角以后,我们很容易找到欧拉角表述的方向,但是当我们获得了一个方向以后,却不一定能唯一写出目标欧拉角来描述旋转,三维空间中的任意一个方向都可以通过至少两种不同欧拉角表示。比如说(0,0,0)和(1,0,-1)在以上欧拉角选取顺序上,是表示同一个目标方向。

    (二)x,y,z顺序欧拉角

    空间中有三个旋转欧拉角α,β,γ,选取顺序为x,y,z,可以通过构建旋转矩阵Rx,Ry,Rz得到旋转矩阵R=Rz(γ)Ry(β)Rx(α),空间某点m(x,y,z)在新的坐标系下的坐标为:Rm(x,y,z)

    旋转矩阵计算欧拉角公式:

     

    俯仰角θ(pitch):围绕Y轴旋转的角度。   

    偏航角ψ(yaw):围绕Z轴旋转的角度。       

    滚转角Φ(roll):围绕X轴旋转的角度。

                                                                                                      

      现在我们如果想实现一个旋转,只要依次绕三个轴转对应的角度就可以实现。但是由于万向节死锁的问题,简单的说就是一旦选择±90°作为pitch角,就会导致第一次旋转和第三次旋转等价,整个旋转表示系统被限制在只能绕竖直轴旋转,丢失了一个表示维度。比如说(5,90,10)与(1,90,14)表示相同的方向,此时绕X轴旋转与绕Z轴旋转没有区别。我们获得一个方向后不一定能得到确定的欧拉角来描述它。所以在通常有关旋转的应用场景中基本不使用欧拉角来旋转,而使用四元数Quaternion,因为四元数可以实现平滑插值。
      

    (三)欧拉角万向锁效应

    在游戏中,当角色旋转的动画触发时,角色就会做一系列连续的旋转变换,每一个变换都要用一组欧拉角来表示,但是不可能吧每一个方位的欧拉角都存储起来,因此动画师定义了一系列关键帧,指定关键帧处角色的方位(用一组欧拉角描述),然后计算机根据时间t对这几组欧拉角进行插值,得到一系列欧拉角。

    如果pitch不是±90°,就不会出现万向锁现象,插值后的一系列欧拉角完全可以刻画出我们所期望的角色旋转路径。

     如果某个关键帧的pitch即绕第二个轴的旋转为90°,就会遇到万向锁

     为了能有一个感性的认识,还是以手机为例,下面我指定了四个关键帧,四个关键帧处手机的方位分别用R0,R1,R2,R3四组欧拉角表示(逆时针为正方向,右手法则):

    (注意R0处的物体坐标系与世界坐标系的指向是相同的,我假定z轴向上,x轴p向右,y轴指向自己的胸口)

                      绕z轴旋转角度       绕y轴旋转角度      绕x轴旋转角度

    R0:                     0                              0                       0

    R1:                    90                             0                       0

    R2:                    90                            90                      0

    R3:                     0                              0                       90

    请先分别对手机做这四个变换,然后记住手机的这四个方位,想象一下你“期望”的连续的动画应该是什么样子的。

    但实际情况是否是这样的呢?

    你可以自己尝试对这个四个方位角插值,然后进行旋转,看看得到的路径是否和上述我们所期望的相同。

    以下是我的尝试:

     求出R0 到R1以及R1到R2的插值,然后旋转,完全符合上面的路径。但是再求出R2到R3的几个插值后,旋转得到的路径与期望不符。比如这两个插值:

       z:60  y:60  x:30

       z:    45     y:45    x:45

    做这两个旋转,你会发现手机与桌面不垂直,也就是R2到R3的路径与期望的发生了偏移(本来R2到R3的过程按照预想应该是手机一直与桌面垂直)。

    其实这是由于欧拉角插值的不光滑引起的。通俗的讲两个欧拉角插值得到的新欧拉角,不一定在你想要的轨迹上。

    总结:如果动画师在某个关键帧处指定了会引发万向锁的方位,则下一个关键帧的方位一旦超出了万向锁的约束范围,则这两个关键帧之间的路径就可能会发生偏移,反映在角色动画上是旋转偏移,反映在镜头控制上就是镜头抖动。

    要获得路径偏移的感性认识,可以参考这个视频:这个视频和我的描述有些不同,该视频使用一个称为万向节的奇怪装置解释的,而我是直接用的物体坐标系但路径偏移都是一样的。

     

     视频网址:http://v.youku.com/v_show/id_XNzkyOTIyMTI=.html

    疑问:当第二次旋转角不是90度时,两帧图片插值是否得到不同的轨迹?

    欧拉角插值问题分析。

    事实1 . 单个欧拉角能够正确表示旋转无论死锁还是不死锁。但是当两个欧拉角插值的时候,由于死锁的存在,导致插值后的欧拉角表示的旋转与原始的两个欧拉角表示的旋转差异很大。 

    事实2. 一种旋转可以用多种欧拉角表示。例如,x角度为100,与x角度为460其实是一样的。X角度为-179其实和+179很接近。更有甚者,当出现死锁的时候,同一种旋转有无数种欧拉角表示。具体方法参照文章Computing Euler angles from a rotation matrix

    事实4. 当欧拉角接近死锁的时候会引起抖动。例如48.5557    82.8384       48.0888以及   141.922       81.0177             142.027.这两个欧拉角其实非常相近,但是除了y角之外其余两个坐标差异比较大。因为两个欧拉角的y旋转角度都接近90°了,越靠近90°,y轴的微小变动就对xz两个角度影响非常大,所以进行插值的时候直接进行插值会引起抖动。例如上面的插值结果可能为5.23894            90.9103       5.05811,这个结果与上面两个原始角度所表达的方向都不一样。

    参考文献:

    www.cnblogs.com/xiaoxiaoqingyi/p/6932008.html

    www.zhihu.com/question/47736315/answer/236808639

    www.cnblogs.com/tclikang/archive/2012/11/29/2794687.html

    转载于:https://www.cnblogs.com/liuzhenbo/p/10749458.html

    展开全文
  • 四元数转欧拉角matlab

    2017-12-05 09:47:13
    四元数转欧拉角matlab,四元数转欧拉角matlab,四元数转欧拉角matlab,
  • 欧拉角

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,777
精华内容 1,110
关键字:

欧拉角