使用Eigen创建俯仰角、偏航角和横滚角的旋转矩阵

24
我如何使用Eigen库创建包含pitch、yaw、roll的旋转矩阵?

你还可以参考这个答案 Eigen将旋转和平移组合成一个矩阵 - Yantao Xie
6个回答

37

因为我找不到一个现成的函数来实现这个功能,所以我自己写了一个,如果将来有人遇到同样的问题,这里就是它。

Eigen::AngleAxisd rollAngle(roll, Eigen::Vector3d::UnitZ());
Eigen::AngleAxisd yawAngle(yaw, Eigen::Vector3d::UnitY());
Eigen::AngleAxisd pitchAngle(pitch, Eigen::Vector3d::UnitX());

Eigen::Quaternion<double> q = rollAngle * yawAngle * pitchAngle;

Eigen::Matrix3d rotationMatrix = q.matrix();

5
好的回答,但正如 @narcispr 所说,坐标轴将取决于你所使用的应用程序。您能否在回答中指明您的目标是飞机应用程序,以避免混淆? - Adri C.S.

20

凯撒的回答没问题,但正如David Hammen所说,这取决于您的应用。对我来说(水下或空中车辆领域),获胜组合是:

Eigen::Quaterniond
euler2Quaternion( const double roll,
                  const double pitch,
                  const double yaw )
{
    Eigen::AngleAxisd rollAngle(roll, Eigen::Vector3d::UnitX());
    Eigen::AngleAxisd pitchAngle(pitch, Eigen::Vector3d::UnitY());
    Eigen::AngleAxisd yawAngle(yaw, Eigen::Vector3d::UnitZ());

    Eigen::Quaterniond q = yawAngle * pitchAngle * rollAngle;
    return q;
}

在飞机的主轴中,Roll是Z,Pitch是X,Yaw是Y。水下的标准是否不同?http://en.wikipedia.org/wiki/Aircraft_principal_axes - Caesar
@Caesar 在我的情况下,我有一个Ladybug全景相机,其轴与这个答案中的轴相同。 - Adri C.S.

12
如何使用Eigen库创建基于pitch、yaw和roll的旋转矩阵?
有48种方法可以做到这一点。哪一个你想要?以下是相关因素:
  • 外围与内围。
    旋转是否围绕固定系统的轴(外围)或围绕旋转轴(内围)进行?

  • 旋转与变换。
    您要表示实际旋转某个对象的矩阵还是要表示将向量从一个参考系转换到另一个参考系的矩阵?

  • 天文序列。
    有六种基本的天文序列。标准的欧拉序列涉及绕z轴旋转,然后绕(旋转后的)x轴旋转,最后再绕(再次旋转后的)z轴旋转。除此标准的z-x-z序列外,还有五个这样的天文式序列(x-y-x,x-z-x,y-x-y,y-z-y和z-y-z)。

  • 航空航天序列。
    为了增加混乱程度,还有六个基本的航空航天序列。例如,俯仰-偏航-滚转序列与滚转-俯仰-偏航序列。虽然天文学界已经基本上在使用z-x-z序列,但航空航天领域并非如此。你会发现有人使用所有六个可能的序列。这个组中的六个序列是x-y-z,x-z-y,y-z-x,y-x-z,z-x-y和z-y-x。

你怎么得出48的?(6个天文学 + 6个航空航天)*(内在,外在各2个)= 24 旋转与变换仍然使用相同的矩阵。 - Dylan Madisetti
@DylanMadisetti - 除非你认为矩阵的转置与原始矩阵相同,否则旋转(又称主动旋转)和变换(又称被动旋转)不使用相同的矩阵。旋转/平移矩阵很少是自共轭的。 - David Hammen
当选择特定的欧拉角旋转方案时,存在一个相当著名的歧义,但问题绝对不是关于这种歧义的,而且这个答案绝对不能回答这个问题。 - lisyarus

10

创建旋转矩阵所需的只有俯仰角、偏航角、翻滚角以及执行矩阵乘法的能力。

首先,为每个旋转轴(即俯仰、偏航、翻滚)创建一个旋转矩阵。这些矩阵将具有以下值:

