MuJoCo bindings and wrappers for the Rust programming language. Includes a Rust-native viewer and also bindings to a modified C++ one.
MuJoCo is a general purpose physics simulator.
More detailed documentation is available at the:
We especially recommend using the guide book.
This library uses FFI bindings to MuJoCo 3.3.5.
For installation see the guide book.
MuJoCo-rs tries to stay close to the MuJoCo's C API, with a few additional features for ease of use. The main features on top of MuJoCo include
-
Safe wrappers around structs:
- Automatic allocation and cleanup.
- Lifetime guarantees.
-
Methods as function wrappers.
-
Easy manipulation of simulation data via attribute views.
-
Visualization:
- Renderer: offscreen rendering to array or file.
- Viewer: onscreen visualization of the 3D simulation.
Screenshot of the built-in Rust viewer. Showing scene from MuJoCo's menagerie.
Optional Cargo features can be enabled:
viewer
: enables the Rust-native MuJoCo viewer. This can currently display everything and respond to mouse/keyboard. No side-panels (the user menu) currently exists.cpp-viewer
: enables the Rust wrapper around the C++ MuJoCo viewer. This is only available if you build the MuJoCo yourself using the steps above (yes, you need to use the forked repository).renderer
: enables the offscreen rendering code for reading RGB and depth data to memory or file.
By default, viewer
and renderer
are enabled.
The crate should work out of the box after you provide it with the MuJoCo library. If the build fails and asks
for additional dependencies, install them via your system package manager.
For example, to install glfw3 on Ubuntu/Debian, this can be done like so: apt install libglfw3-dev
.
This project is WIP but functional. I accept pull requests about bug fixes and feature requests. If you have any questions, please open a discussion.
This example shows how to launch the viewer and print the coordinates
of a moving ball to the terminal.
Other examples can be found under the examples/
directory.
//! Example of using views.
//! The example shows how to obtain a [`MjJointInfo`] struct that can be used
//! to create a (temporary) [`MjJointView`] to corresponding fields in [`MjData`].
use std::time::Duration;
use mujoco_rs::viewer::MjViewer;
use mujoco_rs::prelude::*;
const EXAMPLE_MODEL: &str = "
<mujoco>
<worldbody>
<light ambient=\"0.2 0.2 0.2\"/>
<body name=\"ball\">
<geom name=\"green_sphere\" size=\".1\" rgba=\"0 1 0 1\" solref=\"0.004 1.0\"/>
<joint name=\"ball_joint\" type=\"free\"/>
</body>
<geom name=\"floor1\" type=\"plane\" size=\"10 10 1\" euler=\"15 4 0\" solref=\"0.004 1.0\"/>
<geom name=\"floor2\" type=\"plane\" pos=\"15 -20 0\" size=\"10 10 1\" euler=\"-15 -4 0\" solref=\"0.004 1.0\"/>
</worldbody>
</mujoco>
";
fn main() {
/* Load the model and create data */
let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
let mut data = model.make_data(); // or MjData::new(&model);
/* Launch a passive Rust-native viewer */
let mut viewer = MjViewer::launch_passive(&model, 0)
.expect("could not launch the viewer");
/* Create the joint info */
let ball_info = data.joint("ball_joint").unwrap();
/* Obtain the timestep through the wrapped mjModel */
let timestep = model.ffi().opt.timestep;
while viewer.running() {
/* Step the simulation and sync the viewer */
viewer.sync(&mut data);
data.step();
/* Obtain the view and access first three variables of `qpos` (x, y, z) */
let xyz = &ball_info.view(&data).qpos[..3];
println!("The ball's position is: {xyz:.2?}");
std::thread::sleep(Duration::from_secs_f64(timestep));
}
}