오일러 각도(롤 각도, 피치 각도, 요 각도), 회전 행렬, 쿼터니언 변환 및 유니버설 조인트 교착 상태에 대한 솔루션

1. 개요

물체의 자세(위치와 방향)를 기술하는 방법은 일반적으로 두 개의 좌표계로 표현되는데, 하나는 세계좌표계와 지상좌표계인데 여기서는 기준좌표계에 속하는 지상좌표계라고 부른다. 다른 하나는 자체 좌표계로, 몇 가지 일반적인 용어를 설명하기 위해 항공기를 예로 사용하는 것이 더 적절하다고 생각됩니다. 여기서는 자체 변화에 따라 변경되는 신체 좌표계라고 합니다.
아래 그림과 같이:

2. 신체 좌표계

기체좌표계란 항공기 또는 항공기에 고정되어 오른손 법칙을 따르는 3차원 직교 직각좌표계를 말하며 , 그 원점은 항공기의 질량중심에 위치한다.
X' 축은 항상 기계의 기수를 가리키고, Y' 축은 X' 축이 위치한 대칭 평면에 수직인 동체의 오른쪽을 가리키며, Z' 축은 수평 평면에 수직입니다. X'축이 위치합니다. 즉, 좌표는 항공기를 기준으로 고정되어 있으며, 위의 지상좌표계는 전체 기준좌표로서 고정된 상태로 유지된다.

3. 오일러 각도

오일러각(자세각):
기체 좌표계와 지상 좌표계의 관계는 3개의 각도로, 지면에 대한 항공기의 자세를 반영합니다.

롤 각도 Φ(롤) : X축을 기준으로 회전합니다. 롤 각도는 차량의 가로축과 수평선 사이의 각도를 나타냅니다. 롤각(roll angle)이라고도 하며, 세로축을 중심으로 캐리어가 회전하는 것을 나타내며, 세로축을 중심으로 시계방향 회전은 양의 값, 그렇지 않으면 음의 값으로 비행기가 굴러가는 모습을 상상해 볼 수 있다.

피치 각도 θ(피치) : Y축을 기준으로 회전합니다. 신체좌표계의 x축과 수평면이 이루는 각도로, 피치각은 수평면에서 양의 값을 가지며, 그렇지 않으면 음의 값을 가지며, 항공기가 위를 바라보고 아래로 다이빙하는 모습을 상상하면 된다.

요 각도 ψ(요) : Z축을 중심으로 한 회전입니다. 세로축의 회전 각도에 대해 요 각도를 변경하면 항공기의 비행 방향이 변경될 수 있습니다. 항공기의 기수가 오른쪽을 향하고 있으며 이는 자동차를 운전하여 왼쪽과 오른쪽으로 회전하는 것과 같습니다.

4. 오일러 각도 변환 회전 행렬

물론 오일러 각도의 회전 순서도 매우 관련이 있습니다. 모두 한 좌표계에서 다른 좌표계로의 변경을 설명합니다. 즉, 다른 좌표계에 대한 한 좌표계의 자세는 회전 행렬을 사용하여 결정할 수 있습니다. . 표현하다. 회전 행렬을 살펴보고 다음과 같이 유도해 보겠습니다. 

5. 쿼터니언

오일러 매개변수라고도 알려진 쿼터니언은 3차원 회전을 표현하는 또 다른 방법을 제공합니다. 쿼터니언 방법은 대부분의 계산에 사용될 때 더 빠르며 유니버설 조인트 교착 상태(즉, 회전 각도가 특정 특정 값에 접근하면 오일러 각도 표현으로 인해 무한 루프가 발생함)와 같은 일부 기술적 문제를 피할 수 있습니다. 즉, 두 축이 일치하면 자유도가 하나 없어지고 다시 회전하는 것이 의미가 없는 현상) 이러한 이유로 많은 고속 3차원 그래픽 프로그램에서는 쿼터니언을 사용합니다. 물론 쿼터니언은 오일러 각도만큼 직관적이지 않고 이해하기 더 어려운데, 이것이 단점이기도 합니다.
오일러 각도와 쿼터니언은 모두 회전과 방향을 설명하는 방법이지만 회전을 나타내는 방식과 수학적 구조가 다릅니다.
짐벌 교착 상태의 경우 보다 직관적인 이해를 위해 비디오를 볼 수 있습니다. 오일러 회전 짐벌 교착 상태 쿼터니언
에는 4개의 자유도가 있으며 오일러 각도보다 1도 더 많은 자유도가 있습니다.
Q=a+bi+ cj+dk , 여기서 a, b, c, d는 실수, i, j, k는 허수, i²=j²=k²=-1

6. 파이썬 예제

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      ]]
*/

Transformers3d 또는 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. 요약

여기서는 두 좌표계의 관계를 도면을 통해 직관적으로 이해하고, 항공기 비행 중 발생하는 오일러각의 다양한 표현방법을 이해하게 된다. "유니버설"이 발생합니다. 조인트 교착 상태" 문제이므로 일반적으로 오일러 각도를 대체하기 위해 쿼터니언을 사용합니다. 4개의 자유도는 유니버셜 조인트에서 교착 상태를 방지합니다.

서로 다른 회전 순서는 서로 다른 회전 행렬을 생성하므로 여기에서는 삼각 함수에 대한 지식을 사용하여 오일러 각도를 세 축을 따라 각각 회전하여 얻은 회전 행렬을 유도합니다. 이것이 모두가 더 잘 이해하는 데 도움이 되기를 바랍니다.

Guess you like

Origin blog.csdn.net/weixin_41896770/article/details/134346795