Skip to content

Commit d8e8cc6

Browse files
committed
Added argument checking and testing
1 parent 1f1dd1b commit d8e8cc6

File tree

2 files changed

+97
-29
lines changed

2 files changed

+97
-29
lines changed

roboticstoolbox/robot/ETS.py

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import numpy as np
99
import spatialmath.base as sp
10+
from spatialmath.base.argcheck import getvector, ismatrix
1011
from roboticstoolbox.robot.ET import ET
1112

1213

@@ -175,10 +176,7 @@ def fkine(self, q):
175176
Sequence, J. Haviland and P. Corke
176177
'''
177178

178-
# if not isinstance(q, np.ndarray):
179-
# raise TypeError('q array must be a numpy ndarray.')
180-
# if q.shape != (self._n,):
181-
# raise ValueError('q must be a 1 dim (n,) array')
179+
q = getvector(q, self.n)
182180

183181
j = 0
184182
trans = np.eye(4)
@@ -209,6 +207,9 @@ def jacob0(self, q):
209207
References: Kinematic Derivatives using the Elementary Transform
210208
Sequence, J. Haviland and P. Corke
211209
"""
210+
211+
q = getvector(q, self.n)
212+
212213
T = self.fkine(q)
213214
U = np.eye(4)
214215
j = 0
@@ -236,47 +237,59 @@ def jacob0(self, q):
236237

237238
return J
238239

239-
def hessian0(self, q, J=None):
240+
def hessian0(self, q=None, J0=None):
240241
"""
241242
The manipulator Hessian tensor maps joint acceleration to end-effector
242243
spatial acceleration, expressed in the world-coordinate frame. This
243-
function calulcates this based on the ETS of the robot.
244+
function calulcates this based on the ETS of the robot. One of J0 or q
245+
is required. Supply J0 if already calculated to save computation time
244246
245247
:param q: The joint coordinates of the robot
246248
:type q: float np.ndarray(n,)
249+
:param J0: The manipulator Jacobian in the 0 frame
250+
:type J0: float np.ndarray(6,n)
247251
:return: The manipulator Hessian in 0 frame
248252
:rtype: float np.ndarray(6,n,n)
249253
250254
References: Kinematic Derivatives using the Elementary Transform
251255
Sequence, J. Haviland and P. Corke
252256
"""
253-
if J is None:
254-
J = self.jacob0(q)
257+
258+
if J0 is None:
259+
if q is not None:
260+
q = getvector(q, self.n)
261+
J0 = self.jacob0(q)
262+
else:
263+
raise ValueError('One of q or J0 must be supplied')
264+
# TODO: Check J
255265

256266
H = np.zeros((6, self.n, self.n))
257267

258268
for j in range(self.n):
259269
for i in range(j, self.n):
260270

261-
H[:3, i, j] = np.cross(J[3:, j], J[:3, i])
262-
H[3:, i, j] = np.cross(J[3:, j], J[3:, i])
271+
H[:3, i, j] = np.cross(J0[3:, j], J0[:3, i])
272+
H[3:, i, j] = np.cross(J0[3:, j], J0[3:, i])
263273

264274
if i != j:
265275
H[:3, j, i] = H[:3, i, j]
266276

267277
return H
268278

269-
def manipulability(self, q, J=None):
279+
def manipulability(self, q=None, J=None):
270280
"""
271281
Calculates the manipulability index (scalar) robot at the joint
272282
configuration q. It indicates dexterity, that is, how isotropic the
273283
robot's motion is with respect to the 6 degrees of Cartesian motion.
274284
The measure is high when the manipulator is capable of equal motion
275285
in all directions and low when the manipulator is close to a
276-
singularity.
286+
singularity. One of J or q is required. Supply J if already
287+
calculated to save computation time
277288
278289
:param q: The joint coordinates of the robot
279290
:type q: float np.ndarray(n,)
291+
:param J: The manipulator Jacobian in any frame
292+
:type J: float np.ndarray(6,n)
280293
:return: The manipulability index
281294
:rtype: float
282295
@@ -287,33 +300,48 @@ def manipulability(self, q, J=None):
287300
"""
288301

289302
if J is None:
290-
J = self.jacob0(q)
303+
if q is not None:
304+
q = getvector(q, self.n)
305+
J = self.jacob0(q)
306+
else:
307+
raise ValueError('One of q or J must be supplied')
308+
# TODO: Check J
291309

292310
return np.sqrt(np.linalg.det(J @ np.transpose(J)))
293311

294-
def jacobm(self, q, J=None, H=None, manipulability=None):
312+
def jacobm(self, q=None, J=None, H=None):
295313
"""
296314
Calculates the manipulability Jacobian. This measure relates the rate
297315
of change of the manipulability to the joint velocities of the robot.
316+
One of J or q is required. Supply J and H if already calculated to
317+
save computation time
298318
299319
:param q: The joint coordinates of the robot
300320
:type q: float np.ndarray(n,)
321+
:param J: The manipulator Jacobian in any frame
322+
:type J: float np.ndarray(6,n)
323+
:param H: The manipulator Hessian in any frame
324+
:type H: float np.ndarray(6,n,n)
301325
:return: The manipulability Jacobian
302326
:rtype: float np.ndarray(n,1)
303327
304328
References: Maximising Manipulability in Resolved-Rate Motion Control,
305329
J. Haviland and P. Corke
306330
"""
307331

308-
if manipulability is None:
309-
manipulability = self.manipulability(q)
310-
311332
if J is None:
312-
J = self.jacob0(q)
333+
if q is not None:
334+
q = getvector(q, self.n)
335+
J = self.jacob0(q)
336+
else:
337+
raise ValueError('One of q or J must be supplied')
338+
# TODO: Check J
313339

314340
if H is None:
315-
H = self.hessian0(q)
341+
H = self.hessian0(J0=J)
342+
# TODO: Check H
316343

344+
manipulability = self.manipulability(J=J)
317345
b = np.linalg.inv(J @ np.transpose(J))
318346
Jm = np.zeros((self.n, 1))
319347

test/test_ets.py

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ def test_str_ets(self):
3838

3939
def test_fkine(self):
4040
panda = rp.Panda()
41-
q = np.array([1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9])
41+
q1 = np.array([1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9])
42+
q2 = [1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9]
43+
q3 = np.expand_dims(q1, 0)
44+
q4 = np.expand_dims(q1, 1)
4245

4346
ans = np.array([
4447
[-0.50827907, -0.57904589, 0.63746234, 0.44682295],
@@ -47,11 +50,17 @@ def test_fkine(self):
4750
[0., 0., 0., 1.]
4851
])
4952

50-
nt.assert_array_almost_equal(panda.fkine(q), ans)
53+
nt.assert_array_almost_equal(panda.fkine(q1), ans)
54+
nt.assert_array_almost_equal(panda.fkine(q2), ans)
55+
nt.assert_array_almost_equal(panda.fkine(q3), ans)
56+
nt.assert_array_almost_equal(panda.fkine(q3), ans)
5157

5258
def test_jacob0(self):
5359
panda = rp.Panda()
54-
q = np.array([1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9])
60+
q1 = np.array([1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9])
61+
q2 = [1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9]
62+
q3 = np.expand_dims(q1, 0)
63+
q4 = np.expand_dims(q1, 1)
5564

5665
ans = np.array([
5766
[-1.61683957e-01, 1.07925929e-01, -3.41453006e-02,
@@ -74,11 +83,17 @@ def test_jacob0(self):
7483
7.48247732e-01]
7584
])
7685

77-
nt.assert_array_almost_equal(panda.jacob0(q), ans)
86+
nt.assert_array_almost_equal(panda.jacob0(q1), ans)
87+
nt.assert_array_almost_equal(panda.jacob0(q2), ans)
88+
nt.assert_array_almost_equal(panda.jacob0(q3), ans)
89+
nt.assert_array_almost_equal(panda.jacob0(q4), ans)
7890

7991
def test_hessian0(self):
8092
panda = rp.Panda()
81-
q = np.array([1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9])
93+
q1 = np.array([1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9])
94+
q2 = [1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9]
95+
q3 = np.expand_dims(q1, 0)
96+
q4 = np.expand_dims(q1, 1)
8297

8398
ans = np.array([
8499
[
@@ -221,19 +236,39 @@ def test_hessian0(self):
221236
]
222237
])
223238

224-
nt.assert_array_almost_equal(panda.hessian0(q), ans)
239+
nt.assert_array_almost_equal(panda.hessian0(q1), ans)
240+
nt.assert_array_almost_equal(panda.hessian0(q2), ans)
241+
nt.assert_array_almost_equal(panda.hessian0(q3), ans)
242+
nt.assert_array_almost_equal(panda.hessian0(q4), ans)
243+
nt.assert_array_almost_equal(panda.hessian0(J0=panda.jacob0(q1)), ans)
244+
nt.assert_array_almost_equal(panda.hessian0(
245+
q1, J0=panda.jacob0(q1)), ans)
246+
self.assertRaises(ValueError, panda.hessian0)
247+
self.assertRaises(ValueError, panda.hessian0, [1, 3])
248+
self.assertRaises(TypeError, panda.hessian0, 'Wfgsrth')
225249

226250
def test_manipulability(self):
227251
panda = rp.Panda()
228-
q = np.array([1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9])
252+
q1 = np.array([1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9])
253+
q2 = [1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9]
254+
q3 = np.expand_dims(q1, 0)
255+
q4 = np.expand_dims(q1, 1)
229256

230257
ans = 0.006559178039088341
231258

232-
nt.assert_array_almost_equal(panda.manipulability(q), ans)
259+
nt.assert_array_almost_equal(panda.manipulability(q1), ans)
260+
nt.assert_array_almost_equal(panda.manipulability(q2), ans)
261+
nt.assert_array_almost_equal(panda.manipulability(q3), ans)
262+
nt.assert_array_almost_equal(panda.manipulability(q4), ans)
263+
self.assertRaises(ValueError, panda.manipulability)
264+
self.assertRaises(TypeError, panda.manipulability, 'Wfgsrth')
233265

234266
def test_jacobm(self):
235267
panda = rp.Panda()
236-
q = np.array([1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9])
268+
q1 = np.array([1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9])
269+
q2 = [1.4, 0.2, 1.8, 0.7, 0.1, 3.1, 2.9]
270+
q3 = np.expand_dims(q1, 0)
271+
q4 = np.expand_dims(q1, 1)
237272

238273
ans = np.array([
239274
[1.27080875e-17],
@@ -245,7 +280,12 @@ def test_jacobm(self):
245280
[0.00000000e+00]
246281
])
247282

248-
nt.assert_array_almost_equal(panda.jacobm(q), ans)
283+
nt.assert_array_almost_equal(panda.jacobm(q1), ans)
284+
nt.assert_array_almost_equal(panda.jacobm(q2), ans)
285+
nt.assert_array_almost_equal(panda.jacobm(q3), ans)
286+
nt.assert_array_almost_equal(panda.jacobm(q4), ans)
287+
self.assertRaises(ValueError, panda.jacobm)
288+
self.assertRaises(TypeError, panda.jacobm, 'Wfgsrth')
249289

250290

251291
if __name__ == '__main__':

0 commit comments

Comments
 (0)