欧拉角,四元数和旋转矩阵互转代码【python版】

这篇具有很好参考价值的文章主要介绍了欧拉角,四元数和旋转矩阵互转代码【python版】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写在前面

  • 欧拉角以Roll、Pitch、Yaw的顺序表示
  • 四元数以[ q w q_w qw, q x q_x qx, q y q_y qy, q z q_z qz]的顺序表示
  • 代码包括了欧拉角与四元数互转旋转矩阵与四元数互转欧拉角与旋转矩阵互转,输入参数均为np.array形式
  • 代码内置了角度制和弧度制😃😃当时因为这块吃了好多亏
  • 顺便测试了一下pydrake库,发现:
    1. pydrake库中是弧度制
    2. 输出结果与代码输出结果几乎一致(但pydrake精度更高)
  • 由于原理这块肯定已经有很多很完善的资料了所以不做过多赘述

思路

东拼西凑找出的这些公式,为了验证他们的正确性,采用以下方法验证:
随机生成一个欧拉角e,将其与
a. 欧拉角e -> 旋转矩阵r -> 欧拉角e
b. 欧拉角e -> 四元数q -> 欧拉角e
c. 欧拉角e -> 四元数q -> 旋转矩阵r -> 欧拉角e
d. 欧拉角e -> 旋转矩阵r -> 四元数q -> 欧拉角e
比较,看误差有多大(如图所示),并重复n轮
欧拉角,四元数和旋转矩阵互转代码【python版】
直接上代码!

注意⚠️

涉及到旋转矩阵的四个函数似乎有点问题【虽然自洽但是结果不对!】
如果最后导出的是旋转矩阵,请暂时不要使用本代码!!!
红豆泥私密马赛!


代码部分

utils.py

import math
import numpy as np 

# from pydrake.all import RotationMatrix, RollPitchYaw
 
# 四元数转欧拉角
# ================OKOK
def quaternion_to_euler(q, degree_mode=1):
    qw, qx, qy, qz = q

    roll = math.atan2(2 * (qw * qx + qy * qz), 1 - 2 * (qx ** 2 + qy ** 2))
    pitch = math.asin(2 * (qw * qy - qz * qx))
    yaw = math.atan2(2 * (qw * qz + qx * qy), 1 - 2 * (qy ** 2 + qz ** 2))
    # degree_mode=1:【输出】是角度制,否则弧度制
    if degree_mode == 1:
        roll = np.rad2deg(roll)
        pitch = np.rad2deg(pitch)
        yaw = np.rad2deg(yaw)
    euler = np.array([roll, pitch, yaw])
    return euler
 
# 欧拉角转四元数
# ================OKOK
def euler_to_quaternion(euler, degree_mode=1):
    roll, pitch, yaw = euler
    # degree_mode=1:【输入】是角度制,否则弧度制
    if degree_mode == 1:
        roll = np.deg2rad(roll)
        pitch = np.deg2rad(pitch)
        yaw = np.deg2rad(yaw)

    qx = np.sin(roll/2) * np.cos(pitch/2) * np.cos(yaw/2) - np.cos(roll/2) * np.sin(pitch/2) * np.sin(yaw/2)
    qy = np.cos(roll/2) * np.sin(pitch/2) * np.cos(yaw/2) + np.sin(roll/2) * np.cos(pitch/2) * np.sin(yaw/2)
    qz = np.cos(roll/2) * np.cos(pitch/2) * np.sin(yaw/2) - np.sin(roll/2) * np.sin(pitch/2) * np.cos(yaw/2)
    qw = np.cos(roll/2) * np.cos(pitch/2) * np.cos(yaw/2) + np.sin(roll/2) * np.sin(pitch/2) * np.sin(yaw/2)
    q = np.array([qw, qx, qy, qz])
    return q

# 四元数转旋转矩阵:
def quaternion_to_rot(q): 
    q0,q1,q2,q3=q 

    R=np.array([[1-2*(q2**2+q3**2),2*(q1*q2-q3*q0),2*(q1*q3+q2*q0)], 
                     [2*(q1*q2+q3*q0),1-2*(q1**2+q3**2),2*(q2*q3-q1*q0)], 
                     [2*(q1*q3-q2*q0),2*(q2*q3+q1*q0),1-2*(q1**2+q2**2)]]) 
    return R 
 
