|
a |
|
b/utils/pose_conversion.py |
|
|
1 |
# Two functions |
|
|
2 |
# convert (rotation matrix,translation vector) to (global 3d position, euler angles) |
|
|
3 |
# convert (global 3d position, euler angles) to (rotation matrix,translation vector) |
|
|
4 |
# Used functions from 'Rotation Matrix To Euler Angles' by Satya Mallick |
|
|
5 |
# https://learnopencv.com/rotation-matrix-to-euler-angles/ |
|
|
6 |
import math |
|
|
7 |
import numpy as np |
|
|
8 |
|
|
|
9 |
|
|
|
10 |
# Calculates Rotation Matrix given euler angles. |
|
|
11 |
def eulerAnglesToRotationMatrix(theta): |
|
|
12 |
# inputs |
|
|
13 |
# -- theta: tuple/list (theta_x,theta_y,theta_z) euler angles (in radians) |
|
|
14 |
|
|
|
15 |
R_x = np.array([[1, 0, 0], |
|
|
16 |
[0, math.cos(theta[0]), -math.sin(theta[0])], |
|
|
17 |
[0, math.sin(theta[0]), math.cos(theta[0])] |
|
|
18 |
]) |
|
|
19 |
|
|
|
20 |
R_y = np.array([[math.cos(theta[1]), 0, math.sin(theta[1])], |
|
|
21 |
[0, 1, 0], |
|
|
22 |
[-math.sin(theta[1]), 0, math.cos(theta[1])] |
|
|
23 |
]) |
|
|
24 |
|
|
|
25 |
R_z = np.array([[math.cos(theta[2]), -math.sin(theta[2]), 0], |
|
|
26 |
[math.sin(theta[2]), math.cos(theta[2]), 0], |
|
|
27 |
[0, 0, 1] |
|
|
28 |
]) |
|
|
29 |
|
|
|
30 |
R = np.dot(R_z, np.dot(R_y, R_x)) |
|
|
31 |
|
|
|
32 |
return R |
|
|
33 |
|
|
|
34 |
|
|
|
35 |
# Checks if a matrix is a valid rotation matrix. |
|
|
36 |
def isRotationMatrix(R): |
|
|
37 |
Rt = np.transpose(R) |
|
|
38 |
shouldBeIdentity = np.dot(Rt, R) |
|
|
39 |
I = np.identity(3, dtype=R.dtype) |
|
|
40 |
n = np.linalg.norm(I - shouldBeIdentity) |
|
|
41 |
return n < 1e-6 |
|
|
42 |
|
|
|
43 |
|
|
|
44 |
# Calculates rotation matrix to euler angles |
|
|
45 |
# The result is the same as MATLAB except the order |
|
|
46 |
# of the euler angles ( x and z are swapped ). |
|
|
47 |
def rotationMatrixToEulerAngles(R): |
|
|
48 |
assert (isRotationMatrix(R)) |
|
|
49 |
|
|
|
50 |
sy = math.sqrt(R[0, 0] * R[0, 0] + R[1, 0] * R[1, 0]) |
|
|
51 |
|
|
|
52 |
singular = sy < 1e-6 |
|
|
53 |
|
|
|
54 |
if not singular: |
|
|
55 |
x = math.atan2(R[2, 1], R[2, 2]) |
|
|
56 |
y = math.atan2(-R[2, 0], sy) |
|
|
57 |
z = math.atan2(R[1, 0], R[0, 0]) |
|
|
58 |
else: |
|
|
59 |
x = math.atan2(-R[1, 2], R[1, 1]) |
|
|
60 |
y = math.atan2(-R[2, 0], sy) |
|
|
61 |
z = 0 |
|
|
62 |
|
|
|
63 |
return np.array([x, y, z]) |
|
|
64 |
|
|
|
65 |
|
|
|
66 |
# convert (rotation matrix,translation vector) to (global 3d position, euler angles) |
|
|
67 |
# output is the pose at the center, which is used as the origin of its own frame |
|
|
68 |
# e.g. tag center of apriltag |
|
|
69 |
def transformation_to_pose(transformation): |
|
|
70 |
# input |
|
|
71 |
# -- transformation: tuple/list (3x3 rotation matrix R, 3x1 translation vector t) |
|
|
72 |
# output |
|
|
73 |
# -- pose: tuple (global position (x,y,z), euler angles (theta_x,theta_y,theta_z)) |
|
|
74 |
assert isinstance(transformation, tuple) or isinstance(transformation, list) |
|
|
75 |
assert len(transformation) == 2 |
|
|
76 |
R, t = transformation |
|
|
77 |
assert R.shape == (3, 3) and t.size == 3 |
|
|
78 |
pos = t.reshape(3, ) |
|
|
79 |
angles = rotationMatrixToEulerAngles(R) |
|
|
80 |
|
|
|
81 |
return (pos, angles) |
|
|
82 |
|
|
|
83 |
|
|
|
84 |
# convert (global 3d position, euler angles) to (rotation matrix,translation vector) |
|
|
85 |
# must be the pose data at the center, which is used as the origin of its own frame |
|
|
86 |
def pose_to_transformation(pose): |
|
|
87 |
# input |
|
|
88 |
# -- pose: tuple (global position (x,y,z), euler angles (theta_x,theta_y,theta_z)) |
|
|
89 |
# output |
|
|
90 |
# -- transformation: tuple/list (3x3 rotation matrix R, 3x1 translation vector t) |
|
|
91 |
assert isinstance(pose, tuple) or isinstance(pose, list) |
|
|
92 |
assert len(pose) == 2 |
|
|
93 |
pos, angles = pose |
|
|
94 |
assert len(pos) == 3 and len(angles) == 3 |
|
|
95 |
|
|
|
96 |
t = (np.array(pos)).reshape(3, ) |
|
|
97 |
|
|
|
98 |
R = eulerAnglesToRotationMatrix(angles) |
|
|
99 |
|
|
|
100 |
return (R, t) |
|
|
101 |
|
|
|
102 |
|
|
|
103 |
def rotation_align(z,d): |
|
|
104 |
""" |
|
|
105 |
https://iquilezles.org/www/articles/noacos/noacos.htm |
|
|
106 |
compute rotation matrix to align vector z to vector d |
|
|
107 |
:param z: |
|
|
108 |
:param d: |
|
|
109 |
:return: rotation matrix M |
|
|
110 |
""" |
|
|
111 |
assert np.isclose(np.linalg.norm(z),1) |
|
|
112 |
assert np.isclose(np.linalg.norm(d), 1) |
|
|
113 |
v = np.cross(z,d) |
|
|
114 |
c = np.sum(z*d) |
|
|
115 |
|
|
|
116 |
M = v.reshape(-1,1) @ v.reshape(1,-1) / (1+c) + np.array([ |
|
|
117 |
[c, -v[2], v[1]], |
|
|
118 |
[v[2], c, -v[0]], |
|
|
119 |
[-v[1], v[0], c] |
|
|
120 |
]) |
|
|
121 |
|
|
|
122 |
return M |