Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 23 additions & 35 deletions auto_atom/backend/mjc/mujoco_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1019,34 +1019,29 @@ def _resolve_reference_base_pose(

For enum modes the entity's own ``default_pose`` is returned.

For an entity-name reference, the delta-carry algorithm is applied:
``delta = ref_sampled * ref_default⁻¹``, then ``delta * default_pose``
so the current entity moves with the referenced entity while
preserving their original spatial relationship.
For an entity-name reference, the sampled pose of the referenced
entity is used as the base directly — so ranges like ``x: [-0.005,
0.005]`` are interpreted as offsets from the referenced entity's
currently randomized pose, not from this entity's XML default.
"""
if isinstance(reference, RandomizationReference):
return default_pose
# --- Entity-name reference: delta-carry ---
ref_sampled = sampled_poses.get(reference)
# Resolve the reference entity's default pose.
if reference in self._default_object_poses:
ref_default = self._default_object_poses[reference]
elif reference in self._default_operator_eef_poses:
ref_default = self._default_operator_eef_poses[reference]
elif reference in self.object_handlers:
ref_default = self.object_handlers[reference].get_pose()
elif reference in self.operator_handlers:
ref_default = self.operator_handlers[reference].get_end_effector_pose()
else:
known_entity = (
reference in self._default_object_poses
or reference in self._default_operator_eef_poses
or reference in self.object_handlers
or reference in self.operator_handlers
)
if not known_entity:
raise ValueError(
f"Randomization reference '{reference}' is not a known mode "
"('relative', 'absolute_world', 'absolute_base') nor an "
"existing object/operator name."
)
ref_sampled = sampled_poses.get(reference)
if ref_sampled is None:
return default_pose # entity not randomized → no delta
delta = compose_pose(ref_sampled, inverse_pose(ref_default))
return compose_pose(delta, default_pose)
return default_pose # reference not randomized → fall back
return ref_sampled

def _apply_randomization(self, env_mask: np.ndarray) -> None:
deps = self._randomization_dependencies()
Expand Down Expand Up @@ -1445,29 +1440,22 @@ def _resolve_reference_base_pose_for_env(
) -> PoseState:
if isinstance(reference, RandomizationReference):
return default_pose
ref_sampled = sampled_poses.get(reference)
if reference in self._default_object_poses:
ref_default = self._default_object_poses[reference].select(env_index)
elif reference in self._default_operator_eef_poses:
ref_default = self._default_operator_eef_poses[reference].select(env_index)
elif reference in self.object_handlers:
ref_default = self.object_handlers[reference].get_pose().select(env_index)
elif reference in self.operator_handlers:
ref_default = (
self.operator_handlers[reference]
.get_end_effector_pose()
.select(env_index)
)
else:
known_entity = (
reference in self._default_object_poses
or reference in self._default_operator_eef_poses
or reference in self.object_handlers
or reference in self.operator_handlers
)
if not known_entity:
raise ValueError(
f"Randomization reference '{reference}' is not a known mode "
"('relative', 'absolute_world', 'absolute_base') nor an existing "
"object/operator name."
)
ref_sampled = sampled_poses.get(reference)
if ref_sampled is None:
return default_pose
delta = compose_pose(ref_sampled, inverse_pose(ref_default))
return compose_pose(delta, default_pose)
return ref_sampled

def _current_pose_for_randomization_key(self, name: str) -> PoseState:
rand_range = self.randomization[name]
Expand Down
146 changes: 146 additions & 0 deletions examples/panel_assembly/generated/demo_panel_with_objects.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?xml version='1.0' encoding='utf-8'?>
<mujoco model="demo_panel_base">
<asset>
<material name="red_switch_material" rgba="0.85 0.20 0.20 1" />
<material name="switch_base_material" rgba="0.18 0.18 0.20 1" />
<material name="amber_lamp_shell" rgba="0.16 0.16 0.18 1" />
<material name="amber_lamp_glow" rgba="0.98 0.72 0.18 0.95" />
</asset>
<default>
<default class="amber_lamp_geom">
<geom contype="1" conaffinity="1" />
</default>
</default>
<worldbody>
<body name="panel_mount" pos="0 0 0">
<geom name="panel_backplate" type="box" pos="0 0 0" size="0.420 0.030 0.160" rgba="0.86 0.87 0.89 1" contype="1" conaffinity="1" />
<site name="panel_origin" pos="0 0.030 0" size="0.006" rgba="1 0 0 1" />
<body name="panel_slot_r0_c0" pos="-0.3498 0.03 0.12" quat="0.7071068 -0.7071068 0 0">
<body name="red_switch_r0_c0">
<geom name="red_switch_base__r0_c0" type="box" pos="0 0 0.012" size="0.025 0.008 0.012" material="switch_base_material" />
<geom name="red_switch_toggle__r0_c0" type="box" pos="0 0 0.032" size="0.008 0.006 0.020" material="red_switch_material" />
</body>
</body>
<body name="panel_slot_r0_c1" pos="-0.2332 0.03 0.12" quat="0.7071068 -0.7071068 0 0">
<body name="green_knob_r0_c1">
<geom name="green_knob_base__r0_c1" type="cylinder" pos="0 0 0.005" size="0.020 0.005" rgba="0.15 0.16 0.18 1" />
<geom name="green_knob_cap__r0_c1" type="cylinder" pos="0 0 0.016" size="0.015 0.011" rgba="0.24 0.72 0.32 1" />
<site name="green_knob_tip__r0_c1" pos="0 0.012 0.016" size="0.002" rgba="1 1 1 1" />
</body>
</body>
<body name="panel_slot_r0_c2" pos="-0.1166 0.03 0.12" quat="0.7071068 -0.7071068 0 0">
<body name="amber_lamp_r0_c2">
<geom name="amber_lamp_base__r0_c2" class="amber_lamp_geom" type="box" pos="0 0 0.006" size="0.020 0.010 0.006" material="amber_lamp_shell" />
<geom name="amber_lamp_cover__r0_c2" class="amber_lamp_geom" type="sphere" pos="0 0 0.022" size="0.014" material="amber_lamp_glow" />
</body>
</body>
<body name="panel_slot_r0_c3" pos="0 0.03 0.125" quat="0.7071068 -0.7071068 0 0">
<body name="red_switch_r0_c3">
<geom name="red_switch_base__r0_c3" type="box" pos="0 0 0.012" size="0.025 0.008 0.012" material="switch_base_material" />
<geom name="red_switch_toggle__r0_c3" type="box" pos="0 0 0.032" size="0.008 0.006 0.020" material="red_switch_material" />
</body>
</body>
<body name="panel_slot_r0_c4" pos="0.1166 0.03 0.12" quat="0.7071068 -0.7071068 0 0">
<body name="green_knob_r0_c4">
<geom name="green_knob_base__r0_c4" type="cylinder" pos="0 0 0.005" size="0.020 0.005" rgba="0.15 0.16 0.18 1" />
<geom name="green_knob_cap__r0_c4" type="cylinder" pos="0 0 0.016" size="0.015 0.011" rgba="0.24 0.72 0.32 1" />
<site name="green_knob_tip__r0_c4" pos="0 0.012 0.016" size="0.002" rgba="1 1 1 1" />
</body>
</body>
<body name="panel_slot_r0_c5" pos="0.2332 0.03 0.12" quat="0.7071068 -0.7071068 0 0">
<body name="amber_lamp_r0_c5">
<geom name="amber_lamp_base__r0_c5" class="amber_lamp_geom" type="box" pos="0 0 0.006" size="0.020 0.010 0.006" material="amber_lamp_shell" />
<geom name="amber_lamp_cover__r0_c5" class="amber_lamp_geom" type="sphere" pos="0 0 0.022" size="0.014" material="amber_lamp_glow" />
</body>
</body>
<body name="panel_slot_r0_c6" pos="0.3498 0.03 0.12" quat="0.7071068 -0.7071068 0 0">
<body name="red_switch_r0_c6">
<geom name="red_switch_base__r0_c6" type="box" pos="0 0 0.012" size="0.025 0.008 0.012" material="switch_base_material" />
<geom name="red_switch_toggle__r0_c6" type="box" pos="0 0 0.032" size="0.008 0.006 0.020" material="red_switch_material" />
</body>
</body>
<body name="panel_slot_r1_c0" pos="-0.3498 0.03 0" quat="0.7071068 -0.7071068 0 0">
<body name="green_knob_r1_c0">
<geom name="green_knob_base__r1_c0" type="cylinder" pos="0 0 0.005" size="0.020 0.005" rgba="0.15 0.16 0.18 1" />
<geom name="green_knob_cap__r1_c0" type="cylinder" pos="0 0 0.016" size="0.015 0.011" rgba="0.24 0.72 0.32 1" />
<site name="green_knob_tip__r1_c0" pos="0 0.012 0.016" size="0.002" rgba="1 1 1 1" />
</body>
</body>
<body name="panel_slot_r1_c1" pos="-0.2332 0.03 0" quat="0.7071068 -0.7071068 0 0">
<body name="amber_lamp_r1_c1">
<geom name="amber_lamp_base__r1_c1" class="amber_lamp_geom" type="box" pos="0 0 0.006" size="0.020 0.010 0.006" material="amber_lamp_shell" />
<geom name="amber_lamp_cover__r1_c1" class="amber_lamp_geom" type="sphere" pos="0 0 0.022" size="0.014" material="amber_lamp_glow" />
</body>
</body>
<body name="panel_slot_r1_c2" pos="-0.1166 0.03 0" quat="0.7071068 -0.7071068 0 0">
<body name="red_switch_r1_c2">
<geom name="red_switch_base__r1_c2" type="box" pos="0 0 0.012" size="0.025 0.008 0.012" material="switch_base_material" />
<geom name="red_switch_toggle__r1_c2" type="box" pos="0 0 0.032" size="0.008 0.006 0.020" material="red_switch_material" />
</body>
</body>
<body name="panel_slot_r1_c4" pos="0.1166 0.03 0" quat="0.7071068 -0.7071068 0 0">
<body name="red_switch_r1_c4">
<geom name="red_switch_base__r1_c4" type="box" pos="0 0 0.012" size="0.025 0.008 0.012" material="switch_base_material" />
<geom name="red_switch_toggle__r1_c4" type="box" pos="0 0 0.032" size="0.008 0.006 0.020" material="red_switch_material" />
</body>
</body>
<body name="panel_slot_r1_c5" pos="0.2332 0.03 0" quat="0.7071068 -0.7071068 0 0">
<body name="green_knob_r1_c5">
<geom name="green_knob_base__r1_c5" type="cylinder" pos="0 0 0.005" size="0.020 0.005" rgba="0.15 0.16 0.18 1" />
<geom name="green_knob_cap__r1_c5" type="cylinder" pos="0 0 0.016" size="0.015 0.011" rgba="0.24 0.72 0.32 1" />
<site name="green_knob_tip__r1_c5" pos="0 0.012 0.016" size="0.002" rgba="1 1 1 1" />
</body>
</body>
<body name="panel_slot_r1_c6" pos="0.3498 0.03 0" quat="0.7071068 -0.7071068 0 0">
<body name="amber_lamp_r1_c6">
<geom name="amber_lamp_base__r1_c6" class="amber_lamp_geom" type="box" pos="0 0 0.006" size="0.020 0.010 0.006" material="amber_lamp_shell" />
<geom name="amber_lamp_cover__r1_c6" class="amber_lamp_geom" type="sphere" pos="0 0 0.022" size="0.014" material="amber_lamp_glow" />
</body>
</body>
<body name="panel_slot_r2_c0" pos="-0.3498 0.03 -0.12" quat="0.7071068 -0.7071068 0 0">
<body name="amber_lamp_r2_c0">
<geom name="amber_lamp_base__r2_c0" class="amber_lamp_geom" type="box" pos="0 0 0.006" size="0.020 0.010 0.006" material="amber_lamp_shell" />
<geom name="amber_lamp_cover__r2_c0" class="amber_lamp_geom" type="sphere" pos="0 0 0.022" size="0.014" material="amber_lamp_glow" />
</body>
</body>
<body name="panel_slot_r2_c1" pos="-0.2332 0.03 -0.12" quat="0.7071068 -0.7071068 0 0">
<body name="red_switch_r2_c1">
<geom name="red_switch_base__r2_c1" type="box" pos="0 0 0.012" size="0.025 0.008 0.012" material="switch_base_material" />
<geom name="red_switch_toggle__r2_c1" type="box" pos="0 0 0.032" size="0.008 0.006 0.020" material="red_switch_material" />
</body>
</body>
<body name="panel_slot_r2_c2" pos="-0.1166 0.03 -0.12" quat="0.7071068 -0.7071068 0 0">
<body name="green_knob_r2_c2">
<geom name="green_knob_base__r2_c2" type="cylinder" pos="0 0 0.005" size="0.020 0.005" rgba="0.15 0.16 0.18 1" />
<geom name="green_knob_cap__r2_c2" type="cylinder" pos="0 0 0.016" size="0.015 0.011" rgba="0.24 0.72 0.32 1" />
<site name="green_knob_tip__r2_c2" pos="0 0.012 0.016" size="0.002" rgba="1 1 1 1" />
</body>
</body>
<body name="panel_slot_r2_c3" pos="0 0.03 -0.12" quat="0.7071068 -0.7071068 0 0">
<body name="amber_lamp_r2_c3">
<geom name="amber_lamp_base__r2_c3" class="amber_lamp_geom" type="box" pos="0 0 0.006" size="0.020 0.010 0.006" material="amber_lamp_shell" />
<geom name="amber_lamp_cover__r2_c3" class="amber_lamp_geom" type="sphere" pos="0 0 0.022" size="0.014" material="amber_lamp_glow" />
</body>
</body>
<body name="panel_slot_r2_c4" pos="0.1166 0.03 -0.12" quat="0.7071068 -0.7071068 0 0">
<body name="red_switch_r2_c4">
<geom name="red_switch_base__r2_c4" type="box" pos="0 0 0.012" size="0.025 0.008 0.012" material="switch_base_material" />
<geom name="red_switch_toggle__r2_c4" type="box" pos="0 0 0.032" size="0.008 0.006 0.020" material="red_switch_material" />
</body>
</body>
<body name="panel_slot_r2_c5" pos="0.2332 0.03 -0.12" quat="0.7071068 -0.7071068 0 0">
<body name="green_knob_r2_c5">
<geom name="green_knob_base__r2_c5" type="cylinder" pos="0 0 0.005" size="0.020 0.005" rgba="0.15 0.16 0.18 1" />
<geom name="green_knob_cap__r2_c5" type="cylinder" pos="0 0 0.016" size="0.015 0.011" rgba="0.24 0.72 0.32 1" />
<site name="green_knob_tip__r2_c5" pos="0 0.012 0.016" size="0.002" rgba="1 1 1 1" />
</body>
</body>
<body name="panel_slot_r2_c6" pos="0.3498 0.03 -0.12" quat="0.7071068 -0.7071068 0 0">
<body name="amber_lamp_r2_c6">
<geom name="amber_lamp_base__r2_c6" class="amber_lamp_geom" type="box" pos="0 0 0.006" size="0.020 0.010 0.006" material="amber_lamp_shell" />
<geom name="amber_lamp_cover__r2_c6" class="amber_lamp_geom" type="sphere" pos="0 0 0.022" size="0.014" material="amber_lamp_glow" />
</body>
</body>
</body>
</worldbody>
</mujoco>
110 changes: 110 additions & 0 deletions examples/panel_assembly/w1_b1/create_initial_objects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""One-time script: create the 20 initial switch XMLs in objects/.

Each switch is a simple 8.6cm x 8.6cm square, 7mm thick.
Colours are placeholder grey — edit objects/*.xml to set final colours.
"""

from __future__ import annotations

from pathlib import Path

OBJECTS_DIR = Path(__file__).parent / "objects"

# Geometry (metres)
BTN_HALF = 0.043 # 43mm half-width (86mm full)
BTN_FACE_HALF = 0.040 # 40mm half (80mm inner face)
BEZEL_HALF_Z = 0.001 # bezel base half-thickness
BTN_HALF_Z = 0.0035 # button half-thickness (7mm total)

# Metallic colours: (bezel_rgba, button_rgba, specular, shininess)
COLORS = {
"white": {
"bezel": "0.85 0.85 0.88 1",
"button": "0.95 0.95 0.97 1",
"specular": "0.85",
"shininess": "0.9",
},
"dark_gray": {
"bezel": "0.15 0.15 0.18 1",
"button": "0.25 0.25 0.28 1",
"specular": "0.75",
"shininess": "0.85",
},
"gold": {
"bezel": "0.65 0.53 0.15 1",
"button": "0.83 0.69 0.22 1",
"specular": "0.9",
"shininess": "0.95",
},
"pink": {
"bezel": "0.80 0.50 0.58 1",
"button": "0.95 0.65 0.72 1",
"specular": "0.8",
"shininess": "0.9",
},
"placeholder": {
"bezel": "0.30 0.30 0.33 1",
"button": "0.60 0.60 0.63 1",
"specular": "0.5",
"shininess": "0.5",
},
}

# 20 switches: (class_name, x_mm, y_mm, color)
# 白色: 1-2,4-5,10-11,13-14,18 深灰: 3,7-9,12,15-16 金色: 6,20 粉色: 19
SWITCHES = [
("Switch_Quantity2_07", 349.8, 120.0, "white"), # 1
("Switch_Quantity2_08", 233.2, 120.0, "white"), # 2
("Switch_Quantity2_09", 116.6, 120.0, "dark_gray"), # 3
("Switch_Quantity2_10", 0.0, 120.0, "white"), # 4
("Switch_Quantity4_02", -116.6, 120.0, "white"), # 5
("Switch_Quantity1_45", -233.2, 120.0, "gold"), # 6
("Switch_Quantity1_46", -349.8, 120.0, "dark_gray"), # 7
("Toogle_Quantity1_05", 349.8, 0.0, "dark_gray"), # 8
("Switch_Quantity4_03", 233.2, 0.0, "dark_gray"), # 9
("Switch_Quantity1_47", 116.6, 0.0, "white"), # 10
("Switch_Quantity2_11", -116.6, 0.0, "white"), # 11
("Switch_Quantity1_48", -233.2, 0.0, "dark_gray"), # 12
("Switch_Quantity1_49", -349.8, 0.0, "white"), # 13
("Switch_Quantity3_06", 349.8, -120.0, "white"), # 14
("Toogle_Quantity2_01", 233.2, -120.0, "dark_gray"), # 15
("Toogle_Quantity1_06", 116.6, -120.0, "dark_gray"), # 16
("Placeholder_31", 0.0, -120.0, "placeholder"), # 17
("Switch_Quantity2_12", -116.6, -120.0, "white"), # 18
("Switch_Quantity2_13", -233.2, -120.0, "pink"), # 19
("Switch_Quantity4_04", -349.8, -120.0, "gold"), # 20
]


def generate_switch_xml(class_name: str, color: str) -> str:
c = COLORS[color]
sp, sh = c["specular"], c["shininess"]
return f"""<mujoco model="{class_name}">
<asset>
<material name="{class_name}_bezel" rgba="{c["bezel"]}" specular="{sp}" shininess="{sh}"/>
<material name="{class_name}_button" rgba="{c["button"]}" specular="{sp}" shininess="{sh}"/>
</asset>
<worldbody>
<body name="{class_name}">
<geom name="{class_name}_bezel" type="box"
pos="0 0 {BEZEL_HALF_Z}" size="{BTN_HALF} {BTN_HALF} {BEZEL_HALF_Z}"
material="{class_name}_bezel"/>
<geom name="{class_name}_button" type="box"
pos="0 0 {BTN_HALF_Z}" size="{BTN_FACE_HALF} {BTN_FACE_HALF} {BTN_HALF_Z}"
material="{class_name}_button"/>
</body>
</worldbody>
</mujoco>"""


def main() -> None:
OBJECTS_DIR.mkdir(exist_ok=True)
for class_name, x, y, color in SWITCHES:
path = OBJECTS_DIR / f"{class_name}.xml"
path.write_text(generate_switch_xml(class_name, color), encoding="utf-8")
print(f" {path.name} ({color})")
print(f"\nCreated {len(SWITCHES)} switch XMLs in {OBJECTS_DIR}")


if __name__ == "__main__":
main()
Loading