# 旋转矩阵转四元数:
# ================OKOK
def rot_to_quaternion(R): 
    R=R 
    
    qw=np.sqrt(1+R[0,0]+R[1,1]+R[2,2])/2 
    qx=(R[2,1]-R[1,2])/(4*qw) 
    qy=(R[0,2]-R[2,0])/(4*qw) 
    qz=(R[1,0]-R[0,1])/(4*qw) 
    q = np.array([qw, qx, qy, qz])
    return q

# 旋转矩阵转欧拉角
# ================OKOK
def rot_to_euler(R, degree_mode=1):
    sy = np.sqrt(R[0,0] * R[0,0] +  R[1,0] * R[1,0])
 
    singular = sy < 1e-6
 
    if not singular :
        roll = np.arctan2(R[2,1] , R[2,2])
        pitch = np.arctan2(-R[2,0], sy)
        yaw = np.arctan2(R[1,0], R[0,0])
    else :
        roll = np.arctan2(-R[1,2], R[1,1])
        pitch = np.arctan2(-R[2,0], sy)
        yaw = 0
    
    # degree_mode=1:【输出】是角度制,否则弧度制
    if degree_mode == 1:
        roll = np.rad2deg(roll)
        pitch = np.rad2deg(pitch)
        yaw = np.rad2deg(yaw)

    euler = np.array([roll, pitch, yaw])
    return euler

# 欧拉角转旋转矩阵
# # ================OKOK
def euler_to_rot(euler, degree_mode=1):
    roll, pitch, yaw = euler
    # degree_mode=1:【输入】是角度制,否则弧度制
    if degree_mode == 1:
        roll = np.deg2rad(roll)
        pitch = np.deg2rad(pitch)
        yaw = np.deg2rad(yaw)

    R_x = np.array([
    [1,     0,              0              ],
    [0,     math.cos(roll), -math.sin(roll)],
    [0,     math.sin(roll), math.cos(roll) ]
    ])
 
    R_y = np.array([
    [math.cos(pitch),  0,   math.sin(pitch) ],
    [0,                1,   0               ],
    [-math.sin(pitch), 0,   math.cos(pitch) ]
    ])
 
    R_z = np.array([
    [math.cos(yaw), -math.sin(yaw),  0],
    [math.sin(yaw), math.cos(yaw),   0],
    [0,             0,               1]
    ])
    
    R = np.dot(R_z, np.dot( R_y, R_x ))
    return R


if __name__ == "__main__":
    # 测试思路:随机生成几组欧拉角,用各种转换后看是否与原数据相同
    # 备注:np.sin(),math.sin()的返回值都是弧度制
    # np.atan2(), math.asin()这些也是弧度制
    print(np.sin(90), np.sin(45))
    print(np.sin(3.14), np.sin(1.57))
    print(math.sin(90), math.sin(45))
    print(math.sin(3.14), math.sin(1.57))
    mode = 0  # 当这个值等于1时, 输入和输出的欧拉角均为 <角度制>
    for i in range(10):
        print('=' * 32, "index:", i, '=' * 35)
        euler = np.random.randint(0, 360, 3) - 180
        # euler = np.array([60, 30, 45])

        if mode != 1:
            # 限制最多小数点后三位
            euler = np.array([round(t * math.pi / 180, 3) for t in euler])

        print("euler = ", euler)
        e2q2e = quaternion_to_euler(euler_to_quaternion(euler, mode), mode)
        e2r2e = rot_to_euler(euler_to_rot(euler, mode), mode)
        e2r2q2e = quaternion_to_euler(rot_to_quaternion(euler_to_rot(euler, mode)), mode)
        e2q2r2e = rot_to_euler(quaternion_to_rot(euler_to_quaternion(euler, mode)), mode)
        
        # 限制这些值为[-180,179)
        if mode == 1:
            e2q2e = [(int((180 * 3 + t)) % 360) - 180 for t in e2q2e]
            e2r2e = [(int((180 * 3 + t)) % 360) - 180 for t in e2r2e]
            e2r2q2e = [(int((180 * 3 + t)) % 360) - 180 for t in e2r2q2e]
            e2q2r2e = [(int((180 * 3 + t)) % 360) - 180 for t in e2q2r2e]
        else:  # 限制最多小数点后三位
            e2q2e = [round((int((math.pi * 3 * 1000 + t * 1000)) % 6283 - 3142) / 1000, 3)\
                 for t in e2q2e]    
            e2r2e = [round((int((math.pi * 3 * 1000 + t * 1000)) % 6283 - 3142) / 1000, 3)\
                 for t in e2r2e]   
            e2r2q2e = [round((int((math.pi * 3 * 1000 + t * 1000)) % 6283 - 3142) / 1000, 3)\
                 for t in e2r2q2e]   
            e2q2r2e = [round((int((math.pi * 3 * 1000 + t * 1000)) % 6283 - 3142) / 1000, 3)\
                 for t in e2q2r2e]     

        print("e -> q -> e = ", e2q2e, "norm of delta = ", np.linalg.norm(e2q2e - euler))
        print("e -> r -> e = ", e2r2e, "norm of delta = ", np.linalg.norm(e2r2e - euler))
        print("e -> r -> q -> e = ", e2r2q2e, "norm of delta = ", np.linalg.norm(e2r2q2e - euler))
        print("e -> q -> r -> e = ", e2q2r2e, "norm of delta = ", np.linalg.norm(e2q2r2e - euler))

        # if mode == 0:   
        #     # pydrake中的旋转角是弧度制
        #     print("drake actual rot = ", RotationMatrix(RollPitchYaw(euler[0],euler[1],euler[2])))
        #     print("rot =", euler_to_rot(euler, mode))
        #     print("e -> q -> rot =", quaternion_to_rot(euler_to_quaternion(euler, mode)))

