Skip to content

Commit 6604dce

Browse files
DeepMindcopybara-github
authored andcommitted
Added math.py with utility functions for quaternions. Refactored parse_amc.py to depend on math.py.
PiperOrigin-RevId: 286594366 Change-Id: I55e9843680c6e9fdc98c3b5904971eb3603fc9a4
1 parent 55a41b4 commit 6604dce

4 files changed

Lines changed: 146 additions & 62 deletions

File tree

dm_control/mujoco/math.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Copyright 2019 The dm_control Authors.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
# ============================================================================
15+
16+
"""Utility functions."""
17+
18+
from __future__ import absolute_import
19+
from __future__ import division
20+
from __future__ import print_function
21+
22+
from dm_control.mujoco.wrapper.mjbindings import mjlib
23+
24+
import numpy as np
25+
26+
27+
def euler2quat(ax, ay, az):
28+
"""Converts euler angles to a quaternion.
29+
30+
Note: rotation order is zyx
31+
32+
Args:
33+
ax: Roll angle (deg)
34+
ay: Pitch angle (deg).
35+
az: Yaw angle (deg).
36+
37+
Returns:
38+
A numpy array representing the rotation as a quaternion.
39+
"""
40+
r1 = az
41+
r2 = ay
42+
r3 = ax
43+
44+
c1 = np.cos(np.deg2rad(r1 / 2))
45+
s1 = np.sin(np.deg2rad(r1 / 2))
46+
c2 = np.cos(np.deg2rad(r2 / 2))
47+
s2 = np.sin(np.deg2rad(r2 / 2))
48+
c3 = np.cos(np.deg2rad(r3 / 2))
49+
s3 = np.sin(np.deg2rad(r3 / 2))
50+
51+
q0 = c1 * c2 * c3 + s1 * s2 * s3
52+
q1 = c1 * c2 * s3 - s1 * s2 * c3
53+
q2 = c1 * s2 * c3 + s1 * c2 * s3
54+
q3 = s1 * c2 * c3 - c1 * s2 * s3
55+
56+
return np.array([q0, q1, q2, q3])
57+
58+
59+
def mj_quatprod(q, r):
60+
quaternion = np.zeros(4)
61+
mjlib.mju_mulQuat(quaternion, np.ascontiguousarray(q),
62+
np.ascontiguousarray(r))
63+
return quaternion
64+
65+
66+
def mj_quat2vel(q, dt):
67+
vel = np.zeros(3)
68+
mjlib.mju_quat2Vel(vel, np.ascontiguousarray(q), dt)
69+
return vel
70+
71+
72+
def mj_quatneg(q):
73+
quaternion = np.zeros(4)
74+
mjlib.mju_negQuat(quaternion, np.ascontiguousarray(q))
75+
return quaternion
76+
77+
78+
def mj_quatdiff(source, target):
79+
return mj_quatprod(mj_quatneg(source), np.ascontiguousarray(target))

dm_control/mujoco/math_test.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Copyright 2019 The dm_control Authors.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
# ============================================================================
15+
16+
"""Tests for index."""
17+
from __future__ import absolute_import
18+
from __future__ import division
19+
from __future__ import print_function
20+
21+
import math
22+
from absl.testing import absltest
23+
from absl.testing import parameterized
24+
from dm_control.mujoco import math as mjmath
25+
import numpy as np
26+
27+
28+
class MathTest(parameterized.TestCase):
29+
30+
def testQuatProd(self):
31+
np.testing.assert_allclose(
32+
mjmath.mj_quatprod([0., 1., 0., 0.], [0., 0., 1., 0.]),
33+
[0., 0., 0., 1.])
34+
np.testing.assert_allclose(
35+
mjmath.mj_quatprod([0., 0., 1., 0.], [0., 0., 0., 1.]),
36+
[0., 1., 0., 0.])
37+
np.testing.assert_allclose(
38+
mjmath.mj_quatprod([0., 0., 0., 1.], [0., 1., 0., 0.]),
39+
[0., 0., 1., 0.])
40+
41+
def testQuat2Vel(self):
42+
np.testing.assert_allclose(
43+
mjmath.mj_quat2vel([0., 1., 0., 0.], 0.1), [math.pi / 0.1, 0., 0.])
44+
45+
def testQuatNeg(self):
46+
np.testing.assert_allclose(
47+
mjmath.mj_quatneg([math.sqrt(0.5), math.sqrt(0.5), 0., 0.]),
48+
[math.sqrt(0.5), -math.sqrt(0.5), 0., 0.])
49+
50+
def testQuatDiff(self):
51+
np.testing.assert_allclose(
52+
mjmath.mj_quatdiff([0., 1., 0., 0.], [0., 0., 1., 0.]),
53+
[0., 0., 0., -1.])
54+
55+
def testEuler2Quat(self):
56+
np.testing.assert_allclose(
57+
mjmath.euler2quat(0., 0., 0.), [1., 0., 0., 0.])
58+
59+
60+
if __name__ == '__main__':
61+
absltest.main()

