欧拉角(横滚角、俯仰角、偏航角)、旋转矩阵、四元数的转换与解决万向节死锁

news2024/12/28 6:29:18

1、概述

物体的位姿(位置和方向)的描述方法一般使用两个坐标系来表示,一个是世界坐标系或地面坐标系,这里我都叫做地面坐标系吧,属于参考坐标系;另一个是自身的坐标系,以飞机为例来讲述一些常见的用语,感觉比较合适,这里就叫做机体坐标系,这个会随着自身的变化而发生变化。
如下图所示:

2、机体坐标系

机体坐标系是指固定在飞行器或者飞机上的遵循右手法则的三维正交直角坐标系,其原点位于飞行器的质心。
X'轴永远指向机头,Y'轴指向机身右方,跟X'轴所在的对称平面垂直,Z'轴跟X'轴的所在水平平面垂直。也就是说这个坐标的固定是相对飞机来说的不变化,而上面的地面坐标系是整个的参考坐标,保持固定不变。

3、欧拉角

Euler欧拉角(姿态角):
机体坐标系与地面坐标系的关系是三个角,反应了飞机相对地面的姿态。

横滚角Φ(roll):绕X轴旋转。横滚角是指运载体横轴与水平线之间的夹角。也叫滚转角,代表运载体绕纵轴的转动,绕纵轴轴向顺时针转动为正,否则为负,可以想象成飞机做翻滚运动。

俯仰角θ(pitch):绕Y轴旋转。机体坐标系x轴与水平面的夹角,俯仰角在水平面上面为正,否则为负,可以想象成飞机抬头向上与俯冲向下。

偏航角ψ(yaw):绕Z轴旋转。相对于纵轴的旋转角度,改变偏航角可以改变飞机的飞行方向,机头往右为正,这个跟平时开车,左转弯右转弯一样。

4、欧拉角转换旋转矩阵

当然这个欧拉角的旋转顺序也是很有关系的,都是描述着一个坐标系到另一个坐标系的变化,也就是说一个坐标系相对于另一个坐标系的位姿可以使用一个旋转矩阵来表示。其旋转矩阵我们来看下推导如下: 

5、四元数

四元数,又称欧拉参数,提供另外一种方法来表述三维旋转。四元数方法用在大多数的演算会比较快捷,并能避免一些技术上的问题,如万向节死锁(即当旋转角度接近某些特定值时,欧拉角表示会出现无限循环,换句话说就是两个轴重合,失去一个自由度,然后再旋转也没啥意义了) 现象,因为这些原因,许多高速度三维图形程式制作都使用四元数。当然四元数没有欧拉角来的直观,比较难以理解,这个也是它的缺点。
欧拉角和四元数都是用于描述旋转和方向的方法,但它们在表示旋转的方式和数学结构上有所不同。
对于万向节死锁的情况,可以查看视频来更直观了解:欧拉旋转万向节死锁
四元数是四个自由度,比欧拉角多出一个自由度:
Q=a+bi+cj+dk,其中a,b,c,d是实数,i,j,k是虚数,i²=j²=k²=-1

6、Python示例

6.1、欧拉角转旋转矩阵

import math
import numpy as np
def euler_to_matrix(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

分别计算绕x、y、z轴的旋转矩阵,然后以某个顺序做点积运算即可。

print(euler_to_matrix([math.pi/3,0,math.pi/6]))
/*
[[ 0.8660254 -0.25       0.4330127]
 [ 0.5        0.4330127 -0.75     ]
 [-0.         0.8660254  0.5      ]]
*/

使用transforms3d或者scipy里面的库,分别来验证下,答案是正确的: 

import transforms3d as tfs
print(tfs.euler.euler2mat(math.pi/3,0,math.pi/6,"sxyz"))
print(np.degrees(tfs.euler.mat2euler(euler_to_matrix([math.pi/3,0,math.pi/6]),"sxyz"))) #[60. -0. 30.]

//使用弧度制
from scipy.spatial.transform import Rotation as R
print(R.from_euler('xyz', [math.pi/3,0,math.pi/6], degrees=False).as_matrix())
print(np.degrees(R.from_matrix(euler_to_matrix([math.pi/3,0,math.pi/6])).as_euler('xyz'))) #[60.  0. 30.]
//使用角度制
print(R.from_euler('xyz', [60,0,30], degrees=True).as_matrix())

一般我们都是以弧度为标准,当然有些情况为了直观,我们也可以转成角度来运算。

6.2、欧拉角转四元数

import math

def euler_to_quaternion(roll, pitch, yaw):
    cy = math.cos(yaw * 0.5)
    sy = math.sin(yaw * 0.5)
    cr = math.cos(roll * 0.5)
    sr = math.sin(roll * 0.5)
    cp = math.cos(pitch * 0.5)
    sp = math.sin(pitch * 0.5)
    w = cy * cr * cp + sy * sr * sp
    x = cy * sr * cp - sy * cr * sp
    y = cy * cr * sp + sy * sr * cp
    z = sy * cr * cp - cy * sr * sp
    return w, x, y, z

print(euler_to_quaternion(math.pi/3,0,math.pi/6))
#(0.8365163037378079, 0.4829629131445341, 0.12940952255126034, 0.2241438680420134)

print(tfs.euler.euler2quat(math.pi/3,0,math.pi/6,"sxyz"))
#[0.8365163  0.48296291 0.12940952 0.22414387]

print(euler_to_quaternion(math.pi/3,math.pi,math.pi/2))
#(0.3535533905932738, -0.6123724356957946, 0.6123724356957946, -0.3535533905932737)

print(tfs.euler.euler2quat(math.pi/3,math.pi,math.pi/2,"sxyz"))
#array([ 0.35355339, -0.61237244,  0.61237244, -0.35355339])

6.3、四元数转旋转矩阵

#x, y ,z ,w
def quaternion_to_rotation_matrix(q):
    rot_matrix = np.array(
        [[1.0 - 2 * (q[1] * q[1] + q[2] * q[2]), 2 * (q[0] * q[1] - q[3] * q[2]), 2 * (q[3] * q[1] + q[0] * q[2])],
         [2 * (q[0] * q[1] + q[3] * q[2]), 1.0 - 2 * (q[0] * q[0] + q[2] * q[2]), 2 * (q[1] * q[2] - q[3] * q[0])],
         [2 * (q[0] * q[2] - q[3] * q[1]), 2 * (q[1] * q[2] + q[3] * q[0]), 1.0 - 2 * (q[0] * q[0] + q[1] * q[1])]],
        dtype=q.dtype)
    return rot_matrix


r_matrix=quaternion_to_rotation_matrix(np.array([0.4829629,0.12940952,0.22414387,0.8365163]))
print(r_matrix)
/*
[[ 8.66025403e-01 -2.50000007e-01  4.33012693e-01]
 [ 4.99999996e-01  4.33012726e-01 -7.49999975e-01]
 [ 1.23449401e-09  8.66025378e-01  5.00000027e-01]]
*/

6.4、旋转矩阵转欧拉角

def rotation_matrix_to_euler(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])

