use std::time::Duration;
use mujoco_rs::prelude::*;
use mujoco_rs::viewer::MjViewer;
const EXAMPLE_MODEL: &str = r#"
<mujoco model="tippe top">
<option integrator="RK4"/>
<asset>
<texture name="grid" type="2d" builtin="checker"
rgb1=".1 .2 .3" rgb2=".2 .3 .4" width="300" height="300"/>
<material name="grid" texture="grid" texrepeat="8 8" reflectance=".2"/>
</asset>
<worldbody>
<geom size=".2 .2 .01" type="plane" material="grid"/>
<light pos="0 0 .6"/>
<camera name="closeup" pos="0 -.1 .07" xyaxes="1 0 0 0 1 2"/>
<body name="top" pos="0 0 .02">
<freejoint/>
<geom name="ball" type="sphere" size=".02"/>
<geom name="stem" type="cylinder" pos="0 0 .02" size="0.004 .008"/>
<geom name="ballast" type="box" size=".023 .023 0.005" pos="0 0 -.015"
contype="0" conaffinity="0" group="3"/>
</body>
</worldbody>
<!--
Keyframe that gives the top a high spin rate.
qpos: x y z qw qx qy qz (freejoint - position + quaternion)
qvel: vx vy vz wx wy wz (freejoint - linear velocity + angular velocity)
The spin is 200 rad/s around z and a small 1 rad/s wobble around y.
-->
<keyframe>
<key name="spinning" qpos="0 0 0.02 1 0 0 0" qvel="0 0 0 0 1 200"/>
</keyframe>
</mujoco>
"#;
const DURATION_SECS: f64 = 20.0;
fn main() {
let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
let mut data = MjData::new(&model);
data.reset_keyframe(0).expect("could not reset to keyframe 0");
let mut viewer = MjViewer::launch_passive(&model, 0)
.expect("could not launch the viewer");
println!(
"Simulating tippe-top with the {} integrator.",
if model.opt().integrator == MjtIntegrator::mjINT_RK4 as i32 {
"RK4"
} else {
"Euler"
}
);
println!("Press [ / ] to cycle cameras (try the 'closeup' camera).");
println!("Running for {DURATION_SECS} seconds of simulation time ...");
while viewer.running() && data.time() < DURATION_SECS {
data.step();
viewer.sync_data(&mut data);
viewer.render().unwrap();
std::thread::sleep(Duration::from_secs_f64(model.opt().timestep));
}
println!("Simulation finished at t = {:.3} s.", data.time());
}