diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..68bc17f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,160 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
diff --git a/odio_urdf/__init__.py b/odio_urdf/__init__.py
index 6ebc491..81d9542 100644
--- a/odio_urdf/__init__.py
+++ b/odio_urdf/__init__.py
@@ -17,35 +17,38 @@
Please see README.md for an overview.
"""
-import six
-import xml.etree.ElementTree as ET
import copy
import inspect
import sys
+import xml.etree.ElementTree as ET
+
+import six
def eval_macros(string, env):
- to_eval_start = string.find('${')
+ to_eval_start = string.find("${")
if to_eval_start == -1:
return string
- to_eval_end = string.find('}',to_eval_start)
- if (to_eval_start != to_eval_end):
- res = eval(string[to_eval_start+2:to_eval_end],env)
- string = string[:to_eval_start]+str(res)+string[to_eval_end+1:]
+ to_eval_end = string.find("}", to_eval_start)
+ if to_eval_start != to_eval_end:
+ res = eval(string[to_eval_start + 2 : to_eval_end], env)
+ string = string[:to_eval_start] + str(res) + string[to_eval_end + 1 :]
return eval_macros(string, env)
+
class ElementMeta(type):
- """ Metaclass for URDF element subclasses """
+ """Metaclass for URDF element subclasses"""
+
_defaults_ = dict(
- required_elements=[],
- allowed_elements=[],
- required_attributes=[],
- allowed_attributes=[],
- )
+ required_elements=[],
+ allowed_elements=[],
+ required_attributes=[],
+ allowed_attributes=[],
+ )
def __new__(cls, name, bases, clsdict):
"""
- Populate class attributes from _default_ if they are not explicitly defined
+ Populate class attributes from _default_ if they are not explicitly defined
"""
for k in cls._defaults_:
if not k in clsdict:
@@ -53,54 +56,63 @@ def __new__(cls, name, bases, clsdict):
return super(ElementMeta, cls).__new__(cls, name, bases, clsdict)
+
class NamedElementMeta(ElementMeta):
- """ Many elements have 'name' as a required attribute """
+ """Many elements have 'name' as a required attribute"""
+
_defaults_ = dict(ElementMeta._defaults_, required_attributes=["name"])
def instantiate_if_class(subject):
- """ If subject is a type instead of an instance, instantiate it"""
+ """If subject is a type instead of an instance, instantiate it"""
if type(subject) in [type, ElementMeta, NamedElementMeta]:
ret = globals()[subject.__name__]()
else:
ret = subject
return ret
-def classname( obj ):
- """ Return class name for instance or class object """
+
+def classname(obj):
+ """Return class name for instance or class object"""
obj_type = type(obj)
if obj_type in [type, ElementMeta, NamedElementMeta]:
return obj.__name__
else:
return obj_type.__name__
-def literal_as_str( literal ):
- """ Returns value literals as a str and tuple/lists as a space separated str """
- if isinstance(literal,int) or isinstance(literal,float) or isinstance(literal, str):
+
+def literal_as_str(literal):
+ """Returns value literals as a str and tuple/lists as a space separated str"""
+ if (
+ isinstance(literal, int)
+ or isinstance(literal, float)
+ or isinstance(literal, str)
+ ):
return str(literal)
- elif isinstance(literal,tuple) or isinstance(literal,list):
+ elif isinstance(literal, tuple) or isinstance(literal, list):
return " ".join([str(x) for x in literal])
+
@six.add_metaclass(ElementMeta)
class Element(list):
"""
- Parent class for all URDF elements
+ Parent class for all URDF elements
- All element classes have class attributes that define what sub elements and xml attributes are
- allowed or required.
+ All element classes have class attributes that define what sub elements and xml attributes are
+ allowed or required.
- required_elements: xml sub-elments that MUST be present
- allowed_elements: xml sub-elements that MAY be present
- required_attributes: xml attributes that MUST be present
- allowed_attributes: xml attributes that MAY be present
+ required_elements: xml sub-elments that MUST be present
+ allowed_elements: xml sub-elements that MAY be present
+ required_attributes: xml attributes that MUST be present
+ allowed_attributes: xml attributes that MAY be present
"""
+
element_counter = 0
string_macros = {}
- xacro_tags = ['Xacroproperty','Xacroinclude','Xacroif','Xacrounless']
+ xacro_tags = ["Xacroproperty", "Xacroinclude", "Xacroif", "Xacrounless"]
element_name = None
- def __init__(self,*args,**kwargs):
-
+ def __init__(self, *args, **kwargs):
self.attributes = set()
self._instantiated = {}
self.xmltext = ""
@@ -120,51 +132,52 @@ def __init__(self,*args,**kwargs):
self.append(new_child)
new_child.parent = self
-
- def __call__(self,*args,**kwargs):
+ def __call__(self, *args, **kwargs):
"""
- For our DSL, allow existing instances to be populated with sub-elements the same way
- we allow during instantiation
+ For our DSL, allow existing instances to be populated with sub-elements the same way
+ we allow during instantiation
- ```
- robot = Robot('my_robot_name', Link('my_link_name')) # populate with a link during object creation
- robot( Link('My_second_link') ) # Add a second link to the instance
+ ```
+ robot = Robot('my_robot_name', Link('my_link_name')) # populate with a link during object creation
+ robot( Link('My_second_link') ) # Add a second link to the instance
- ```
+ ```
"""
self._populate_element_(*args, **kwargs)
- def _populate_element_(self,*args,**kwargs):
- """ Populate a URDF element with attributes and sub elements
+ def _populate_element_(self, *args, **kwargs):
+ """Populate a URDF element with attributes and sub elements
- *args of type str and int will be assigned one-by-one to the attributes in Class.arm_attributes
- *args derrived from Element will be added to the sub-element list
+ *args of type str and int will be assigned one-by-one to the attributes in Class.arm_attributes
+ *args derrived from Element will be added to the sub-element list
- **kwargs will be assigned to the attribute implied by the keyword
+ **kwargs will be assigned to the attribute implied by the keyword
- xmltext = "" will be directly injected into the output
+ xmltext = "" will be directly injected into the output
"""
- if 'xmltext' in kwargs:
- self.xmltext = kwargs['xmltext']
- del kwargs['xmltext']
+ if "xmltext" in kwargs:
+ self.xmltext = kwargs["xmltext"]
+ del kwargs["xmltext"]
- if 'xacro_xml' in kwargs:
- xacroroot = ET.fromstring(kwargs['xacro_xml']) # The root shoud be
+ if "xacro_xml" in kwargs:
+ xacroroot = ET.fromstring(kwargs["xacro_xml"]) # The root shoud be
for child in xacroroot:
- # Add the xml to our
+ # Add the xml to our
if sys.version_info[0] < 3:
self.xmltext += ET.tostring(child)
else:
- self.xmltext += ET.tostring(child, encoding='unicode')
- del kwargs['xacro_xml']
+ self.xmltext += ET.tostring(child, encoding="unicode")
+ del kwargs["xacro_xml"]
callers_local_vars = inspect.currentframe().f_back.f_locals.items()
- allowed_attributes = type(self).required_attributes + type(self).allowed_attributes
+ allowed_attributes = (
+ type(self).required_attributes + type(self).allowed_attributes
+ )
name = ""
- unlabeled = 0 # Count of unlabeled strings we have encountered so far
+ unlabeled = 0 # Count of unlabeled strings we have encountered so far
allowed_unlabeled = len(allowed_attributes)
for arg in args:
arg_type = type(arg)
@@ -176,7 +189,7 @@ def _populate_element_(self,*args,**kwargs):
elif arg_type is Group:
for elt in arg:
self.append(elt)
- if hasattr(arg,'xmltext'):
+ if hasattr(arg, "xmltext"):
self.xmltext += arg.xmltext
else:
name = classname(arg)
@@ -186,29 +199,43 @@ def _populate_element_(self,*args,**kwargs):
self.append(new_child)
new_child.parent = self
- self._instantiated[name] = None # Keep track of Elements we instantiate
-
- #If name is required and not there already, add it using the variable name
- if 'name' in type(new_child).required_attributes and not 'name' in new_child.attributes:
- #If we were a named variable, use it
- name_val_list = [(var_name,var_val) for var_name, var_val in callers_local_vars if var_val is arg]
- if len(name_val_list)>0:
- name_val = name_val_list[-1][0] #Use most recent label
+ self._instantiated[
+ name
+ ] = None # Keep track of Elements we instantiate
+
+ # If name is required and not there already, add it using the variable name
+ if (
+ "name" in type(new_child).required_attributes
+ and not "name" in new_child.attributes
+ ):
+ # If we were a named variable, use it
+ name_val_list = [
+ (var_name, var_val)
+ for var_name, var_val in callers_local_vars
+ if var_val is arg
+ ]
+ if len(name_val_list) > 0:
+ name_val = name_val_list[-1][0] # Use most recent label
new_child.name = name_val
- new_child.attributes.add('name')
+ new_child.attributes.add("name")
elif name in Element.xacro_tags:
pass
else:
- raise Exception("Illegal element ["+name+']')
+ raise Exception("Illegal element [" + name + "]")
- for key,value in kwargs.items():
+ for key, value in kwargs.items():
if key in allowed_attributes:
setattr(self, key, literal_as_str(value))
self.attributes.add(key)
else:
- raise Exception("Attribute ["+key+"] is not in allowed_attributes list of "+str(type(self)))
+ raise Exception(
+ "Attribute ["
+ + key
+ + "] is not in allowed_attributes list of "
+ + str(type(self))
+ )
return self
def __str__(self):
@@ -217,255 +244,647 @@ def __str__(self):
def __repr__(self):
return self.urdf()
- def urdf(self,depth=0):
+ def urdf(self, depth=0):
name = type(self).__name__.lower()
- if self.element_name: name = self.element_name
- s = " "*depth + "<" + name + " "
- if hasattr(self,'attributes'):
+ if self.element_name:
+ name = self.element_name
+ s = " " * depth + "<" + name + " "
+ if hasattr(self, "attributes"):
for attr in self.attributes:
- to_insert = str(getattr(self,attr))
- if isinstance(to_insert,tuple):
- to_insert = str(to_insert).strip('(').strip(')').replace(',','')
-
- s+= ' '+str(attr)+'="'+eval_macros(to_insert,Element.string_macros)+'" '
- #Flag required but unnamed attributes
+ to_insert = str(getattr(self, attr))
+ if isinstance(to_insert, tuple):
+ to_insert = str(to_insert).strip("(").strip(")").replace(",", "")
+
+ s += (
+ " "
+ + str(attr)
+ + '="'
+ + eval_macros(to_insert, Element.string_macros)
+ + '" '
+ )
+ # Flag required but unnamed attributes
for attr in set(type(self).required_attributes).difference(self.attributes):
- s+= ' '+str(attr)+'="'+"UNNAMED_"+str(Element.element_counter)+'" '
+ s += (
+ " "
+ + str(attr)
+ + '="'
+ + "UNNAMED_"
+ + str(Element.element_counter)
+ + '" '
+ )
Element.element_counter += 1
if len(self) == 0 and self.xmltext == "":
- s+= "/>\n"
+ s += "/>\n"
else:
- s+= ">\n"
+ s += ">\n"
for elt in self:
- s += elt.urdf(depth+1)
+ s += elt.urdf(depth + 1)
if self.xmltext != "":
- s +=" "*(depth+1) + self.xmltext + "\n"
- s +=" "*depth + "" + type(self).__name__.lower() + ">\n"
+ s += " " * (depth + 1) + self.xmltext + "\n"
+ # s +=" "*depth + "" + type(self).__name__.lower() + ">\n"
+ s += " " * depth + "" + name + ">\n"
+ # print(s)
return s
+
@six.add_metaclass(NamedElementMeta)
class NamedElement(Element):
pass
+
+
############# elements #############
+
class Xacroinclude(Element):
- allowed_attributes = ['filename']
-class Xacrounless(Element):pass
-class Xacroif(Element):pass
+ allowed_attributes = ["filename"]
+
+
+class Xacrounless(Element):
+ pass
+
+
+class Xacroif(Element):
+ pass
+
+
class Xacroproperty(Element):
def __init__(self, **kwargs):
- if ('name' in kwargs and 'value' in kwargs):
- Element.string_macros[kwargs['name']] = float(kwargs['value'])
+ if "name" in kwargs and "value" in kwargs:
+ Element.string_macros[kwargs["name"]] = float(kwargs["value"])
class Group(Element):
- """ A group of top level elements that will be appended to the Robot() that owns this group"""
- allowed_elements = ['Joint','Link','Material','Transmission','Gazebo']
- allowed_attributes = ['name']
+ """A group of top level elements that will be appended to the Robot() that owns this group"""
+
+ allowed_elements = ["Joint", "Link", "Material", "Transmission", "Gazebo", "Sensor"]
+ allowed_attributes = ["name"]
class Robot(NamedElement):
- """ Robot is the top level element in a URDF """
- allowed_elements = ['Joint','Link','Material','Transmission','Gazebo']
+ """Robot is the top level element in a URDF"""
+
+ allowed_elements = ["Joint", "Link", "Material", "Transmission", "Gazebo", "Sensor"]
def urdf(self, depth=0):
- return '\n'+super(Robot,self).urdf(0)
+ return '\n' + super(Robot, self).urdf(0)
+
class Joint(Element):
- required_elements = ['Parent','Child']
- allowed_elements = ['Origin','Inertial','Visual','Collision','Axis','Calibration','Dynamics','Limit','Mimic','Safety_controller']
- required_attributes = ['name','type']
+ required_elements = ["Parent", "Child"]
+ allowed_elements = [
+ "Origin",
+ "Inertial",
+ "Visual",
+ "Collision",
+ "Axis",
+ "Calibration",
+ "Dynamics",
+ "Limit",
+ "Mimic",
+ "Safety_controller",
+ ]
+ required_attributes = ["name", "type"]
def __init__(self, *args, **kwargs):
+ if not "type" in kwargs:
+ kwargs["type"] = "revolute"
- if not 'type' in kwargs:
- kwargs['type'] = 'revolute'
-
- Joint_types = ['revolute','continuous','prismatic','fixed','floating','planar']
- if kwargs['type'] not in Joint_types:
- raise Exception('Joint type not correct')
+ Joint_types = [
+ "revolute",
+ "continuous",
+ "prismatic",
+ "fixed",
+ "floating",
+ "planar",
+ ]
+ if kwargs["type"] not in Joint_types:
+ raise Exception("Joint type not correct")
- super(Joint, self).__init__(*args,**kwargs)
+ super(Joint, self).__init__(*args, **kwargs)
class Link(NamedElement):
- allowed_elements = ['Inertial','Visual','Collision','Self_collision_checking', 'Contact']
+ allowed_elements = [
+ "Inertial",
+ "Visual",
+ "Collision",
+ "Self_collision_checking",
+ "Contact",
+ ]
+
class Transmission(NamedElement):
- allowed_elements = ['Type','Transjoint','Actuator']
+ allowed_elements = ["Type", "Transjoint", "Actuator"]
+ allowed_attributes = ["name"]
+
+
+class Type(Element):
+ allowed_attributes = ["xmltext"]
-class Type(Element): pass
class Transjoint(NamedElement):
- allowed_elements = ['Hardwareinterface']
+ allowed_elements = ["Hardwareinterface"]
element_name = "joint"
-class Hardwareinterface(Element): pass
-class Mechanicalreduction(Element):pass
+class Hardwareinterface(NamedElement):
+ allowed_attributes = ["xmltext"]
+ element_name = "hardwareInterface"
+
+
+class Mechanicalreduction(Element):
+ allowed_attributes = ["xmltext"]
+
class Actuator(NamedElement):
- allowed_elements = ['Mechanicalreduction','Hardwareinterface']
+ allowed_elements = ["Mechanicalreduction", "Hardwareinterface"]
+
class Parent(Element):
- required_attributes = ['link']
+ required_attributes = ["link"]
+ allowed_attributes = ["joint"]
def __init__(self, *args, **kwargs):
- """ If Link type passed in, extract name string """
- args = [arg for arg in args]
- for i,arg in enumerate(args):
+ """If Link type passed in, extract name string"""
+ args = [arg for arg in args]
+ for i, arg in enumerate(args):
if isinstance(arg, Link):
args[i] = arg.name
- super(Parent, self).__init__(*args,**kwargs)
+ super(Parent, self).__init__(*args, **kwargs)
+
class Child(Parent):
- required_attributes = ['link']
+ required_attributes = ["link"]
+
class Inertia(Element):
- allowed_attributes = ['ixx','ixy','ixz','iyy','iyz','izz']
+ allowed_attributes = ["ixx", "ixy", "ixz", "iyy", "iyz", "izz"]
+
def __init__(self, *args, **kwargs):
- if len(args) == 1 and isinstance(args[0],list):
+ if len(args) == 1 and isinstance(args[0], list):
if len(args[0]) == 6:
- kwargs["ixx"]=str(args[0][0])
- kwargs["ixy"]=str(args[0][1])
- kwargs["ixz"]=str(args[0][2])
- kwargs["iyy"]=str(args[0][3])
- kwargs["iyz"]=str(args[0][4])
- kwargs["izz"]=str(args[0][5])
+ kwargs["ixx"] = str(args[0][0])
+ kwargs["ixy"] = str(args[0][1])
+ kwargs["ixz"] = str(args[0][2])
+ kwargs["iyy"] = str(args[0][3])
+ kwargs["iyz"] = str(args[0][4])
+ kwargs["izz"] = str(args[0][5])
del args[0]
- super(Inertia, self).__init__(*args,**kwargs)
+ super(Inertia, self).__init__(*args, **kwargs)
+
class Visual(Element):
- allowed_elements = ['Origin','Geometry','Material']
+ allowed_elements = ["Origin", "Geometry", "Material"]
+
class Geometry(Element):
- allowed_elements = ['Box','Cylinder','Sphere','Mesh','Capsule']
- allowed_attributes = ['name']
+ allowed_elements = ["Box", "Cylinder", "Sphere", "Mesh", "Capsule"]
+ allowed_attributes = ["name"]
def __init__(self, *args, **kwargs):
- if (len(args) != 1):
+ if len(args) != 1:
raise Exception("Can only have one shape!")
- super(Geometry, self).__init__(*args,**kwargs)
+ super(Geometry, self).__init__(*args, **kwargs)
+
class Box(Element):
- allowed_attributes = ['size']
+ allowed_attributes = ["size"]
+
class Capsule(Element):
- allowed_attributes = ['radius','length']
+ allowed_attributes = ["radius", "length"]
+
class Cylinder(Element):
- allowed_attributes = ['radius','length']
+ allowed_attributes = ["radius", "length"]
+
class Sphere(Element):
- allowed_attributes = ['radius']
+ allowed_attributes = ["radius"]
+
class Mesh(Element):
- allowed_attributes = ['filename','scale']
+ allowed_attributes = ["filename", "scale"]
+
class Material(Element):
- allowed_elements = ['Color','Texture']
- allowed_attributes = ['name']
+ allowed_elements = ["Color", "Texture"]
+ allowed_attributes = ["name"]
+
class Color(Element):
- allowed_attributes = ['rgba']
+ allowed_attributes = ["rgba"]
+
class Texture(Element):
- allowed_attributes = ['filename']
+ allowed_attributes = ["filename"]
+
class Collision(Element):
- allowed_elements = ['Origin','Geometry','Material']
- allowed_attributes = ['name']
+ allowed_elements = ["Origin", "Geometry", "Material", "Surface"]
+ allowed_attributes = ["name"]
+
+
+class Surface(Element):
+ allowed_elements = ["Bounce"]
+
+
+class Bounce(Element):
+ allowed_elements = ["Restitution_coefficient", "Threshold"]
+
+
+class Restitution_coefficient(Element):
+ pass
+
+
+class Threshold(Element):
+ pass
+
class Self_collision_checking(Element):
- allowed_elements = ['Origin','Geometry']
- allowed_attributes = ['name']
+ allowed_elements = ["Origin", "Geometry"]
+ allowed_attributes = ["name"]
+
class Mass(Element):
- allowed_attributes = ['value']
+ allowed_attributes = ["value"]
+
class Origin(Element):
- allowed_attributes = ['xyz','rpy']
+ allowed_attributes = ["xyz", "rpy"]
+
def __init__(self, *args, **kwargs):
- if len(args) > 0 and isinstance(args[0],list):
+ if len(args) > 0 and isinstance(args[0], list):
if len(args[0]) == 6:
- kwargs["xyz"]=str(args[0][0])+' '+str(args[0][1])+' '+str(args[0][2])
- kwargs["rpy"]=str(args[0][3])+' '+str(args[0][4])+' '+str(args[0][5])
+ kwargs["xyz"] = (
+ str(args[0][0]) + " " + str(args[0][1]) + " " + str(args[0][2])
+ )
+ kwargs["rpy"] = (
+ str(args[0][3]) + " " + str(args[0][4]) + " " + str(args[0][5])
+ )
del args[0]
- super(Origin, self).__init__(*args,**kwargs)
+ super(Origin, self).__init__(*args, **kwargs)
+
class Axis(Element):
- allowed_attributes = ['xyz']
+ allowed_attributes = ["xyz"]
+
class Calibration(Element):
- allowed_attributes = ['rising','falling']
+ allowed_attributes = ["rising", "falling"]
+
class Safety_controller(Element):
- allowed_attributes = ['soft_lower_limit','soft_upper_limit','k_position','k_velocity']
+ allowed_attributes = [
+ "soft_lower_limit",
+ "soft_upper_limit",
+ "k_position",
+ "k_velocity",
+ ]
+
class Limit(Element):
- required_attributes = ['effort','velocity']
- allowed_attributes = ['lower','upper']
+ required_attributes = ["effort", "velocity"]
+ allowed_attributes = ["lower", "upper"]
+
class Dynamics(Element):
- allowed_attributes = ['damping','friction']
+ allowed_attributes = ["damping", "friction"]
+
class Mimic(Element):
- allowed_attributes = ['joint','multiplier','offset']
+ allowed_attributes = ["joint", "multiplier", "offset"]
+
def __init__(self, *args, **kwargs):
- if 'joint' not in kwargs:
+ if "joint" not in kwargs:
raise Exception('Mimic must have "joint" attribute')
- super(Mimic, self).__init__(*args,**kwargs)
+ super(Mimic, self).__init__(*args, **kwargs)
+
class Inertial(Element):
- allowed_elements = ['Origin','Mass','Inertia']
+ allowed_elements = ["Origin", "Mass", "Inertia"]
+
class Gazebo(Element):
- allowed_elements = ['Material','Gravity','Dampingfactor','Maxvel','Mindepth','Mu1','Mu2',
- 'Fdir1','Kp','Kd','Selfcollide','Maxcontacts','Laserretro','Plugin']
- allowed_attributes = ['reference','xmltext']
+ allowed_elements = [
+ "Collision",
+ "Material",
+ "Gravity",
+ "Dampingfactor",
+ "Maxvel",
+ "Mindepth",
+ "Mu1",
+ "Mu2",
+ "Fdir1",
+ "Kp",
+ "Kd",
+ "Selfcollide",
+ "Maxcontacts",
+ "Laserretro",
+ "Plugin",
+ "Preservefixedjoint",
+ "Disablefixedjointlumping",
+ "Sensor",
+ "Implicitspringdamper",
+ "Pose",
+ ]
+ allowed_attributes = ["reference", "xmltext"]
+
class Plugin(Element):
- allowed_elements = ['Robotnamespace']
- allowed_attributes = ['name','filename']
-
-class Robotnamespace(Element): pass
-class Gravity(Element): pass
-class Laserretro(Element): pass
-class Maxcontacts(Element): pass
-class Selfcollide(Element): pass
-class Kd(Element): pass
-class Kp(Element): pass
-class Fdir1(Element): pass
-class Mu2(Element): pass
-class Dampingfactor(Element): pass
-class Maxvel(Element): pass
-class Mindepth(Element): pass
-class Mu1(Element): pass
+ allowed_elements = [
+ "Robotnamespace",
+ "Yarpconfigurationfile",
+ "Initialconfiguration",
+ "Robotnamefromconfigfile",
+ "Yarprobotinterfaceconfigurationfile",
+ "Yarpconfigurationstring",
+ ]
+ allowed_attributes = ["name", "filename"]
+
+
+class Sensor(Element):
+ allowed_elements = [
+ "Always_on",
+ "Update_rate",
+ "Force_torque",
+ "Pose",
+ "Plugin",
+ "Parent",
+ "Origin",
+ "Camera",
+ "Visualize",
+ "Ray",
+ ]
+ allowed_attributes = ["name", "type"]
+
+
+class Camera(Element):
+ allowed_elements = ["Horizontal_fov", "Distortion", "Image", "Clip", "Pose"]
+ allowed_attributes = ["name"]
+ pass
+
+
+class Ray(Element):
+ allowed_elements = ["Scan", "Range", "Noise"]
+
+
+class Scan(Element):
+ allowed_elements = ["Horizontal"]
+
+
+class Horizontal(Element):
+ allowed_elements = ["Samples", "Resolution", "Min_angle", "Max_angle"]
+
+
+class Samples(Element):
+ pass
+
+
+class Resolution(Element):
+ pass
+
+
+class Min_angle(Element):
+ pass
+
+
+class Max_angle(Element):
+ pass
+
+
+class Range(Element):
+ allowed_elements = ["Min", "Max", "Resolution"]
+
+
+class Min(Element):
+ pass
+
+
+class Max(Element):
+ pass
+
+
+class Noise(Element):
+ allowed_elements = ["Type", "Mean", "Stddev"]
+
+
+# class Type(Element): pass
+class Mean(Element):
+ pass
+
+
+class Stddev(Element):
+ pass
+
+
+class Horizontal_fov(Element):
+ pass
+
+
+class Distortion(Element):
+ allowed_elements = ["K1", "K2", "K3", "P1", "P2", "Center"]
+
+
+class K1(Element):
+ pass
+
+
+class K2(Element):
+ pass
+
+
+class K3(Element):
+ pass
+
+
+class P1(Element):
+ pass
+
+
+class P2(Element):
+ pass
+
+
+class Center(Element):
+ pass
+
+
+class Visualize(Element):
+ pass
+
+
+class Image(Element):
+ allowed_elements = ["Width", "Height", "Format"]
+
+
+class Width(Element):
+ pass
+
+
+class Height(Element):
+ pass
+
+
+class Format(Element):
+ pass
+
+
+class Clip(Element):
+ allowed_elements = ["Near", "Far"]
+
+
+class Near(Element):
+ pass
+
+
+class Far(Element):
+ pass
+
+
+class Force_torque(Element):
+ allowed_elements = ["Measure_direction", "Frame"]
+
+
+class Measure_direction(Element):
+ pass
+
+
+class Frame(Element):
+ pass
+
+
+class Always_on(Element):
+ pass
+
+
+class Update_rate(Element):
+ pass
+
+
+class Pose(Element):
+ allowed_attributes = ["frame"]
+ pass
+
+
+class Yarprobotinterfaceconfigurationfile(Element):
+ pass
+
+
+class Implicitspringdamper(Element):
+ pass
+
+
+class Yarpconfigurationstring(Element):
+ pass
+
+
+class Robotnamefromconfigfile(Element):
+ pass
+
+
+class Initialconfiguration(Element):
+ pass
+
+
+class Yarpconfigurationfile(Element):
+ pass
+
+
+class Robotnamespace(Element):
+ pass
+
+
+class Gravity(Element):
+ pass
+
+
+class Laserretro(Element):
+ pass
+
+
+class Maxcontacts(Element):
+ pass
+
+
+class Selfcollide(Element):
+ pass
+
+
+class Kd(Element):
+ pass
+
+
+class Kp(Element):
+ pass
+
+
+class Fdir1(Element):
+ pass
+
+
+class Mu2(Element):
+ pass
+
+
+class Dampingfactor(Element):
+ pass
+
+
+class Maxvel(Element):
+ pass
+
+
+class Mindepth(Element):
+ pass
+
+
+class Mu1(Element):
+ pass
+
+
+# add new classes -- which will be ignored too
+class Preservefixedjoint(Element):
+ pass
+
+
+class Disablefixedjointlumping(Element):
+ pass
+
class Contact(Element):
"""Bullet3 element."""
- allowed_elements = ['Stiffness', 'Damping', 'Lateral_Friction']
+
+ allowed_elements = ["Stiffness", "Damping", "Lateral_Friction"]
+
class Stiffness(Element):
"""Bullet3 element."""
- allowed_attributes = ['value']
+
+ allowed_attributes = ["value"]
+
class Damping(Element):
"""Bullet3 element."""
- allowed_attributes = ['value']
+
+ allowed_attributes = ["value"]
+
class Lateral_Friction(Element):
"""Bullet3 element."""
- allowed_attributes = ['value']
+
+ allowed_attributes = ["value"]
+
################## elements###########
+
def urdf_to_odio(urdf_string):
"""
- Dump a URDF string to odio DSL representation
+ Dump a URDF string to odio DSL representation
"""
root = ET.fromstring(urdf_string)
@@ -473,63 +892,48 @@ def urdf_to_odio(urdf_string):
return s
-def xml_to_odio(root,depth=0):
+def xml_to_odio(root, depth=0):
"""
- Dump an xml ElementTree to the odio DSL representation
+ Dump an xml ElementTree to the odio DSL representation
"""
special_names = {}
s = ""
name = root.tag
- if (root.tag[0] == '{'):
- name = 'xacro'+root.tag[root.tag.find('}')+1:]
+ if root.tag[0] == "{":
+ name = "xacro" + root.tag[root.tag.find("}") + 1 :]
if name in special_names:
name = special_names[name]
- s += "\n"+ ' '*depth + name.capitalize() + '('
+ s += "\n" + " " * depth + name.capitalize() + "("
for tag in root:
- s+= xml_to_odio(tag,depth+1) + ','
+ s += xml_to_odio(tag, depth + 1) + ","
if len(root.attrib.items()) < 3:
space = ""
- if (len(root)>0):
- s+= '\n'+' '*(depth+1)
+ if len(root) > 0:
+ s += "\n" + " " * (depth + 1)
else:
- space = '\n'+' '*(depth+1)
+ space = "\n" + " " * (depth + 1)
- for key,value in root.attrib.items():
- s+= space + key + '= "'+value+'",'
+ for key, value in root.attrib.items():
+ s += space + key + '= "' + value + '",'
if root.text and root.text.strip() != "":
- s+= space + 'xmltext = "'+root.text+'",'
+ s += space + 'xmltext = "' + root.text + '",'
- if s[-1]==',':
+ if s[-1] == ",":
s = s[:-1]
if len(root) < 0:
- s += ')'
+ s += ")"
else:
- s+= space + ')'
- #s+= '\n'+' '*depth +')'
+ s += space + ")"
+ # s+= '\n'+' '*depth +')'
return s
+
if __name__ == "__main__":
pass
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-