线性代数——欧拉角,旋转矩阵和四元数的关系

目录

欧拉角转旋转矩阵(右手定则逆时针旋转)

欧拉角转旋转矩阵(左手定则顺时针旋转)

旋转矩阵转欧拉角

四元数转旋转矩阵

旋转矩阵转四元数

四元数转欧拉角

参考网址: https://www.zhihu.com/search?type=content&q=%E5%9B%9B%E5%85%83%E6%95%B0%EF%BC%8C%E6%AC%A7%E6%8B%89%E8%A7%92%E5%92%8C%E6%97%8B%E8%BD%AC%E7%9F%A9%E9%98%B5


欧拉角转旋转矩阵(右手定则逆时针旋转)

因此,从一个坐标系oxyz 转换到另一个坐标系txyz, 转换矩阵为:

欧拉角转换乘矩阵,一个点(1,0,0) 从一个坐标系转换到另一个坐标系下的例子如下

(自己写的初始例子)

#include <iostream>
#include <cmath>
using namespace std;
/*
作用:2个3x3 矩阵点乘,
输入: 3x3矩阵m1, 3x3矩阵m2
输出:  矩阵m1 点乘 m2 后的3x3 矩阵m_target
*/
void matrixDot(float m1[][3], float m2[][3],float (*m_target)[3] )
{
    //float m_target[3][3];
    m_target[0][0]=m1[0][0]*m2[0][0]+m1[0][1]*m2[1][0]+m1[0][2]*m2[2][0];
    m_target[0][1]=m1[0][0]*m2[0][1]+m1[0][1]*m2[1][1]+m1[0][2]*m2[2][1];
    m_target[0][2]=m1[0][0]*m2[0][2]+m1[0][1]*m2[1][2]+m1[0][2]*m2[2][2];

    m_target[1][0]=m1[1][0]*m2[0][0]+m1[1][1]*m2[1][0]+m1[1][2]*m2[2][0];
    m_target[1][1]=m1[1][0]*m2[0][1]+m1[1][1]*m2[1][1]+m1[1][2]*m2[2][1];
    m_target[1][2]=m1[1][0]*m2[0][2]+m1[1][1]*m2[1][2]+m1[1][2]*m2[2][2];

    m_target[2][0]=m1[2][0]*m2[0][0]+m1[2][1]*m2[1][0]+m1[2][2]*m2[2][0];
    m_target[2][1]=m1[2][0]*m2[0][1]+m1[2][1]*m2[1][1]+m1[2][2]*m2[2][1];
    m_target[2][2]=m1[2][0]*m2[0][2]+m1[2][1]*m2[1][2]+m1[2][2]*m2[2][2];

    //return m_target;
}

/*
作用:点point 左乘旋转3x3矩阵matrix, 从一个坐标系转换到另一个坐标系的点
输入: 3x3旋转矩阵matrix, 起始点point, 是一个3x1的矩阵
输出: 3x1 目标点target_point 
*/
void matrixDot(float matrix[][3], float point[][1],float (*target_point)[1] )
{
    //float m_target[3][3];
    target_point[0][0]=matrix[0][0]*point[0][0]+matrix[0][1]*point[1][0]+matrix[0][2]*point[2][0];
    target_point[1][0]=matrix[1][0]*point[0][0]+matrix[1][1]*point[1][0]+matrix[1][2]*point[2][0];
    target_point[2][0]=matrix[2][0]*point[0][0]+matrix[2][1]*point[1][0]+matrix[2][2]*point[2][0];
}

/*
作用: 欧拉角转换成旋转矩阵,顺序是先绕x轴逆时针(正向)旋转roll 角, 再绕y 轴逆时针旋转pitch 角
      最后绕z轴逆时针旋转yaw 角,注意必须按顺序旋转,顺序不同,结果不一样
参数:单位弧度,绕x轴旋转的roll 角,绕y轴旋转的pitch角,绕z轴旋转的yaw 角
输出: 3x3 的旋转矩阵,某个点通过左乘旋转矩阵,从一个坐标系下转换到另一个坐标系下的点。
*/
void eulerToMatrix3x3(float yaw, float pitch,float roll,float(*c_target)[3])
{
    //绕x 轴逆时针旋转矩阵
    float c_roll[3][3];
    c_roll[0][0]=1; c_roll[0][1]=0; c_roll[0][2]=0;
    c_roll[1][0]=0; c_roll[1][1]=cos(roll); c_roll[1][2]=sin(roll);
    c_roll[2][0]=0; c_roll[2][1]=-sin(roll); c_roll[2][2]=cos(roll);

    //绕y 轴逆时针旋转矩阵
    float c_pitch[3][3];
    c_pitch[0][0]=cos(pitch); c_pitch[0][1]=0; c_pitch[0][2]=-sin(pitch);
    c_pitch[1][0]=0;           c_pitch[1][1]=1; c_pitch[1][2]=0;
    c_pitch[2][0]=sin(pitch); c_pitch[2][1]=0; c_pitch[2][2]=cos(pitch);

    //绕z 轴逆时针旋转矩阵
    float c_yaw[3][3];
    c_yaw[0][0]=cos(yaw); c_yaw[0][1]=sin(yaw); c_yaw[0][2]=0;
    c_yaw[1][0]=-sin(yaw); c_yaw[1][1]=cos(yaw); c_yaw[1][2]=0;
    c_yaw[2][0]=0;        c_yaw[2][1]=0;        c_yaw[2][2]=1;

    float c_tmp[3][3]={0};
    matrixDot(c_pitch,c_roll,c_tmp);

    //float c_target[3][3]={0};
    matrixDot(c_yaw,c_tmp,c_target);
    //return c_target;
}

