欧拉角转换特殊情况(万向锁等)

问题说明

旋转的表示方式有:角轴,旋转矩阵、四元数、欧拉角。具体见旋转矩阵、欧拉角、四元数及四元数插值

欧拉角表示
优点:理解友好;3个变量3个自由度
缺点:奇异性(万向锁);同一个旋转可由多组欧拉角来表示,即一个旋转对应多组欧拉角。
这篇文章从旋转矩阵转化欧拉角来分析这些情况。
主要说明同一个旋转解析出不同欧拉角的特殊情况。

首先提以下旋转矩阵概念:
旋转矩阵根据内外旋可以写成左右乘的形式,左右乘的旋转矩阵是互相的转置。旋转矩阵既可以表征旋转运动,也可以用来表征姿态角。同理欧拉角,四元数、角轴等能够表征旋转的,都可以用来表征一个物体旋转运动后的姿态。

这里以左乘,(左前上)坐标系为例。

欧拉角到旋转矩阵

三轴欧拉角: r x , r y , r z rx,ry,rz rxryrz
使用Y->X->Z的顺序构造成的旋转矩阵: c r x crx crx代表 c o s ( r x ) cos(rx) cos(rx), s r x srx srx代表 s i n ( r x ) sin(rx) sin(rx),其他同理。
R z R x R y = [ c r z s r z 0 − s r z c r z 0 0 0 1 ] ⋅ [ 1 0 0 0 c r x s r x 0 − s r x c r x ] ⋅ [ c r y 0 − s r y 0 1 0 s r y 0 c r y ] R_zR_xR_y=\left[\begin{matrix}crz&srz&0\\-srz&crz&0\\0&0&1\\\end{matrix}\right] \cdot \left[\begin{matrix}1&0&0\\0&crx&srx\\0&-srx&crx\\\end{matrix}\right] \cdot \left[\begin{matrix}cry&0&-sry\\0&1&0\\sry&0&cry\\\end{matrix}\right] RzRxRy= crzsrz0srzcrz0001 1000crxsrx0srxcrx cry0sry010sry0cry
[ c r z c r y + s r z s r x s r y s r z c r x − c r z s r y + s r z s r x c r y − s r z c r y + c r z s r x s r y c r z c r x s r z s r y + c r z s r x c r y c r x s r y − s r x c r x c r y ] \left[\begin{matrix}crzcry+srzsrxsry&srzcrx&-crzsry+srzsrxcry\\-srzcry+crzsrxsry&crzcrx&srzsry+crzsrxcry\\crxsry&-srx&crxcry\\\end{matrix}\right] crzcry+srzsrxsrysrzcry+crzsrxsrycrxsrysrzcrxcrzcrxsrxcrzsry+srzsrxcrysrzsry+crzsrxcrycrxcry

旋转矩阵到欧拉角

欧拉角将旋转按顺序分解到三个基轴上,便于人的直观理解。但是使用欧拉角表示旋转,或者在其他旋转表述方式中恢复欧拉角时会出现特殊情况。

计算公式详见:
旋转矩阵、欧拉角、四元数及四元数插值

这里主要说明旋转矩阵中解算欧拉角的特殊情况

同一旋转矩阵对应多组欧拉角:
1、万向锁(Gimbal lock):
当中间轴(本例中为x轴)转动 ± π / 2 \pm\pi/2 ±π/2时,会发生万向锁问题,此时 R R R阵对应多组欧拉角
2、 ( r x , r y , r z ) (rx,ry,rz) (rx,ry,rz) ( ± π − r x ,   r y ± π ,   r z ± π ) (\pm\pi-rx,\ ry\pm\pi,\ rz\pm\pi) (±πrx, ry±π, rz±π)对应同一个旋转矩阵。
3、 ( r x , r y , r z ) (rx,ry,rz) (rx,ry,rz) ( r x ± 2 π ,   r y ± 2 π , r z ± 2 π ) (rx\pm2\pi,\ ry\pm2\pi,rz±2π) (rx±2π, ry±2π,rz±2π)

万向锁

参考链接:
推荐:
https://krasjet.github.io/quaternion/bonus_gimbal_lock.pdf
https://wang-yimu.com/gimbal-lock/

万向锁是在使用欧拉角时出现的问题,由于欧拉角多使用动态轴来定义,即围绕自身轴的旋转。因此,欧拉角需要定义三轴的旋转次序。虽然角度相同,定义的次序不同,则代表的旋转不同。
万向锁问题的主要原因是由于固定的旋转次序而引起的。
实际的物体旋转,可以归结为绕三维空间角轴的旋转,要最后的旋转过程按顺序分解为三个正交基轴的3次旋转。