那串看起来非常笨重的限制我感觉我玷污了这个语言的美、、

一个问题

  • 使用随机数,会发现部分随机的欧拉角会变成另一个角,这两个角的效果应该是等效的
    欧拉角,四元数和旋转矩阵互转代码【python版】
    (使用弧度制也是一样)

  • 不过个人感觉在实际应用中应该也不会出现这种"错误的角度",因为角度都是通过各种正确值之间的转换得来的

补充

这里感谢下这个博主——欧拉角,四元数和旋转矩阵互转代码【python版】
下面这几个网站都是从他的这篇文章转过来的👇

工具网站推荐 - 欧拉角四元数在线可视化转化网站/三维在线旋转变换网站

1 欧拉角四元数在线可视化转换网站

内容:四元数与欧拉角的可视化
特点:直观,明显
缺点:没有旋转矩阵
网站地址:https://quaternions.online/
欧拉角,四元数和旋转矩阵互转代码【python版】

2 三维在线旋转变换网站

内容:四元数与欧拉角与旋转矩阵的转换
特点:全面,丰富,可以调欧拉角形式
缺点:有一些并不常用的参数,容易搞混懵圈
网站地址:https://www.andre-gaschler.com/rotationconverter/
欧拉角,四元数和旋转矩阵互转代码【python版】文章来源地址https://www.toymoban.com/news/detail-421055.html

补充一点关于上面的问题

  • 输入这个"错误欧拉角"在两个网站里也会得到一个不同的欧拉角,见上图和下图,所以应该不影响,也就是说正常使用时不会出现这种"错误欧拉角"
    欧拉角,四元数和旋转矩阵互转代码【python版】