dm_control/suite/utils/parse_amc.py

Lines changed: 5 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,11 @@
2121

2222
import collections
2323

24-
from dm_control.mujoco.wrapper import mjbindings
24+
from dm_control.mujoco import math as mjmath
2525
import numpy as np
2626
from scipy import interpolate
2727
from six.moves import range
2828

29-
mjlib = mjbindings.mjlib
30-
3129
MOCAP_DT = 1.0/120.0
3230
CONVERSION_LENGTH = 0.056444
3331

@@ -104,7 +102,8 @@ def convert(file_name, physics, timestep):
104102
p_tp1 = qpos_values_resampled[:, t + 1]
105103
p_t = qpos_values_resampled[:, t]
106104
qvel = [(p_tp1[:3]-p_t[:3])/ timestep,
107-
mj_quat2vel(mj_quatdiff(p_t[3:7], p_tp1[3:7]), timestep),
105+
mjmath.mj_quat2vel(
106+
mjmath.mj_quatdiff(p_t[3:7], p_tp1[3:7]), timestep),
108107
(p_tp1[7:]-p_t[7:])/ timestep]
109108
qvel_list.append(np.concatenate(qvel))
110109

@@ -187,65 +186,10 @@ def __call__(self, amc_val):
187186

188187
# Root.
189188
qpos[:3] = np.dot(self.root_xyz_ransform, amc_val[:3])
190-
qpos_quat = euler2quat(amc_val[3], amc_val[4], amc_val[5])
191-
qpos_quat = mj_quatprod(euler2quat(90, 0, 0), qpos_quat)
189+
qpos_quat = mjmath.euler2quat(amc_val[3], amc_val[4], amc_val[5])
190+
qpos_quat = mjmath.mj_quatprod(mjmath.euler2quat(90, 0, 0), qpos_quat)
192191

193192
for i, ind in enumerate(self.qpos_root_quat_ind):
194193
qpos[ind] = qpos_quat[i]
195194

196195
return qpos
197-
198-
199-
def euler2quat(ax, ay, az):
200-
"""Converts euler angles to a quaternion.
201-
202-
Note: rotation order is zyx
203-
204-
Args:
205-
ax: Roll angle (deg)
206-
ay: Pitch angle (deg).
207-
az: Yaw angle (deg).
208-
209-
Returns:
210-
A numpy array representing the rotation as a quaternion.
211-
"""
212-
r1 = az
213-
r2 = ay
214-
r3 = ax
215-
216-
c1 = np.cos(np.deg2rad(r1 / 2))
217-
s1 = np.sin(np.deg2rad(r1 / 2))
218-
c2 = np.cos(np.deg2rad(r2 / 2))
219-
s2 = np.sin(np.deg2rad(r2 / 2))
220-
c3 = np.cos(np.deg2rad(r3 / 2))
221-
s3 = np.sin(np.deg2rad(r3 / 2))
222-
223-
q0 = c1 * c2 * c3 + s1 * s2 * s3
224-
q1 = c1 * c2 * s3 - s1 * s2 * c3
225-
q2 = c1 * s2 * c3 + s1 * c2 * s3
226-
q3 = s1 * c2 * c3 - c1 * s2 * s3
227-
228-
return np.array([q0, q1, q2, q3])
229-
230-
231-
def mj_quatprod(q, r):
232-
quaternion = np.zeros(4)
233-
mjlib.mju_mulQuat(quaternion, np.ascontiguousarray(q),
234-
np.ascontiguousarray(r))
235-
return quaternion
236-
237-
238-
def mj_quat2vel(q, dt):
239-
vel = np.zeros(3)
240-
mjlib.mju_quat2Vel(vel, np.ascontiguousarray(q), dt)
241-
return vel
242-
243-
244-
def mj_quatneg(q):
245-
quaternion = np.zeros(4)
246-
mjlib.mju_negQuat(quaternion, np.ascontiguousarray(q))
247-
return quaternion
248-
249-
250-
def mj_quatdiff(source, target):
251-
return mj_quatprod(mj_quatneg(source), np.ascontiguousarray(target))

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ def find_data_files(package_dir, patterns):
165165

166166
setup(
167167
name='dm_control',
168-
version='0.0.286587932',
168+
version='0.0.286594366',
169169
description='Continuous control environments and MuJoCo Python bindings.',
170170
author='DeepMind',
171171
license='Apache License, Version 2.0',

0 commit comments

Comments
 (0)