00001 from urdf_parser_py.xml_reflection.basics import *
00002 import urdf_parser_py.xml_reflection as xmlr
00003
00004
00005
00006
00007
00008 xmlr.start_namespace('urdf')
00009
00010 xmlr.add_type('element_link', xmlr.SimpleElementType('link', str))
00011 xmlr.add_type('element_xyz', xmlr.SimpleElementType('xyz', 'vector3'))
00012
00013 verbose = True
00014
00015 class Pose(xmlr.Object):
00016 def __init__(self, xyz=None, rpy=None):
00017 self.xyz = xyz
00018 self.rpy = rpy
00019
00020 def check_valid(self):
00021 assert self.xyz is not None or self.rpy is not None
00022
00023
00024 @property
00025 def rotation(self): return self.rpy
00026 @rotation.setter
00027 def rotation(self, value): self.rpy = value
00028 @property
00029 def position(self): return self.xyz
00030 @position.setter
00031 def position(self, value): self.xyz = value
00032
00033 xmlr.reflect(Pose, params = [
00034 xmlr.Attribute('xyz', 'vector3', False),
00035 xmlr.Attribute('rpy', 'vector3', False)
00036 ])
00037
00038
00039
00040 name_attribute = xmlr.Attribute('name', str)
00041 origin_element = xmlr.Element('origin', Pose, False)
00042
00043 class Color(xmlr.Object):
00044 def __init__(self, *args):
00045
00046 count = len(args)
00047 if count == 4 or count == 3:
00048 self.rgba = args
00049 elif count == 1:
00050 self.rgba = args[0]
00051 elif count == 0:
00052 self.rgba = None
00053 if self.rgba is not None:
00054 if len(self.rgba) == 3:
00055 self.rgba += [1.]
00056 if len(self.rgba) != 4:
00057 raise Exception('Invalid color argument count')
00058
00059 xmlr.reflect(Color, params = [
00060 xmlr.Attribute('rgba', 'vector4')
00061 ])
00062
00063
00064 class JointDynamics(xmlr.Object):
00065 def __init__(self, damping=None, friction=None):
00066 self.damping = damping
00067 self.friction = friction
00068
00069 xmlr.reflect(JointDynamics, params = [
00070 xmlr.Attribute('damping', float, False),
00071 xmlr.Attribute('friction', float, False)
00072 ])
00073
00074
00075 class Box(xmlr.Object):
00076 def __init__(self, size = None):
00077 self.size = size
00078
00079 xmlr.reflect(Box, params = [
00080 xmlr.Attribute('size', 'vector3')
00081 ])
00082
00083
00084 class Cylinder(xmlr.Object):
00085 def __init__(self, radius = 0.0, length = 0.0):
00086 self.radius = radius
00087 self.length = length
00088
00089 xmlr.reflect(Cylinder, params = [
00090 xmlr.Attribute('radius', float),
00091 xmlr.Attribute('length', float)
00092 ])
00093
00094
00095 class Sphere(xmlr.Object):
00096 def __init__(self, radius=0.0):
00097 self.radius = radius
00098
00099 xmlr.reflect(Sphere, params = [
00100 xmlr.Attribute('radius', float)
00101 ])
00102
00103
00104 class Mesh(xmlr.Object):
00105 def __init__(self, filename = None, scale = None):
00106 self.filename = filename
00107 self.scale = scale
00108
00109 xmlr.reflect(Mesh, params = [
00110 xmlr.Attribute('filename', str),
00111 xmlr.Attribute('scale', 'vector3', required=False)
00112 ])
00113
00114
00115 class GeometricType(xmlr.ValueType):
00116 def __init__(self):
00117 self.factory = xmlr.FactoryType('geometric', {
00118 'box': Box,
00119 'cylinder': Cylinder,
00120 'sphere': Sphere,
00121 'mesh': Mesh
00122 })
00123
00124 def from_xml(self, node):
00125 children = xml_children(node)
00126 assert len(children) == 1, 'One element only for geometric'
00127 return self.factory.from_xml(children[0])
00128
00129 def write_xml(self, node, obj):
00130 name = self.factory.get_name(obj)
00131 child = node_add(node, name)
00132 obj.write_xml(child)
00133
00134 xmlr.add_type('geometric', GeometricType())
00135
00136 class Collision(xmlr.Object):
00137 def __init__(self, geometry = None, origin = None):
00138 self.geometry = geometry
00139 self.origin = origin
00140
00141 xmlr.reflect(Collision, params = [
00142 origin_element,
00143 xmlr.Element('geometry', 'geometric')
00144 ])
00145
00146
00147 class Texture(xmlr.Object):
00148 def __init__(self, filename = None):
00149 self.filename = filename
00150
00151 xmlr.reflect(Texture, params = [
00152 xmlr.Attribute('filename', str)
00153 ])
00154
00155
00156 class Material(xmlr.Object):
00157 def __init__(self, name=None, color=None, texture=None):
00158 self.name = name
00159 self.color = color
00160 self.texture = texture
00161
00162 def check_valid(self):
00163 if self.color is None and self.texture is None:
00164 xmlr.on_error("Material has neither a color nor texture")
00165
00166 xmlr.reflect(Material, params = [
00167 name_attribute,
00168 xmlr.Element('color', Color, False),
00169 xmlr.Element('texture', Texture, False)
00170 ])
00171
00172
00173 class Visual(xmlr.Object):
00174 def __init__(self, geometry = None, material = None, origin = None):
00175 self.geometry = geometry
00176 self.material = material
00177 self.origin = origin
00178
00179 xmlr.reflect(Visual, params = [
00180 origin_element,
00181 xmlr.Element('geometry', 'geometric'),
00182 xmlr.Element('material', Material, False)
00183 ])
00184
00185
00186 class Inertia(xmlr.Object):
00187 KEYS = ['ixx', 'ixy', 'ixz', 'iyy', 'iyz', 'izz']
00188
00189 def __init__(self, ixx=0.0, ixy=0.0, ixz=0.0, iyy=0.0, iyz=0.0, izz=0.0):
00190 self.ixx = ixx
00191 self.ixy = ixy
00192 self.ixz = ixz
00193 self.iyy = iyy
00194 self.iyz = iyz
00195 self.izz = izz
00196
00197 def to_matrix(self):
00198 return [
00199 [self.ixx, self.ixy, self.ixz],
00200 [self.ixy, self.iyy, self.iyz],
00201 [self.ixz, self.iyz, self.izz]]
00202
00203 xmlr.reflect(Inertia, params = [xmlr.Attribute(key, float) for key in Inertia.KEYS])
00204
00205
00206 class Inertial(xmlr.Object):
00207 def __init__(self, mass = 0.0, inertia = None, origin=None):
00208 self.mass = mass
00209 self.inertia = inertia
00210 self.origin = origin
00211
00212 xmlr.reflect(Inertial, params = [
00213 origin_element,
00214 xmlr.Element('mass', 'element_value'),
00215 xmlr.Element('inertia', Inertia, False)
00216 ])
00217
00218
00219
00220
00221 class JointCalibration(xmlr.Object):
00222 def __init__(self, rising=None, falling=None):
00223 self.rising = rising
00224 self.falling = falling
00225
00226 xmlr.reflect(JointCalibration, params = [
00227 xmlr.Attribute('rising', float, False),
00228 xmlr.Attribute('falling', float, False)
00229 ])
00230
00231 class JointLimit(xmlr.Object):
00232 def __init__(self, effort=None, velocity=None, lower=None, upper=None):
00233 self.effort = effort
00234 self.velocity = velocity
00235 self.lower = lower
00236 self.upper = upper
00237
00238 xmlr.reflect(JointLimit, params = [
00239 xmlr.Attribute('effort', float),
00240 xmlr.Attribute('lower', float, False, 0),
00241 xmlr.Attribute('upper', float, False, 0),
00242 xmlr.Attribute('velocity', float)
00243 ])
00244
00245
00246 class JointMimic(xmlr.Object):
00247 def __init__(self, joint_name=None, multiplier=None, offset=None):
00248 self.joint = joint_name
00249 self.multiplier = multiplier
00250 self.offset = offset
00251
00252 xmlr.reflect(JointMimic, params = [
00253 xmlr.Attribute('joint', str),
00254 xmlr.Attribute('multiplier', float, False),
00255 xmlr.Attribute('offset', float, False)
00256 ])
00257
00258 class SafetyController(xmlr.Object):
00259 def __init__(self, velocity=None, position=None, lower=None, upper=None):
00260 self.k_velocity = velocity
00261 self.k_position = position
00262 self.soft_lower_limit = lower
00263 self.soft_upper_limit = upper
00264
00265 xmlr.reflect(SafetyController, params = [
00266 xmlr.Attribute('k_velocity', float),
00267 xmlr.Attribute('k_position', float, False, 0),
00268 xmlr.Attribute('soft_lower_limit', float, False, 0),
00269 xmlr.Attribute('soft_upper_limit', float, False, 0)
00270 ])
00271
00272 class Joint(xmlr.Object):
00273 TYPES = ['unknown', 'revolute', 'continuous', 'prismatic', 'floating', 'planar', 'fixed']
00274
00275 def __init__(self, name=None, parent=None, child=None, joint_type=None,
00276 axis=None, origin=None,
00277 limit=None, dynamics=None, safety_controller=None, calibration=None,
00278 mimic=None):
00279 self.name = name
00280 self.parent = parent
00281 self.child = child
00282 self.type = joint_type
00283 self.axis = axis
00284 self.origin = origin
00285 self.limit = limit
00286 self.dynamics = dynamics
00287 self.safety_controller = safety_controller
00288 self.calibration = calibration
00289 self.mimic = mimic
00290
00291 def check_valid(self):
00292 assert self.type in self.TYPES, "Invalid joint type: {}".format(self.type)
00293
00294
00295 @property
00296 def joint_type(self): return self.type
00297 @joint_type.setter
00298 def joint_type(self, value): self.type = value
00299
00300 xmlr.reflect(Joint, params = [
00301 name_attribute,
00302 xmlr.Attribute('type', str),
00303 origin_element,
00304 xmlr.Element('axis', 'element_xyz', False),
00305 xmlr.Element('parent', 'element_link'),
00306 xmlr.Element('child', 'element_link'),
00307 xmlr.Element('limit', JointLimit, False),
00308 xmlr.Element('dynamics', JointDynamics, False),
00309 xmlr.Element('safety_controller', SafetyController, False),
00310 xmlr.Element('calibration', JointCalibration, False),
00311 xmlr.Element('mimic', JointMimic, False)
00312 ])
00313
00314
00315 class Link(xmlr.Object):
00316 def __init__(self, name=None, visual=None, inertial=None, collision=None, origin = None):
00317 self.name = name
00318 self.visual = visual
00319 self.inertial = inertial
00320 self.collision = collision
00321 self.origin = origin
00322
00323 xmlr.reflect(Link, params = [
00324 name_attribute,
00325 origin_element,
00326 xmlr.Element('inertial', Inertial, False),
00327 xmlr.Element('visual', Visual, False),
00328 xmlr.Element('collision', Collision, False)
00329 ])
00330
00331
00332 class Actuator(xmlr.Object):
00333 def __init__(self, name = None, hardwareInterface = None, mechanicalReduction = 1):
00334 self.name = name
00335 self.hardwareInterface = None
00336 self.mechanicalReduction = None
00337
00338 xmlr.reflect(Actuator, tag = 'actuator', params = [
00339 name_attribute,
00340 xmlr.Element('hardwareInterface', str),
00341 xmlr.Element('mechanicalReduction', float, required = False)
00342 ])
00343
00344 class Transmission(xmlr.Object):
00345 def __init__(self, name = None, joint = None, actuator = None):
00346 self.name = name
00347 self.joint = joint
00348 self.actuator = actuator
00349
00350 xmlr.reflect(Transmission, tag = 'new_transmission', params = [
00351 name_attribute,
00352 xmlr.Attribute('type', str),
00353 xmlr.Element('joint', 'element_name'),
00354 xmlr.Element('actuator', Actuator),
00355 ])
00356
00357 class PR2Compensator(xmlr.Object):
00358 def __init__(self, k_belt=4000.0, kd_motor=10.0, lambda_combined=0.0, lambda_joint=60.0, lambda_motor=60.0, mass_motor=0.05):
00359 self.k_belt = k_belt
00360 self.kd_motor = kd_motor
00361 self.lambda_combined = lambda_combined
00362 self.lambda_joint = lambda_joint
00363 self.lambda_motor = lambda_motor
00364 self.mass_motor = mass_motor
00365
00366 xmlr.reflect(PR2Compensator, tag = 'compensator', params = [
00367 xmlr.Attribute('k_belt', float),
00368 xmlr.Attribute('kd_motor', float),
00369 xmlr.Attribute('lambda_combined', float),
00370 xmlr.Attribute('lambda_joint', float),
00371 xmlr.Attribute('lambda_motor', float),
00372 xmlr.Attribute('mass_motor', float)
00373 ])
00374
00375 class PR2SimulatedActuatedJoint(xmlr.Object):
00376 def __init__(self, name = None, simulated_reduction = 3000, passive_actuated_joint = None):
00377 self.name = name
00378 self.simulated_reduction = simulated_reduction
00379 self.passive_actuated_joint = passive_actuated_joint
00380
00381 xmlr.reflect(PR2SimulatedActuatedJoint, tag = 'simulated_actuated_joint', params = [
00382 name_attribute,
00383 xmlr.Attribute('simulated_reduction', float),
00384 xmlr.Attribute('passive_actuated_joint', str, False)
00385 ])
00386
00387 class PR2Transmission(xmlr.Object):
00388 def __init__(self, name = None, joint = None, actuator = None, mechanicalReduction = None, compensator = None, simulated_actuated_joint = None):
00389 self.name = name
00390 self.joint = joint
00391 self.actuator = actuator
00392 self.mechanicalReduction = mechanicalReduction
00393 self.compensator = compensator
00394 self.simulated_actuated_joint = simulated_actuated_joint
00395
00396 xmlr.reflect(PR2Transmission, tag = 'pr2_transmission', params = [
00397 name_attribute,
00398 xmlr.Attribute('type', str),
00399 xmlr.Element('joint', 'element_name'),
00400 xmlr.Element('actuator', 'element_name'),
00401 xmlr.Element('mechanicalReduction', float),
00402 xmlr.Element('compensator', PR2Compensator, False),
00403 xmlr.Element('simulated_actuated_joint', PR2SimulatedActuatedJoint, False)
00404 ])
00405
00406 class PR2Actuator(xmlr.Object):
00407 def __init__(self, name = None, mechanicalReduction = 1):
00408 self.name = name
00409 self.mechanicalReduction = mechanicalReduction
00410
00411 xmlr.reflect(PR2Actuator, tag = 'pr2_actuator', params = [
00412 name_attribute,
00413 xmlr.Attribute('mechanicalReduction', float)
00414 ])
00415
00416 class PR2WristTransmission(xmlr.Object):
00417 def __init__(self, name = None, type = None, rightActuator = None, leftActuator = None, flexJoint = None, rollJoint = None):
00418 self.name = name
00419 self.type = type
00420 self.rightActuator = rightActuator
00421 self.leftActuator = leftActuator
00422 self.flexJoint = flexJoint
00423 self.rollJoint = rollJoint
00424
00425 xmlr.reflect(PR2WristTransmission, tag = 'pr2_wrist_transmission', params = [
00426 name_attribute,
00427 xmlr.Attribute('type', str),
00428 xmlr.Element('rightActuator', PR2Actuator),
00429 xmlr.Element('leftActuator', PR2Actuator),
00430 xmlr.Element('flexJoint', PR2Actuator),
00431 xmlr.Element('rollJoint', PR2Actuator)
00432 ])
00433
00434
00435 class PR2GapJoint(xmlr.Object):
00436 def __init__(self, L0=0.0, a=0.0, b=0.0, gear_ratio=40.0, h=0.0, mechanical_reduction=1.0, name=None, phi0=0.5, r=0.0, screw_reduction=0.0, t0=0.0, theta0=0.0):
00437 self.L0 = L0
00438 self.a = a
00439 self.b = b
00440 self.gear_ratio = gear_ratio
00441 self.h = h
00442 self.mechanical_reduction = mechanical_reduction
00443 self.name = name
00444 self.phi0 = phi0
00445 self.r = r
00446 self.screw_reduction = screw_reduction
00447 self.t0 = t0
00448 self.theta0 = theta0
00449
00450 xmlr.reflect(PR2GapJoint, tag = 'pr2_gap_joint', params = [
00451 xmlr.Attribute('L0', float),
00452 xmlr.Attribute('a', float),
00453 xmlr.Attribute('b', float),
00454 xmlr.Attribute('gear_ratio', float),
00455 xmlr.Attribute('h', float),
00456 xmlr.Attribute('mechanical_reduction', float),
00457 xmlr.Attribute('name', str),
00458 xmlr.Attribute('phi0', float),
00459 xmlr.Attribute('r', float),
00460 xmlr.Attribute('screw_reduction', float),
00461 xmlr.Attribute('t0', float),
00462 xmlr.Attribute('theta0', float)
00463 ])
00464
00465 class PR2GripperTransmission(xmlr.Object):
00466 def __init__(self, name = None, type = None, actuator = None, gap_joint = None, use_simulated_gripper_joint = None, passive_joint = [], simulated_actuated_joint = None):
00467 self.aggregate_init()
00468 self.name = name
00469 self.type = type
00470 self.actuator = actuator
00471 self.gap_joint = gap_joint
00472 self.use_simulated_gripper_joint = use_simulated_gripper_joint
00473 self.passive_joint = passive_joint
00474 self.simulated_actuated_joint = simulated_actuated_joint
00475
00476 xmlr.reflect(PR2GripperTransmission, tag = 'pr2_gripper_transmission', params = [
00477 name_attribute,
00478 xmlr.Attribute('type', str),
00479 xmlr.Element('actuator', 'element_name'),
00480 xmlr.Element('gap_joint', PR2GapJoint),
00481 xmlr.Element('use_simulated_gripper_joint', 'element_name'),
00482 xmlr.AggregateElement('passive_joint', 'element_name', 'passive_joint'),
00483 xmlr.Element('simulated_actuated_joint', PR2SimulatedActuatedJoint),
00484 ])
00485
00486
00487 xmlr.add_type('transmission', xmlr.DuckTypedFactory('transmission', [Transmission, PR2Transmission, PR2WristTransmission, PR2GripperTransmission]))
00488
00489
00490 class Robot(xmlr.Object):
00491 def __init__(self, name = None):
00492 self.aggregate_init()
00493
00494 self.name = name
00495 self.joints = []
00496 self.links = []
00497 self.materials = []
00498 self.gazebos = []
00499 self.transmissions = []
00500
00501 self.joint_map = {}
00502 self.link_map = {}
00503
00504 self.parent_map = {}
00505 self.child_map = {}
00506
00507 def add_aggregate(self, typeName, elem):
00508 xmlr.Object.add_aggregate(self, typeName, elem)
00509
00510 if typeName == 'joint':
00511 joint = elem
00512 self.joint_map[joint.name] = joint
00513 self.parent_map[ joint.child ] = (joint.name, joint.parent)
00514 if joint.parent in self.child_map:
00515 self.child_map[joint.parent].append( (joint.name, joint.child) )
00516 else:
00517 self.child_map[joint.parent] = [ (joint.name, joint.child) ]
00518 elif typeName == 'link':
00519 link = elem
00520 self.link_map[link.name] = link
00521
00522 def add_link(self, link):
00523 self.add_aggregate('link', link)
00524
00525 def add_joint(self, joint):
00526 self.add_aggregate('joint', joint)
00527
00528 def get_chain(self, root, tip, joints=True, links=True, fixed=True):
00529 chain = []
00530 if links:
00531 chain.append(tip)
00532 link = tip
00533 while link != root:
00534 (joint, parent) = self.parent_map[link]
00535 if joints:
00536 if fixed or self.joint_map[joint].joint_type != 'fixed':
00537 chain.append(joint)
00538 if links:
00539 chain.append(parent)
00540 link = parent
00541 chain.reverse()
00542 return chain
00543
00544 def get_root(self):
00545 root = None
00546 for link in self.link_map:
00547 if link not in self.parent_map:
00548 assert root is None, "Multiple roots detected, invalid URDF."
00549 root = link
00550 assert root is not None, "No roots detected, invalid URDF."
00551 return root
00552
00553 @classmethod
00554 def from_parameter_server(cls, key = 'robot_description'):
00555 """
00556 Retrieve the robot model on the parameter server
00557 and parse it to create a URDF robot structure.
00558
00559 Warning: this requires roscore to be running.
00560 """
00561
00562 import rospy
00563 return cls.from_xml_string(rospy.get_param(key))
00564
00565 xmlr.reflect(Robot, tag = 'robot', params = [
00566
00567 xmlr.Attribute('name', str, False),
00568 xmlr.AggregateElement('link', Link),
00569 xmlr.AggregateElement('joint', Joint),
00570 xmlr.AggregateElement('gazebo', xmlr.RawType()),
00571 xmlr.AggregateElement('transmission', 'transmission'),
00572 xmlr.AggregateElement('material', Material)
00573 ])
00574
00575
00576 URDF = Robot
00577
00578 xmlr.end_namespace()