Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use of MjSpec in environment #494

Open
LilianLaporte opened this issue Sep 20, 2024 · 0 comments
Open

Use of MjSpec in environment #494

LilianLaporte opened this issue Sep 20, 2024 · 0 comments

Comments

@LilianLaporte
Copy link

Hello,

I would like to create a RL pipeline in order to find a policy to stack rebars in the most stable way depending on their shape. As I want to stack them, I need to spawn them at one by one. One way (and the easiest for me) would be to use the MjSpec class from mujoco and recompile the model every time I want to spawn a rebar. However, when I wanted to make the environment for the training, I realized that it was not trivial to use this MjSpec feature that I am using with the Physics class...
So my question would be to know if there is an easy way to do it or if I have to rewrite the Environment class?

Thank you

Example

Here is an example of my problem with a simple script.

xml file
<?xml version="1.0" ?>
<mujoco model="coil">
	<extension>
		<plugin plugin="mujoco.elasticity.cable"/>
	</extension>

	<option integrator="implicit" timestep="0.001"/>
	<visual>
        <map force="0.1" zfar="30"/>
        <rgba haze="0.15 0.25 0.35 1"/>
        <quality shadowsize="2048"/>
        <global offwidth="800" offheight="800"/>
    </visual>

	<worldbody>
		<body name="stirrup" pos="0 0 1.005" quat="1 0 0 0">
			<freejoint/>
			<inertial pos="0.28 0.09 0.005" mass="1" diaginertia="0.001 0.001 0.001"/>
			<composite prefix="stirrup0" type="cable" vertex="
				3.061617e-19 5.000000e-03 0.000000e+00 
				5.650000e-01 5.000000e-03 0.000000e+00 
				5.950000e-01 3.500000e-02 0.000000e+00 
				5.950000e-01 1.550000e-01 0.000000e+00 
				5.650000e-01 1.850000e-01 0.000000e+00 
				-9.184851e-19 1.850000e-01 0.000000e+00
			" offset="0 0 0">
				<plugin plugin="mujoco.elasticity.cable">
					<config key="twist" value="5e8"/>
					<config key="bend" value="15e8"/>
					<config key="vmax" value="0"/>
				</plugin>
				<joint kind="main" damping="1" armature="100" stiffness="100" range="0 2"/>
				<geom type="capsule" size=".005" rgba=".8 .2 .1 1"/>
			</composite>
		</body>

	</worldbody>
	<asset>
		<texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072"/>
		<texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300"/>
		<material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.2"/>
	</asset>
	<worldbody>
		<light pos="0 0 3.5" dir="0 0 -1" directional="true"/>
		<geom name="floor" size="0 0 0.05" type="plane" material="groundplane"/>
	</worldbody>
</mujoco>
python code
import sys, os
import time
# Add the parent directory to sys.path
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

import mujoco
import mujoco.viewer

def display_video(frames, videoname='animation.mp4', framerate=30):
    """Display a list of frames as a video.
    Args:
        frames (list): list of frames to display.
        videoname (str, optional): name of the video. Defaults to 'animation.mp4'.
        framerate (int, optional): # frames per second. Defaults to 30.
    """

    height, width, _ = frames[0].shape
    dpi = 10
    orig_backend = matplotlib.get_backend()
    matplotlib.use('Agg')  # Switch to headless 'Agg' to inhibit figure rendering.
    fig, ax = plt.subplots(1, 1, figsize=(width / dpi, height / dpi), dpi=dpi)
    matplotlib.use(orig_backend)  # Switch back to the original backend.
    ax.set_axis_off()
    ax.set_aspect('equal')
    ax.set_position([0, 0, 1, 1])
    im = ax.imshow(frames[0])
    def update(frame):
      im.set_data(frame)
      return [im]
    interval = 1000/framerate
    anim = animation.FuncAnimation(fig=fig, func=update, frames=frames,
                                   interval=interval, blit=True, repeat=False)
    # return HTML(anim.to_html5_video())
    # Save as MP4
    anim.save(videoname, writer='ffmpeg', fps=framerate)
    plt.close(fig)

