Углы Эйлера и ориентация в пространстве

Три числа, которыми задают ориентацию тела в трёхмерном пространстве — и подводные камни этого способа.

Углы Эйлера — три угла последовательных поворотов вокруг осей, задающие произвольную ориентацию тела в пространстве.

На плоскости ориентация — один угол. В пространстве нужно три. Популярная схема — roll-pitch-yaw (крен-тангаж-рыскание): поворот вокруг $z$ на угол $\psi$ (yaw), затем вокруг $y$ на $\phi$ (pitch), затем вокруг $x$ на $\gamma$ (roll). Итоговая матрица — произведение:

$$ R = R_z(\psi) \, R_y(\phi) \, R_x(\gamma) $$

где элементарные повороты, например:

$$ R_z(\psi) = \begin{bmatrix} \cos\psi & -\sin\psi & 0 \\\\ \sin\psi & \cos\psi & 0 \\\\ 0 & 0 & 1 \end{bmatrix} $$

Порядок имеет значение

В 3D повороты не коммутируют: повернуть сначала вокруг $z$, потом вокруг $y$ — не то же самое, что наоборот. Поэтому всегда указывают порядок осей (ZYX, XYZ и т.д.). Перемножим матрицы и повернём вектор $(1,0,0)$ только вокруг $z$ на $90^\circ$ — ждём $(0,1,0)$.

import math

def Rz(a):
    c, s = math.cos(a), math.sin(a)
    return [[c, -s, 0], [s, c, 0], [0, 0, 1]]
def Ry(a):
    c, s = math.cos(a), math.sin(a)
    return [[c, 0, s], [0, 1, 0], [-s, 0, c]]
def Rx(a):
    c, s = math.cos(a), math.sin(a)
    return [[1, 0, 0], [0, c, -s], [0, s, c]]

def mm(A, B):
    return [[sum(A[i][k] * B[k][j] for k in range(3)) for j in range(3)] for i in range(3)]
def mv(A, v):
    return [round(sum(A[i][k] * v[k] for k in range(3)), 4) for i in range(3)]

R = mm(mm(Rz(math.radians(90)), Ry(0)), Rx(0))
print("вектор (1,0,0) после yaw=90:", mv(R, [1, 0, 0]))

Вывод:

вектор (1,0,0) после yaw=90: [0.0, 1.0, 0.0]

Как работает под капотом

У углов Эйлера есть болезнь — gimbal lock (складывание рамок): при некоторых ориентациях (например $\phi = 90^\circ$) две оси поворота совпадают, и одна степень свободы теряется. Из-за этого в реальных системах ориентацию чаще хранят в кватернионах — четырёх числах без сингулярностей; углы Эйлера оставляют для интерфейса с человеком, потому что их легко представить.

Частые ошибки

  • Не указать порядок осей: «углы Эйлера» без последовательности (ZYX/XYZ) — неоднозначность.
  • Менять порядок множителей и удивляться другому результату — в 3D это норма.
  • Игнорировать gimbal lock в задачах с большими поворотами.

Итог

  • Ориентацию в 3D задают тремя углами Эйлера (roll-pitch-yaw).
  • Итоговая матрица — произведение трёх элементарных поворотов в заданном порядке.
  • Повороты в 3D не коммутируют — порядок осей критичен.
  • Углы Эйлера страдают от gimbal lock; для вычислений надёжнее кватернионы.
Проверьте себя
1. Коммутативны ли повороты в трёхмерном пространстве?
AДа, порядок не важен
BНет, результат зависит от порядка поворотов
CТолько для прямых углов
DТолько вокруг оси z
2. Что такое gimbal lock?
AПоломка сустава
BПотеря одной степени свободы при совпадении осей поворота в углах Эйлера
CСлишком быстрый поворот
DОшибка округления