int main()
{
    //设置初始点是(1,0,0)
    float point[3][1];
    point[0][0]=1; point[1][0]=0; point[2][0]=0;
#if 0    //绕y轴逆时针旋转-90度,(1,0,0)——>(0,0,-1)
    float matrix[3][3];
    float yaw=0.0;
    float pitch=-M_PI_2;
    float roll =0.0;
    eulerToMatrix3x3(yaw,pitch,roll,matrix);
    float target_point[3][1];
    matrixDot(matrix,point,target_point);
    cout << "target_point=(" <<target_point[0][0]<<","
          <<target_point[1][0]<<","<<target_point[2][0]<<")"<< endl;
 #endif

 #if 0  //绕y轴逆时针旋转90度,(1,0,0)——>(0,0,1)
    float matrix[3][3];
    float yaw=0.0;
    float pitch=M_PI_2;
    float roll =0.0;
    eulerToMatrix3x3(yaw,pitch,roll,matrix);
    float target_point[3][1];
    matrixDot(matrix,point,target_point);
    cout << "target_point=(" <<target_point[0][0]<<","
          <<target_point[1][0]<<","<<target_point[2][0]<<")"<< endl;
#endif
    //绕x轴逆时针旋转90度,绕y轴旋转0度,再绕z轴逆时针旋转90度,(1,0,0)——>(0,-1,0)
    float matrix[3][3];
    float yaw=M_PI_2;
    float pitch=0.0;
    float roll =M_PI_2;
    eulerToMatrix3x3(yaw,pitch,roll,matrix);
    float target_point[3][1];
    matrixDot(matrix,point,target_point);
    cout << "target_point=(" <<target_point[0][0]<<","
          <<target_point[1][0]<<","<<target_point[2][0]<<")"<< endl;

    return 0;
}

欧拉角转旋转矩阵(左手定则顺时针旋转)

在ROS  geometry-indigo-devel  tf 转换中,欧拉角 转换到 旋转矩阵用的是顺时针旋转(左手定则)

原理如下:

ros代码实现如下

    /** @brief Set the matrix from euler angles YPR around ZYX axes
    * @param eulerZ Yaw aboud Z axis
    * @param eulerY Pitch around Y axis
    * @param eulerX Roll about X axis
    *
    * These angles are used to produce a rotation matrix. The euler
    * angles are applied in ZYX order. I.e a vector is first rotated
    * about X then Y and then Z
    旋转矩阵是: 按顺时针旋转,左手定则, (刚好和右手定则相反)
    cosr*cosy , sinp*sinr*cosy - cosr*siny , sinp*cosr*cosy + sinr*siny
    cosp*siny , sinp*sinr*siny + cosr*cosy , sinp*cosr*siny - sinr*cosy
    -sinp     , cosp*sinr                  , cosp*cosr
    **/
    void setEulerYPR(tfScalar eulerZ, tfScalar eulerY,tfScalar eulerX)  {
        tfScalar ci ( tfCos(eulerX));
        tfScalar cj ( tfCos(eulerY));
        tfScalar ch ( tfCos(eulerZ));
        tfScalar si ( tfSin(eulerX));
        tfScalar sj ( tfSin(eulerY));
        tfScalar sh ( tfSin(eulerZ));
        tfScalar cc = ci * ch;
        tfScalar cs = ci * sh;
        tfScalar sc = si * ch;
        tfScalar ss = si * sh;

        setValue(cj * ch, sj * sc - cs, sj * cc + ss,
            cj * sh, sj * ss + cc, sj * cs - sc,
            -sj,      cj * si,      cj * ci);
    }

    void setValue(const tfScalar& xx, const tfScalar& xy, const tfScalar& xz, 
		const tfScalar& yx, const tfScalar& yy, const tfScalar& yz, 
		const tfScalar& zx, const tfScalar& zy, const tfScalar& zz)
   {
	m_el[0].setValue(xx,xy,xz);
	m_el[1].setValue(yx,yy,yz);
	m_el[2].setValue(zx,zy,zz);
   }

旋转矩阵转欧拉角

      /*
      * 作用: 通过旋转矩阵,解算出欧拉角yaw,pitch, roll
      */
      void getEulerYPR(double& yaw, double& pitch, double& roll) const
      {
          pitch = -asin(m_el[2].x());
          roll = atan2(m_el[2].y()/cos(pitch), m_el[2].z()/cos(pitch));
          yaw = atan2(m_el[1].x()/cos(pitch), m_el[0].x()/cos(pitch));
      }

 

 

四元数转旋转矩阵

推理过程:
 

 

 

旋转矩阵转四元数

已知旋转矩阵:

则求解四元数时根据的方法就是从四元数转旋转矩阵的公式中得到:

但从上式中是无法确定正负号的,所以又有:

这样只要得到q0到q4中的任意一个就能根据上面的关系求出剩余3个分量的值,假设我们先求q0的值,则有:

从上式中可以看到,求得的四元数有两个,但他们表示的是同一种旋转关系,至于先求q0到q4中的哪个值,在实际使用时应该全部一起求,看哪个值大,就选取哪个,以防止某一项在出现0时无法计算的情况

 

四元数转欧拉角

已知四元数:

欧拉角为:

但是当β角度为90度时,四元数反向计算欧拉角时会出现奇点,是无法计算的。因为这时候简化后的四元数是这样的:

所以atan2中后面那一项就变成了0:

这时候我们通常令α=0,然后解出欧拉角的值

 

欧拉角转四元数

 具体推导如下图:

 

 四元数球面线性插值

具体原理参考:  https://www.cnblogs.com/21207-iHome/p/6952004.html

 

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值