def add_body_in_spec(spec):
  """
  Add a body to the mujoco model.
  Args:
    spec: mujoco.MjSpec, the mujoco model specification.
  Returns:
    spec: mujoco.MjSpec, the updated mujoco model specification.
  Note: The body is a classic U-shape stirrup
  TODO: make this process adaptve to every kind of stirrup.
  """
  # plugin2_0 = spec.add_plugin()
  # plugin2_0.instance_name = "compositestirrup0"
  # plugin2_0.active = 1
  body2 = spec.worldbody.add_body()
  # body2 = spec.find_body("stirrup")
  body2.name = "stirrup2"
  body2.pos = [0.5, 0.1, 0.5]
  # body2.quat = [ 0, 0, 0.7071068, 0.7071068 ]
  body2.quat = [0.707107, 0, -0.707107, 0]
  body2.mass = 1
  body2.inertia = [0.001, 0.001, 0.001]
  body2.ipos = [0.28, 0, 0.005]
  joint = body2.add_joint()
  joint.type = mujoco.mjtJoint.mjJNT_FREE

  body2_0 = body2.add_body()
  body2_0.name = "stirrup20B0"
  body2_0.pos = [0, 0.005, 0]
  joint2_0 = body2_0.add_joint()
  joint2_0.name = "stirrup20J0"
  joint2_0.type = mujoco.mjtJoint.mjJNT_BALL
  joint2_0.group = 3
  joint2_0.pos = [0, 0, 0]
  joint2_0.armature = 100
  joint2_0.damping = 1
  joint2_0.stiffness = 100
  joint2_0.range = [0, 2]
  geom2_0 = body2_0.add_geom()
  geom2_0.name = "stirrup2G0"
  geom2_0.size = [0.005, 0.2825, 0]
  geom2_0.pos = [0.2825, 0, 0]
  geom2_0.quat = [0.707107, 0, -0.707107, 0]
  # geom2_0.quat = [1, 0, 0, 0]
  geom2_0.type = mujoco.mjtGeom.mjGEOM_CAPSULE
  geom2_0.rgba = [0.8, 0.2, 0.1, 1]
  site2_0 = body2_0.add_site()
  site2_0.name = "stirrup2S0"
  site2_0.pos = [0, 0, 0]
  site2_0.group = 3

  body2_1 = body2_0.add_body()
  body2_1.name = "stirrup20B1"
  body2_1.pos = [0.565, 0, 0]
  body2_1.quat = [0.92388, 0, 0, 0.382683]
  joint2_1 = body2_1.add_joint()
  joint2_1.name = "stirrup20J1"
  joint2_1.type = mujoco.mjtJoint.mjJNT_BALL
  joint2_1.group = 3
  joint2_1.pos = [0, 0, 0]
  joint2_1.armature = 100
  joint2_1.damping = 1
  joint2_1.stiffness = 100
  joint2_1.range = [0, 2]
  geom2_1 = body2_1.add_geom()
  geom2_1.name = "stirrup2G1"
  geom2_1.size = [0.005, 0.0212132, 0]
  geom2_1.pos = [0.0212132, 0, 0]
  geom2_1.quat = [0.707107, 0, -0.707107, 0]
  geom2_1.type = mujoco.mjtGeom.mjGEOM_CAPSULE
  geom2_1.rgba = [0.8, 0.2, 0.1, 1]
  site2_1 = body2_1.add_site()
  site2_1.name = "stirrup2S1"
  site2_1.pos = [0, 0, 0]
  site2_1.group = 3

  body2_2 = body2_1.add_body()
  body2_2.name = "stirrup20B2"
  body2_2.pos = [0.0424264, 0, 0]
  body2_2.quat = [0.92388, 0, 0, 0.382683]
  joint2_2 = body2_2.add_joint()
  joint2_2.name = "stirrup20J2"
  joint2_2.type = mujoco.mjtJoint.mjJNT_BALL
  joint2_2.group = 3
  joint2_2.pos = [0, 0, 0]
  joint2_2.armature = 100
  joint2_2.damping = 1
  joint2_2.stiffness = 100
  joint2_2.range = [0, 2]
  geom2_2 = body2_2.add_geom()
  geom2_2.name = "stirrup2G2"
  geom2_2.size = [0.005, 0.06, 0]
  geom2_2.pos = [0.06, 0, 0]
  geom2_2.quat = [0.707107, 0, -0.707107, 0]
  geom2_2.type = mujoco.mjtGeom.mjGEOM_CAPSULE
  geom2_2.rgba = [0.8, 0.2, 0.1, 1]
  site2_2 = body2_2.add_site()
  site2_2.name = "stirrup2S2"
  site2_2.pos = [0, 0, 0]
  site2_2.group = 3

  body2_3 = body2_2.add_body()
  body2_3.name = "stirrup20B3"
  body2_3.pos = [0.12, 0, 0]
  body2_3.quat = [0.92388, 0, 0, 0.382683]
  joint2_3 = body2_3.add_joint()
  joint2_3.name = "stirrup20J3"
  joint2_3.type = mujoco.mjtJoint.mjJNT_BALL
  joint2_3.group = 3
  joint2_3.pos = [0, 0, 0]
  joint2_3.armature = 100
  joint2_3.damping = 1
  joint2_3.stiffness = 100
  joint2_3.range = [0, 2]
  geom2_3 = body2_3.add_geom()
  geom2_3.name = "stirrup2G3"
  geom2_3.size = [0.005, 0.0212132, 0]
  geom2_3.pos = [0.0212132, 0, 0]
  geom2_3.quat = [0.707107, 0, -0.707107, 0]
  geom2_3.type = mujoco.mjtGeom.mjGEOM_CAPSULE
  geom2_3.rgba = [0.8, 0.2, 0.1, 1]
  site2_3 = body2_3.add_site()
  site2_3.name = "stirrup2S3"
  site2_3.pos = [0, 0, 0]
  site2_3.group = 3

  body2_4 = body2_3.add_body()
  body2_4.name = "stirrup20B4"
  body2_4.pos = [0.0424264, 0, 0]
  body2_4.quat = [0.92388, 0, 0, 0.382683]
  joint2_4 = body2_4.add_joint()
  joint2_4.name = "stirrup20J4"
  joint2_4.type = mujoco.mjtJoint.mjJNT_BALL
  joint2_4.group = 3
  joint2_4.pos = [0, 0, 0]
  joint2_4.armature = 100
  joint2_4.damping = 1
  joint2_4.stiffness = 100
  joint2_4.range = [0, 2]
  geom2_4 = body2_4.add_geom()
  geom2_4.name = "stirrup2G4"
  geom2_4.size = [0.005, 0.2825, 0]
  geom2_4.pos = [0.2825, 0, 0]
  geom2_4.quat = [0.707107, 0, -0.707107, 0]
  geom2_4.type = mujoco.mjtGeom.mjGEOM_CAPSULE
  geom2_4.rgba = [0.8, 0.2, 0.1, 1]
  site2_4 = body2_4.add_site()
  site2_4.name = "stirrup2S4"
  site2_4.pos = [0, 0, 0]
  site2_4.group = 3

  return spec