俯仰矩阵:

1, 0, 0, 0,
0, cos(pitch), sin(pitch), 0,
0, -sin(pitch), cos(pitch), 0,
0, 0, 0, 1

偏航矩阵:
cos(yaw), 0, -sin(yaw),  0,
0, 1, 0, 0,
sin(yaw), 0, cos(yaw), 0,
0, 0, 0, 1

滚动矩阵:

cos(roll), sin(roll), 0, 0,
-sin(roll), cos(roll), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1

接下来,将它们全部相乘。顺序很重要。对于普通的旋转,您需要先将Roll矩阵乘以Yaw矩阵,然后将乘积乘以Pitch矩阵。但是,如果您想通过倒退来“撤消”旋转,则需要按相反的顺序执行乘法(除了角度具有相反的值之外)。


谢谢您的回答,我已经知道了,但我希望这个库有一个预先构建的函数来完成这个任务。 - Caesar
@MohammedMajeed 我不认为有内置函数,但是请参考https://dev59.com/127Xa4cB1Zd3GeqPudUm#15043888,其中使用四元数的方法非常简洁。 - ApproachingDarknessFish
这里有文档记录链接 - ggael
1
这是针对左手坐标系的,我猜是吧? 如果要应用于右手坐标系,您只需更改输入值的符号。即设置滚转 = -滚转,偏航 = -偏航,俯仰 = -俯仰 - user183833
@user183833 如果我没记错的话,这是左手的。 - ApproachingDarknessFish

0

我从Euler Angle Visualization Tool这个网站上将他们的Java实现翻译成了C++。

#include <iostream>
#include <math.h>
#include <Eigen/Dense>

Eigen::Matrix3d rotation_from_euler(double roll, double pitch, double yaw){
    // roll and pitch and yaw in radians
    double su = sin(roll);
    double cu = cos(roll);
    double sv = sin(pitch);
    double cv = cos(pitch);
    double sw = sin(yaw);
    double cw = cos(yaw);
    Eigen::Matrix3d Rot_matrix(3, 3);
    Rot_matrix(0, 0) = cv*cw;
    Rot_matrix(0, 1) = su*sv*cw - cu*sw;
    Rot_matrix(0, 2) = su*sw + cu*sv*cw;
    Rot_matrix(1, 0) = cv*sw;
    Rot_matrix(1, 1) = cu*cw + su*sv*sw;
    Rot_matrix(1, 2) = cu*sv*sw - su*cw;
    Rot_matrix(2, 0) = -sv;
    Rot_matrix(2, 1) = su*cv;
    Rot_matrix(2, 2) = cu*cv;
    return Rot_matrix;
}



int main() {
    Eigen::Matrix3d rot_mat = rotation_from_euler(0, 0, 0.5*M_PI);
    std::cout << rot_mat << std::endl;
    return 0;
}


0

这里是一个使用标准的ZYX顺序实现的例子,就像在wikipedia中找到的那样。

template <typename T>
Eigen::Matrix3<T> eulerZYX_2_rot(T roll_rad, T pitch_rad, T yaw_rad) {
  // ZYX order, same as rot_z(yaw_rad) * rot_y(pitch_rad) * rot_x(roll_rad)
  static_assert(std::is_floating_point_v<T>, "Floating point required.");
  T sx = sin(roll_rad);
  T cx = cos(roll_rad);
  T sy = sin(pitch_rad);
  T cy = cos(pitch_rad);
  T sz = sin(yaw_rad);
  T cz = cos(yaw_rad);
  Eigen::Matrix3<T> rot(3, 3);
  rot(0, 0) = cz * cy;
  rot(0, 1) = cz * sy * sx - sz * cx;
  rot(0, 2) = cz * sy * cx + sz * sx;
  rot(1, 0) = sz * cy;
  rot(1, 1) = sz * sy * sx + cz * cx;
  rot(1, 2) = sz * sy * cx - cz * sx;
  rot(2, 0) = -sy;
  rot(2, 1) = cy * sx;
  rot(2, 2) = cy * cx;
  return rot;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接