Basic simulation¶
Loading¶
To perform basic simulation with MuJoCo, create a MjModel struct by calling one of the following methods:
MjModel::from_xml (loads XML from a file),
MjModel::from_xml_vfs (loads XML from a file on a virtual file system),
MjModel::from_xml_string (loads XML from a model defined in a string in memory),
MjModel::from_buffer (loads a compiled model from a buffer).
For example:
use mujoco_rs::prelude::*;
fn main() {
let model = MjModel::from_xml("model.xml").expect("could not load the model");
}
MjModel represents the compiled moded from an XML file and contains everything from basic metadata to physics parameters.
For managing actual simulation state, MjData is used. It can be created either through the MjData::new method or through the MjModel::make_data method. For example:
fn main() {
let model = MjModel::from_xml("model.xml").expect("could not load the model");
let mut data = MjData::new(&model); // or model.make_data()
}
Tip
Using the MjData::new method is far more flexible than using the MjModel::make_data method. The former allows parameters to be of any type as long as they implement the Deref trait (e.g., Box<MjModel>). For example:
fn main() {
let model = Box::new(MjModel::from_xml("model.xml").expect("could not load the model"));
let mut data = MjData::new(model); // move model into the data
let model_ref = data.model(); // obtain a reference to the model
}
Note that Box<MjModel> can’t be used in contexts that require explicit borrowing. One of such examples is MjViewer. In such cases, Rc<MjModel> can be used instead.
Using Box or Rc (instead of direct references) allows usage in environments with lifetime restrictions.
One such example are Python bindings created with PyO3.
The pyo3_application example shows how create a simple MuJoCo-rs based application
for use from the Python programming language.
Running¶
Then to run/step the simulation, just call the MjData::step method like so:
fn main() {
let model = MjModel::from_xml("model.xml").expect("could not load the model");
let mut data = MjData::new(&model);
loop {
data.step();
}
}
The method MjData::step is just a wrapper around the mujoco_c::mj_step FFI function. Similarly, MjData::step1 and MjData::step2 wrap mujoco_c::mj_step1 and mujoco_c::mj_step2, respectively.
For more information about specific MuJoCo functions, see the MuJoCo documentation.
Realtime¶
The example above runs the simulation as fast as possible. To slow it down, you can either add a call to std::thread::sleep for an approximate delay, or use std::time::Instant with Instant::elapsed for precise timing.
use std::time::Duration;
use std::thread;
fn main() {
let model = MjModel::from_xml("model.xml").expect("could not load the model");
let mut data = MjData::new(&model);
let timestep = model.opt().timestep;
loop {
data.step();
/* Approximate-time delay */
thread::sleep(Duration::from_secs_f64(timestep))
}
}