使用欧拉角表述旋转,会出现万向锁情况,当第二次序旋转轴旋转 ± π / 2 \pm\pi/2 ±π/2时,会将第一次序轴转到与第三次序轴所在的方向上。因此,使绕第一次序轴和第三次序轴的旋转均是在绕3维空间中的同一轴旋转,从而欧拉角可表示的空间维度减少一维。

具体看下图(借用第一个参考链接的图,因此旋转次序这里按x-y-z的顺序):
绕x轴旋转任意角度:
在这里插入图片描述
绕y轴旋转90度:
在这里插入图片描述
此时我们发现,新z轴和原始的x轴位于同一个空间轴,也就是说第一次旋转和第三次旋转都是绕同一个空间轴旋转,因此,此时的欧拉角只能表征空间中两个方向的旋转,一个是y轴,一个原始x轴和新z轴的旋转。旋转维度减一。此时出现万向锁。
总结就是。第二次序轴旋转是 ± π / 2 \pm\pi/2 ±π/2时,欧拉角不能表征三维的旋转。
回到我们自己的例子,分析万向锁情况下的欧拉角表征的旋转矩阵:
r x   =   ± π / 2 rx\ =\ \pm\pi/2 rx = ±π/2 R = R z R x R y = [ c r z c r y + s r z s r x s r y s r z c r x − c r z s r y + s r z s r x c r y − s r z c r y + c r z s r x s r y c r z c r x s r z s r y + c r z s r x c r y c r x s r y − s r x c r x c r y ] R=R_zR_xR_y=\left[\begin{matrix}crzcry+srzsrxsry&srzcrx&-crzsry+srzsrxcry\\-srzcry+crzsrxsry&crzcrx&srzsry+crzsrxcry\\crxsry&-srx&crxcry\\\end{matrix}\right] R=RzRxRy= crzcry+srzsrxsrysrzcry+crzsrxsrycrxsrysrzcrxcrzcrxsrxcrzsry+srzsrxcrysrzsry+crzsrxcrycrxcry = [ c r z c r y ± s r z s r y 0 − c r z s r y ± s r z c r y − s r z c r y ± c r z s r y 0 s r z s r y ± c r z c r y 0 ∓ 1 0 ] =\left[\begin{matrix}crzcry\pm srzsry&0&-crzsry\pm srzcry\\-srzcry\pm crzsry&0&srzsry\pm crzcry\\0&\mp1&0\\\end{matrix}\right] = crzcry±srzsrysrzcry±crzsry0001crzsry±srzcrysrzsry±crzcry0 = [ cos ⁡ ( r z ∓ r y ) 0 ± sin ⁡ ( r z ∓ r y ) − sin ⁡ ( r z ∓ r y ) 0 ± cos ⁡ ( r z ∓ r y ) 0 ∓ 1 0 ] =\left[\begin{matrix}\cos{\left(rz\mp r y\right)}&0&\pm\sin{\left(rz\mp r y\right)}\\-\sin{\left(rz\mp r y\right)}&0&\pm\cos{\left(rz\mp r y\right)}\\0&\mp1&0\\\end{matrix}\right] = cos(rzry)sin(rzry)0001±sin(rzry)±cos(rzry)0
r z ∓ r y =   d rz\mp ry=\ d rzry= d
则:原式化为:
在这里插入图片描述
从公式也可以得出,当中间(第二)次序轴的转动角度为 ± π / 2 \pm\pi/2 ±π/2时,此时的欧拉角只能表征两轴旋转。
此时从旋转矩阵中恢复欧拉角时。满足 r x = ( ± π / 2 ) , r y , r z ; s . t . . r z ∓ r y = d rx=(\pm\pi/2), ry, rz;s.t.. rz\mp ry= d rx=(±π/2),ry,rzs.t..rzry=d均对应同一组旋转矩阵

代码测试:

Enter the rx: 90
Enter the ry: 30
Enter the rz: 50
catch the rpy value: 90 30 50
Start to test rotation to euler
R:
0.939693 0 0.34202
-0.34202 2.38419e-07 0.939692
0 -1 2.38419e-07
euler: rx, ry, rz: 90 -20 0


Enter the rx: -90
Enter the ry: 30
Enter the rz: 40
catch the rpy value: -90 30 40
Start to test rotation to euler
R:
0.34202 0 -0.939692
-0.939692 1.78814e-07 -0.34202
0 1 1.78814e-07
euler: rx, ry, rz: -90 70 0

π \pi π结合

首先从旋转矩阵、欧拉角、四元数及四元数插值中可知,将3轴按顺序绕 ± π \pm\pi ±π后,坐标系回到起始状态。是否存在将三个欧拉角与 π \pi π结合,而与原欧拉角所代表的旋转相同的情况。

