Skip to content

Commit d0f94aa

Browse files
authored
Add slerp function (#22)
1 parent 98e04ef commit d0f94aa

File tree

3 files changed

+63
-2
lines changed

3 files changed

+63
-2
lines changed

src/general_robotics_toolbox/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from .general_robotics_toolbox import hat, invhat, rot, R2rot, screw_matrix, q2R, R2q, q2rot, rot2q, quatcomplement, \
44
quatproduct, quatjacobian, rpy2R, R2rpy, Robot, Transform, fwdkin, robotjacobian, subproblem0, subproblem1, \
55
subproblem2, subproblem3, subproblem4, apply_robot_aux_transforms, unapply_robot_aux_transforms, \
6-
identity_transform, random_R, random_p, random_transform
6+
identity_transform, random_R, random_p, random_transform, slerp
77

88
from .general_robotics_toolbox_invkin import robot6_sphericalwrist_invkin, ur_invkin, equivalent_configurations, \
99
iterative_invkin
@@ -12,5 +12,5 @@
1212
'quatproduct', 'quatjacobian', 'rpy2R', 'R2rpy', 'Robot', 'Transform', 'fwdkin', 'robotjacobian', 'subproblem0',
1313
'subproblem1', 'subproblem2', 'subproblem3', 'subproblem4', 'apply_robot_aux_transforms',
1414
'unapply_robot_aux_transforms', 'identity_transform', 'random_R', 'random_p', 'random_transform',
15-
'robot6_sphericalwrist_invkin', 'ur_invkin', 'equivalent_configurations', 'iterative_invkin']
15+
'robot6_sphericalwrist_invkin', 'ur_invkin', 'equivalent_configurations', 'iterative_invkin', 'slerp']
1616

src/general_robotics_toolbox/general_robotics_toolbox.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,38 @@ def R2rpy(R):
298298

299299
return (r,p,y)
300300

301+
# Add slerp function using [w,x,y,z] quaternion representation (github copilot)
302+
def slerp(q0, q1, t):
303+
"""
304+
Spherical linear interpolation between two quaternions
305+
306+
:type q0: numpy.array
307+
:param q0: 4 x 1 vector representation of a quaternion q = [q0;qv]
308+
:type q1: numpy.array
309+
:param q1: 4 x 1 vector representation of a quaternion q = [q0;qv]
310+
:type t: number
311+
:param t: interpolation parameter in the range [0,1]
312+
:rtype: numpy.array
313+
:returns: the 4 x 1 interpolated quaternion
314+
"""
315+
316+
assert (t >= 0 and t <= 1), "t must be in the range [0,1]"
317+
318+
q0 = q0/np.linalg.norm(q0)
319+
q1 = q1/np.linalg.norm(q1)
320+
321+
if (np.dot(q0,q1) < 0):
322+
q0 = -q0
323+
324+
theta = np.arccos(np.dot(q0,q1))
325+
326+
if (np.abs(theta) < 1e-6):
327+
return q0
328+
329+
q = (np.sin((1-t)*theta)*q0 + np.sin(t*theta)*q1)/np.sin(theta)
330+
331+
return q/np.linalg.norm(q)
332+
301333
class Robot(object):
302334
"""
303335
Holds the kinematic information for a single chain robot

test/test_general_robotics_toolbox.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,35 @@ def test_rpy2R():
190190
rox.R2rpy(R3)
191191

192192

193+
def _test_slerp_params(k1,theta1,k2,theta2,t):
194+
R1 = rox.rot(k1, theta1)
195+
R2 = rox.rot(k2, theta2)
196+
197+
q1 = rox.R2q(R1)
198+
q2 = rox.R2q(R2)
199+
200+
R1_2 = R1.T @ R2
201+
k,theta = rox.R2rot(R1_2)
202+
203+
R_t = R1 @ rox.rot(k, theta*t)
204+
q_t = rox.slerp(q1, q2, t)
205+
R_qt = rox.q2R(q_t)
206+
207+
np.testing.assert_allclose(R_t, R_qt)
208+
209+
q_t2 = rox.slerp(q1, -q2, t)
210+
R_qt2 = rox.q2R(q_t2)
211+
212+
np.testing.assert_allclose(R_t, R_qt2)
213+
214+
def test_slerp():
215+
_test_slerp_params([0.53436371, 0.24406035, 0.80925273], -4.643,
216+
[-0.71076104, 0.57683297, 0.40259467], 0.25945178, 0.72)
217+
_test_slerp_params([0,0,1],0,[0,0,1],1e-7,0.5)
218+
_test_slerp_params([0,0,1],1.82,[1,0,0],18.7,0.76)
219+
220+
221+
193222
def test_fwdkin():
194223

195224
#TODO: other joint types

0 commit comments

Comments
 (0)