if __name__ == '__main__':
  spec = mujoco.MjSpec()
  spec.from_file("src/rebar_mujoco/environments/xml_files/mujoco.xml")
  model = spec.compile()
  data = mujoco.MjData(model)

  framerate = 40  # (Hz)
  timestep = 0.001  # (seconds)
  duration = 5  # (seconds)
  width, height = 500, 500
  renderer = mujoco.Renderer(model, height=height, width=width)
  video_name = "src/rebar_mujoco/tests/tmp/test_mjSpec.mp4"
  scene_option = mujoco.MjvOption()
  frames = []
  frame_count = 0

  camera = mujoco.MjvCamera()
  mujoco.mjv_defaultFreeCamera(model, camera)
  camera.distance = 2.5
  camera.elevation = -20
  # camera.azimuth = -130
  camera.lookat = (0, 0, 0.5)

  add_body_time = 2 # seconds
  add_body = False

  z_pos_vec = []
  
  nb_step = 0
  while nb_step*timestep < duration:
      
    mujoco.mj_step(model, data)

    if nb_step*timestep > add_body_time and not add_body:
      print("Adding body")
      add_body = True
      spec = add_body_in_spec(spec)

      ## Recompile model and data while maintaining the state.
      model, data = spec.recompile(model, data)
      renderer.close()
      renderer = mujoco.Renderer(model, height=height, width=width)

    if frame_count < nb_step*timestep * framerate:
      z_pos_vec.append(data.geom_xpos[-1][2])
      renderer.update_scene(data, camera=camera, scene_option=scene_option)
      frame = renderer.render()
      frames.append(frame)
      frame_count += 1

    nb_step += 1

  display_video(frames, video_name, framerate)
  print(f"Video saved at {video_name}")
  import matplotlib.pyplot as plt
  plt.plot(z_pos_vec)
  plt.show()

Context:

  • Operating system: Ubuntu 20.04
  • MuJoCo version: 3.2.2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant