##########################################################
# Copyright (c) 2024 Lara Bergmann, Bielefeld University #
##########################################################
import numpy as np
import mujoco
from mujoco import MjData, MjModel, mjtObj
[docs]
def set_actuator_ctrl(model: MjModel, data: MjData, actuator_name: str, value: float) -> None:
"""Set the control inputs for the desired actuator.
:param model: the MuJoCo model (MjModel)
:param data: the MuJoCo data structure (MjData)
:param actuator_name: the name of the actuator for which to set the control input
:param value: the control input of the actuator
"""
actuator_id = model.actuator(actuator_name).id
assert actuator_id != -1, 'Actuator name not found in MuJoCo model.'
data.ctrl[actuator_id] = value
[docs]
def get_joint_qacc(model: MjModel, data: MjData, name: str) -> np.ndarray:
"""Return the joint's linear and angular acceleration (qacc) depending on the type of joint.
:param model: mjModel of the MuJoCo environment
:param data: mjData of the MuJoCo environment
:param name: the name of the joint
:return: the qacc of the joint
"""
joint_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_JOINT, name)
assert joint_id != -1, 'Joint name not found in MuJoCo model.'
joint_type = model.jnt_type[joint_id]
joint_addr = model.jnt_dofadr[joint_id]
if joint_type == mujoco.mjtJoint.mjJNT_FREE:
ndim = 6
elif joint_type == mujoco.mjtJoint.mjJNT_BALL:
ndim = 4
else:
assert joint_type in (mujoco.mjtJoint.mjJNT_HINGE, mujoco.mjtJoint.mjJNT_SLIDE)
ndim = 1
start_idx = joint_addr
end_idx = joint_addr + ndim
return data.qacc[start_idx:end_idx].copy()
[docs]
def get_mujoco_type_names(model: MjModel, obj_type: str, name_pattern: str = '') -> list[str]:
"""Return a list of names of the current model that belong to objects of the specified type and whose names match
the given name_pattern.
:param model: mjModel of the MuJoCo environment
:param obj_type: mjData of the MuJoCo environment
:param name_pattern: the pattern to search for in the object names, defaults to ''
:return: a list of object names matching the name_pattern and the obj_type
"""
mj_model_names = MujocoModelNames(model)
names_all = getattr(mj_model_names, f'{obj_type}_names')
names = [name for name in names_all if name_pattern in name]
return names
##############################################################################################################
# The following functions and classes are completely or at least partially adopted from gymnasium-robotics: #
# https://github.com/Farama-Foundation/Gymnasium-Robotics/blob/main/gymnasium_robotics/utils/mujoco_utils.py #
##############################################################################################################
MJ_OBJ_TYPES = [
'mjOBJ_BODY',
'mjOBJ_JOINT',
'mjOBJ_GEOM',
'mjOBJ_SITE',
'mjOBJ_CAMERA',
'mjOBJ_ACTUATOR',
'mjOBJ_SENSOR',
]
[docs]
def set_joint_qpos(model: MjModel, data: MjData, name: str, value: float | np.ndarray) -> None:
"""Set the joint positions (qpos) of the model.
:param model: mjModel of the MuJoCo environment
:param data: mjData of the MuJoCo environment
:param name: the name of the joint
:param value: the new qpos
"""
joint_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_JOINT, name)
assert joint_id != -1, 'Joint name not found in MuJoCo model.'
joint_type = model.jnt_type[joint_id]
joint_addr = model.jnt_qposadr[joint_id]
if joint_type == mujoco.mjtJoint.mjJNT_FREE:
ndim = 7
elif joint_type == mujoco.mjtJoint.mjJNT_BALL:
ndim = 4
else:
assert joint_type in (mujoco.mjtJoint.mjJNT_HINGE, mujoco.mjtJoint.mjJNT_SLIDE)
ndim = 1
start_idx = joint_addr
end_idx = joint_addr + ndim
value = np.array(value)
if ndim > 1:
assert value.shape == (end_idx - start_idx), f'Value has incorrect shape {name}: {value}'
data.qpos[start_idx:end_idx] = value
[docs]
def get_joint_qpos(model: MjModel, data: MjData, name: str) -> np.ndarray:
"""Return the joint's position and orientation (qpos) depending on the type of the joint.
:param model: mjModel of the MuJoCo environment
:param data: mjData of the MuJoCo environment
:param name: the name of the joint
:return: the qpos of the joint
"""
joint_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_JOINT, name)
assert joint_id != -1, 'Joint name not found in MuJoCo model.'
joint_type = model.jnt_type[joint_id]
joint_addr = model.jnt_qposadr[joint_id]
if joint_type == mujoco.mjtJoint.mjJNT_FREE:
ndim = 7
elif joint_type == mujoco.mjtJoint.mjJNT_BALL:
ndim = 4
else:
assert joint_type in (mujoco.mjtJoint.mjJNT_HINGE, mujoco.mjtJoint.mjJNT_SLIDE)
ndim = 1
start_idx = joint_addr
end_idx = joint_addr + ndim
return data.qpos[start_idx:end_idx].copy()
[docs]
def set_joint_qvel(model: MjModel, data: MjData, name: str, value: float | np.ndarray) -> None:
"""Set the joints linear and angular (qvel) of the model.
:param model: mjModel of the MuJoCo environment
:param data: mjData of the MuJoCo environment
:param name: the name of the joint
:param value: the new qvel
"""
joint_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_JOINT, name)
assert joint_id != -1, 'Joint name not found in MuJoCo model.'
joint_type = model.jnt_type[joint_id]
joint_addr = model.jnt_dofadr[joint_id]
if joint_type == mujoco.mjtJoint.mjJNT_FREE:
ndim = 6
elif joint_type == mujoco.mjtJoint.mjJNT_BALL:
ndim = 3
else:
assert joint_type in (mujoco.mjtJoint.mjJNT_HINGE, mujoco.mjtJoint.mjJNT_SLIDE)
ndim = 1
start_idx = joint_addr
end_idx = joint_addr + ndim
value = np.array(value)
if ndim > 1:
assert value.shape == (end_idx - start_idx), f'Value has incorrect shape {name}: {value}'
data.qvel[start_idx:end_idx] = value
[docs]
def get_joint_qvel(model: MjModel, data: MjData, name: str) -> np.ndarray:
"""Return the joint's linear and angular velocities (qvel) depending on the type of the joint.
:param model: mjModel of the MuJoCo environment
:param data: mjData of the MuJoCo environment
:param name: the name of the joint
:return: the qvel of the joint
"""
joint_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_JOINT, name)
assert joint_id != -1, 'Joint name not found in MuJoCo model.'
joint_type = model.jnt_type[joint_id]
joint_addr = model.jnt_dofadr[joint_id]
if joint_type == mujoco.mjtJoint.mjJNT_FREE:
ndim = 6
elif joint_type == mujoco.mjtJoint.mjJNT_BALL:
ndim = 4
else:
assert joint_type in (mujoco.mjtJoint.mjJNT_HINGE, mujoco.mjtJoint.mjJNT_SLIDE)
ndim = 1
start_idx = joint_addr
end_idx = joint_addr + ndim
return data.qvel[start_idx:end_idx].copy()
[docs]
class MujocoModelNames:
"""Access mjtObj object names and ids of the current MuJoCo model.
This class supports access to the names and ids of the following mjObj types:
- mjOBJ_BODY
- mjOBJ_JOINT
- mjOBJ_GEOM
- mjOBJ_SITE
- mjOBJ_CAMERA
- mjOBJ_ACTUATOR
- mjOBJ_SENSOR
The properties provided for each ``mjObj`` are:
- ``mjObj`` names: list of the mjObj names in the model of type mjOBJ_FOO
- ``mjObj`` name2id: dictionary with name of the mjObj as keys and id of the mjObj as values
- ``mjObj`` id2name: dictionary with id of the mjObj as keys and name of the mjObj as values
"""
def __init__(self, model: MjModel) -> None:
"""Access mjtObj object names and ids of the current MuJoCo model.
:param model: mjModel of the MuJoCo environment
"""
(
self._body_names,
self._body_name2id,
self._body_id2name,
) = extract_mj_names(model, mujoco.mjtObj.mjOBJ_BODY)
(
self._joint_names,
self._joint_name2id,
self._joint_id2name,
) = extract_mj_names(model, mujoco.mjtObj.mjOBJ_JOINT)
(
self._geom_names,
self._geom_name2id,
self._geom_id2name,
) = extract_mj_names(model, mujoco.mjtObj.mjOBJ_GEOM)
(
self._site_names,
self._site_name2id,
self._site_id2name,
) = extract_mj_names(model, mujoco.mjtObj.mjOBJ_SITE)
(
self._camera_names,
self._camera_name2id,
self._camera_id2name,
) = extract_mj_names(model, mujoco.mjtObj.mjOBJ_CAMERA)
(
self._actuator_names,
self._actuator_name2id,
self._actuator_id2name,
) = extract_mj_names(model, mujoco.mjtObj.mjOBJ_ACTUATOR)
(
self._sensor_names,
self._sensor_name2id,
self._sensor_id2name,
) = extract_mj_names(model, mujoco.mjtObj.mjOBJ_SENSOR)
@property
def body_names(self) -> tuple[str, ...] | tuple[()]:
"""Return a tuple of body names in the MuJoCo model.
:return: body names
"""
return self._body_names
@property
def body_name2id(self) -> dict[str, int]:
"""Return a dict containing name-id pairs of the bodies in the MuJoCo model.
:return: dict with name-id pairs
"""
return self._body_name2id
@property
def body_id2name(self) -> dict[int, str]:
"""Return a dict containing id-name pairs of the bodies in the MuJoCo model.
:return: dict with id-name pairs
"""
return self._body_id2name
@property
def joint_names(self) -> tuple[str, ...] | tuple[()]:
"""Return a tuple of joint names in the MuJoCo model.
:return: joint names
"""
return self._joint_names
@property
def joint_name2id(self) -> dict[str, int]:
"""Return a dict containing name-id pairs of the joints in the MuJoCo model.
:return: dict with name-id pairs
"""
return self._joint_name2id
@property
def joint_id2name(self) -> dict[int, str]:
"""Return a dict containing id-name pairs of the joints in the MuJoCo model.
:return: dict with id-name pairs
"""
return self._joint_id2name
@property
def geom_names(self) -> tuple[str, ...] | tuple[()]:
"""Return a tuple of geom names in the MuJoCo model.
:return: geom names
"""
return self._geom_names
@property
def geom_name2id(self) -> dict[str, int]:
"""Return a dict containing name-id pairs of the geoms in the MuJoCo model.
:return: dict with name-id pairs
"""
return self._geom_name2id
@property
def geom_id2name(self) -> dict[int, str]:
"""Return a dict containing id-name pairs of the geoms in the MuJoCo model.
:return: dict with id-name pairs
"""
return self._geom_id2name
@property
def site_names(self) -> tuple[str, ...] | tuple[()]:
"""Return the site names in the MuJoCo model.
:return: tuple of model site names
"""
return self._site_names
@property
def site_name2id(self) -> dict[str, int]:
"""Return a dict containing name-id pairs of the sites in the MuJoCo model.
:return: dict with name-id pairs
"""
return self._site_name2id
@property
def site_id2name(self) -> dict[int, str]:
"""Return a dict containing id-name pairs of the sites in the MuJoCo model.
:return: dict with id-name pairs
"""
return self._site_id2name
@property
def camera_names(self) -> tuple[str, ...] | tuple[()]:
"""Return a tuple of camera names in the MuJoCo model.
:return: camera names
"""
return self._camera_names
@property
def camera_name2id(self) -> dict[str, int]:
"""Return a dict containing name-id pairs of the cameras in the MuJoCo model.
:return: dict with name-id pairs
"""
return self._camera_name2id
@property
def camera_id2name(self) -> dict[int, str]:
"""Return a dict containing id-name pairs of the cameras in the MuJoCo model.
:return: dict with id-name pairs
"""
return self._camera_id2name
@property
def actuator_names(self) -> tuple[str, ...] | tuple[()]:
"""Return a tuple of actuator names in the MuJoCo model.
:return: actuator names
"""
return self._actuator_names
@property
def actuator_name2id(self) -> dict[str, int]:
"""Return a dict containing name-id pairs of the actuators in the MuJoCo model.
:return: dict with name-id pairs
"""
return self._actuator_name2id
@property
def actuator_id2name(self) -> dict[int, str]:
"""Return a dict containing id-name pairs of the actuators in the MuJoCo model.
:return: dict with id-name pairs
"""
return self._actuator_id2name
@property
def sensor_names(self) -> tuple[str, ...] | tuple[()]:
"""Return a tuple of sensor names in the MuJoCo model.
:return: sensor names
"""
return self._sensor_names
@property
def sensor_name2id(self) -> dict[str, int]:
"""Return a dict containing name-id pairs of the sensors in the MuJoCo model.
:return: dict with name-id pairs
"""
return self._sensor_name2id
@property
def sensor_id2name(self) -> dict[int, str]:
"""Return a dict containing id-name pairs of the sensors in the MuJoCo model.
:return: dict with id-name pairs
"""
return self._sensor_id2name