Attribute views¶
The MuJoCo library stores data about joints, bodies, and other elements in contiguous arrays. These can be challenging to work with, particularly when the array’s length varies between elements. For example, different types of joints may have different number of degrees of freedom. MuJoCo’s Python bindings solve this issue by providing views to specific ranges in the corresponding arrays.
Like MuJoCo’s Python bindings, MuJoCo-rs also provides views. Specifically, we provide views for attributes of MjData and MjModel.
A view cannot be created directly, as that would require recreating the view after each simulation step. Allowing preservation of views between simulation steps would violate Rust’s borrow checker rules. To overcome this, “info” structs exist, which store required information for fast view creation after each step.
Reading¶
For example, let’s say we want to read the position of a free joint. We will first create an info struct by calling MjData::joint like so:
fn main() {
let model = MjModel::from_xml("model.xml").expect("could not load the model");
let mut data = model.make_data();
let joint_info = data.joint("football-ball").expect("name not found");
loop {
data.step();
...
}
}
To actually view the data, we will now call MjJointDataInfo::view and pass it a reference to MjData, like so:
fn main() {
let model = MjModel::from_xml("model.xml").expect("could not load the model");
let mut data = model.make_data();
let joint_info = data.joint("football-ball").expect("name not found");
loop {
data.step();
println!("{:?}", &joint_info.view(&data).qpos[..3]); // print x, y and z coordinates.
}
}
All the attributes inside views, like MjJointDataView::qpos, are instances of mujoco_rs::util::PointerView, which implements the Deref trait and on deref acts like a slice. While some fields might be scalers, we still treat those as arrays for implementation simplicity reasons.
Writing¶
The above example shows a read-only view. For mutability, MjJointDataInfo::view_mut must be called and passed a mutable reference to MjData, like so:
fn main() {
let model = MjModel::from_xml("model.xml").expect("could not load the model");
let mut data = model.make_data();
let joint_info = data.joint("football-ball").expect("name not found");
loop {
data.step();
joint_info.view_mut(&mut data).qpos[0] = 0.5;
}
}
Other views¶
Views can be created for other types of items too, as well as for MjModel. The process is exactly the same as shown above.