print(rotation_matrix_to_euler(r_matrix))
//弧度
#[ 1.04719751e+00 -1.23449401e-09  5.23598772e-01]
print(np.degrees(rotation_matrix_to_euler(r_matrix)))
//角度
#[ 5.99999979e+01 -7.07312966e-08  2.99999998e+01]

7、小结

这里通过画图直观了解到两种坐标系的关系,以及飞机在飞行过程中产生的欧拉角的多种表示方法,由于欧拉角是三自由度,当两根轴重叠之后将发生“万向节死锁”的问题,所以我们一般都使用四元数来代替欧拉角,四个自由度避免了万向节发生死锁。

由于不同顺序的旋转将会产生不一样的旋转矩阵,这里我也通过三角函数的知识,将欧拉角分别沿着三个轴做旋转得到的旋转矩阵做了推导,希望可以帮助到大家更好地理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1196092.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux学习教程(第一章 简介)4

第一章 简介 十一、Linux的主要应用领域有哪些? Linux 似乎在我们平时的生活中很少看到,那么它应用在哪些领域呢?其实,在生活中随时随地都有 Linux 为我们服务着。 1、网站服务器 用事实说话!访问国际知名的 Netcraft 网站 http:// www.netcraft.com,在 "Whats …

NLP领域的突破催生大模型范式的形成与发展

当前的大模型领域的发展&#xff0c;只是范式转变的开始&#xff0c;基础大模型才刚刚开始改变人工智能系统在世界上的构建和部署方式。 1、大模型范式 1.1 传统思路&#xff08;2019年以前&#xff09; NLP领域历来专注于为具有挑战性的语言任务定义和设计系统&#xff0c…

OpenCV C++ 图像处理实战 ——《多二维码识别》

OpenCV C++ 图像处理实战 ——《多二维码识别》 一、结果演示二、zxing库配置2.1下载编译三、多二维码识别3.1 Method one3.1.1 源码3.2 Method two3.2.1 源码四、源码测试图像下载总结一、结果演示 </

王道数据结构课后代码题p150 15.设有一棵满二叉树(所有结点值均不同),已知其先序序列为 pre,设计一个算法求其后序序列post。(c语言代码实现)

对一般二叉树&#xff0c;仅根据先序或后序序列&#xff0c;不能确定另一个遍历序列。但对满二叉树&#xff0c;任意一个结点的左、右子树均含有相等的结点数&#xff0c;同时&#xff0c;先序序列的第一个结点作为后序序列的最后个结点。 本题代码如下 void pretopost(char …

目标检测最新创新点: EMS-YOLO:首个用于目标检测的直接训练脉冲神经网络

EMS-YOLO&#xff1a;第一个用于目标检测的深度直接训练脉冲神经网络&#xff0c;首次使用代理梯度训练深度 SNN 进行检测&#xff0c;并设计全脉冲残差块EMS-ResNet&#xff0c;代码刚刚开源&#xff01;单位&#xff1a;国科大, 西安交大, 清华, 北大, 华为 脉冲神经网络 (S…

【MybatisPlus】条件构造器、自定义SQL、Service接口

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 MybatisPlus 一、条件构造器1.1 基于QueryW…

