Updates to simmechanics_to_urdf and resource_retriever

This commit is contained in:
davidlu 2012-06-09 18:29:46 -05:00
parent 4f07e9d19a
commit 3970d34724
4 changed files with 114 additions and 173 deletions

View File

@ -0,0 +1,36 @@
import roslib; roslib.load_manifest('resource_retriever')
import subprocess
import urlgrabber, string
PACKAGE_PREFIX = 'package://'
def rospack_find(package):
process = subprocess.Popen(['rospack', 'find', package], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(stdout, stderr) = process.communicate()
if len(stderr) > 0:
raise Exception(stderr)
else:
return string.strip(stdout)
def get_filename(url, use_protocol=True ):
mod_url = url
if url.find(PACKAGE_PREFIX) == 0:
mod_url = url[len(PACKAGE_PREFIX):]
pos = mod_url.find('/')
if pos == -1:
raise Exception("Could not parse package:// format into file:// format for "+url)
package = mod_url[0:pos]
mod_url = mod_url[pos:]
package_path = rospack_find(package)
if use_protocol:
protocol = "file://"
else:
protocol = ""
mod_url = protocol + package_path + mod_url;
return mod_url
def get(url):
return urlgrabber.urlopen(get_filename(url))

View File

@ -1,31 +0,0 @@
import roslib; roslib.load_manifest('resource_retriever2')
import rospy
import subprocess
import urlgrabber, string
PACKAGE_PREFIX = 'package://'
def rospack_find(package):
process = subprocess.Popen(['rospack', 'find', package], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(stdout, stderr) = process.communicate()
if len(stderr) > 0:
raise Exception(stderr)
else:
return string.strip(stdout)
def get(url):
mod_url = url
if url.find(PACKAGE_PREFIX) == 0:
mod_url = url[len(PACKAGE_PREFIX):]
pos = mod_url.find('/')
if pos == -1:
raise Exception("Could not parse package:// format into file:// format for "+url)
package = mod_url[0:pos]
mod_url = mod_url[pos:]
package_path = rospack_find(package)
mod_url = "file://" + package_path + mod_url;
return urlgrabber.urlopen(mod_url)

View File

@ -5,12 +5,13 @@ import rospy
import sys
import tf
from tf.transformations import euler_from_quaternion, quaternion_from_matrix
from geometry_msgs.msg import TransformStamped
import xml.dom.minidom
from xml.dom.minidom import Document
import threading
import math
import numpy
import numpy #for creating matrix to convert to quaternion
import yaml
from urdf_python.urdf import *
# Conversion Factors
INCH2METER = 0.0254
@ -22,10 +23,10 @@ MM2M = .001
WORLD = "WORLD"
# Arbitrary List of colors to give pieces different looks
COLORS =[("green", "0 1 0 1"), ("black", "0 0 0 1"), ("red", "1 0 0 1"),
("blue", "0 0 1 1"), ("yellow", "1 1 0 1"), ("pink", "1 0 1 1"),
("cyan", "0 1 1 1"), ("green", "0 1 0 1"), ("white", "1 1 1 1"),
("dblue", "0 0 .8 1"), ("dgreen", ".1 .8 .1 1"), ("gray", ".5 .5 .5 1")]
COLORS =[("green", (0, 1, 0, 1)), ("black", (0, 0, 0, 1)), ("red", (1, 0, 0, 1)),
("blue", (0, 0, 1, 1)), ("yellow", (1, 1, 0, 1)), ("pink", (1, 0, 1, 1)),
("cyan", (0, 1, 1, 1)), ("green", (0, 1, 0, 1)), ("white", (1, 1, 1, 1)),
("dblue", (0, 0, .8, 1)), ("dgreen", (.1, .8, .1, 1)), ("gray", (.5, .5, .5, 1))]
class Converter:
def __init__(self):
@ -40,7 +41,6 @@ class Converter:
# Start the Transform Manager
self.tfman = TransformManager()
self.tfman.start()
# Extra Transforms for Debugging
self.tfman.add([0,0,0], [0.70682518,0,0,0.70682518], "ROOT", WORLD) # rotate so Z axis is up
@ -56,12 +56,11 @@ class Converter:
self.buildTree(self.root)
# Create the output
self.result = Document()
self.output(self.root)
# output the output
if mode == "xml":
print self.result.toprettyxml()
print self.result.to_xml()
if mode == "graph":
print self.graph()
if mode == "groups":
@ -140,8 +139,7 @@ class Converter:
colorelement = linkdict['MaterialProp'][1]
color = colorelement.childNodes[0].data
linkdict['MaterialProp'] = None
linkdict['color'] = color.replace(",", " ") + " 1"
linkdict['color'] = map(float, color.split(",")) + [1.0]
self.links[uid] = linkdict
self.parseFrames(frames, uid)
@ -302,17 +300,14 @@ class Converter:
def output(self, rootid):
"""Creates the URDF from the parsed document.
Makes the document and starts the recursive build process"""
doc = self.result;
self.root = doc.createElement("robot")
doc.appendChild(self.root)
self.root.setAttribute("name", self.name)
self.result = URDF(self.name)
self.outputLink(rootid)
self.processLink(rootid)
def processLink(self, id):
""" Creates the output for the specified node's
child links, the connecting joints, then
recursively processes each child """
child links, the connecting joints, then
recursively processes each child """
link = self.links[id]
for cid in link['children']:
jid = link['jointmap'][cid]
@ -323,102 +318,78 @@ class Converter:
def outputLink(self, id):
""" Creates the URDF output for a single link """
doc = self.result
linkdict = self.links[id]
if linkdict['name'] == "RootPart":
return
link = doc.createElement("link")
link.setAttribute("name", id)
visual = doc.createElement("visual")
inertial = doc.createElement("inertial")
collision = doc.createElement("collision")
link.appendChild(visual)
link.appendChild(inertial)
link.appendChild(collision)
visual = Visual()
inertial = Inertial()
collision = Collision()
# Define Geometry
geometry = doc.createElement("geometry")
mesh = doc.createElement("mesh")
filename = linkdict['geometryFileName']
if self.forcelowercase:
filename = filename.lower()
filename = self.filenameformat % filename
mesh.setAttribute("filename", self.filenameformat % filename)
if self.scale != None:
mesh.setAttribute("scale", self.scale)
geometry.appendChild(mesh)
visual.appendChild(geometry)
collision.appendChild(geometry.cloneNode(1))
visual.geometry = Mesh(filename, self.scale)
collision.geometry = visual.geometry
# Define Inertial Frame
mass = doc.createElement("mass")
units = linkdict['massUnits']
massval = convert(float(linkdict['mass']), units)
mass.setAttribute("value", str(massval))
inertial.appendChild(mass)
inertial.mass = massval
inertia = doc.createElement("inertia")
matrix = getlist(linkdict["inertia"])
units = linkdict['inertiaUnits']
for i in range(0,len(matrix)):
matrix[i] = convert(matrix[i], units)
inertia.setAttribute("ixx", str(matrix[0]))
inertia.setAttribute("ixy", str(matrix[1]))
inertia.setAttribute("ixz", str(matrix[2]))
inertia.setAttribute("iyy", str(matrix[4]))
inertia.setAttribute("iyz", str(matrix[5]))
inertia.setAttribute("izz", str(matrix[8]))
inertial.appendChild(inertia)
inertial.matrix['ixx'] = matrix[0]
inertial.matrix['ixy'] = matrix[1]
inertial.matrix['ixz'] = matrix[2]
inertial.matrix['iyy'] = matrix[4]
inertial.matrix['iyz'] = matrix[5]
inertial.matrix['izz'] = matrix[8]
# Inertial origin is the center of gravity
iorigin = doc.createElement("origin")
(off, rot) = self.tfman.get("X" + id, id+"CG")
rpy = list(euler_from_quaternion(rot))
iorigin.setAttribute("xyz", " ".join(map(str,zero(off))))
iorigin.setAttribute("rpy", " ".join(map(str,zero(rpy))))
inertial.appendChild(iorigin)
# Create link's origin
origin = doc.createElement("origin")
inertial.origin = Pose(zero(off), zero(rpy))
# Visual offset is difference between origin and CS1
(off, rot) = self.tfman.get("X" + id, id+"CS1")
rpy = list(euler_from_quaternion(rot))
origin.setAttribute("xyz", " ".join(map(str,zero(off))))
origin.setAttribute("rpy", " ".join(map(str,zero(rpy))))
visual.appendChild(origin)
collision.appendChild(origin.cloneNode(1))
visual.origin = Pose(zero(off), zero(rpy))
collision.origin = visual.origin
# Define Material
material = doc.createElement("material")
visual.material = Material()
# Use specified color, if exists. Otherwise, get random color
if 'color' in linkdict:
cname = "%s_color"%id
rgba = linkdict['color']
(r,g,b,a) = linkdict['color']
else:
(cname, rgba) = self.getColor(linkdict['name'])
material.setAttribute("name", cname)
visual.appendChild(material)
(cname, (r,g,b,a)) = self.getColor(linkdict['name'])
visual.material.name = cname
# If color has already been output, only output name
if not cname in self.usedcolors:
color = doc.createElement("color")
color.setAttribute("rgba", rgba)
material.appendChild(color)
visual.material.color = Color(r,g,b,a)
self.usedcolors[cname] = True
self.root.appendChild(link)
link = Link(id, visual, inertial, collision)
self.result.add_link(link)
def getColor(self, s):
""" Gets a two element list containing a color name,
and it's rgba. The color selected is based on the mesh name.
If already seen, returns the saved color
Otherwise, returns the next available color"""
and it's rgba. The color selected is based on the mesh name.
If already seen, returns the saved color
Otherwise, returns the next available color"""
if s in self.colormap:
return self.colormap[s]
color = COLORS[self.colorindex]
@ -428,14 +399,11 @@ class Converter:
def outputJoint(self, id, parentname):
""" Outputs URDF for a single joint """
doc = self.result
jointdict = self.joints[id]
if "Root" in jointdict['name']:
return
joint = doc.createElement("joint")
joint.setAttribute('name', id)
# Define the parent and child
pid = self.getLinkNameByFrame(jointdict['parent'])
@ -447,38 +415,27 @@ class Converter:
cid = pid
pid = parentname
parent = doc.createElement("parent")
child = doc.createElement("child")
parent.setAttribute('link', pid)
child.setAttribute('link', cid)
joint.appendChild(parent)
joint.appendChild(child)
# Define joint type
jtype = jointdict['type']
joint.setAttribute('type', jtype)
limits = None
axis = None
if 'limits' in jointdict:
limit = doc.createElement("limit")
limits = JointLimit(None, None)
for (k,v) in jointdict['limits'].items():
limit.setAttribute(str(k), str(v))
joint.appendChild(limit)
setattr(limits, k, v)
if 'axis' in jointdict and jtype != 'fixed':
axis = doc.createElement("axis")
xyz = jointdict['axis'].replace(',', ' ')
axis.setAttribute('xyz', xyz)
joint.appendChild(axis)
axis = jointdict['axis'].replace(',', ' ')
# Define the origin
origin = doc.createElement("origin")
(off, rot) = self.tfman.get("X" + pid, "X" + cid)
rpy = list(euler_from_quaternion(rot))
off = zero(off)
rpy = zero(rpy)
origin.setAttribute("xyz", " ".join(map(str,off)))
origin.setAttribute("rpy", " ".join(map(str,rpy)))
joint.appendChild(origin)
origin = Pose(zero(off), zero(rpy))
self.root.appendChild(joint)
joint = Joint(id, pid, cid, jtype, limits=limits, axis=axis, origin=origin)
self.result.add_joint(joint)
def getName(self, basename):
"""Return a unique name of the format
@ -540,7 +497,7 @@ class Converter:
def groups(self, root):
""" For planning purposes, print out lists of
all the links between the different joints"""
all the links between the different joints"""
self.groups = {}
self.makeGroup(root, "BASE")
s = ""
@ -554,7 +511,7 @@ class Converter:
def makeGroup(self, id, gid):
""" Helper function for recursively gathering
groups of joints. """
groups of joints. """
if gid in self.groups:
idlist = self.groups[gid]
idlist.append(id)
@ -624,9 +581,9 @@ def matrixToQuaternion(matrix):
(R11, R12, R13, R21, R22, R23, R31, R32, R33) = matrix
# Build 4x4 matrix
M = [[R11, R21, R31, 0],
[R12, R22, R32, 0],
[R13, R23, R33, 0],
[0, 0, 0, 1]]
[R12, R22, R32, 0],
[R13, R23, R33, 0],
[0, 0, 0, 1]]
A = numpy.array(M)
[w,x,y,z] = quaternion_from_matrix(A)
return [w,x,y,z]
@ -646,48 +603,28 @@ def zero(arr):
return arr
class TransformManager(threading.Thread):
"""Bridge to the ROS tf package. Constantly broadcasts
all tfs, and retrieves them on demand."""
class TransformManager:
def __init__(self):
threading.Thread.__init__(self)
self.running = True
self.tfs = []
self.listener = tf.TransformListener()
self.tf = tf.Transformer(True, rospy.Duration(10.0))
def run(self):
"""Broadcasts tfs until shutdown"""
rate = rospy.Rate(10.0)
br = tf.TransformBroadcaster()
while self.running:
for transform in self.tfs:
br.sendTransform(transform['trans'],
transform['rot'],
rospy.Time.now(),
transform['child'],
transform['parent'])
rate.sleep()
def add(self, trans, rot, parent, child):
def add(self, offset, angle, parent, child):
"""Adds a new transform to the set"""
tf = {'trans':trans, 'rot':rot, 'child':child, 'parent':parent}
self.tfs.append(tf)
m = TransformStamped()
m.header.frame_id = parent
m.child_frame_id = child
m.transform.translation.x = offset[0]
m.transform.translation.y = offset[1]
m.transform.translation.z = offset[2]
m.transform.rotation.x = angle[0]
m.transform.rotation.y = angle[1]
m.transform.rotation.z = angle[2]
m.transform.rotation.w = angle[3]
self.tf.setTransform(m)
def get(self, parent, child):
"""Attempts to retrieve a transform"""
attempts = 0
rate = rospy.Rate(10.0)
while attempts < 50:
try:
(off,rpy) = self.listener.lookupTransform(parent, child, rospy.Time(0))
return [list(off), list(rpy)]
except (tf.LookupException, tf.ConnectivityException):
attempts+=1
rate.sleep()
continue
raise Exception("Attempt to transform %s exceeded attempt limit" % (parent + "/" + child))
"""Retrieves a transform"""
(off,rpy) = self.tf.lookupTransform(parent, child, rospy.Time(0))
return [list(off), list(rpy)]
def printTransform(self, parent, child):
"""Attempts to print the specified transform"""
@ -725,8 +662,6 @@ if __name__ == '__main__':
None
except Exception:
raise
finally:
con.tfman.kill()
except rospy.ROSInterruptException: pass

View File

@ -9,6 +9,7 @@
<depend package="rospy"/>
<depend package="sensor_msgs"/>
<depend package="tf"/>
<depend package="urdf_python"/>
<rosdep name="python-yaml"/>
</package>