到了这里,关于欧拉角,四元数和旋转矩阵互转代码【python版】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 欧拉角,轴角,四元数与旋转矩阵详解

    入门小菜鸟,希望像做笔记记录自己学的东西,也希望能帮助到同样入门的人,更希望大佬们帮忙纠错啦~侵权立删。 目录 一、欧拉角 1、静态定义 2、欧拉角的表示  3、欧拉角表示的优缺点  4、欧拉角的万向节死锁(静态不存在万向锁的问题) 二、四元数 1、提出意义和定

    2024年01月17日
    浏览(47)
  • 【数理知识】三维空间旋转矩阵的欧拉角表示法,四元数表示法,两者之间的转换,Matlab 代码实现

    序号 内容 1 【数理知识】自由度 degree of freedom 及自由度的计算方法 2 【数理知识】刚体 rigid body 及刚体的运动 3 【数理知识】刚体基本运动,平动,转动 4 【数理知识】向量数乘,内积,外积,matlab代码实现 5 【数理知识】最小二乘法,从线性回归出发,数值举例并用最小

    2024年02月12日
    浏览(51)
  • 【Eigen库使用】角轴、旋转矩阵、欧拉角、四元数转换

    在slam中经常用到的四种描述机器人orientation的变量,他们之间可以相互转化,使用Eigen库可以很容易的做到这一点, 需要特别关注的是:欧拉角与其余量之间的转换关系 : 1)首先要明确的是, 必须要明确欧拉角的旋转次序 ,你可以选择RPY、YPR等方式,在相同的orientation下,

    2024年01月18日
    浏览(51)
  • 《动手学机器人学》7.2.4姿态之间的互相转换,Python&&C++支持四元数,欧拉角旋转矩阵、轴角

    本系列教程作者:小鱼 公众号:鱼香ROS QQ交流群:139707339 教学视频地址:小鱼的B站 完整文档地址:鱼香ROS官网 版权声明:如非允许禁止转载与商业用途。 上一节小鱼带你一起学习了四种姿态表示方式,这节课我们就利用相关的开源库,来完成姿态的不同表示方式之间的转

    2024年02月02日
    浏览(48)
  • 持之以恒(一)位姿转换:姿态 / 四元数 / 旋转矩阵 / 欧拉角 及 位姿矩阵

    姿态的几种表示形式, 姿态角 、 四元数 、 欧拉角 、 旋转矩阵 、 位姿矩阵 。 姿态 说明 表示形式 Eigen 姿态角 指的是机体坐标系与地理坐标系的夹角,即旋转向量 rx,ry,rz Eigen::Vector3f(Degrees) 四元数 四元素不存在万向节死锁问题、利用球面插值可以获得均匀的转速 w,x,y,z

    2024年02月15日
    浏览(54)
  • ROS系列——使用python的transforms3d、numpy库实现四元数、旋转矩阵、欧拉角、轴角等的相互转换

    pip3 install transforms3d 四元数模块在transforms3d.quaternions里,直接导入即可使用 2.1.1四元数转旋转矩阵 2.1.2 旋转矩阵转四元数 2.2.1 四元数转轴角 2.2.2 轴角转四元数 四元数模块在transforms3d.euler里,直接导入即可使用 3.1.1 固定轴欧拉角转四元数 3.1.2 四元数转固定轴欧拉角 3.2.1 固定

    2024年02月07日
    浏览(93)
  • ABB机器人欧拉角与四元数的相互转化以及旋转矩阵的求法

    做项目时用到ABB机器人,直接通过ABB内置的函数可以轻松实现四元数读数与欧拉角的相互转化。但实际项目需要从示教器读出相关位置并自行计算,尤其需要计算旋转矩阵。 本文以 ABB IRB120机器人 (不确定其他机器人是否与ABB机器人一致)为例如下姿态为例来描述上述几个量

    2024年02月03日
    浏览(57)
  • 车辆姿态表达:旋转矩阵、欧拉角、四元数的转换以及eigen、matlab、pathon方法实现

    旋转矩阵、欧拉角、四元数主要用于表示坐标系中的旋转关系,通过三者之间的转换可以减小一些算法的复杂度。 本文主要概述旋转矩阵、欧拉角、四元数的基本理论、三者之间的转换关系以及三者转换在eigen、matlab和pathon上的方法实现。 对于两个三维点 p1 、 p2 : p 1 ( x

    2023年04月11日
    浏览(47)
  • 坐标系变换推导(欧拉角、方向余弦矩阵、四元数)+代码解析

    描述两个坐标系之间的变换关系主要有几个方法 1、欧拉角法(存在奇异性和万向锁而且三个轴旋转的顺序不好定) 2、方向余弦矩阵法(翻译为Directional cosine matrix,简称DCM,也称为旋转矩阵,看了很多博客写的是C11-C33的那个矩阵,没明白为什么也称之为一个方法,有知道的指导

    2024年02月08日
    浏览(95)
  • Unity旋转 欧拉角和四元数

    Unity中的旋转最为常知的是Transform.rotation,但其内部实现是由 Quaternion (四元数)进行计算处理,而Inspactor中显示的旋转值是由 EulerAngles (欧拉角)处理。 Unity使用四元数对实际的旋转值进行计算和存储,使用欧拉角对基于世界空间坐标的旋转进行描述和显示,而Inspacetor中显示

    2024年02月13日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包