def draw(self, context, rect): """Draws the overlay. Args: context: A `types.MJRCONTEXT` pointer. rect: A `types.MJRRECT`. """ mjlib.mjr_overlay(self.style, self.position, rect, util.to_binary_string(self.title), util.to_binary_string(self.body), context)
def _temporary_vfs(filenames_and_contents): """Creates a temporary VFS containing one or more files. Args: filenames_and_contents: A dict containing `{filename: contents}` pairs. The length of each filename must not exceed 98 characters. Yields: A `types.MJVFS` instance. Raises: Error: If a file cannot be added to the VFS, or if an error occurs when looking up the filename. ValueError: If the length of a filename exceeds 98 characters. """ vfs = types.MJVFS() mjlib.mj_defaultVFS(vfs) for filename, contents in six.iteritems(filenames_and_contents): if len(filename) > _MAX_VFS_FILENAME_CHARACTERS: raise ValueError( _VFS_FILENAME_TOO_LONG.format( length=len(filename), limit=_MAX_VFS_FILENAME_CHARACTERS, filename=filename)) filename = util.to_binary_string(filename) contents = util.to_binary_string(contents) _, extension = os.path.splitext(filename) # For XML files we need to append a NULL byte, otherwise MuJoCo's parser # can sometimes read past the end of the string. However, we should *not* # do this for other file types (in particular for STL meshes, where this # causes MuJoCo's compiler to complain that the file size is incorrect). append_null = extension.lower() == b".xml" num_bytes = len(contents) + append_null retcode = mjlib.mj_makeEmptyFileVFS(vfs, filename, num_bytes) if retcode == 1: raise Error("Failed to create {!r}: VFS is full.".format(filename)) elif retcode == 2: raise Error( "Failed to create {!r}: duplicate filename.".format(filename)) file_index = mjlib.mj_findFileVFS(vfs, filename) if file_index == -1: raise Error("Could not find {!r} in the VFS".format(filename)) vf = vfs.filedata[file_index] vf_as_char_arr = ctypes.cast(vf, ctypes.POINTER(ctypes.c_char * num_bytes)) vf_as_char_arr.contents[:len(contents)] = contents if append_null: vf_as_char_arr.contents[-1] = _NULL try: yield vfs finally: mjlib.mj_deleteVFS(vfs) # Ensure that we free the VFS afterwards.
def _get_model_ptr_from_binary(binary_path=None, byte_string=None): """Returns a pointer to an mjModel from the contents of a MuJoCo model binary. Args: binary_path: Path to an MJB file (as produced by MjModel.save_binary). byte_string: String of bytes (as returned by MjModel.to_bytes). One of `binary_path` or `byte_string` must be specified. Returns: A `ctypes.POINTER` to a new `mjbindings.types.MJMODEL` instance. Raises: TypeError: If both or neither of `byte_string` and `binary_path` are specified. """ if binary_path is None and byte_string is None: raise TypeError( "At least one of `byte_string` or `binary_path` must be specified.") elif binary_path is not None and byte_string is not None: raise TypeError( "Only one of `byte_string` or `binary_path` may be specified.") _maybe_register_license() if byte_string is not None: with _temporary_vfs({_FAKE_BINARY_FILENAME: byte_string}) as vfs: ptr = mjlib.mj_loadModel(_FAKE_BINARY_FILENAME, vfs) else: ptr = mjlib.mj_loadModel(util.to_binary_string(binary_path), None) # Free resources when the ctypes pointer is garbage collected. _create_finalizer(ptr, mjlib.mj_deleteModel) return ptr
def export_with_assets(mjcf_model, out_dir, out_file_name=None): """Saves mjcf.model in the given directory in MJCF (XML) format. Creates an MJCF XML file named `out_file_name` in the specified `out_dir`, and writes all of its assets into the same directory. Args: mjcf_model: `mjcf.RootElement` instance to export. out_dir: Directory to save the model and assets. Will be created if it does not already exist. out_file_name: (Optional) Name of the XML file to create. Defaults to the model name (`mjcf_model.model`) suffixed with '.xml'. Raises: ValueError: If `out_file_name` is a string that does not end with '.xml'. """ if out_file_name is None: out_file_name = mjcf_model.model + '.xml' elif not out_file_name.lower().endswith('.xml'): raise ValueError('If `out_file_name` is specified it must end with ' '\'.xml\': got {}'.format(out_file_name)) assets = mjcf_model.get_assets() # This should never happen because `mjcf` does not support `.xml` assets. assert out_file_name not in assets assets[out_file_name] = mjcf_model.to_xml_string() if not os.path.exists(out_dir): os.makedirs(out_dir) for filename, contents in assets.items(): with open(os.path.join(out_dir, filename), 'wb') as f: f.write(util.to_binary_string(contents))
def _maybe_register_license(path=None): """Registers the MuJoCo license if not already registered. Args: path: Optional custom path to license key file. Raises: Error: If the license could not be registered. """ with _REGISTRATION_LOCK: global _REGISTERED if not _REGISTERED: if path is None: path = util.get_mjkey_path() # TODO(b/176220357): Repeatedly activating a trial license results in # errors (for example this could happen if # `mj_activate` was already called by another library # within the same process). To avoid such errors we # unconditionally deactivate any active licenses before # calling `mj_activate`. mjlib.mj_deactivate() result = mjlib.mj_activate(util.to_binary_string(path)) if result == 1: _REGISTERED = True # Internal analytics of mj_activate. elif result == 0: raise Error("Could not register license.") else: raise Error( "Unknown registration error (code: {})".format(result))
def render(self, context, viewport, location): """Renders the overlay on screen. Args: context: MjrContext instance. viewport: Viewport instance. location: Value defined in PanelLocation enum. """ columns = self._model.get_columns() if not columns: return columns = np.asarray(columns) left_column = '\n'.join(columns[:, 0]) right_column = '\n'.join(columns[:, 1]) mjlib.mjr_overlay(enums.mjtFont.mjFONT_NORMAL, location.value, viewport.mujoco_rect, util.to_binary_string(left_column), util.to_binary_string(right_column), context.ptr)
def _load_xml(filename, vfs_or_none): """Invokes `mj_loadXML` with logging/error handling.""" error_buf = ctypes.create_string_buffer(_ERROR_BUFSIZE) model_ptr = mjlib.mj_loadXML(util.to_binary_string(filename), vfs_or_none, error_buf, _ERROR_BUFSIZE) if not model_ptr: raise Error(util.to_native_string(error_buf.value)) elif error_buf.value: logging.warning(util.to_native_string(error_buf.value)) # Free resources when the ctypes pointer is garbage collected. _create_finalizer(model_ptr, mjlib.mj_deleteModel) return model_ptr
def testFileNameTrimming(self): original_filename = ( 'THIS_IS_AN_EXTREMELY_LONG_FILENAME_THAT_WOULD_CAUSE_MUJOCO_TO_COMPLAIN' '_THAT_ITS_INTERNAL_LENGTH_LIMIT_IS_EXCEEDED_IF_NOT_TRIMMED_DOWN') extension = '.some_extension' asset = attribute.Asset( contents='', extension=extension, prefix=original_filename) vfs_filename = asset.get_vfs_filename() self.assertLen(vfs_filename, constants.MAX_VFS_FILENAME_LENGTH) vfs = types.MJVFS() mjlib.mj_defaultVFS(vfs) success_code = 0 retval = mjlib.mj_makeEmptyFileVFS( vfs, util.to_binary_string(vfs_filename), 1) self.assertEqual(retval, success_code) mjlib.mj_deleteVFS(vfs)
def get_vfs_filename(self): """Returns the name of the asset file as registered in MuJoCo's VFS.""" # Hash the contents of the asset to get a unique identifier. hash_string = hashlib.sha1(util.to_binary_string(self.contents)).hexdigest() # Prepend the prefix, if one exists. if self.prefix: prefix = self.prefix raw_length = len(prefix) + len(hash_string) + len(self.extension) + 1 if raw_length > constants.MAX_VFS_FILENAME_LENGTH: trim_amount = raw_length - constants.MAX_VFS_FILENAME_LENGTH prefix = prefix[:-trim_amount] filename = '-'.join([prefix, hash_string]) else: filename = hash_string # An extension is needed because MuJoCo's compiler looks at this when # deciding how to load meshes and heightfields. return filename + self.extension
def save_last_parsed_model_to_xml(xml_path, check_model=None): """Writes a description of the most recently loaded model to an MJCF XML file. Args: xml_path: Path to the output XML file. check_model: Optional `MjModel` instance. If specified, this model will be checked to see if it is the most recently parsed one, and a ValueError will be raised otherwise. Raises: Error: If MuJoCo encounters an error while writing the XML file. ValueError: If `check_model` was passed, and this model is not the most recently parsed one. """ if check_model and check_model.ptr is not _LAST_PARSED_MODEL_PTR: raise ValueError(_NOT_LAST_PARSED_ERROR) error_buf = ctypes.create_string_buffer(_ERROR_BUFSIZE) mjlib.mj_saveLastXML(util.to_binary_string(xml_path), _LAST_PARSED_MODEL_PTR, error_buf, _ERROR_BUFSIZE) if error_buf.value: raise Error(error_buf.value)
def _maybe_register_license(path=None): """Registers the MuJoCo license if not already registered. Args: path: Optional custom path to license key file. Raises: Error: If the license could not be registered. """ global _REGISTERED if not _REGISTERED: if path is None: path = util.get_mjkey_path() result = mjlib.mj_activate(util.to_binary_string(path)) if result == 1: _REGISTERED = True elif result == 0: raise Error("Could not register license.") else: raise Error("Unknown registration error (code: {})".format(result))
def name2id(self, name, object_type): """Returns the integer ID of a specified MuJoCo object. Args: name: String specifying the name of the object to query. object_type: The type of the object. Can be either a lowercase string (e.g. 'body', 'geom') or an `mjtObj` enum value. Returns: An integer object ID. Raises: Error: If `object_type` is not a valid MuJoCo object type, or if no object with the corresponding name and type was found. """ if not isinstance(object_type, int): object_type = _str2type(object_type) obj_id = mjlib.mj_name2id( self.ptr, object_type, util.to_binary_string(name)) if obj_id == -1: raise Error("Object of type {!r} with name {!r} does not exist.".format( _type2str(object_type), name)) return obj_id
def main(num_objs, path, model_name, gRange_inp=0.6): global gRange #gRange = gRange_inp xml_file = os.path.join(path, "assets", model_name) mjcf_model = etree.parse(xml_file) # pdb.set_trace() #mjcf_model = mjcf.from_path(xml_file) worldbody = mjcf_model.find('./worldbody') build_walls = True targets = [] floor = create_floor() worldbody.append(floor) worldbody.append(make_camera()) if num_objs: for obj in range(num_objs): body, pos, target = make_object(obj, mjcf_model) worldbody.append(body) targets.append(target) else: targets.append(make_target(0, mjcf_model)) for tar in targets: worldbody.append(tar) if build_walls: walls = make_walls() for wall in walls: worldbody.append(wall) agent, pos = make_agent(0) worldbody.append(agent) contents = etree.tostring(mjcf_model, pretty_print=True) contents= minidom.parseString(contents).toprettyxml(indent=" ") with open(os.path.join(path, "assets/point/", 'output.xml'), 'wb') as f: f.write(util.to_binary_string(contents))
def save_binary(self, binary_path): """Saves the MjModel instance to a binary file.""" mjlib.mj_saveModel(self.ptr, util.to_binary_string(binary_path), None, 0)
def _str2type(type_str): type_id = mjlib.mju_str2Type(util.to_binary_string(type_str)) if not type_id: raise Error("{!r} is not a valid object type name.".format(type_str)) return type_id