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 sys
import tf import tf
from tf.transformations import euler_from_quaternion, quaternion_from_matrix from tf.transformations import euler_from_quaternion, quaternion_from_matrix
from geometry_msgs.msg import TransformStamped
import xml.dom.minidom import xml.dom.minidom
from xml.dom.minidom import Document from xml.dom.minidom import Document
import threading
import math import math
import numpy import numpy #for creating matrix to convert to quaternion
import yaml import yaml
from urdf_python.urdf import *
# Conversion Factors # Conversion Factors
INCH2METER = 0.0254 INCH2METER = 0.0254
@ -22,10 +23,10 @@ MM2M = .001
WORLD = "WORLD" WORLD = "WORLD"
# Arbitrary List of colors to give pieces different looks # 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"), 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"), ("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"), ("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")] ("dblue", (0, 0, .8, 1)), ("dgreen", (.1, .8, .1, 1)), ("gray", (.5, .5, .5, 1))]
class Converter: class Converter:
def __init__(self): def __init__(self):
@ -40,7 +41,6 @@ class Converter:
# Start the Transform Manager # Start the Transform Manager
self.tfman = TransformManager() self.tfman = TransformManager()
self.tfman.start()
# Extra Transforms for Debugging # Extra Transforms for Debugging
self.tfman.add([0,0,0], [0.70682518,0,0,0.70682518], "ROOT", WORLD) # rotate so Z axis is up 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) self.buildTree(self.root)
# Create the output # Create the output
self.result = Document()
self.output(self.root) self.output(self.root)
# output the output # output the output
if mode == "xml": if mode == "xml":
print self.result.toprettyxml() print self.result.to_xml()
if mode == "graph": if mode == "graph":
print self.graph() print self.graph()
if mode == "groups": if mode == "groups":
@ -140,8 +139,7 @@ class Converter:
colorelement = linkdict['MaterialProp'][1] colorelement = linkdict['MaterialProp'][1]
color = colorelement.childNodes[0].data color = colorelement.childNodes[0].data
linkdict['MaterialProp'] = None linkdict['MaterialProp'] = None
linkdict['color'] = color.replace(",", " ") + " 1" linkdict['color'] = map(float, color.split(",")) + [1.0]
self.links[uid] = linkdict self.links[uid] = linkdict
self.parseFrames(frames, uid) self.parseFrames(frames, uid)
@ -302,10 +300,7 @@ class Converter:
def output(self, rootid): def output(self, rootid):
"""Creates the URDF from the parsed document. """Creates the URDF from the parsed document.
Makes the document and starts the recursive build process""" Makes the document and starts the recursive build process"""
doc = self.result; self.result = URDF(self.name)
self.root = doc.createElement("robot")
doc.appendChild(self.root)
self.root.setAttribute("name", self.name)
self.outputLink(rootid) self.outputLink(rootid)
self.processLink(rootid) self.processLink(rootid)
@ -323,96 +318,72 @@ class Converter:
def outputLink(self, id): def outputLink(self, id):
""" Creates the URDF output for a single link """ """ Creates the URDF output for a single link """
doc = self.result
linkdict = self.links[id] linkdict = self.links[id]
if linkdict['name'] == "RootPart": if linkdict['name'] == "RootPart":
return return
link = doc.createElement("link") visual = Visual()
link.setAttribute("name", id) inertial = Inertial()
collision = Collision()
visual = doc.createElement("visual")
inertial = doc.createElement("inertial")
collision = doc.createElement("collision")
link.appendChild(visual)
link.appendChild(inertial)
link.appendChild(collision)
# Define Geometry # Define Geometry
geometry = doc.createElement("geometry")
mesh = doc.createElement("mesh")
filename = linkdict['geometryFileName'] filename = linkdict['geometryFileName']
if self.forcelowercase: if self.forcelowercase:
filename = filename.lower() filename = filename.lower()
filename = self.filenameformat % filename
mesh.setAttribute("filename", self.filenameformat % filename) visual.geometry = Mesh(filename, self.scale)
if self.scale != None: collision.geometry = visual.geometry
mesh.setAttribute("scale", self.scale)
geometry.appendChild(mesh)
visual.appendChild(geometry)
collision.appendChild(geometry.cloneNode(1))
# Define Inertial Frame # Define Inertial Frame
mass = doc.createElement("mass")
units = linkdict['massUnits'] units = linkdict['massUnits']
massval = convert(float(linkdict['mass']), units) massval = convert(float(linkdict['mass']), units)
mass.setAttribute("value", str(massval)) inertial.mass = massval
inertial.appendChild(mass)
inertia = doc.createElement("inertia")
matrix = getlist(linkdict["inertia"]) matrix = getlist(linkdict["inertia"])
units = linkdict['inertiaUnits'] units = linkdict['inertiaUnits']
for i in range(0,len(matrix)): for i in range(0,len(matrix)):
matrix[i] = convert(matrix[i], units) matrix[i] = convert(matrix[i], units)
inertia.setAttribute("ixx", str(matrix[0])) inertial.matrix['ixx'] = matrix[0]
inertia.setAttribute("ixy", str(matrix[1])) inertial.matrix['ixy'] = matrix[1]
inertia.setAttribute("ixz", str(matrix[2])) inertial.matrix['ixz'] = matrix[2]
inertia.setAttribute("iyy", str(matrix[4])) inertial.matrix['iyy'] = matrix[4]
inertia.setAttribute("iyz", str(matrix[5])) inertial.matrix['iyz'] = matrix[5]
inertia.setAttribute("izz", str(matrix[8])) inertial.matrix['izz'] = matrix[8]
inertial.appendChild(inertia)
# Inertial origin is the center of gravity # Inertial origin is the center of gravity
iorigin = doc.createElement("origin")
(off, rot) = self.tfman.get("X" + id, id+"CG") (off, rot) = self.tfman.get("X" + id, id+"CG")
rpy = list(euler_from_quaternion(rot)) rpy = list(euler_from_quaternion(rot))
iorigin.setAttribute("xyz", " ".join(map(str,zero(off)))) inertial.origin = Pose(zero(off), zero(rpy))
iorigin.setAttribute("rpy", " ".join(map(str,zero(rpy))))
inertial.appendChild(iorigin)
# Create link's origin
origin = doc.createElement("origin")
# Visual offset is difference between origin and CS1 # Visual offset is difference between origin and CS1
(off, rot) = self.tfman.get("X" + id, id+"CS1") (off, rot) = self.tfman.get("X" + id, id+"CS1")
rpy = list(euler_from_quaternion(rot)) rpy = list(euler_from_quaternion(rot))
origin.setAttribute("xyz", " ".join(map(str,zero(off)))) visual.origin = Pose(zero(off), zero(rpy))
origin.setAttribute("rpy", " ".join(map(str,zero(rpy)))) collision.origin = visual.origin
visual.appendChild(origin)
collision.appendChild(origin.cloneNode(1))
# Define Material # Define Material
material = doc.createElement("material") visual.material = Material()
# Use specified color, if exists. Otherwise, get random color # Use specified color, if exists. Otherwise, get random color
if 'color' in linkdict: if 'color' in linkdict:
cname = "%s_color"%id cname = "%s_color"%id
rgba = linkdict['color'] (r,g,b,a) = linkdict['color']
else: else:
(cname, rgba) = self.getColor(linkdict['name']) (cname, (r,g,b,a)) = self.getColor(linkdict['name'])
material.setAttribute("name", cname)
visual.appendChild(material) visual.material.name = cname
# If color has already been output, only output name # If color has already been output, only output name
if not cname in self.usedcolors: if not cname in self.usedcolors:
color = doc.createElement("color") visual.material.color = Color(r,g,b,a)
color.setAttribute("rgba", rgba)
material.appendChild(color)
self.usedcolors[cname] = True self.usedcolors[cname] = True
self.root.appendChild(link) link = Link(id, visual, inertial, collision)
self.result.add_link(link)
def getColor(self, s): def getColor(self, s):
""" Gets a two element list containing a color name, """ Gets a two element list containing a color name,
@ -428,14 +399,11 @@ class Converter:
def outputJoint(self, id, parentname): def outputJoint(self, id, parentname):
""" Outputs URDF for a single joint """ """ Outputs URDF for a single joint """
doc = self.result
jointdict = self.joints[id] jointdict = self.joints[id]
if "Root" in jointdict['name']: if "Root" in jointdict['name']:
return return
joint = doc.createElement("joint")
joint.setAttribute('name', id)
# Define the parent and child # Define the parent and child
pid = self.getLinkNameByFrame(jointdict['parent']) pid = self.getLinkNameByFrame(jointdict['parent'])
@ -447,38 +415,27 @@ class Converter:
cid = pid cid = pid
pid = parentname 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 # Define joint type
jtype = jointdict['type'] jtype = jointdict['type']
joint.setAttribute('type', jtype)
limits = None
axis = None
if 'limits' in jointdict: if 'limits' in jointdict:
limit = doc.createElement("limit") limits = JointLimit(None, None)
for (k,v) in jointdict['limits'].items(): for (k,v) in jointdict['limits'].items():
limit.setAttribute(str(k), str(v)) setattr(limits, k, v)
joint.appendChild(limit)
if 'axis' in jointdict and jtype != 'fixed': if 'axis' in jointdict and jtype != 'fixed':
axis = doc.createElement("axis") axis = jointdict['axis'].replace(',', ' ')
xyz = jointdict['axis'].replace(',', ' ')
axis.setAttribute('xyz', xyz)
joint.appendChild(axis)
# Define the origin # Define the origin
origin = doc.createElement("origin")
(off, rot) = self.tfman.get("X" + pid, "X" + cid) (off, rot) = self.tfman.get("X" + pid, "X" + cid)
rpy = list(euler_from_quaternion(rot)) rpy = list(euler_from_quaternion(rot))
off = zero(off) origin = Pose(zero(off), zero(rpy))
rpy = zero(rpy)
origin.setAttribute("xyz", " ".join(map(str,off)))
origin.setAttribute("rpy", " ".join(map(str,rpy)))
joint.appendChild(origin)
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): def getName(self, basename):
"""Return a unique name of the format """Return a unique name of the format
@ -646,48 +603,28 @@ def zero(arr):
return arr return arr
class TransformManager(threading.Thread): class TransformManager:
"""Bridge to the ROS tf package. Constantly broadcasts
all tfs, and retrieves them on demand."""
def __init__(self): def __init__(self):
threading.Thread.__init__(self) self.tf = tf.Transformer(True, rospy.Duration(10.0))
self.running = True
self.tfs = []
self.listener = tf.TransformListener()
def run(self): def add(self, offset, angle, parent, child):
"""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):
"""Adds a new transform to the set""" """Adds a new transform to the set"""
tf = {'trans':trans, 'rot':rot, 'child':child, 'parent':parent} m = TransformStamped()
self.tfs.append(tf) 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): def get(self, parent, child):
"""Attempts to retrieve a transform""" """Retrieves a transform"""
attempts = 0 (off,rpy) = self.tf.lookupTransform(parent, child, rospy.Time(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)] 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))
def printTransform(self, parent, child): def printTransform(self, parent, child):
"""Attempts to print the specified transform""" """Attempts to print the specified transform"""
@ -725,8 +662,6 @@ if __name__ == '__main__':
None None
except Exception: except Exception:
raise raise
finally:
con.tfman.kill()
except rospy.ROSInterruptException: pass except rospy.ROSInterruptException: pass

View File

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