回転行列は、座標系やベクトルの回転を記述する直交行列です。ロボット工学、航空宇宙、コンピュータグラフィックスなど、3次元空間を扱うあらゆる分野の基盤となる数学的道具です。
本記事では、2次元の回転行列から出発して3次元の回転行列を導出し、オイラー角による表現、回転行列の性質、Pythonでの座標変換の実装までを解説します。
本記事の内容
- 2次元の回転行列の導出
- 3次元の基本回転行列(各軸まわり)
- 回転行列の性質(直交行列、行列式=1)
- オイラー角(3-1-3系列、3-2-1系列)
- ジンバルロック
- Pythonでの座標変換の実装と可視化
前提知識
この記事を読む前に、以下の記事を読んでおくと理解が深まります。
2次元の回転行列
導出
$xy$ 平面上で、点 $P = (x, y)$ を原点を中心に角度 $\theta$ だけ反時計回りに回転させた点 $P’ = (x’, y’)$ を求めます。
点 $P$ を極座標で表すと
$$ x = r\cos\phi, \quad y = r\sin\phi $$
角度 $\theta$ だけ回転させると
$$ x’ = r\cos(\phi + \theta), \quad y’ = r\sin(\phi + \theta) $$
加法定理を適用します。
$$ x’ = r(\cos\phi \cos\theta – \sin\phi \sin\theta) = x\cos\theta – y\sin\theta $$
$$ y’ = r(\sin\phi \cos\theta + \cos\phi \sin\theta) = x\sin\theta + y\cos\theta $$
行列で表すと
$$ \boxed{\begin{pmatrix} x’ \\ y’ \end{pmatrix} = \begin{pmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{pmatrix} \begin{pmatrix} x \\ y \end{pmatrix}} $$
この行列
$$ R(\theta) = \begin{pmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{pmatrix} $$
が2次元の回転行列です。
検証
$\theta = 90°$ のとき
$$ R(90°) = \begin{pmatrix} 0 & -1 \\ 1 & 0 \end{pmatrix} $$
$(1, 0) \to (0, 1)$、$(0, 1) \to (-1, 0)$ となり、確かに反時計回り $90°$ の回転です。
回転行列の性質
直交行列
回転行列は直交行列(orthogonal matrix)です。
$$ \boxed{R^T R = R R^T = I} $$
これは回転が長さと角度を保存する変換であることに対応します。
証明: $R(\theta)$ について直接計算します。
$$ R^T R = \begin{pmatrix} \cos\theta & \sin\theta \\ -\sin\theta & \cos\theta \end{pmatrix} \begin{pmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{pmatrix} $$
$$ = \begin{pmatrix} \cos^2\theta + \sin^2\theta & -\cos\theta\sin\theta + \sin\theta\cos\theta \\ -\sin\theta\cos\theta + \cos\theta\sin\theta & \sin^2\theta + \cos^2\theta \end{pmatrix} = \begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix} $$
したがって $R^{-1} = R^T$ です。逆回転は転置で計算できます。
行列式が1
$$ \boxed{\det(R) = +1} $$
証明:
$$ \det R(\theta) = \cos\theta \cdot \cos\theta – (-\sin\theta) \cdot \sin\theta = \cos^2\theta + \sin^2\theta = 1 $$
$\det = +1$ の直交行列を特殊直交行列(proper orthogonal matrix)と呼び、集合 $SO(n)$ を構成します。$\det = -1$ の場合は回転ではなく鏡映を含む変換です。
回転の合成
2つの回転 $R(\alpha)$ と $R(\beta)$ の合成は行列の積です。
$$ R(\alpha) R(\beta) = R(\alpha + \beta) $$
2次元では回転は可換です: $R(\alpha) R(\beta) = R(\beta) R(\alpha)$。しかし3次元では一般に非可換です。
3次元の基本回転行列
各軸まわりの回転
3次元では、$x$ 軸、$y$ 軸、$z$ 軸のそれぞれまわりの回転を基本回転として定義します。
$x$ 軸まわりの回転 $R_x(\theta)$(軸1まわり):
$x$ 軸は固定され、$y$-$z$ 平面で回転が起こります。
$$ \boxed{R_x(\theta) = \begin{pmatrix} 1 & 0 & 0 \\ 0 & \cos\theta & -\sin\theta \\ 0 & \sin\theta & \cos\theta \end{pmatrix}} $$
$y$ 軸まわりの回転 $R_y(\theta)$(軸2まわり):
$y$ 軸は固定され、$z$-$x$ 平面で回転が起こります。
$$ \boxed{R_y(\theta) = \begin{pmatrix} \cos\theta & 0 & \sin\theta \\ 0 & 1 & 0 \\ -\sin\theta & 0 & \cos\theta \end{pmatrix}} $$
$R_y$ の符号が他と異なる($\sin\theta$ の位置が反転)のは、$x \to y \to z$ の巡回順序に由来します。右手系で $z$ 軸から $x$ 軸への回転を考えると自然に導出されます。
$z$ 軸まわりの回転 $R_z(\theta)$(軸3まわり):
$z$ 軸は固定され、$x$-$y$ 平面で回転が起こります。
$$ \boxed{R_z(\theta) = \begin{pmatrix} \cos\theta & -\sin\theta & 0 \\ \sin\theta & \cos\theta & 0 \\ 0 & 0 & 1 \end{pmatrix}} $$
導出($R_z$ の場合)
$z$ 軸まわりの回転では $z$ 成分は変化せず、$x$-$y$ 平面での2次元回転と同じです。
$$ \begin{pmatrix} x’ \\ y’ \\ z’ \end{pmatrix} = \begin{pmatrix} \cos\theta & -\sin\theta & 0 \\ \sin\theta & \cos\theta & 0 \\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} x \\ y \\ z \end{pmatrix} $$
$R_x$, $R_y$ も同様に、回転しない軸の成分を固定し、残りの2次元回転を埋め込むことで得られます。
基本回転行列の性質の確認
各基本回転行列について
$$ R_i^T R_i = I, \quad \det(R_i) = 1 \quad (i = x, y, z) $$
が成り立つことは直接計算で確認できます。
オイラー角
3次元回転の表現
任意の3次元回転は、3つの基本回転の積で表すことができます(オイラーの回転定理)。3つの回転角の組をオイラー角と呼びます。
軸の選び方により12通りの系列が存在します。隣り合う回転軸が異なる必要があります。
- 固有オイラー角(Euler angles): 同じ軸が最初と最後に使われる(例: 3-1-3, 3-2-3, 1-3-1 など 6通り)
- テイト-ブライアン角(Tait-Bryan angles): すべて異なる軸(例: 3-2-1, 1-2-3 など 6通り)
3-1-3系列(古典的オイラー角)
天体力学や回転体の力学でよく使われる系列です。
角度 $(\alpha, \beta, \gamma)$ に対して、まず $z$ 軸まわりに $\alpha$、次に $x$ 軸まわりに $\beta$、再び $z$ 軸まわりに $\gamma$ 回転します。
$$ R_{313}(\alpha, \beta, \gamma) = R_z(\gamma) \, R_x(\beta) \, R_z(\alpha) $$
行列を展開すると
$$ R_{313} = \begin{pmatrix} c_\alpha c_\gamma – s_\alpha c_\beta s_\gamma & -c_\alpha s_\gamma – s_\alpha c_\beta c_\gamma & s_\alpha s_\beta \\ s_\alpha c_\gamma + c_\alpha c_\beta s_\gamma & -s_\alpha s_\gamma + c_\alpha c_\beta c_\gamma & -c_\alpha s_\beta \\ s_\beta s_\gamma & s_\beta c_\gamma & c_\beta \end{pmatrix} $$
ここで $c_\alpha = \cos\alpha$, $s_\alpha = \sin\alpha$ 等の略記を用いました。
3-2-1系列(航空宇宙のヨー・ピッチ・ロール)
航空機や衛星の姿勢表現で最もよく使われる系列です。
- $\psi$(ヨー, yaw): $z$ 軸まわり
- $\theta$(ピッチ, pitch): $y$ 軸まわり
- $\phi$(ロール, roll): $x$ 軸まわり
$$ R_{321}(\psi, \theta, \phi) = R_x(\phi) \, R_y(\theta) \, R_z(\psi) $$
行列を展開すると
$$ R_{321} = \begin{pmatrix} c_\theta c_\psi & c_\theta s_\psi & -s_\theta \\ s_\phi s_\theta c_\psi – c_\phi s_\psi & s_\phi s_\theta s_\psi + c_\phi c_\psi & s_\phi c_\theta \\ c_\phi s_\theta c_\psi + s_\phi s_\psi & c_\phi s_\theta s_\psi – s_\phi c_\psi & c_\phi c_\theta \end{pmatrix} $$
オイラー角の逆問題
回転行列 $R$ からオイラー角を求めることを逆問題と呼びます。
3-2-1系列の場合、$R$ の要素から
$$ \theta = -\arcsin(R_{13}) $$
$$ \phi = \text{atan2}(R_{23}, R_{33}) $$
$$ \psi = \text{atan2}(R_{12}, R_{11}) $$
ただし $\cos\theta \neq 0$ の場合に限ります。
ジンバルロック
現象
3-2-1系列で $\theta = \pm 90°$(ピッチが $\pm 90°$)のとき、$R_{11} = R_{12} = R_{23} = R_{33} = 0$ となり、$\psi$ と $\phi$ が独立に決められなくなります。
$\theta = 90°$ のとき
$$ R = \begin{pmatrix} 0 & 0 & -1 \\ \sin(\phi – \psi) & \cos(\phi – \psi) & 0 \\ \cos(\phi – \psi) & -\sin(\phi – \psi) & 0 \end{pmatrix} $$
$\phi – \psi$ の値は決まりますが、$\phi$ と $\psi$ の個別の値は不定です。
これは物理的には、ヨー軸とロール軸が一致してしまい、実質的に2自由度しか表現できなくなる現象です。
対処法
- 四元数(クォータニオン): ジンバルロックが生じない。計算効率も良い
- 回転ベクトル(ロドリゲスの回転公式): 軸と角度で回転を表現
Pythonでの実装
回転行列の計算と可視化
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# --- 基本回転行列 ---
def Rx(theta):
"""x軸まわりの回転行列"""
c, s = np.cos(theta), np.sin(theta)
return np.array([
[1, 0, 0],
[0, c, -s],
[0, s, c]
])
def Ry(theta):
"""y軸まわりの回転行列"""
c, s = np.cos(theta), np.sin(theta)
return np.array([
[ c, 0, s],
[ 0, 1, 0],
[-s, 0, c]
])
def Rz(theta):
"""z軸まわりの回転行列"""
c, s = np.cos(theta), np.sin(theta)
return np.array([
[c, -s, 0],
[s, c, 0],
[0, 0, 1]
])
# --- オイラー角 ---
def euler_313(alpha, beta, gamma):
"""3-1-3系列のオイラー角から回転行列を生成"""
return Rz(gamma) @ Rx(beta) @ Rz(alpha)
def euler_321(psi, theta, phi):
"""3-2-1系列(ヨー・ピッチ・ロール)から回転行列を生成"""
return Rx(phi) @ Ry(theta) @ Rz(psi)
def rotation_to_euler_321(R):
"""回転行列から3-2-1オイラー角を抽出"""
theta = -np.arcsin(np.clip(R[0, 2], -1, 1))
if np.abs(np.cos(theta)) > 1e-10:
phi = np.arctan2(R[1, 2], R[2, 2])
psi = np.arctan2(R[0, 1], R[0, 0])
else:
phi = np.arctan2(-R[2, 1], R[1, 1])
psi = 0
return psi, theta, phi
# --- 性質の検証 ---
print("=== 回転行列の性質の検証 ===")
theta_test = np.radians(30)
R_test = Rz(theta_test)
print(f"\nR_z({np.degrees(theta_test):.0f}°) =")
print(np.round(R_test, 4))
print(f"\nR^T R =")
print(np.round(R_test.T @ R_test, 10))
print(f"\ndet(R) = {np.linalg.det(R_test):.10f}")
# 合成のテスト
R1 = euler_321(np.radians(30), np.radians(20), np.radians(10))
print(f"\n3-2-1 Euler (ψ=30°, θ=20°, φ=10°):")
print(f"det(R) = {np.linalg.det(R1):.10f}")
print(f"R^T R ≈ I: {np.allclose(R1.T @ R1, np.eye(3))}")
# 逆問題
psi_r, theta_r, phi_r = rotation_to_euler_321(R1)
print(f"逆問題: ψ={np.degrees(psi_r):.1f}°, θ={np.degrees(theta_r):.1f}°, φ={np.degrees(phi_r):.1f}°")
# --- 可視化 ---
fig = plt.figure(figsize=(16, 12))
# (1) 2次元回転の可視化
ax1 = fig.add_subplot(2, 2, 1)
# 元のベクトル
v = np.array([1, 0.5])
angles = [0, 30, 60, 90, 120, 150]
colors = plt.cm.viridis(np.linspace(0, 1, len(angles)))
for angle, color in zip(angles, colors):
rad = np.radians(angle)
R2d = np.array([[np.cos(rad), -np.sin(rad)],
[np.sin(rad), np.cos(rad)]])
v_rot = R2d @ v
ax1.arrow(0, 0, v_rot[0], v_rot[1], head_width=0.05, head_length=0.03,
fc=color, ec=color, linewidth=1.5)
ax1.annotate(f'{angle}°', xy=(v_rot[0]*1.1, v_rot[1]*1.1), fontsize=8, color=color)
circle = plt.Circle((0, 0), np.linalg.norm(v), fill=False, linestyle='--', alpha=0.3)
ax1.add_patch(circle)
ax1.set_xlim(-1.5, 1.5)
ax1.set_ylim(-1.5, 1.5)
ax1.set_aspect('equal')
ax1.set_xlabel('x', fontsize=11)
ax1.set_ylabel('y', fontsize=11)
ax1.set_title('2D Rotation', fontsize=13)
ax1.grid(True, alpha=0.3)
ax1.axhline(y=0, color='k', linewidth=0.5)
ax1.axvline(x=0, color='k', linewidth=0.5)
# (2) 3次元での各軸回転
ax2 = fig.add_subplot(2, 2, 2, projection='3d')
# 座標軸
axis_len = 1.5
ax2.quiver(0, 0, 0, axis_len, 0, 0, color='red', arrow_length_ratio=0.1, linewidth=1)
ax2.quiver(0, 0, 0, 0, axis_len, 0, color='green', arrow_length_ratio=0.1, linewidth=1)
ax2.quiver(0, 0, 0, 0, 0, axis_len, color='blue', arrow_length_ratio=0.1, linewidth=1)
ax2.text(axis_len*1.1, 0, 0, 'x', fontsize=12, color='red')
ax2.text(0, axis_len*1.1, 0, 'y', fontsize=12, color='green')
ax2.text(0, 0, axis_len*1.1, 'z', fontsize=12, color='blue')
# 元のベクトル
v3d = np.array([1, 0, 0])
# 各軸回転
angle = np.radians(45)
rotations = {
'Rx(45°)': Rx(angle),
'Ry(45°)': Ry(angle),
'Rz(45°)': Rz(angle),
}
rot_colors = ['red', 'green', 'blue']
for (name, R), color in zip(rotations.items(), rot_colors):
v_rot = R @ v3d
ax2.quiver(0, 0, 0, v_rot[0], v_rot[1], v_rot[2],
color=color, arrow_length_ratio=0.1, linewidth=2, alpha=0.7)
ax2.text(v_rot[0]*1.1, v_rot[1]*1.1, v_rot[2]*1.1, name, fontsize=9, color=color)
# 元のベクトル
ax2.quiver(0, 0, 0, v3d[0], v3d[1], v3d[2],
color='black', arrow_length_ratio=0.1, linewidth=2)
ax2.text(v3d[0]*1.1, v3d[1]*1.1, v3d[2]*1.1, 'Original', fontsize=9)
ax2.set_xlabel('x')
ax2.set_ylabel('y')
ax2.set_zlabel('z')
ax2.set_title('3D Basic Rotations (45°)', fontsize=13)
# (3) 3-2-1オイラー角の効果
ax3 = fig.add_subplot(2, 2, 3, projection='3d')
# 航空機の座標軸を描画
def draw_axes(ax, R, origin=(0,0,0), length=1.0, label_prefix='', alpha=1.0):
"""回転された座標軸を描画"""
colors = ['red', 'green', 'blue']
labels = ['x', 'y', 'z']
for i in range(3):
direction = R[:, i] * length
ax.quiver(*origin, *direction, color=colors[i],
arrow_length_ratio=0.1, linewidth=2, alpha=alpha)
ax.text(origin[0]+direction[0]*1.1, origin[1]+direction[1]*1.1,
origin[2]+direction[2]*1.1,
f'{label_prefix}{labels[i]}', fontsize=9, color=colors[i], alpha=alpha)
# 元の座標系
draw_axes(ax3, np.eye(3), label_prefix='', alpha=0.3)
# オイラー角による回転
psi_deg, theta_deg, phi_deg = 30, 20, 10
R_euler = euler_321(np.radians(psi_deg), np.radians(theta_deg), np.radians(phi_deg))
draw_axes(ax3, R_euler, label_prefix="'", alpha=1.0)
ax3.set_xlabel('x')
ax3.set_ylabel('y')
ax3.set_zlabel('z')
ax3.set_title(f'Euler 3-2-1: ψ={psi_deg}°, θ={theta_deg}°, φ={phi_deg}°', fontsize=12)
ax3.set_xlim([-1.2, 1.2])
ax3.set_ylim([-1.2, 1.2])
ax3.set_zlim([-1.2, 1.2])
# (4) 回転の非可換性の可視化
ax4 = fig.add_subplot(2, 2, 4, projection='3d')
v0 = np.array([1, 0, 0])
alpha_rot = np.radians(90)
# Rx(90°) → Rz(90°)
v1 = Rz(alpha_rot) @ Rx(alpha_rot) @ v0
# Rz(90°) → Rx(90°)
v2 = Rx(alpha_rot) @ Rz(alpha_rot) @ v0
# 座標軸
ax4.quiver(0, 0, 0, 1.3, 0, 0, color='gray', arrow_length_ratio=0.05, linewidth=0.5)
ax4.quiver(0, 0, 0, 0, 1.3, 0, color='gray', arrow_length_ratio=0.05, linewidth=0.5)
ax4.quiver(0, 0, 0, 0, 0, 1.3, color='gray', arrow_length_ratio=0.05, linewidth=0.5)
# 元のベクトル
ax4.quiver(0, 0, 0, v0[0], v0[1], v0[2], color='black',
arrow_length_ratio=0.1, linewidth=2)
ax4.text(v0[0]*1.1, v0[1]*1.1, v0[2]*1.1, 'Original', fontsize=9)
# Rx→Rz
ax4.quiver(0, 0, 0, v1[0], v1[1], v1[2], color='red',
arrow_length_ratio=0.1, linewidth=2)
ax4.text(v1[0]*1.15, v1[1]*1.15, v1[2]*1.15, 'Rx→Rz', fontsize=9, color='red')
# Rz→Rx
ax4.quiver(0, 0, 0, v2[0], v2[1], v2[2], color='blue',
arrow_length_ratio=0.1, linewidth=2)
ax4.text(v2[0]*1.15, v2[1]*1.15, v2[2]*1.15, 'Rz→Rx', fontsize=9, color='blue')
ax4.set_xlabel('x')
ax4.set_ylabel('y')
ax4.set_zlabel('z')
ax4.set_title('Non-commutativity: Rx(90°)·Rz(90°) ≠ Rz(90°)·Rx(90°)', fontsize=11)
ax4.set_xlim([-1.2, 1.2])
ax4.set_ylim([-1.2, 1.2])
ax4.set_zlim([-1.2, 1.2])
plt.tight_layout()
plt.show()
# --- 結果の表示 ---
print(f"\n=== 非可換性の確認 ===")
print(f"v0 = {v0}")
print(f"Rz(90°)·Rx(90°)·v0 = {np.round(v1, 4)}")
print(f"Rx(90°)·Rz(90°)·v0 = {np.round(v2, 4)}")
print(f"結果が異なる → 3次元回転は非可換")
ジンバルロックの可視化
import numpy as np
import matplotlib.pyplot as plt
# --- ジンバルロックの確認 ---
# 3-2-1オイラー角でピッチθを変化させたときの自由度
def euler_321_matrix(psi, theta, phi):
"""3-2-1オイラー角から回転行列"""
cp, sp = np.cos(psi), np.sin(psi)
ct, st = np.cos(theta), np.sin(theta)
cf, sf = np.cos(phi), np.sin(phi)
return np.array([
[ct*cp, ct*sp, -st],
[sf*st*cp - cf*sp, sf*st*sp + cf*cp, sf*ct],
[cf*st*cp + sf*sp, cf*st*sp - sf*cp, cf*ct]
])
# ピッチ角を変化させたとき、行列の(1,3)要素の変化を確認
thetas = np.linspace(-np.pi/2, np.pi/2, 200)
R13_values = -np.sin(thetas)
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# (1) R[0,2] = -sin(θ) の変化
axes[0].plot(np.degrees(thetas), R13_values, 'b-', linewidth=2)
axes[0].axhline(y=-1, color='r', linestyle='--', alpha=0.5, label='θ = 90° (gimbal lock)')
axes[0].axhline(y=1, color='r', linestyle='--', alpha=0.5, label='θ = -90° (gimbal lock)')
axes[0].axvline(x=90, color='r', linestyle=':', alpha=0.5)
axes[0].axvline(x=-90, color='r', linestyle=':', alpha=0.5)
axes[0].set_xlabel('Pitch angle θ [deg]', fontsize=11)
axes[0].set_ylabel('R[0,2] = -sin(θ)', fontsize=11)
axes[0].set_title('Gimbal Lock Condition', fontsize=13)
axes[0].legend(fontsize=10)
axes[0].grid(True, alpha=0.3)
# (2) θ=90°でのψとφの不定性
# θ=90°のとき、R[0,2]=-1, R[0,0]=0, R[0,1]=0
# φ-ψ のみ決まり、個別のφ,ψは不定
psi_values = np.linspace(0, 2*np.pi, 100)
phi_diff = np.radians(45) # φ-ψ = 45° とする
# θ=89°(ジンバルロック近傍)での逆問題の精度
theta_test_values = np.linspace(0, 89.9, 50)
error_psi = []
error_phi = []
psi_true = np.radians(30)
phi_true = np.radians(45)
for theta_deg in theta_test_values:
theta_true = np.radians(theta_deg)
R = euler_321_matrix(psi_true, theta_true, phi_true)
# 逆問題
theta_est = -np.arcsin(np.clip(R[0, 2], -1, 1))
if np.abs(np.cos(theta_est)) > 1e-10:
phi_est = np.arctan2(R[1, 2], R[2, 2])
psi_est = np.arctan2(R[0, 1], R[0, 0])
else:
phi_est = np.arctan2(-R[2, 1], R[1, 1])
psi_est = 0
error_psi.append(np.abs(np.degrees(psi_est - psi_true)))
error_phi.append(np.abs(np.degrees(phi_est - phi_true)))
axes[1].semilogy(theta_test_values, error_psi, 'b-', linewidth=1.5, label='|ψ error|')
axes[1].semilogy(theta_test_values, error_phi, 'r-', linewidth=1.5, label='|φ error|')
axes[1].set_xlabel('Pitch angle θ [deg]', fontsize=11)
axes[1].set_ylabel('Angle Error [deg]', fontsize=11)
axes[1].set_title('Euler Angle Extraction Error near Gimbal Lock', fontsize=13)
axes[1].legend(fontsize=10)
axes[1].grid(True, alpha=0.3, which='both')
plt.tight_layout()
plt.show()
まとめ
本記事では、回転行列と座標変換の理論と実装について解説しました。
- 2次元回転行列: $R(\theta) = \begin{pmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{pmatrix}$、加法定理から導出
- 3次元基本回転: $R_x(\theta)$, $R_y(\theta)$, $R_z(\theta)$ を各軸まわりに定義
- 直交行列の性質: $R^T R = I$、$\det(R) = 1$。逆行列は転置に等しい
- 3次元回転は非可換: $R_x R_z \neq R_z R_x$(一般に順序が重要)
- オイラー角: 3-1-3系列(天体力学)、3-2-1系列(航空宇宙のヨー・ピッチ・ロール)
- ジンバルロック: 特定のオイラー角で自由度を1つ失う特異点
次のステップとして、以下の記事も参考にしてください。