mirror of
https://github.com/bulletphysics/bullet3
synced 2024-12-15 14:10:11 +00:00
ef9570c315
This recreates pull request #2192
641 lines
26 KiB
Python
641 lines
26 KiB
Python
import pybullet as p
|
|
import time
|
|
|
|
|
|
class UrdfInertial(object):
|
|
|
|
def __init__(self):
|
|
self.mass = 1
|
|
self.inertia_xxyyzz = [7, 8, 9]
|
|
self.origin_rpy = [1, 2, 3]
|
|
self.origin_xyz = [4, 5, 6]
|
|
|
|
|
|
class UrdfContact(object):
|
|
|
|
def __init__(self):
|
|
self.lateral_friction = 1
|
|
self.rolling_friction = 0
|
|
self.spinning_friction = 0
|
|
|
|
|
|
class UrdfLink(object):
|
|
|
|
def __init__(self):
|
|
self.link_name = "dummy"
|
|
self.urdf_inertial = UrdfInertial()
|
|
self.urdf_visual_shapes = []
|
|
self.urdf_collision_shapes = []
|
|
|
|
|
|
class UrdfVisual(object):
|
|
|
|
def __init__(self):
|
|
self.origin_rpy = [1, 2, 3]
|
|
self.origin_xyz = [4, 5, 6]
|
|
self.geom_type = p.GEOM_BOX
|
|
self.geom_radius = 1
|
|
self.geom_extents = [7, 8, 9]
|
|
self.geom_length = 10
|
|
self.geom_meshfilename = "meshfile"
|
|
self.geom_meshscale = [1, 1, 1]
|
|
self.material_rgba = [1, 0, 0, 1]
|
|
self.material_name = ""
|
|
|
|
|
|
class UrdfCollision(object):
|
|
|
|
def __init__(self):
|
|
self.origin_rpy = [1, 2, 3]
|
|
self.origin_xyz = [4, 5, 6]
|
|
self.geom_type = p.GEOM_BOX
|
|
self.geom_radius = 1
|
|
self.geom_length = 2
|
|
self.geom_extents = [7, 8, 9]
|
|
self.geom_meshfilename = "meshfile"
|
|
self.geom_meshscale = [1, 1, 1]
|
|
|
|
|
|
class UrdfJoint(object):
|
|
|
|
def __init__(self):
|
|
self.link = UrdfLink()
|
|
self.joint_name = "joint_dummy"
|
|
self.joint_type = p.JOINT_REVOLUTE
|
|
self.joint_lower_limit = 0
|
|
self.joint_upper_limit = -1
|
|
self.parent_name = "parentName"
|
|
self.child_name = "childName"
|
|
self.joint_origin_xyz = [1, 2, 3]
|
|
self.joint_origin_rpy = [1, 2, 3]
|
|
self.joint_axis_xyz = [1, 2, 3]
|
|
|
|
|
|
class UrdfEditor(object):
|
|
|
|
def __init__(self):
|
|
self.initialize()
|
|
|
|
def initialize(self):
|
|
self.urdfLinks = []
|
|
self.urdfJoints = []
|
|
self.robotName = ""
|
|
self.linkNameToIndex = {}
|
|
self.jointTypeToName={p.JOINT_FIXED: "JOINT_FIXED" ,\
|
|
p.JOINT_REVOLUTE: "JOINT_REVOLUTE",\
|
|
p.JOINT_PRISMATIC: "JOINT_PRISMATIC" }
|
|
|
|
def convertLinkFromMultiBody(self, bodyUid, linkIndex, urdfLink, physicsClientId):
|
|
dyn = p.getDynamicsInfo(bodyUid, linkIndex, physicsClientId=physicsClientId)
|
|
urdfLink.urdf_inertial.mass = dyn[0]
|
|
urdfLink.urdf_inertial.inertia_xxyyzz = dyn[2]
|
|
#todo
|
|
urdfLink.urdf_inertial.origin_xyz = dyn[3]
|
|
rpy = p.getEulerFromQuaternion(dyn[4])
|
|
urdfLink.urdf_inertial.origin_rpy = rpy
|
|
|
|
visualShapes = p.getVisualShapeData(bodyUid, physicsClientId=physicsClientId)
|
|
matIndex = 0
|
|
for v in visualShapes:
|
|
if (v[1] == linkIndex):
|
|
urdfVisual = UrdfVisual()
|
|
urdfVisual.geom_type = v[2]
|
|
if (v[2] == p.GEOM_BOX):
|
|
urdfVisual.geom_extents = v[3]
|
|
if (v[2] == p.GEOM_SPHERE):
|
|
urdfVisual.geom_radius = v[3][0]
|
|
if (v[2] == p.GEOM_MESH):
|
|
urdfVisual.geom_meshfilename = v[4].decode("utf-8")
|
|
urdfVisual.geom_meshscale = v[3]
|
|
if (v[2] == p.GEOM_CYLINDER):
|
|
urdfVisual.geom_length = v[3][0]
|
|
urdfVisual.geom_radius = v[3][1]
|
|
if (v[2] == p.GEOM_CAPSULE):
|
|
urdfVisual.geom_length = v[3][0]
|
|
urdfVisual.geom_radius = v[3][1]
|
|
urdfVisual.origin_xyz = v[5]
|
|
urdfVisual.origin_rpy = p.getEulerFromQuaternion(v[6])
|
|
urdfVisual.material_rgba = v[7]
|
|
name = 'mat_{}_{}'.format(linkIndex, matIndex)
|
|
urdfVisual.material_name = name
|
|
urdfLink.urdf_visual_shapes.append(urdfVisual)
|
|
matIndex = matIndex + 1
|
|
|
|
collisionShapes = p.getCollisionShapeData(bodyUid, linkIndex, physicsClientId=physicsClientId)
|
|
for v in collisionShapes:
|
|
urdfCollision = UrdfCollision()
|
|
urdfCollision.geom_type = v[2]
|
|
if (v[2] == p.GEOM_BOX):
|
|
urdfCollision.geom_extents = v[3]
|
|
if (v[2] == p.GEOM_SPHERE):
|
|
urdfCollision.geom_radius = v[3][0]
|
|
if (v[2] == p.GEOM_MESH):
|
|
urdfCollision.geom_meshfilename = v[4].decode("utf-8")
|
|
urdfCollision.geom_meshscale = v[3]
|
|
if (v[2] == p.GEOM_CYLINDER):
|
|
urdfCollision.geom_length = v[3][0]
|
|
urdfCollision.geom_radius = v[3][1]
|
|
if (v[2] == p.GEOM_CAPSULE):
|
|
urdfCollision.geom_length = v[3][0]
|
|
urdfCollision.geom_radius = v[3][1]
|
|
pos,orn = p.multiplyTransforms(dyn[3],dyn[4],\
|
|
v[5], v[6])
|
|
urdfCollision.origin_xyz = pos
|
|
urdfCollision.origin_rpy = p.getEulerFromQuaternion(orn)
|
|
urdfLink.urdf_collision_shapes.append(urdfCollision)
|
|
|
|
def initializeFromBulletBody(self, bodyUid, physicsClientId):
|
|
self.initialize()
|
|
|
|
#always create a base link
|
|
baseLink = UrdfLink()
|
|
baseLinkIndex = -1
|
|
self.convertLinkFromMultiBody(bodyUid, baseLinkIndex, baseLink, physicsClientId)
|
|
baseLink.link_name = p.getBodyInfo(bodyUid, physicsClientId=physicsClientId)[0].decode("utf-8")
|
|
self.linkNameToIndex[baseLink.link_name] = len(self.urdfLinks)
|
|
self.urdfLinks.append(baseLink)
|
|
|
|
#optionally create child links and joints
|
|
for j in range(p.getNumJoints(bodyUid, physicsClientId=physicsClientId)):
|
|
jointInfo = p.getJointInfo(bodyUid, j, physicsClientId=physicsClientId)
|
|
urdfLink = UrdfLink()
|
|
self.convertLinkFromMultiBody(bodyUid, j, urdfLink, physicsClientId)
|
|
urdfLink.link_name = jointInfo[12].decode("utf-8")
|
|
self.linkNameToIndex[urdfLink.link_name] = len(self.urdfLinks)
|
|
self.urdfLinks.append(urdfLink)
|
|
|
|
urdfJoint = UrdfJoint()
|
|
urdfJoint.link = urdfLink
|
|
urdfJoint.joint_name = jointInfo[1].decode("utf-8")
|
|
urdfJoint.joint_type = jointInfo[2]
|
|
urdfJoint.joint_axis_xyz = jointInfo[13]
|
|
orgParentIndex = jointInfo[16]
|
|
if (orgParentIndex < 0):
|
|
urdfJoint.parent_name = baseLink.link_name
|
|
else:
|
|
parentJointInfo = p.getJointInfo(bodyUid, orgParentIndex, physicsClientId=physicsClientId)
|
|
urdfJoint.parent_name = parentJointInfo[12].decode("utf-8")
|
|
urdfJoint.child_name = urdfLink.link_name
|
|
|
|
#todo, compensate for inertia/link frame offset
|
|
|
|
dynChild = p.getDynamicsInfo(bodyUid, j, physicsClientId=physicsClientId)
|
|
childInertiaPos = dynChild[3]
|
|
childInertiaOrn = dynChild[4]
|
|
parentCom2JointPos = jointInfo[14]
|
|
parentCom2JointOrn = jointInfo[15]
|
|
tmpPos, tmpOrn = p.multiplyTransforms(childInertiaPos, childInertiaOrn, parentCom2JointPos,
|
|
parentCom2JointOrn)
|
|
tmpPosInv, tmpOrnInv = p.invertTransform(tmpPos, tmpOrn)
|
|
dynParent = p.getDynamicsInfo(bodyUid, orgParentIndex, physicsClientId=physicsClientId)
|
|
parentInertiaPos = dynParent[3]
|
|
parentInertiaOrn = dynParent[4]
|
|
|
|
pos, orn = p.multiplyTransforms(parentInertiaPos, parentInertiaOrn, tmpPosInv, tmpOrnInv)
|
|
pos, orn_unused = p.multiplyTransforms(parentInertiaPos, parentInertiaOrn,
|
|
parentCom2JointPos, [0, 0, 0, 1])
|
|
|
|
urdfJoint.joint_origin_xyz = pos
|
|
urdfJoint.joint_origin_rpy = p.getEulerFromQuaternion(orn)
|
|
|
|
self.urdfJoints.append(urdfJoint)
|
|
|
|
def writeInertial(self, file, urdfInertial, precision=5):
|
|
file.write("\t\t<inertial>\n")
|
|
str = '\t\t\t<origin rpy=\"{:.{prec}f} {:.{prec}f} {:.{prec}f}\" xyz=\"{:.{prec}f} {:.{prec}f} {:.{prec}f}\"/>\n'.format(\
|
|
urdfInertial.origin_rpy[0],urdfInertial.origin_rpy[1],urdfInertial.origin_rpy[2],\
|
|
urdfInertial.origin_xyz[0],urdfInertial.origin_xyz[1],urdfInertial.origin_xyz[2], prec=precision)
|
|
file.write(str)
|
|
str = '\t\t\t<mass value=\"{:.{prec}f}\"/>\n'.format(urdfInertial.mass, prec=precision)
|
|
file.write(str)
|
|
str = '\t\t\t<inertia ixx=\"{:.{prec}f}\" ixy=\"0\" ixz=\"0\" iyy=\"{:.{prec}f}\" iyz=\"0\" izz=\"{:.{prec}f}\"/>\n'.format(\
|
|
urdfInertial.inertia_xxyyzz[0],\
|
|
urdfInertial.inertia_xxyyzz[1],\
|
|
urdfInertial.inertia_xxyyzz[2],prec=precision)
|
|
file.write(str)
|
|
file.write("\t\t</inertial>\n")
|
|
|
|
def writeVisualShape(self, file, urdfVisual, precision=5):
|
|
#we don't support loading capsule types from visuals, so auto-convert from collision shape
|
|
if urdfVisual.geom_type == p.GEOM_CAPSULE:
|
|
return
|
|
|
|
file.write("\t\t<visual>\n")
|
|
str = '\t\t\t<origin rpy="{:.{prec}f} {:.{prec}f} {:.{prec}f}" xyz="{:.{prec}f} {:.{prec}f} {:.{prec}f}"/>\n'.format(\
|
|
urdfVisual.origin_rpy[0],urdfVisual.origin_rpy[1],urdfVisual.origin_rpy[2],
|
|
urdfVisual.origin_xyz[0],urdfVisual.origin_xyz[1],urdfVisual.origin_xyz[2], prec=precision)
|
|
file.write(str)
|
|
file.write("\t\t\t<geometry>\n")
|
|
if urdfVisual.geom_type == p.GEOM_BOX:
|
|
str = '\t\t\t\t<box size=\"{:.{prec}f} {:.{prec}f} {:.{prec}f}\"/>\n'.format(urdfVisual.geom_extents[0],\
|
|
urdfVisual.geom_extents[1],urdfVisual.geom_extents[2], prec=precision)
|
|
file.write(str)
|
|
if urdfVisual.geom_type == p.GEOM_SPHERE:
|
|
str = '\t\t\t\t<sphere radius=\"{:.{prec}f}\"/>\n'.format(urdfVisual.geom_radius,\
|
|
prec=precision)
|
|
file.write(str)
|
|
if urdfVisual.geom_type == p.GEOM_MESH:
|
|
|
|
str = '\t\t\t\t<mesh filename=\"{}\" scale=\"{:.{prec}f} {:.{prec}f} {:.{prec}f}\"/>\n'.format(
|
|
urdfVisual.geom_meshfilename,urdfVisual.geom_meshscale[0],urdfVisual.geom_meshscale[1],urdfVisual.geom_meshscale[2],\
|
|
prec=precision)
|
|
file.write(str)
|
|
if urdfVisual.geom_type == p.GEOM_CYLINDER:
|
|
str = '\t\t\t\t<cylinder length=\"{:.{prec}f}\" radius=\"{:.{prec}f}\"/>\n'.format(\
|
|
urdfVisual.geom_length, urdfVisual.geom_radius, prec=precision)
|
|
file.write(str)
|
|
if urdfVisual.geom_type == p.GEOM_CAPSULE:
|
|
str = '\t\t\t\t<capsule length=\"{:.{prec}f}\" radius=\"{:.{prec}f}\"/>\n'.format(\
|
|
urdfVisual.geom_length, urdfVisual.geom_radius, prec=precision)
|
|
file.write(str)
|
|
|
|
file.write("\t\t\t</geometry>\n")
|
|
str = '\t\t\t<material name=\"{}\">\n'.format(urdfVisual.material_name)
|
|
file.write(str)
|
|
str = '\t\t\t\t<color rgba="{:.{prec}f} {:.{prec}f} {:.{prec}f} {:.{prec}f}" />\n'.format(urdfVisual.material_rgba[0],\
|
|
urdfVisual.material_rgba[1],urdfVisual.material_rgba[2],urdfVisual.material_rgba[3],prec=precision)
|
|
file.write(str)
|
|
file.write("\t\t\t</material>\n")
|
|
file.write("\t\t</visual>\n")
|
|
|
|
def writeCollisionShape(self, file, urdfCollision, precision=5):
|
|
file.write("\t\t<collision>\n")
|
|
str = '\t\t\t<origin rpy="{:.{prec}f} {:.{prec}f} {:.{prec}f}" xyz="{:.{prec}f} {:.{prec}f} {:.{prec}f}"/>\n'.format(\
|
|
urdfCollision.origin_rpy[0],urdfCollision.origin_rpy[1],urdfCollision.origin_rpy[2],
|
|
urdfCollision.origin_xyz[0],urdfCollision.origin_xyz[1],urdfCollision.origin_xyz[2], prec=precision)
|
|
file.write(str)
|
|
file.write("\t\t\t<geometry>\n")
|
|
if urdfCollision.geom_type == p.GEOM_BOX:
|
|
str = '\t\t\t\t<box size=\"{:.{prec}f} {:.{prec}f} {:.{prec}f}\"/>\n'.format(urdfCollision.geom_extents[0],\
|
|
urdfCollision.geom_extents[1],urdfCollision.geom_extents[2], prec=precision)
|
|
file.write(str)
|
|
if urdfCollision.geom_type == p.GEOM_SPHERE:
|
|
str = '\t\t\t\t<sphere radius=\"{:.{prec}f}\"/>\n'.format(urdfCollision.geom_radius,\
|
|
prec=precision)
|
|
file.write(str)
|
|
if urdfCollision.geom_type == p.GEOM_MESH:
|
|
str = '\t\t\t\t<mesh filename=\"{}\" scale=\"{:.{prec}f} {:.{prec}f} {:.{prec}f}\"/>\n'.format(urdfCollision.geom_meshfilename,\
|
|
urdfCollision.geom_meshscale[0],urdfCollision.geom_meshscale[1],urdfCollision.geom_meshscale[2],prec=precision)
|
|
file.write(str)
|
|
if urdfCollision.geom_type == p.GEOM_CYLINDER:
|
|
str = '\t\t\t\t<cylinder length=\"{:.{prec}f}\" radius=\"{:.{prec}f}\"/>\n'.format(\
|
|
urdfCollision.geom_length, urdfCollision.geom_radius, prec=precision)
|
|
file.write(str)
|
|
if urdfCollision.geom_type == p.GEOM_CAPSULE:
|
|
str = '\t\t\t\t<capsule length=\"{:.{prec}f}\" radius=\"{:.{prec}f}\"/>\n'.format(\
|
|
urdfCollision.geom_length, urdfCollision.geom_radius, prec=precision)
|
|
file.write(str)
|
|
file.write("\t\t\t</geometry>\n")
|
|
file.write("\t\t</collision>\n")
|
|
|
|
def writeLink(self, file, urdfLink, saveVisuals):
|
|
file.write("\t<link name=\"")
|
|
file.write(urdfLink.link_name)
|
|
file.write("\">\n")
|
|
|
|
self.writeInertial(file, urdfLink.urdf_inertial)
|
|
hasCapsules = False
|
|
for v in urdfLink.urdf_visual_shapes:
|
|
if (v.geom_type == p.GEOM_CAPSULE):
|
|
hasCapsules = True
|
|
if (saveVisuals and not hasCapsules):
|
|
for v in urdfLink.urdf_visual_shapes:
|
|
self.writeVisualShape(file, v)
|
|
for c in urdfLink.urdf_collision_shapes:
|
|
self.writeCollisionShape(file, c)
|
|
file.write("\t</link>\n")
|
|
|
|
def writeJoint(self, file, urdfJoint, precision=5):
|
|
jointTypeStr = "invalid"
|
|
if urdfJoint.joint_type == p.JOINT_REVOLUTE:
|
|
if urdfJoint.joint_upper_limit < urdfJoint.joint_lower_limit:
|
|
jointTypeStr = "continuous"
|
|
else:
|
|
jointTypeStr = "revolute"
|
|
if urdfJoint.joint_type == p.JOINT_FIXED:
|
|
jointTypeStr = "fixed"
|
|
if urdfJoint.joint_type == p.JOINT_PRISMATIC:
|
|
jointTypeStr = "prismatic"
|
|
str = '\t<joint name=\"{}\" type=\"{}\">\n'.format(urdfJoint.joint_name, jointTypeStr)
|
|
file.write(str)
|
|
str = '\t\t<parent link=\"{}\"/>\n'.format(urdfJoint.parent_name)
|
|
file.write(str)
|
|
str = '\t\t<child link=\"{}\"/>\n'.format(urdfJoint.child_name)
|
|
file.write(str)
|
|
|
|
if urdfJoint.joint_type == p.JOINT_PRISMATIC:
|
|
#todo: handle limits
|
|
lowerLimit = -0.5
|
|
upperLimit = 0.5
|
|
str = '<limit effort="1000.0" lower="{:.{prec}f}" upper="{:.{prec}f}" velocity="0.5"/>'.format(
|
|
lowerLimit, upperLimit, prec=precision)
|
|
file.write(str)
|
|
|
|
file.write("\t\t<dynamics damping=\"1.0\" friction=\"0.0001\"/>\n")
|
|
str = '\t\t<origin xyz=\"{:.{prec}f} {:.{prec}f} {:.{prec}f}\"/>\n'.format(urdfJoint.joint_origin_xyz[0],\
|
|
urdfJoint.joint_origin_xyz[1],urdfJoint.joint_origin_xyz[2], prec=precision)
|
|
str = '\t\t<origin rpy=\"{:.{prec}f} {:.{prec}f} {:.{prec}f}\" xyz=\"{:.{prec}f} {:.{prec}f} {:.{prec}f}\"/>\n'.format(urdfJoint.joint_origin_rpy[0],\
|
|
urdfJoint.joint_origin_rpy[1],urdfJoint.joint_origin_rpy[2],\
|
|
urdfJoint.joint_origin_xyz[0],\
|
|
urdfJoint.joint_origin_xyz[1],urdfJoint.joint_origin_xyz[2], prec=precision)
|
|
|
|
file.write(str)
|
|
str = '\t\t<axis xyz=\"{:.{prec}f} {:.{prec}f} {:.{prec}f}\"/>\n'.format(urdfJoint.joint_axis_xyz[0],\
|
|
urdfJoint.joint_axis_xyz[1],urdfJoint.joint_axis_xyz[2], prec=precision)
|
|
file.write(str)
|
|
file.write("\t</joint>\n")
|
|
|
|
def saveUrdf(self, fileName, saveVisuals=True):
|
|
file = open(fileName, "w")
|
|
file.write("<?xml version=\"0.0\" ?>\n")
|
|
file.write("<robot name=\"")
|
|
file.write(self.robotName)
|
|
file.write("\">\n")
|
|
|
|
for link in self.urdfLinks:
|
|
self.writeLink(file, link, saveVisuals)
|
|
|
|
for joint in self.urdfJoints:
|
|
self.writeJoint(file, joint)
|
|
|
|
file.write("</robot>\n")
|
|
file.close()
|
|
|
|
|
|
#def addLink(...)
|
|
|
|
def joinUrdf(self,
|
|
childEditor,
|
|
parentLinkIndex=0,
|
|
jointPivotXYZInParent=[0, 0, 0],
|
|
jointPivotRPYInParent=[0, 0, 0],
|
|
jointPivotXYZInChild=[0, 0, 0],
|
|
jointPivotRPYInChild=[0, 0, 0],
|
|
parentPhysicsClientId=0,
|
|
childPhysicsClientId=0):
|
|
|
|
childLinkIndex = len(self.urdfLinks)
|
|
insertJointIndex = len(self.urdfJoints)
|
|
|
|
#combine all links, and add a joint
|
|
|
|
for link in childEditor.urdfLinks:
|
|
self.linkNameToIndex[link.link_name] = len(self.urdfLinks)
|
|
self.urdfLinks.append(link)
|
|
for joint in childEditor.urdfJoints:
|
|
self.urdfJoints.append(joint)
|
|
#add a new joint between a particular
|
|
|
|
jointPivotQuatInChild = p.getQuaternionFromEuler(jointPivotRPYInChild)
|
|
invJointPivotXYZInChild, invJointPivotQuatInChild = p.invertTransform(
|
|
jointPivotXYZInChild, jointPivotQuatInChild)
|
|
|
|
#apply this invJointPivot***InChild to all inertial, visual and collision element in the child link
|
|
#inertial
|
|
pos, orn = p.multiplyTransforms(self.urdfLinks[childLinkIndex].urdf_inertial.origin_xyz,
|
|
p.getQuaternionFromEuler(
|
|
self.urdfLinks[childLinkIndex].urdf_inertial.origin_rpy),
|
|
invJointPivotXYZInChild,
|
|
invJointPivotQuatInChild,
|
|
physicsClientId=parentPhysicsClientId)
|
|
self.urdfLinks[childLinkIndex].urdf_inertial.origin_xyz = pos
|
|
self.urdfLinks[childLinkIndex].urdf_inertial.origin_rpy = p.getEulerFromQuaternion(orn)
|
|
#all visual
|
|
for v in self.urdfLinks[childLinkIndex].urdf_visual_shapes:
|
|
pos, orn = p.multiplyTransforms(v.origin_xyz, p.getQuaternionFromEuler(v.origin_rpy),
|
|
invJointPivotXYZInChild, invJointPivotQuatInChild)
|
|
v.origin_xyz = pos
|
|
v.origin_rpy = p.getEulerFromQuaternion(orn)
|
|
#all collision
|
|
for c in self.urdfLinks[childLinkIndex].urdf_collision_shapes:
|
|
pos, orn = p.multiplyTransforms(c.origin_xyz, p.getQuaternionFromEuler(c.origin_rpy),
|
|
invJointPivotXYZInChild, invJointPivotQuatInChild)
|
|
c.origin_xyz = pos
|
|
c.origin_rpy = p.getEulerFromQuaternion(orn)
|
|
|
|
childLink = self.urdfLinks[childLinkIndex]
|
|
parentLink = self.urdfLinks[parentLinkIndex]
|
|
|
|
joint = UrdfJoint()
|
|
joint.link = childLink
|
|
joint.joint_name = "joint_dummy1"
|
|
joint.joint_type = p.JOINT_REVOLUTE
|
|
joint.joint_lower_limit = 0
|
|
joint.joint_upper_limit = -1
|
|
joint.parent_name = parentLink.link_name
|
|
joint.child_name = childLink.link_name
|
|
joint.joint_origin_xyz = jointPivotXYZInParent
|
|
joint.joint_origin_rpy = jointPivotRPYInParent
|
|
joint.joint_axis_xyz = [0, 0, 1]
|
|
|
|
#the following commented line would crash PyBullet, it messes up the joint indexing/ordering
|
|
#self.urdfJoints.append(joint)
|
|
|
|
#so make sure to insert the joint in the right place, to links/joints match
|
|
self.urdfJoints.insert(insertJointIndex, joint)
|
|
return joint
|
|
|
|
def createMultiBody(self,
|
|
basePosition=[0, 0, 0],
|
|
baseOrientation=[0, 0, 0, 1],
|
|
physicsClientId=0):
|
|
#assume link[0] is base
|
|
if (len(self.urdfLinks) == 0):
|
|
return -1
|
|
|
|
#for i in range (len(self.urdfLinks)):
|
|
# print("link", i, "=",self.urdfLinks[i].link_name)
|
|
|
|
base = self.urdfLinks[0]
|
|
|
|
#v.tmp_collision_shape_ids=[]
|
|
baseMass = base.urdf_inertial.mass
|
|
baseCollisionShapeIndex = -1
|
|
baseShapeTypeArray = []
|
|
baseRadiusArray = []
|
|
baseHalfExtentsArray = []
|
|
lengthsArray = []
|
|
fileNameArray = []
|
|
meshScaleArray = []
|
|
basePositionsArray = []
|
|
baseOrientationsArray = []
|
|
|
|
for v in base.urdf_collision_shapes:
|
|
shapeType = v.geom_type
|
|
baseShapeTypeArray.append(shapeType)
|
|
baseHalfExtentsArray.append(
|
|
[0.5 * v.geom_extents[0], 0.5 * v.geom_extents[1], 0.5 * v.geom_extents[2]])
|
|
baseRadiusArray.append(v.geom_radius)
|
|
lengthsArray.append(v.geom_length)
|
|
fileNameArray.append(v.geom_meshfilename)
|
|
meshScaleArray.append(v.geom_meshscale)
|
|
basePositionsArray.append(v.origin_xyz)
|
|
orn = p.getQuaternionFromEuler(v.origin_rpy)
|
|
baseOrientationsArray.append(orn)
|
|
|
|
if (len(baseShapeTypeArray)):
|
|
#print("fileNameArray=",fileNameArray)
|
|
baseCollisionShapeIndex = p.createCollisionShapeArray(
|
|
shapeTypes=baseShapeTypeArray,
|
|
radii=baseRadiusArray,
|
|
halfExtents=baseHalfExtentsArray,
|
|
lengths=lengthsArray,
|
|
fileNames=fileNameArray,
|
|
meshScales=meshScaleArray,
|
|
collisionFramePositions=basePositionsArray,
|
|
collisionFrameOrientations=baseOrientationsArray,
|
|
physicsClientId=physicsClientId)
|
|
|
|
urdfVisuals = base.urdf_visual_shapes
|
|
|
|
shapeTypes = [v.geom_type for v in urdfVisuals]
|
|
halfExtents = [[ext * 0.5 for ext in v.geom_extents] for v in urdfVisuals]
|
|
radii = [v.geom_radius for v in urdfVisuals]
|
|
lengths = [v.geom_length for v in urdfVisuals]
|
|
fileNames = [v.geom_meshfilename for v in urdfVisuals]
|
|
meshScales = [v.geom_meshscale for v in urdfVisuals]
|
|
rgbaColors = [v.material_rgba for v in urdfVisuals]
|
|
visualFramePositions = [v.origin_xyz for v in urdfVisuals]
|
|
visualFrameOrientations = [p.getQuaternionFromEuler(v.origin_rpy) for v in urdfVisuals]
|
|
baseVisualShapeIndex = -1
|
|
|
|
if (len(shapeTypes)):
|
|
#print("len(shapeTypes)=",len(shapeTypes))
|
|
#print("len(halfExtents)=",len(halfExtents))
|
|
#print("len(radii)=",len(radii))
|
|
#print("len(lengths)=",len(lengths))
|
|
#print("len(fileNames)=",len(fileNames))
|
|
#print("len(meshScales)=",len(meshScales))
|
|
#print("len(rgbaColors)=",len(rgbaColors))
|
|
#print("len(visualFramePositions)=",len(visualFramePositions))
|
|
#print("len(visualFrameOrientations)=",len(visualFrameOrientations))
|
|
|
|
baseVisualShapeIndex = p.createVisualShapeArray(
|
|
shapeTypes=shapeTypes,
|
|
halfExtents=halfExtents,
|
|
radii=radii,
|
|
lengths=lengths,
|
|
fileNames=fileNames,
|
|
meshScales=meshScales,
|
|
rgbaColors=rgbaColors,
|
|
visualFramePositions=visualFramePositions,
|
|
visualFrameOrientations=visualFrameOrientations,
|
|
physicsClientId=physicsClientId)
|
|
|
|
linkMasses = []
|
|
linkCollisionShapeIndices = []
|
|
linkVisualShapeIndices = []
|
|
linkPositions = []
|
|
linkOrientations = []
|
|
|
|
linkInertialFramePositions = []
|
|
linkInertialFrameOrientations = []
|
|
linkParentIndices = []
|
|
linkJointTypes = []
|
|
linkJointAxis = []
|
|
|
|
for joint in self.urdfJoints:
|
|
link = joint.link
|
|
linkMass = link.urdf_inertial.mass
|
|
linkCollisionShapeIndex = -1
|
|
linkVisualShapeIndex = -1
|
|
linkPosition = [0, 0, 0]
|
|
linkOrientation = [0, 0, 0]
|
|
linkInertialFramePosition = [0, 0, 0]
|
|
linkInertialFrameOrientation = [0, 0, 0]
|
|
linkParentIndex = self.linkNameToIndex[joint.parent_name]
|
|
linkJointType = joint.joint_type
|
|
linkJointAx = joint.joint_axis_xyz
|
|
linkShapeTypeArray = []
|
|
linkRadiusArray = []
|
|
linkHalfExtentsArray = []
|
|
lengthsArray = []
|
|
fileNameArray = []
|
|
linkMeshScaleArray = []
|
|
linkPositionsArray = []
|
|
linkOrientationsArray = []
|
|
|
|
for v in link.urdf_collision_shapes:
|
|
shapeType = v.geom_type
|
|
linkShapeTypeArray.append(shapeType)
|
|
linkHalfExtentsArray.append(
|
|
[0.5 * v.geom_extents[0], 0.5 * v.geom_extents[1], 0.5 * v.geom_extents[2]])
|
|
linkRadiusArray.append(v.geom_radius)
|
|
lengthsArray.append(v.geom_length)
|
|
fileNameArray.append(v.geom_meshfilename)
|
|
linkMeshScaleArray.append(v.geom_meshscale)
|
|
linkPositionsArray.append(v.origin_xyz)
|
|
linkOrientationsArray.append(p.getQuaternionFromEuler(v.origin_rpy))
|
|
|
|
if (len(linkShapeTypeArray)):
|
|
linkCollisionShapeIndex = p.createCollisionShapeArray(
|
|
shapeTypes=linkShapeTypeArray,
|
|
radii=linkRadiusArray,
|
|
halfExtents=linkHalfExtentsArray,
|
|
lengths=lengthsArray,
|
|
fileNames=fileNameArray,
|
|
meshScales=linkMeshScaleArray,
|
|
collisionFramePositions=linkPositionsArray,
|
|
collisionFrameOrientations=linkOrientationsArray,
|
|
physicsClientId=physicsClientId)
|
|
|
|
urdfVisuals = link.urdf_visual_shapes
|
|
linkVisualShapeIndex = -1
|
|
shapeTypes = [v.geom_type for v in urdfVisuals]
|
|
halfExtents = [[ext * 0.5 for ext in v.geom_extents] for v in urdfVisuals]
|
|
radii = [v.geom_radius for v in urdfVisuals]
|
|
lengths = [v.geom_length for v in urdfVisuals]
|
|
fileNames = [v.geom_meshfilename for v in urdfVisuals]
|
|
meshScales = [v.geom_meshscale for v in urdfVisuals]
|
|
rgbaColors = [v.material_rgba for v in urdfVisuals]
|
|
visualFramePositions = [v.origin_xyz for v in urdfVisuals]
|
|
visualFrameOrientations = [p.getQuaternionFromEuler(v.origin_rpy) for v in urdfVisuals]
|
|
|
|
if (len(shapeTypes)):
|
|
print("fileNames=", fileNames)
|
|
|
|
linkVisualShapeIndex = p.createVisualShapeArray(
|
|
shapeTypes=shapeTypes,
|
|
halfExtents=halfExtents,
|
|
radii=radii,
|
|
lengths=lengths,
|
|
fileNames=fileNames,
|
|
meshScales=meshScales,
|
|
rgbaColors=rgbaColors,
|
|
visualFramePositions=visualFramePositions,
|
|
visualFrameOrientations=visualFrameOrientations,
|
|
physicsClientId=physicsClientId)
|
|
|
|
linkMasses.append(linkMass)
|
|
linkCollisionShapeIndices.append(linkCollisionShapeIndex)
|
|
linkVisualShapeIndices.append(linkVisualShapeIndex)
|
|
linkPositions.append(joint.joint_origin_xyz)
|
|
linkOrientations.append(p.getQuaternionFromEuler(joint.joint_origin_rpy))
|
|
linkInertialFramePositions.append(link.urdf_inertial.origin_xyz)
|
|
linkInertialFrameOrientations.append(p.getQuaternionFromEuler(link.urdf_inertial.origin_rpy))
|
|
linkParentIndices.append(linkParentIndex)
|
|
linkJointTypes.append(joint.joint_type)
|
|
linkJointAxis.append(joint.joint_axis_xyz)
|
|
obUid = p.createMultiBody(baseMass,\
|
|
baseCollisionShapeIndex=baseCollisionShapeIndex,
|
|
baseVisualShapeIndex=baseVisualShapeIndex,
|
|
basePosition=basePosition,
|
|
baseOrientation=baseOrientation,
|
|
baseInertialFramePosition=base.urdf_inertial.origin_xyz,
|
|
baseInertialFrameOrientation=p.getQuaternionFromEuler(base.urdf_inertial.origin_rpy),
|
|
linkMasses=linkMasses,
|
|
linkCollisionShapeIndices=linkCollisionShapeIndices,
|
|
linkVisualShapeIndices=linkVisualShapeIndices,
|
|
linkPositions=linkPositions,
|
|
linkOrientations=linkOrientations,
|
|
linkInertialFramePositions=linkInertialFramePositions,
|
|
linkInertialFrameOrientations=linkInertialFrameOrientations,
|
|
linkParentIndices=linkParentIndices,
|
|
linkJointTypes=linkJointTypes,
|
|
linkJointAxis=linkJointAxis,
|
|
physicsClientId=physicsClientId)
|
|
return obUid
|
|
|
|
def __del__(self):
|
|
pass
|