659.46 3D 회전 표현: 쿼터니언 (Quaternion) 기초
1. 개요
3차원 공간에서의 회전은 로봇공학의 모든 분야에 걸쳐 핵심적인 수학적 개념이다. 회전을 표현하는 방법에는 오일러 각(Euler angles), 회전 행렬(rotation matrix), 축-각(axis-angle), 그리고 쿼터니언(quaternion)이 있으며, 이 중 쿼터니언은 짐벌 락(gimbal lock) 문제가 발생하지 않고, 수치적 안정성이 높으며, 회전 합성과 보간을 효율적으로 수행할 수 있다는 장점으로 인해 로봇 시스템에서 가장 널리 사용되는 회전 표현 방식이다. TF2 라이브러리에서도 모든 좌표 변환의 회전 성분을 쿼터니언으로 표현하며, geometry_msgs::Quaternion 메시지 타입을 표준으로 사용한다. 본 절에서는 쿼터니언의 기본 개념, 기하학적 의미, 그리고 로봇공학에서의 활용 배경을 체계적으로 다룬다.
2. 쿼터니언의 역사적 배경
쿼터니언은 1843년 아일랜드의 수학자 윌리엄 로원 해밀턴(William Rowan Hamilton)에 의해 발견되었다. 해밀턴은 복소수(complex number)를 3차원으로 확장하려는 시도 중에, 3차원이 아닌 4차원의 수체계가 필요하다는 사실을 깨닫고 쿼터니언을 정의하였다. 해밀턴의 원래 동기는 순수 수학적이었으나, 쿼터니언은 이후 항공우주 공학, 컴퓨터 그래픽스, 로봇공학 등 다양한 공학 분야에서 3D 회전을 표현하는 핵심적인 도구로 자리잡았다.
쿼터니언이 로봇공학에서 특히 중요한 이유는, 오일러 각이 가지는 특이성(singularity) 문제를 완전히 회피하면서도 4개의 파라미터만으로 회전을 간결하게 표현할 수 있기 때문이다. 회전 행렬이 9개의 원소를 사용하는 것과 비교하면 메모리 효율 측면에서도 우수하다.
3. 쿼터니언의 수학적 기초
3.1 복소수에서 쿼터니언으로의 확장
복소수는 실수부와 허수부로 구성된 \mathbb{R}^2 상의 수이다:
z = a + bi, \quad a, b \in \mathbb{R}, \quad i^2 = -1
복소수의 곱셈은 2차원 평면에서의 회전을 자연스럽게 표현한다. 단위 복소수 e^{i\theta} = \cos\theta + i\sin\theta는 원점을 중심으로 각도 \theta만큼의 2D 회전에 해당한다.
해밀턴은 이를 3차원으로 확장하기 위해 허수 단위를 세 개로 늘려 쿼터니언을 다음과 같이 정의하였다:
\mathbf{q} = w + xi + yj + zk
여기서 w, x, y, z \in \mathbb{R}이며, i, j, k는 다음의 기본 관계를 만족하는 허수 단위이다:
i^2 = j^2 = k^2 = ijk = -1
이 관계로부터 다음의 곱셈 규칙이 유도된다:
ij = k, \quad jk = i, \quad ki = j
ji = -k, \quad kj = -i, \quad ik = -j
중요한 점은 쿼터니언의 곱셈이 **비가환적(non-commutative)**이라는 것이다. 즉, 일반적으로 \mathbf{q}_1 \mathbf{q}_2 \neq \mathbf{q}_2 \mathbf{q}_1이다. 이 비가환성은 3차원 회전의 비가환성을 정확히 반영한다.
3.2 스칼라부와 벡터부
쿼터니언 \mathbf{q} = w + xi + yj + zk는 스칼라부(scalar part)와 벡터부(vector part)로 분리하여 표기할 수 있다:
\mathbf{q} = (w, \mathbf{v}), \quad \mathbf{v} = (x, y, z) \in \mathbb{R}^3
여기서 w는 스칼라부, \mathbf{v}는 벡터부이다. 이 표기법은 쿼터니언 연산의 기하학적 의미를 해석하는 데 유용하다.
벡터부만으로 구성된 쿼터니언, 즉 w = 0인 쿼터니언을 **순수 쿼터니언(pure quaternion)**이라 한다. 3차원 공간의 점이나 벡터를 쿼터니언으로 표현할 때, 해당 점의 좌표 (p_x, p_y, p_z)를 순수 쿼터니언 \mathbf{p} = (0, p_x, p_y, p_z)로 변환하여 사용한다.
3.3 쿼터니언의 표기 규약
로봇공학 및 ROS2에서 쿼터니언의 성분 순서에 대한 두 가지 주요 규약이 존재한다:
| 규약 | 순서 | 사용 분야 |
|---|---|---|
| Hamilton 규약 | (w, x, y, z) | 수학, 물리학, Eigen 라이브러리 |
| JPL 규약 | (x, y, z, w) | 항공우주 일부 분야 |
| ROS2 / geometry_msgs | (x, y, z, w) | ROS2 생태계 전체 |
ROS2의 geometry_msgs::Quaternion 메시지에서는 (x, y, z, w) 순서를 사용한다. 이는 벡터부 (x, y, z)를 먼저 배치하고 스칼라부 w를 마지막에 두는 형식이다. 반면 Eigen 라이브러리에서는 내부적으로 (x, y, z, w) 순서로 저장하지만, 생성자는 (w, x, y, z) 순서를 취하므로 혼동에 주의해야 한다:
// Eigen 라이브러리의 쿼터니언 생성자: (w, x, y, z) 순서
Eigen::Quaterniond q(w, x, y, z);
// 그러나 내부 계수 배열은 [x, y, z, w] 순서
q.coeffs(); // [x, y, z, w]
이러한 규약 차이는 라이브러리 간 데이터 교환 시 빈번한 오류의 원인이 되므로, 항상 사용 중인 라이브러리의 규약을 확인해야 한다.
4. 쿼터니언과 3D 회전의 관계
4.1 단위 쿼터니언 (Unit Quaternion)
3차원 회전을 표현하기 위해서는 **단위 쿼터니언(unit quaternion)**을 사용한다. 단위 쿼터니언은 그 노름(norm)이 1인 쿼터니언이다:
\|\mathbf{q}\| = \sqrt{w^2 + x^2 + y^2 + z^2} = 1
단위 쿼터니언은 4차원 단위 초구(unit hypersphere) S^3 상의 점에 해당한다. 3차원 회전군 SO(3)의 원소와 단위 쿼터니언 사이에는 **2대1 사상(two-to-one mapping)**이 존재한다. 즉, 쿼터니언 \mathbf{q}와 -\mathbf{q}는 동일한 회전을 나타낸다. 이 이중 피복(double cover) 성질은 쿼터니언을 이용한 보간이나 최적화에서 중요한 고려 사항이 된다.
4.2 축-각 표현과의 관계
임의의 3차원 회전은 로드리게스 회전 정리(Rodrigues’ rotation theorem)에 의해 단위 벡터 \hat{\mathbf{n}} = (n_x, n_y, n_z)를 축으로 각도 \theta만큼 회전하는 것으로 유일하게 표현된다. 이 축-각 표현으로부터 단위 쿼터니언을 다음과 같이 구성할 수 있다:
\mathbf{q} = \cos\frac{\theta}{2} + \sin\frac{\theta}{2}(n_x i + n_y j + n_z k)
즉, 스칼라부와 벡터부로 분리하면:
w = \cos\frac{\theta}{2}, \quad \mathbf{v} = \sin\frac{\theta}{2} \hat{\mathbf{n}}
여기서 회전 각도가 \theta가 아닌 \theta/2로 나타나는 것은 쿼터니언의 이중 피복 성질에 기인한다. 이 관계를 통해 쿼터니언의 각 성분에 대한 기하학적 의미를 다음과 같이 해석할 수 있다:
- w = \cos(\theta/2): 회전 각도의 절반에 대한 코사인 값. w = 1이면 회전 없음(항등 회전)을 의미한다.
- (x, y, z) = \sin(\theta/2) \hat{\mathbf{n}}: 회전축의 방향에 회전 각도의 절반에 대한 사인을 곱한 벡터.
4.3 쿼터니언에 의한 벡터 회전
쿼터니언 \mathbf{q}에 의해 벡터 \mathbf{p} \in \mathbb{R}^3를 회전시키는 연산은 다음과 같이 정의된다. 먼저 벡터 \mathbf{p}를 순수 쿼터니언 \hat{\mathbf{p}} = (0, \mathbf{p})로 변환한 후, 다음의 쿼터니언 곱을 수행한다:
\hat{\mathbf{p}}' = \mathbf{q} \hat{\mathbf{p}} \mathbf{q}^{*}
여기서 \mathbf{q}^{*}는 \mathbf{q}의 켤레(conjugate)이다. 결과 \hat{\mathbf{p}}'의 벡터부가 회전된 벡터 \mathbf{p}'에 해당한다.
이 연산에는 쿼터니언 곱셈이 두 번 필요하므로, 단순 계산량만으로는 회전 행렬과 벡터의 곱(3 \times 3 행렬-벡터 곱)보다 비효율적으로 보일 수 있다. 그러나 쿼터니언을 이용한 회전 합성은 4 \times 4 행렬 곱셈보다 연산량이 적고, 정규화를 통해 수치 오차의 누적을 방지할 수 있다는 장점이 있다.
5. 쿼터니언의 주요 특성
5.1 항등 쿼터니언 (Identity Quaternion)
회전이 없는 상태, 즉 항등 변환(identity transformation)을 나타내는 쿼터니언은 다음과 같다:
\mathbf{q}_{\text{identity}} = (1, 0, 0, 0) \quad \text{또는} \quad w=1, x=0, y=0, z=0
ROS2에서 좌표 프레임 간의 회전이 없음을 표현할 때 이 항등 쿼터니언을 사용한다:
geometry_msgs::msg::Quaternion identity;
identity.x = 0.0;
identity.y = 0.0;
identity.z = 0.0;
identity.w = 1.0;
from geometry_msgs.msg import Quaternion
identity = Quaternion(x=0.0, y=0.0, z=0.0, w=1.0)
5.2 이중 피복 (Double Cover)
단위 쿼터니언 \mathbf{q}와 -\mathbf{q}는 동일한 3D 회전을 나타낸다:
\mathbf{q} \hat{\mathbf{p}} \mathbf{q}^{*} = (-\mathbf{q}) \hat{\mathbf{p}} (-\mathbf{q})^{*}
이 성질은 다음과 같은 실용적 함의를 가진다:
- 보간 시 최단 경로 선택: 두 쿼터니언 간의 SLERP(구면 선형 보간)를 수행할 때, 내적 \mathbf{q}_1 \cdot \mathbf{q}_2 < 0이면 둘 중 하나의 부호를 반전시켜 최단 호(shortest arc)를 통한 보간이 이루어지도록 해야 한다.
- 평균 계산 시 부호 통일: 복수의 쿼터니언을 평균할 때, 모든 쿼터니언이 동일한 반구(hemisphere)에 있도록 부호를 조정해야 한다.
- 비교 연산: 두 회전의 동일성을 판별할 때, \mathbf{q}_1 = \mathbf{q}_2 또는 \mathbf{q}_1 = -\mathbf{q}_2인지를 동시에 검사해야 한다.
5.3 수치적 안정성
쿼터니언은 연속적인 회전 합성 시 수치 오류가 누적될 수 있으나, **정규화(normalization)**를 통해 이를 효과적으로 보정할 수 있다. 정규화는 단순히 4개의 성분을 노름으로 나누는 연산이다:
\mathbf{q}_{\text{normalized}} = \frac{\mathbf{q}}{\|\mathbf{q}\|}
이 연산은 회전 행렬의 직교화(orthogonalization) 과정에 비해 계산 비용이 매우 낮다. 회전 행렬의 직교화는 그람-슈미트(Gram-Schmidt) 과정이나 SVD(특이값 분해)를 필요로 하지만, 쿼터니언의 정규화는 제곱근 하나와 나눗셈 네 번으로 완료된다.
6. 로봇공학에서의 쿼터니언 활용
6.1 TF2에서의 쿼터니언
TF2 라이브러리에서 모든 좌표 변환은 병진(translation)과 회전(rotation)의 조합으로 표현되며, 회전 성분은 항상 쿼터니언으로 저장된다. geometry_msgs::msg::TransformStamped 메시지의 transform.rotation 필드가 쿼터니언에 해당한다:
geometry_msgs::msg::TransformStamped t;
t.header.stamp = this->get_clock()->now();
t.header.frame_id = "world";
t.child_frame_id = "robot";
// 병진 설정
t.transform.translation.x = 1.0;
t.transform.translation.y = 0.0;
t.transform.translation.z = 0.0;
// 회전 설정 (z축 기준 90도 회전)
t.transform.rotation.x = 0.0;
t.transform.rotation.y = 0.0;
t.transform.rotation.z = 0.7071068; // sin(π/4)
t.transform.rotation.w = 0.7071068; // cos(π/4)
6.2 오일러 각 대비 쿼터니언의 장점
로봇공학에서 쿼터니언이 오일러 각보다 선호되는 주된 이유는 다음과 같다:
| 특성 | 오일러 각 | 쿼터니언 |
|---|---|---|
| 파라미터 수 | 3 | 4 (구속 조건 1개) |
| 짐벌 락 | 발생 가능 | 발생하지 않음 |
| 회전 합성 | 삼각함수 연산 필요 | 쿼터니언 곱셈 (16회 곱셈, 12회 덧셈) |
| 보간 | 비선형, 복잡 | SLERP으로 균일 보간 가능 |
| 정규화 비용 | 해당 없음 | O(1) (제곱근 1회) |
| 수치 안정성 | 특이점 근처에서 불안정 | 항상 안정적 |
| 직관성 | 높음 (각도 직접 표현) | 낮음 (기하학적 해석 필요) |
오일러 각의 직관성은 사람이 회전을 이해하는 데에는 유리하지만, 계산적 처리에서는 쿼터니언이 전반적으로 우수하다. 따라서 사용자 인터페이스에서의 입출력에는 오일러 각을 사용하고, 내부 연산에는 쿼터니언을 사용하는 것이 일반적인 설계 방침이다.
6.3 ROS2에서의 쿼터니언 유틸리티
ROS2에서는 쿼터니언과 오일러 각 간의 변환을 지원하는 유틸리티를 제공한다:
C++ (tf2 라이브러리):
#include <tf2/LinearMath/Quaternion.h>
#include <tf2/LinearMath/Matrix3x3.h>
// 오일러 각에서 쿼터니언으로 변환
tf2::Quaternion q;
q.setRPY(roll, pitch, yaw); // Roll-Pitch-Yaw 순서
// 쿼터니언에서 오일러 각으로 변환
tf2::Matrix3x3 m(q);
double roll, pitch, yaw;
m.getRPY(roll, pitch, yaw);
Python (tf_transformations 또는 scipy):
from tf_transformations import quaternion_from_euler, euler_from_quaternion
# 오일러 각에서 쿼터니언으로 변환
q = quaternion_from_euler(roll, pitch, yaw) # 반환: [x, y, z, w]
# 쿼터니언에서 오일러 각으로 변환
(roll, pitch, yaw) = euler_from_quaternion([q.x, q.y, q.z, q.w])
7. 쿼터니언의 기하학적 시각화
쿼터니언은 4차원 객체이므로 직접적인 시각화가 어렵다. 그러나 축-각 표현과의 관계를 이용하면 기하학적 해석이 가능하다.
단위 쿼터니언 \mathbf{q} = (w, x, y, z)가 주어졌을 때:
- 회전축: \hat{\mathbf{n}} = \frac{(x, y, z)}{\sqrt{x^2 + y^2 + z^2}} (벡터부가 0이 아닌 경우)
- 회전 각도: \theta = 2 \arccos(w) 또는 \theta = 2 \arctan2(\|\mathbf{v}\|, w)
\arctan2 함수를 사용하는 방법이 수치적으로 더 안정적이다. \arccos는 w \approx \pm 1 부근에서 수치 오차에 민감하기 때문이다.
예를 들어, z축을 중심으로 90도 회전하는 쿼터니언은 다음과 같다:
\mathbf{q} = \left(\cos\frac{\pi/2}{2}, 0, 0, \sin\frac{\pi/2}{2}\right) = \left(\frac{\sqrt{2}}{2}, 0, 0, \frac{\sqrt{2}}{2}\right)
ROS2의 (x, y, z, w) 규약으로는 (0, 0, 0.7071, 0.7071)이 된다.
8. 주요 특수 쿼터니언
다음 표는 로봇공학에서 빈번하게 사용되는 기본 회전에 해당하는 쿼터니언을 정리한 것이다 (ROS2의 (x, y, z, w) 순서):
| 회전 설명 | x | y | z | w |
|---|---|---|---|---|
| 항등 (회전 없음) | 0 | 0 | 0 | 1 |
| X축 90° 회전 | 0.7071 | 0 | 0 | 0.7071 |
| Y축 90° 회전 | 0 | 0.7071 | 0 | 0.7071 |
| Z축 90° 회전 | 0 | 0 | 0.7071 | 0.7071 |
| X축 180° 회전 | 1 | 0 | 0 | 0 |
| Y축 180° 회전 | 0 | 1 | 0 | 0 |
| Z축 180° 회전 | 0 | 0 | 1 | 0 |
| X축 -90° 회전 | -0.7071 | 0 | 0 | 0.7071 |
| Y축 -90° 회전 | 0 | -0.7071 | 0 | 0.7071 |
| Z축 -90° 회전 | 0 | 0 | -0.7071 | 0.7071 |
이 표에서 0.7071 \approx \frac{\sqrt{2}}{2} \approx \sin(45°) = \cos(45°)이다.
9. 쿼터니언 사용 시 주의사항
9.1 정규화 검증
TF2에 전달되는 쿼터니언은 반드시 단위 쿼터니언이어야 한다. 비정규화된 쿼터니언은 예측 불가능한 변환 결과를 초래한다. 쿼터니언을 수동으로 설정할 때는 항상 정규화 여부를 확인해야 한다:
tf2::Quaternion q(x, y, z, w);
q.normalize(); // 정규화 수행
9.2 영 쿼터니언 방지
모든 성분이 0인 쿼터니언 (0, 0, 0, 0)은 유효한 회전을 나타내지 않으며, 정규화 시 0으로 나누는 오류가 발생한다. geometry_msgs::Quaternion의 기본 생성자가 모든 필드를 0으로 초기화하는 경우가 있으므로, 반드시 유효한 값을 설정해야 한다.
9.3 성분 순서 확인
앞서 언급한 바와 같이, (w, x, y, z) 순서와 (x, y, z, w) 순서의 혼용은 심각한 오류를 유발한다. 특히 ROS2 메시지와 Eigen 라이브러리, tf2::Quaternion 간의 데이터 변환 시 성분 순서를 반드시 확인해야 한다.
10. 요약
쿼터니언은 4차원 초복소수(hypercomplex number)로서, 단위 쿼터니언을 통해 3차원 회전을 특이점 없이 표현할 수 있다. 짐벌 락이 발생하지 않으며, 회전 합성과 보간이 효율적이고, 정규화를 통한 수치 안정성 유지가 용이하다. TF2 라이브러리를 포함한 ROS2 생태계 전체에서 회전의 표준 표현 방식으로 채택되어 있으며, 로봇공학에서 좌표 변환을 다루는 데 필수적인 수학적 도구이다. 쿼터니언을 사용할 때는 성분 순서 규약, 단위 조건, 이중 피복 성질 등의 특성을 정확히 이해하고 적용해야 한다.
11. 참고 문헌
- Hamilton, W. R. (1844). “On Quaternions; or on a New System of Imaginaries in Algebra.” Philosophical Magazine, 25(3), 489-495.
- Kuipers, J. B. (1999). Quaternions and Rotation Sequences: A Primer with Applications to Orbits, Aerospace, and Virtual Reality. Princeton University Press.
- Diebel, J. (2006). “Representing Attitude: Euler Angles, Unit Quaternions, and Rotation Vectors.” Stanford University Technical Report.
- Slabaugh, G. G. (1999). “Computing Euler Angles from a Rotation Matrix.” City University London.
- Open Robotics. “tf2 — ROS 2 Documentation.” https://docs.ros.org/en/rolling/Concepts/Intermediate/About-Tf2.html
- Foote, T. (2013). “tf: The Transform Library.” IEEE International Conference on Technologies for Practical Robot Applications (TePRA).