@@ -190,7 +190,7 @@ def angle(theta, fmt=None):
190
190
Column ("dⱼ" , headalign = "^" ),
191
191
* qlim_columns ,
192
192
border = "thick"
193
- )
193
+ )
194
194
for j , L in enumerate (self ):
195
195
if has_qlim :
196
196
if L .isprismatic :
@@ -214,7 +214,7 @@ def angle(theta, fmt=None):
214
214
Column ("⍺ⱼ" , headalign = "^" ),
215
215
* qlim_columns ,
216
216
border = "thick"
217
- )
217
+ )
218
218
for j , L in enumerate (self ):
219
219
if has_qlim :
220
220
if L .isprismatic :
@@ -227,7 +227,8 @@ def angle(theta, fmt=None):
227
227
table .row (
228
228
angle (L .theta ), qstr (j , L ), f"{ L .a :.4g} " , angle (L .alpha ), * ql )
229
229
else :
230
- table .row (qstr (j , L ), f"{ L .d :.4g} " , f"{ L .a :.4g} " , angle (L .alpha ), * ql )
230
+ table .row (qstr (j , L ), f"{ L .d :.4g} " ,
231
+ f"{ L .a :.4g} " , angle (L .alpha ), * ql )
231
232
232
233
s += str (table )
233
234
@@ -302,6 +303,41 @@ def __add__(self, L):
302
303
303
304
# return new
304
305
306
+ # --------------------------------------------------------------------- #
307
+
308
+ def _set_link_fk (self , q ):
309
+ '''
310
+ robot._set_link_fk(q) evaluates fkine for each link within a
311
+ robot and stores that pose in a private variable within the link.
312
+
313
+ This method is not for general use.
314
+
315
+ :param q: The joint angles/configuration of the robot
316
+ :type q: float ndarray(n)
317
+
318
+ .. note::
319
+
320
+ - The robot's base transform, if present, are incorporated
321
+ into the result.
322
+ '''
323
+
324
+ q = getvector (q , self .n )
325
+
326
+ t = self .base
327
+
328
+ tall = self .fkine_all (q , old = True )
329
+
330
+ for i , link in enumerate (self .links ):
331
+
332
+ # Update the link model transforms
333
+ for col in link .collision :
334
+ col .wT = tall [i ]
335
+
336
+ for gi in link .geometry :
337
+ gi .wT = tall [i ]
338
+
339
+ # --------------------------------------------------------------------- #
340
+
305
341
@property
306
342
def mdh (self ):
307
343
"""
@@ -512,7 +548,7 @@ def nbranches(self):
512
548
:rtype: int
513
549
514
550
Number of branches in this robot.
515
-
551
+
516
552
Example:
517
553
518
554
.. runblock:: pycon
@@ -525,8 +561,6 @@ def nbranches(self):
525
561
"""
526
562
return 1
527
563
528
-
529
-
530
564
def A (self , j , q = None ):
531
565
"""
532
566
Link forward kinematics
@@ -631,7 +665,7 @@ def isspherical(self):
631
665
(L [0 ].alpha == alpha [0 ] and L [1 ].alpha == alpha [1 ])
632
666
or
633
667
(L [0 ].alpha == alpha [1 ] and L [1 ].alpha == alpha [0 ])
634
- ) \
668
+ ) \
635
669
and L [0 ].sigma == 0 \
636
670
and L [1 ].sigma == 0 \
637
671
and L [2 ].sigma == 0
@@ -900,7 +934,6 @@ def fkine_path(self, q, old=None):
900
934
901
935
return T
902
936
903
-
904
937
def segments (self ):
905
938
906
939
segments = [None ]
@@ -1114,26 +1147,25 @@ def jacob0(self, q=None, T=None, half=None, analytical=None, start=None, end=Non
1114
1147
elif analytical == 'exp' :
1115
1148
# TODO: move to SMTB.base, Horner form with skew(v)
1116
1149
(theta , v ) = trlog (t2r (T ))
1117
- A = np .eye (3 ,3 ) - (1 - math .cos (theta )) / theta * skew (v ) \
1150
+ A = np .eye (3 , 3 ) - (1 - math .cos (theta )) / theta * skew (v ) \
1118
1151
+ (theta - math .sin (theta )) / theta * skew (v )** 2
1119
1152
else :
1120
1153
raise ValueError ('bad order specified' )
1121
-
1122
- J0 = block_diag (np .eye (3 ,3 ), np .linalg .inv (A )) @ J0
1154
+
1155
+ J0 = block_diag (np .eye (3 , 3 ), np .linalg .inv (A )) @ J0
1123
1156
1124
1157
# TODO optimize computation above if half matrix is returned
1125
1158
1126
1159
# return top or bottom half if asked
1127
1160
if half is not None :
1128
1161
if half == 'trans' :
1129
- J0 = J0 [:3 ,:]
1162
+ J0 = J0 [:3 , :]
1130
1163
elif half == 'rot' :
1131
- J0 = J0 [3 :,:]
1164
+ J0 = J0 [3 :, :]
1132
1165
else :
1133
1166
raise ValueError ('bad half specified' )
1134
1167
return J0
1135
1168
1136
-
1137
1169
def hessian0 (self , q = None , J0 = None , start = None , end = None ):
1138
1170
r"""
1139
1171
Manipulator Hessian in base frame
@@ -1162,14 +1194,14 @@ def hessian0(self, q=None, J0=None, start=None, end=None):
1162
1194
.. math::
1163
1195
1164
1196
\dmat{J} = \mat{H} \dvec{q}
1165
-
1197
+
1166
1198
and :math:`\mat{H} \in \mathbb{R}^{6\times n \times n}` is the
1167
1199
Hessian tensor.
1168
1200
1169
1201
The elements of the Hessian are
1170
1202
1171
1203
.. math::
1172
-
1204
+
1173
1205
\mat{H}_{i,j,k} = \frac{d^2 u_i}{d q_j d q_k}
1174
1206
1175
1207
where :math:`u = \{t_x, t_y, t_z, r_x, r_y, r_z\}` are the elements
@@ -1178,7 +1210,7 @@ def hessian0(self, q=None, J0=None, start=None, end=None):
1178
1210
Similarly, we can write
1179
1211
1180
1212
.. math::
1181
-
1213
+
1182
1214
\mat{J}_{i,j} = \frac{d u_i}{d q_j}
1183
1215
1184
1216
:references:
@@ -1489,7 +1521,7 @@ def removesmall(x):
1489
1521
_cross (wd , pstar )
1490
1522
+ _cross (w , _cross (w , pstar ))
1491
1523
+ vd
1492
- ) \
1524
+ ) \
1493
1525
+ 2 * _cross (Rt @ w , z0 * qd_k [j ]) \
1494
1526
+ z0 * qdd_k [j ]
1495
1527
# trailing underscore means new value, update here
@@ -1734,6 +1766,8 @@ def config_validate(self, config, allowables):
1734
1766
if all ([a not in config for a in allowable ]):
1735
1767
config += allowable [0 ]
1736
1768
return config
1769
+
1770
+
1737
1771
class SerialLink (DHRobot ):
1738
1772
def __init__ (self , * args , ** kwargs ):
1739
1773
warnings .warn (
0 commit comments