def validate(xml_dict): ''' If we make assumptions elsewhere in XML processing, then they should be enforced here. ''' # Assumption: radians for angles, "xyz" euler angle sequence, etc. values = {'@coordinate': 'local', '@angle': 'radian', '@eulerseq': 'xyz'} for key, value in values.items(): if key in xml_dict: assert value == xml_dict[ key], 'Invalid value for \"%s\". We support only \"%s\"' % ( key, value) # Assumption: all meshes have name if "asset" in xml_dict and "mesh" in xml_dict["asset"]: for mesh in xml_dict["asset"]["mesh"]: assert "@name" in mesh, "%s is missing name" % mesh # Assumption: none all the default classes is global. if "default" in xml_dict: for key, value in xml_dict["default"].items(): assert key == "default", "Dont use global variables in default %s %s" % ( key, value) # Assumption: all joints have name. def assert_joint_names(node): if "joint" in node: for joint in node["joint"]: assert "@name" in joint, "Missing name for %s" % joint if "worldbody" in xml_dict: closure_transform(assert_joint_names)(xml_dict["worldbody"])
def extract_includes(xml_dict, root_xml_path, enforce_validation=True): ''' extracts "include" xmls and substitutes them. ''' def transform_include(node): if "include" in node: if isinstance(node["include"], OrderedDict): node["include"] = [node["include"]] include_xmls = [] for include_dict in node["include"]: include_path = include_dict["@file"] if not exists(include_path): include_path = join(dirname(abspath(root_xml_path)), include_path) assert exists( include_path), "Cannot include file: %s" % include_path with open(include_path) as f: include_string = f.read() include_xml = xmltodict.parse(include_string.strip()) closure_transform(transform_include)(include_xml) assert "mujocoinclude" in include_xml, "Missing <mujocoinclude>." include_xmls.append(include_xml["mujocoinclude"]) del node["include"] for include_xml in include_xmls: preprocess(include_xml, root_xml_path, enforce_validation=enforce_validation) update_mujoco_dict(node, include_xml) closure_transform(transform_include)(xml_dict)
def fun(xml_dict): def closure(node): if 'joint' in node: node["joint"] = [ j for j in node["joint"] if j["@type"] != "hinge" or np.linalg.norm(j["@axis"] - axis) >= 1e-5 ] return closure_transform(closure)(xml_dict)
def set_joint_damping_transform(damping, joint_name): ''' Set joints damping to a single value. Args: damping (float): damping to set joint_name (string): partial name of joint. Any joint with joint_name as a substring will be affected. ''' def closure(node): for joint in node.get('joint', []): if joint_name in joint['@name']: joint['@damping'] = damping return closure_transform(closure)
def to_xml_dict(self): ''' Generates XML for this object and all of its children. see generate_xml() for parameter documentation Returns merged xml_dict ''' full_xml_dict = OrderedDict() # First add all of our own xml self.xml_dict = self.generate_xml_dict() # Removed joints marked to be static. We set positions in XML instead of using qpos. for body in self.xml_dict.get("worldbody", {}).get("body", []): remaining_joints = [] for jnt in body.get("joint", []): if jnt["@type"] == "slide": axis_idx = get_axis_index(jnt["@axis"]) if self._keep_slide_joint[axis_idx]: remaining_joints.append(jnt) else: body["@pos"][axis_idx] = float( body["@pos"] [axis_idx]) + self.absolute_position[axis_idx] elif jnt["@type"] == "hinge": axis_idx = get_axis_index(jnt["@axis"]) if self._keep_hinge_joint[axis_idx]: remaining_joints.append(jnt) elif jnt["@type"] == "ball": remaining_joints.append(jnt) body["joint"] = remaining_joints if len(self.markers) > 0: bodies = [ body for body in self.xml_dict["worldbody"]["body"] if "annotation" not in body["@name"] and ( "@mocap" not in body or not body["@mocap"]) ] assert len(bodies) == 1, ("Object %s should have only one body " % self) + \ "to attach markers to. Otherwise mark() is" + \ "ambiguous." body = bodies[0] if "site" not in body: body["site"] = [] for marker in self.markers: site = OrderedDict() site['@name'] = marker['name'] site['@pos'] = marker['position'] site['@size'] = marker['size'] site['@rgba'] = marker['rgba'] site['@type'] = marker['type'] body['site'].append(site) # Adding material influences nodes of the parent. if self._material is not None: update_mujoco_dict(self.xml_dict, self._material.generate_xml_dict()) def assign_material(node): if "geom" in node: for g in node["geom"]: g["@material"] = self._material.name closure_transform(assign_material)(self.xml_dict) update_mujoco_dict(full_xml_dict, self.xml_dict) for transform in self.transforms: transform(full_xml_dict) # Then add the xml of all of our children for children in self.children.values(): for child, _ in children: child_dict = child.to_xml_dict() update_mujoco_dict(full_xml_dict, child_dict) return full_xml_dict