Overview of Agility Cassie Description (MJCF)
mainmujoco_wasm environment. The model is based on assets provided by Agility Robotics.repository·main·Indexed 19 days ago
https://github.com/zalo/mujoco_wasmA 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.
mujoco_wasm environment. The model is based on assets provided by Agility Robotics.The provided Cassie MJCF has been modified from the original Agility Robotics version to optimize it for MuJoCo usage:
PGS to Newton.nuser_actuator and nuser_sensor tags (as these are automatically inferred in MuJoCo 2.1.2+).<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.The project provides a JavaScript interface to run MuJoCo 3.3.8 models in the browser using official WebAssembly bindings.
load_mujoco and await its execution.mujoco.FS to manage the Emscripten Virtual File System (e.g., creating directories, mounting memory file systems, and writing files fetched from the network).mujoco.MjModel.loadFromXML() and create a corresponding data object with new mujoco.MjData(model).mujoco.mj_step(model, data) to advance the simulation and mujoco.mj_forward(model, data) for forward kinematics.opt.timestep) and data buffers (like qpos, qvel, ctrl, xpos) are accessible as typed arrays..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();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 installThe setupGUI function initializes a user interface for interacting with a MuJoCoDemo instance. It configures several interactive elements:
F1 key. It displays a dark, transparent overlay with a table of actions and their corresponding keyboard triggers.Space key.Ctrl + L.Backspace.ctrlnoiserate and ctrlnoisestd (range 0.0 to 2.0, step 0.01).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);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:
parent context.mujoco.MjModel.loadFromXML("/working/" + filename).mujoco.MjData.Group named "MuJoCo Root" to hold all visual elements.InstancedMesh.Returns:
An array containing [model, data, bodies, lights].
const [model, data, bodies, lights] = await loadSceneFromURL(mujoco, 'humanoid.xml', parentContext);The toMujocoPos(target) function converts a THREE.Vector3 from Three.js coordinate space to MuJoCo coordinate space.
Mapping:
x $\rightarrow$ xy $\rightarrow$ -zz $\rightarrow$ yThis 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);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);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);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:
new MuJoCoDemo(): Initializes the Three.js scene, camera, lights, renderer, and internal state.await demo.init(): Downloads example scenes into the MuJoCo virtual file system and loads the initial XML model into the physics engine.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();The init() method is required to prepare the simulation environment. It performs two critical tasks:
downloadExampleScenesFolder(mujoco) to populate the Emscripten virtual file system with necessary XML and asset files.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);
}