使用 huggingface_hub 镜像下载 大模型

download.py &#x1f447; import os # 配置 hf镜像 os.environ[HF_ENDPOINT] https://hf-mirror.com# 设置保存的路径 local_dir "XXXXXX"# 设置仓库id model_id "sensenova/piccolo-large-zh"cmd f"huggingface-cli download --resume-downlo…

Android---MVP 中 presenter 声明周期的管理

我们经常在 Android MVP 架构中的 Presenter 层做一些耗时操作&#xff0c;比如请求网络数据&#xff0c;然后根据请求后的结果刷新 View。但是&#xff0c;如果按返回结束 Activity&#xff0c;而 Presenter 依然在执行耗时操作。那么就有可能造成内存泄漏&#xff0c;严重时甚…

Pytorch常用的函数(四)深度学习中常见的上采样方法总结

Pytorch常用的函数(四)深度学习中常见的上采样方法总结 我们知道在深度学习中下采样的方式比较常用的有两种&#xff1a; 池化 步长为2的卷积 而在上采样过程中常用的方式有三种&#xff1a; 插值 反池化 反卷积 不论是语义分割、目标检测还是三维重建等模型&#xff0…

使用迁移学习在线校准深度学习模型

使用迁移学习在线校准深度学习模型 本文参考的是2023年发表于Engineering Applications of Artificial Intelligence, EAAI的Deep Gaussian mixture adaptive network for robust soft sensor modeling with a closed-loop calibration mechanism 1. 动机 概念漂移导致历史训…

基于SSM的科技公司门户网站

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

幸运素数(找出给定区间的所有幸运素数)

从键盘输入一个区间&#xff0c;程序判定输出区间的所有幸运素数。 (笔记模板由python脚本于2023年11月11日 12:44:43创建&#xff0c;本篇笔记适合熟悉python整型数据类型和基本编程技巧的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.o…

如何将NetCore Web程序独立发布部署到Linux服务器

简介 在将 .NET Core 应用程序部署到 Linux 服务器上时,可以采用独立发布的方式,以便在目标服务器上运行应用程序而无需安装 .NET Core 运行时。本文介绍如果将NetCore Web程序独立发布部署到Linux服务器。 1、准备一台服务器 服务器配置:2核2G 系统环境:Alibaba Cloud…

解决win11更新后,文件夹打不开的bug

更新win11系统了&#xff0c;给我更了个bug&#xff0c;找了好多解决方案&#xff0c;发现下面这个可以解决问题。 第一步 找到注册表 第二步 备份注册表 为了防止意外情况&#xff0c;备份注册表。如有意外问题&#xff0c;可以导入导出的注册表进行恢复。 第三步 删除指定…

Android 解决CameraView叠加2个以上滤镜拍照黑屏的BUG (一)

1. 前言 这段时间&#xff0c;在使用 natario1/CameraView 来实现带滤镜的预览、拍照、录像功能。 由于CameraView封装的比较到位&#xff0c;在项目前期&#xff0c;的确为我们节省了不少时间。 但随着项目持续深入&#xff0c;对于CameraView的使用进入深水区&#xff0c;逐…

程序员千万不能去这些公司,听一下我这个学长的经验。

俗话说“条条大路通罗马”&#xff0c;但是对于程序员来说&#xff0c;有些路千万别走&#xff0c;走得越久越难以抽身&#xff0c;甚至说毁掉你的职业生涯。 今天来跟大家讲一下&#xff0c;作为程序员&#xff0c;有些公司千万不要进去&#xff0c;你以为稀松平常&#xff0…

华为防火墙vrrp+hrp双机热备负载分担(两端为交换机)

主要配置&#xff1a; FW1 hrp enable hrp interface GigabitEthernet1/0/2 remote 172.16.0.2 interface GigabitEthernet1/0/0 这里可以假想为接两条外线&#xff0c;一条外线对应一个vrrid undo shutdown ip address 1.1.1.2 255.255.255.0 vrrp vrid 3 virtual-ip 1.1.1…

基于SpringBoot的SSMP整合案例(实体类开发与数据层开发)

实体类开发 导入依赖 Lombok&#xff0c;一个Java类库&#xff0c;提供了一组注解&#xff0c;简化POJO实体类开发<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId> </dependency>lombok版本由SpringB…

LeetCode【215】数组中第k大的元素

题目&#xff1a; 思路&#xff1a; https://zhuanlan.zhihu.com/p/59110615 代码&#xff1a; public int findKthLargest(int[] nums, int k) {PriorityQueue<Integer> queue new PriorityQueue<>((o1, o2) -> o1 - o2);for (int i 0; i < nums.lengt…

刚学C语言太无趣 推荐一个好用易学的可视化框架:EasyX。VC6.0就能写

很多同学在大一刚学C语言时&#xff0c;是不是很好奇为什么别人编程都在做软件&#xff0c;而自己只能面对着黑窗口进行 printf &#xff1f; EasyX&#xff0c;C语言可视化编程。 分享我大一时候做的一个项目&#xff0c;用 VC6.0 开发的一款画图软件&#xff1a; 这个软件源…