From 6985b3743a5d39ebc1894e3a9f69cc4df33cdbb2 Mon Sep 17 00:00:00 2001 From: wpumacay Date: Thu, 9 Jul 2026 23:36:03 -0700 Subject: [PATCH 1/2] Upgrades composer to use mujoco==3.10.0 --- pyproject.toml | 8 ++++---- python/rcs/sim/composer.py | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index dda7fda7..ed4da7fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ requires = [ "pybind11", "cmake", "ninja", - "mujoco==3.2.6", + "mujoco==3.10.0", "pin==3.7.0", ] build-backend = "scikit_build_core.build" @@ -36,7 +36,7 @@ dependencies = [ "rpyc~=6.0.2", "pyarrow", "simplejpeg", - "mujoco==3.2.6", + "mujoco==3.10.0", "pin==3.7.0", # pin 3.7.0 currently resolves against older urdfdom/tinyxml SONAMEs at runtime "cmeel-urdfdom<5", @@ -74,7 +74,7 @@ dev = [ "cmake", ] build_deps = [ - "mujoco==3.2.6", + "mujoco==3.10.0", "pin==3.7.0", "cmeel-urdfdom<5", "cmeel-tinyxml2<11", @@ -86,7 +86,7 @@ skip = ["cp314*", "*-musllinux*"] # Install X11 headers needed to compile GLFW before-all = "yum install -y libXi-devel libXcursor-devel libXinerama-devel libXrandr-devel glfw-devel" # Exclude MuJoCo AND Pinocchio from being bundled. -repair-wheel-command = "auditwheel repair -w {dest_dir} {wheel} --exclude libmujoco.so.3.2.6 --exclude libpinocchio_default.so.3.7.0 --exclude libpinocchio_parsers.so.3.7.0" +repair-wheel-command = "auditwheel repair -w {dest_dir} {wheel} --exclude libmujoco.so.* --exclude libpinocchio_default.so.3.7.0 --exclude libpinocchio_parsers.so.3.7.0" [tool.scikit-build] build.verbose = true diff --git a/python/rcs/sim/composer.py b/python/rcs/sim/composer.py index 2a6ebe6e..3e8ea294 100644 --- a/python/rcs/sim/composer.py +++ b/python/rcs/sim/composer.py @@ -54,7 +54,7 @@ def _find_site(self, name: str) -> Optional[mujoco._specs.MjsSite]: def _find_body(self, name: str) -> Optional[mujoco._specs.MjsBody]: try: - return self.spec.find_body(name) + return self.spec.body(name) except ValueError: return None @@ -104,7 +104,7 @@ def add_camera( camera_mount = mujoco.MjSpec().worldbody.add_body() camera_mount.name = "mount" - camera_mount = attachment_site.attach(camera_mount, f"{name}_", "") + camera_mount = attachment_site.attach_body(camera_mount, f"{name}_", "") self._apply_pose(camera_mount, pose) @@ -147,7 +147,7 @@ def add_camera_xml( if robot_prefix is None: attach_frame = self.spec.worldbody.add_frame() - attach_frame.attach(camera_spec, prefix, "") + self.spec.attach(camera_spec, prefix=prefix, suffix="", frame=attach_frame) attached_root_name = f"{prefix}{root_body.name}" attached_root = self._find_body(attached_root_name) if attached_root is None: @@ -161,7 +161,7 @@ def add_camera_xml( msg = f"Attachment site '{site_name}' not found." raise ValueError(msg) - attached_root = attachment_site.attach(root_body, prefix, "") + attached_root = attachment_site.attach_body(root_body, prefix=prefix, suffix="") self._apply_pose(attached_root, pose) @@ -189,11 +189,11 @@ def add_robot(self, xml_path: str, prefix: str, pose: Pose | None = None) -> muj # 1. Use a frame to attach the child spec (most comprehensive) frame = self.spec.worldbody.add_frame() - frame.attach(child_spec, prefix, "") + self.spec.attach(child_spec, prefix=prefix, frame=frame) # 2. Identify the robot root body (it was prefixed) child_root_name = child_spec.worldbody.first_body().name - prefixed_root_name = f"{prefix}{child_root_name}" + prefixed_root_name = f"{child_root_name}" robot_root = self._find_body(prefixed_root_name) if not robot_root: @@ -229,7 +229,7 @@ def add_gripper( self._resolve_asset_paths(gripper_spec, xml_path) gripper_root = gripper_spec.worldbody.first_body() - gripper_root = attachment_site.attach(gripper_root, gripper_prefix, "") + gripper_root = attachment_site.attach_body(gripper_root, gripper_prefix, "") self._apply_pose(gripper_root, pose) if gripper_prefix: self._gravcomp_prefixes.add(gripper_prefix) @@ -261,7 +261,7 @@ def add_object_robot_frame( self.register_root_relative_replay_free_joints(self._prefixed_free_joint_names(object_spec, object_prefix)) object_root = object_spec.worldbody.first_body() - object_root = attachment_site.attach(object_root, object_prefix, "") + object_root = attachment_site.attach_body(object_root, prefix=object_prefix, suffix="") self._apply_pose(object_root, pose) return object_root @@ -291,7 +291,7 @@ def add_object_world_frame( # Attach using a frame frame = self.spec.worldbody.add_frame() - frame.attach(child_spec, object_prefix, "") + self.spec.attach(child_spec, prefix=object_prefix, suffix="", frame=frame) # Identify the root of the added object child_root_name = child_spec.worldbody.first_body().name From aa3afcdd8ac67be9db7477be6d6a13a923cef391 Mon Sep 17 00:00:00 2001 From: wpumacay Date: Fri, 10 Jul 2026 00:22:28 -0700 Subject: [PATCH 2/2] (fix): upgrade of mjspec changes the attached obj - With the new mjspec API, when attaching an object, the old reference spec (e.g. child_spec) is updated as well, and its names changes. This was causing the prefix being duplicated and was making it fail when searching for a specific reference in the new spec --- python/rcs/sim/composer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/python/rcs/sim/composer.py b/python/rcs/sim/composer.py index 3e8ea294..c9e2bbb0 100644 --- a/python/rcs/sim/composer.py +++ b/python/rcs/sim/composer.py @@ -137,6 +137,7 @@ def add_camera_xml( if root_body is None: msg = f"Camera MJCF '{xml_path}' must contain a root body." raise ValueError(msg) + root_body_name = root_body.name camera_names = [camera.name for camera in camera_spec.cameras] if len(camera_names) != 1 or camera_names[0] is None: @@ -148,7 +149,7 @@ def add_camera_xml( if robot_prefix is None: attach_frame = self.spec.worldbody.add_frame() self.spec.attach(camera_spec, prefix=prefix, suffix="", frame=attach_frame) - attached_root_name = f"{prefix}{root_body.name}" + attached_root_name = f"{prefix}{root_body_name}" attached_root = self._find_body(attached_root_name) if attached_root is None: msg = f"Could not find camera root body '{attached_root_name}' after attachment." @@ -285,6 +286,7 @@ def add_object_world_frame( # Load the child spec child_spec = mujoco.MjSpec.from_file(xml_path) + child_root_name = child_spec.worldbody.first_body().name self._resolve_asset_paths(child_spec, xml_path) if register_root_relative_replay_free_joints: self.register_root_relative_replay_free_joints(self._prefixed_free_joint_names(child_spec, object_prefix)) @@ -294,7 +296,6 @@ def add_object_world_frame( self.spec.attach(child_spec, prefix=object_prefix, suffix="", frame=frame) # Identify the root of the added object - child_root_name = child_spec.worldbody.first_body().name prefixed_root_name = f"{object_prefix}{child_root_name}" obj_root = self._find_body(prefixed_root_name) if not obj_root: