@@ -287,42 +287,72 @@ def visit_link(link, jindex):
287
287
288
288
super ().__init__ (orlinks , ** kwargs )
289
289
290
- # Cached paths through links
291
- # TODO Add listners on setters to reset cache
292
- self ._reset_cache ()
293
290
294
- @ classmethod
295
- def URDF ( cls , file_path , gripper = None ):
291
+
292
+ def __str__ ( self ):
296
293
"""
297
- Construct an ERobot object from URDF file
294
+ Pretty prints the ETS Model of the robot.
298
295
299
- :param file_path: [description]
300
- :type file_path: [type]
301
- :param gripper: index or name of the gripper link
302
- :type gripper: int or str
303
- :return: [description]
304
- :rtype: [type]
296
+ :return: Pretty print of the robot model
297
+ :rtype: str
305
298
306
- If ``gripper`` is specified, links from that link outward are removed
307
- from the rigid-body tree and folded into a ``Gripper`` object.
299
+ .. note::
300
+ - Constant links are shown in blue.
301
+ - End-effector links are prefixed with an @
302
+ - Angles in degrees
303
+ - The robot base frame is denoted as ``BASE`` and is equal to the
304
+ robot's ``base`` attribute.
308
305
"""
309
- links , name = ERobot .URDF_read (file_path )
306
+ table = ANSITable (
307
+ Column ("id" , headalign = "^" , colalign = ">" ),
308
+ Column ("link" , headalign = "^" , colalign = "<" ),
309
+ Column ("joint" , headalign = "^" , colalign = ">" ),
310
+ Column ("parent" , headalign = "^" , colalign = "<" ),
311
+ Column ("ETS" , headalign = "^" , colalign = "<" ),
312
+ border = "thin" )
313
+ for k , link in enumerate (self ):
314
+ color = "" if link .isjoint else "<<blue>>"
315
+ ee = "@" if link in self .ee_links else ""
316
+ ets = link .ets ()
317
+ if link .parent is None :
318
+ parent_name = "BASE"
319
+ else :
320
+ parent_name = link .parent .name
321
+ s = ets .__str__ (f"q{ link ._jindex } " )
322
+ if len (s ) > 0 :
323
+ s = " \u2295 " + s
310
324
311
- if gripper is not None :
312
- if isinstance (gripper , int ):
313
- gripper = links [gripper ]
314
- elif ininstance (gripper , str ):
315
- for link in links :
316
- if link .name == gripper :
317
- gripper = link
318
- break
325
+ if link .isjoint :
326
+ if link ._joint_name is not None :
327
+ jname = link ._joint_name
319
328
else :
320
- raise ValueError ( f"no link named { gripper } " )
329
+ jname = link . jindex
321
330
else :
322
- raise TypeError ('bad argument passed as gripper' )
323
-
324
-
325
- return cls (links , name = name , gripper = gripper )
331
+ jname = ''
332
+ table .row (
333
+ k ,
334
+ color + ee + link .name ,
335
+ jname ,
336
+ parent_name ,
337
+ f"{{{ link .name } }} = {{{ parent_name } }}{ s } "
338
+ )
339
+
340
+ s = f"{ self .__class__ .__name__ } : { self .name } "
341
+ if self .manufacturer is not None and len (self .manufacturer ) > 0 :
342
+ s += f" (by { self .manufacturer } )"
343
+ s += f", { self .n } joints ({ self .structure } )"
344
+ if self .nbranches > 1 :
345
+ s += f", { self .nbranches } branches"
346
+ if self ._hasdynamics :
347
+ s += ", dynamics"
348
+ if any ([len (link .geometry ) > 0 for link in self .links ]):
349
+ s += ", geometry"
350
+ if any ([len (link .collision ) > 0 for link in self .links ]):
351
+ s += ", collision"
352
+ s += "\n "
353
+
354
+ s += str (table )
355
+ s += self .configurations_str ()
326
356
327
357
def _reset_cache (self ):
328
358
self ._path_cache = {}
0 commit comments