分析旋转矩阵,当rx,ry,rz结合 π \pi π对应如下的三角函数符号变化,则对应同样的旋转。

rzrxry
cos(rz) 变号cos(rx) 变号cos(ry) 变号
sin(rz) 变号sin(rx) 不变号sin(ry) 变号

以下一组满足上述变号情况:

[ r x , r y , r z ] − > [ ± π − r x ,   r y ± π ,   r z ± π ] [rx, ry, rz]->[ \pm\pi-rx,\ ry\pm\pi,\ rz\pm\pi] [rx,ry,rz]>[±πrx, ry±π, rz±π]对应一组相同旋转。
sin ⁡ ( ± π − r x ) = sin ⁡ ( α ) , cos ⁡ ( ± π − r x ) = − cos ⁡ ( α ) \sin{\left(\pm\pi-rx\right)}=\sin{\left(\alpha\right)},\cos{\left(\pm\pi-rx\right)}=-\cos{\left(\alpha\right)} sin(±πrx)=sin(α),cos(±πrx)=cos(α) sin ⁡ ( α ± π ) = − sin ⁡ ( α ) , cos ⁡ ( α ± π ) = − cos ⁡ ( α ) \sin{\left(\alpha\pm\pi\right)}=-\sin{\left(\alpha\right)},\cos{\left(\alpha\pm\pi\right)}=-\cos{\left(\alpha\right)} sin(α±π)=sin(α),cos(α±π)=cos(α)

代码测试:

Enter the rx: 90
Enter the ry: 30
Enter the rz: 50
catch the rpy value: 90 30 50
Start to test rotation to euler
R:
0.939693 0 0.34202
-0.34202 2.38419e-07 0.939692
0 -1 2.38419e-07
euler: rx, ry, rz: 90 -20 0
rx: pi-rx; ry ± pi; rz ± pi
rpy value turn to be: 180 180 -3.4565e+258
after R:
0.939693 0 0.34202
-0.34202 2.38419e-07 0.939692
0 -1 2.38419e-07
euler: rx, ry, rz: 90 -20 0

测试代码

#include <iostream>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <math.h>

using namespace std;

//# define M_PI 3.141592653
double deg2rad = M_PI/180;
int main()
{
  double rx_orig = 0;
  double ry_orig = 0;
  double rz_orig = 0;

  cout << "Enter the rx: ";
  cin >> rx_orig;
  cout << "Enter the ry: ";
  cin >> ry_orig;
  cout << "Enter the rz: ";
  cin >> rz_orig;

  cout << "catch the rpy value: " << rx_orig << " " << ry_orig << " " << rz_orig << endl;

  cout << "******Start to test rotation to euler******" << endl;

  Eigen::AngleAxisf rxA(-rx_orig*deg2rad, Eigen::Vector3f::UnitX());
  Eigen::AngleAxisf ryA(-ry_orig*deg2rad, Eigen::Vector3f::UnitY());
  Eigen::AngleAxisf rzA(-rz_orig*deg2rad, Eigen::Vector3f::UnitZ());
  Eigen::Matrix3f R = (rzA * rxA * ryA).matrix();

  cout << "R: " << endl << R << endl;

  Eigen::Vector3f Nqr = R.eulerAngles(2,0,1);
  cout << "euler: rx, ry, rz: " << -Nqr[1]/deg2rad  << " " << -Nqr[2]/deg2rad << " "   << -Nqr[0]/deg2rad<< endl;


  cout << "rx: pi-rx; ry +- pi; rz +- pi" << endl;
  double rx = 180 - rx;
  double ry = ry + 180;
  double rz = rz - 180;

  cout << "rpy value turn to be: " << rx << " " << ry << " " << rz << endl;
  Eigen::AngleAxisf rxB(-rx_orig*deg2rad, Eigen::Vector3f::UnitX());
  Eigen::AngleAxisf ryB(-ry_orig*deg2rad, Eigen::Vector3f::UnitY());
  Eigen::AngleAxisf rzB(-rz_orig*deg2rad, Eigen::Vector3f::UnitZ());
  R = (rzB * rxB * ryB).matrix();

  cout << "after R: " << endl << R << endl;

  Nqr = R.eulerAngles(2,0,1);
  cout << "euler: rx, ry, rz: " << -Nqr[1]/deg2rad  << " " << -Nqr[2]/deg2rad << " "   << -Nqr[0]/deg2rad<< endl;


  return 0;
}

//g++ quaternion2euler.cpp `pkg-config eigen3 --libs --cflags`
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值