mujoco_wasm

repository·main·Indexed 19 days ago

https://github.com/zalo/mujoco_wasm

A project providing MuJoCo 3.3.8 capabilities in the browser via WebAssembly and JavaScript bindings. It includes a JavaScript API for managing the Emscripten Virtual File System, loading XML models, and running simulation loops. The package also features the MuJoCoDemo class for Three.js integration, utility functions for coordinate conversion between MuJoCo and Three.js, and optimized MJCF assets for robots such as Agility Cassie and the Shadow Hand E3M5.

Tokens
3.1K
Snippets
9
Records
12
Agent score
66%

What's inside mujoco_wasm

  1. Use Shadow Hand E3M5 MJCF assets

    main
    This package provides MJCF (MuJoCo XML) descriptions for the 'E3M5' version of the Shadow Hand robot, supporting both right-handed and left-handed configurations. These assets are derived from the original URDF provided by Shadow Robot Company and are optimized for use in MuJoCo environments.
  2. Modifications in the Agility Cassie MJCF model

    main

    The provided Cassie MJCF has been modified from the original Agility Robotics version to optimize it for MuJoCo usage:

    • Syntax & Cleanup: Replaced single quotes with double quotes and removed redundant attribute specifications that match defaults.
    • Collision Geometry: Improved collision geometry and moved collision geoms to a hidden group (group 3) to make them visible for debugging if needed.
    • Solver & Performance: Changed the solver from PGS to Newton.
    • Compatibility: Removed nuser_actuator and nuser_sensor tags (as these are automatically inferred in MuJoCo 2.1.2+).
    • Visuals: Removed <visual> clauses and added a scene.xml file. The scene.xml includes the robot along with a textured groundplane, skybox, and haze for a complete simulation environment.
  3. Use the MuJoCo JavaScript API

    main

    The project provides a JavaScript interface to run MuJoCo 3.3.8 models in the browser using official WebAssembly bindings.

    Workflow

    1. Load the Module: Import load_mujoco and await its execution.
    2. File System Setup: Use mujoco.FS to manage the Emscripten Virtual File System (e.g., creating directories, mounting memory file systems, and writing files fetched from the network).
    3. Initialize Model and Data: Load an XML model using mujoco.MjModel.loadFromXML() and create a corresponding data object with new mujoco.MjData(model).
    4. Simulation Loop: Use mujoco.mj_step(model, data) to advance the simulation and mujoco.mj_forward(model, data) for forward kinematics.
    5. Access State: Model properties (like opt.timestep) and data buffers (like qpos, qvel, ctrl, xpos) are accessible as typed arrays.
    6. Cleanup: Explicitly call .delete() on model and data objects to free resources.
    import load_mujoco from "./dist/mujoco_wasm.js";
    
    // Load the MuJoCo Module
    const mujoco = await load_mujoco();
    
    // Set up Emscripten's Virtual File System
    mujoco.FS.mkdir('/working');
    mujoco.FS.mount(mujoco.MEMFS, { root: '.' }, '/working');
    mujoco.FS.writeFile("/working/humanoid.xml", await (await fetch("./assets/scenes/humanoid.xml")).text());
    
    // Load model and create data
    let model = mujoco.MjModel.loadFromXML("/working/humanoid.xml");
    let data  = new mujoco.MjData(model);
    
    // Access model properties directly
    let timestep = model.opt.timestep;
    let nbody = model.nbody;
    
    // Access data buffers (typed arrays)
    let qpos = data.qpos;  // Joint positions
    let qvel = data.qvel;  // Joint velocities
    let ctrl = data.ctrl;  // Control inputs
    let xpos = data.xpos; // Body positions
    
    // Step the simulation
    mujoco.mj_step(model, data);
    
    // Run forward kinematics
    mujoco.mj_forward(model, data);
    
    // Reset simulation
    mujoco.mj_resetData(model, data);
    
    // Apply forces (force, torque, point, body, qfrc_target)
    mujoco.mj_applyFT(model, data, [fx, fy, fz], [tx, ty, tz], [px, py, pz], bodyId, data.qfrc_applied);
    
    // Clean up
    data.delete();
    model.delete();
  4. Install and build mujoco_wasm

    main

    To set up the project environment, ensure npm is installed. Run npm install to pull dependencies, including three.js and the official MuJoCo WebAssembly bindings.

    To run the project during development, serve the index.html page using an HTTP server (e.g., five-server).

    npm install
  5. Setup the GUI context with setupGUI

    main

    The setupGUI function initializes a user interface for interacting with a MuJoCoDemo instance. It configures several interactive elements:

    • Scene Selection: A dropdown menu to switch between predefined XML scenes (e.g., "Humanoid", "Cassie", "Mug"). Changing the selection triggers a scene reload.
    • Help Menu: Accessible via the F1 key. It displays a dark, transparent overlay with a table of actions and their corresponding keyboard triggers.
    • Simulation Controls (under a "Simulation" folder):
      • Pause Simulation: Toggles simulation pausing. Triggered via the checkbox or the Space key.
      • Reload: Reloads the current XML model. Triggered via the button or Ctrl + L.
      • Reset: Resets the simulation to its initial state. Triggered via the button or Backspace.
      • Keyframe Slider: Allows loading specific keyframes from the model. The slider's visibility and range are automatically updated based on the number of keyframes in the loaded model.
      • Noise Controls: Sliders for ctrlnoiserate and ctrlnoisestd (range 0.0 to 2.0, step 0.01).
    • Actuators: Automatically generates sliders for all actuators in the model that have limited control ranges. These are grouped under an "Actuators" folder.
    • Camera Reset: Resets the free camera to a default position. Triggered via Ctrl + A.

    Note: setupGUI modifies the parentContext (an instance of MuJoCoDemo) by adding to its updateGUICallbacks and params objects.

    import { setupGUI } from './mujocoUtils.js';
    
    // Assuming parentContext is an instance of MuJoCoDemo
    setupGUI(parentContext);
  6. Load a MuJoCo scene with loadSceneFromURL

    main

    The loadSceneFromURL function asynchronously loads a MuJoCo model from the Emscripten Virtual File System and prepares the Three.js visualization.

    Parameters:

    • mujoco: The MuJoCo WASM namespace object.
    • filename: The name of the .xml file located in the /working/ directory of the MuJoCo Virtual File System.
    • parent: The MuJoCoDemo context object (which contains the Three.js scene).

    Behavior:

    1. Clears existing model and data from the parent context.
    2. Loads the model using mujoco.MjModel.loadFromXML("/working/" + filename).
    3. Initializes mujoco.MjData.
    4. Creates a Three.js Group named "MuJoCo Root" to hold all visual elements.
    5. Iterates through MuJoCo geoms to create corresponding Three.js geometries (Spheres, Capsules, Cylinders, Boxes, and Meshes).
    6. Handles material properties including colors, transparency, specular intensity, and textures.
    7. Parses and visualizes tendons and flex elements using InstancedMesh.
    8. Parses and adds lights defined in the XML.

    Returns: An array containing [model, data, bodies, lights].

    const [model, data, bodies, lights] = await loadSceneFromURL(mujoco, 'humanoid.xml', parentContext);
  7. Convert Three.js positions to MuJoCo positions

    main

    The toMujocoPos(target) function converts a THREE.Vector3 from Three.js coordinate space to MuJoCo coordinate space.

    Mapping:

    • x $\rightarrow$ x
    • y $\rightarrow$ -z
    • z $\rightarrow$ y

    This is useful when you want to apply user interactions (like dragging an object in the 3D view) back to the MuJoCo simulation.

    const mujocoPos = toMujocoPos(threeJsVector);
  8. Convert MuJoCo coordinates to Three.js with getPosition and getQuaternion

    main

    Because MuJoCo and Three.js use different coordinate systems/handedness, these utility functions perform the necessary 'swizzling' to ensure visual accuracy.

    getPosition(buffer, index, target, swizzle = true)

    Extracts a position vector from a buffer at a specific index and applies it to a THREE.Vector3 target.

    • swizzle: true (Default): Converts MuJoCo coordinates to Three.js: (x, z, -y).
    • swizzle: false: Uses raw coordinates: (x, y, z).

    getQuaternion(buffer, index, target, swizzle = true)

    Extracts a quaternion from a buffer at a specific index and applies it to a THREE.Quaternion target.

    • swizzle: true (Default): Converts MuJoCo quaternions to Three.js: (-y, -w, z, -x).
    • swizzle: false: Uses raw coordinates: (x, y, z, w).
    const pos = new THREE.Vector3();
    getPosition(data.qpos, index, pos);
    
    const quat = new THREE.Quaternion();
    getQuaternion(data.qpos, index, quat);
  9. Download example scenes to the virtual filesystem

    main

    The downloadExampleScenesFolder function fetches a predefined list of assets (XML models, .obj meshes, and .png textures) from the ./assets/scenes/ directory and writes them into the MuJoCo Emscripten Virtual File System under the /working/ prefix. This is necessary to ensure that loadSceneFromURL can find the files it needs to load.

    await downloadExampleScenesFolder(mujoco);
  10. Use the MuJoCoDemo class to run simulations

    main

    The MuJoCoDemo class provides a high-level interface for running MuJoCo simulations integrated with a Three.js visualizer. It handles the MuJoCo WASM lifecycle, scene loading, physics stepping, and 3D rendering.

    To use it, instantiate the class and call the asynchronous init() method. The class automatically creates a container element and appends it to the document body.

    Lifecycle:

    1. new MuJoCoDemo(): Initializes the Three.js scene, camera, lights, renderer, and internal state.
    2. await demo.init(): Downloads example scenes into the MuJoCo virtual file system and loads the initial XML model into the physics engine.
    3. render(): (Internal) The animation loop that steps the physics engine (mj_step) and updates Three.js object transforms based on MuJoCo data.
    import { MuJoCoDemo } from './src/main.js';
    
    const demo = new MuJoCoDemo();
    await demo.init();
  11. Initialize MuJoCoDemo with init()

    main

    The init() method is required to prepare the simulation environment. It performs two critical tasks:

    1. Downloads assets: It calls downloadExampleScenesFolder(mujoco) to populate the Emscripten virtual file system with necessary XML and asset files.
    2. Loads the scene: It uses loadSceneFromURL to parse the initial XML file and populate the model, data, bodies, and lights properties of the instance.

    Note that init() is an async function and must be awaited.

    async init() {
        // Download the the examples to MuJoCo's virtual file system
        await downloadExampleScenesFolder(mujoco);
    
        // Initialize the three.js Scene using the .xml Model in initialScene
        [this.model, this.data, this.bodies, this.lights] =
          await loadSceneFromURL(mujoco, initialScene, this);
    
        this.gui = new GUI();
        setupGUI(this);
    }