use mujoco_rs::viewer::MjViewer;
use mujoco_rs::prelude::*;
use std::time::Instant;
fn main() {
const FPS: f64 = 60.0; const RENDER_TIME_MS: u128 = (1000.0 / FPS) as u128;
let model = create_model();
let mut data = MjData::new(&model); let mut viewer = MjViewer::launch_passive(&model, 0).expect("could not launch viewer");
let timestep = model.opt().timestep;
let mut timer = Instant::now(); let mut timer_refresh = Instant::now();
while viewer.running() {
if timer_refresh.elapsed().as_millis() > RENDER_TIME_MS {
timer_refresh = Instant::now();
viewer.render().unwrap();
}
if timer.elapsed().as_secs_f64() > timestep { timer = Instant::now();
data.step();
viewer.sync_data(&mut data);
}
}
}
fn create_model() -> MjModel {
let mut spec = MjSpec::new();
spec.compiler_mut().set_degree(false);
spec.option_mut().timestep = 0.0005;
let timeconst = 2.0 * spec.option().timestep;
let main_class = spec.default_mut("main").unwrap();
main_class.geom_mut()
.with_solref([timeconst, 0.5])
.with_type(MjtGeom::mjGEOM_BOX);
let world = spec.world_body_mut();
for x in (-5..5).step_by(5) {
for y in (-5..5).step_by(5) {
world.add_light().with_pos([x as f64, y as f64, 40.0]).with_dir([-x as f64, -y as f64, -15.0]);
}
}
connected_spheres(&mut spec);
let base_name = "stairs".to_string();
let mut direction;
for i in -2..2 {
for j in -2..2 {
direction = if rand::random_bool(0.5) { 1 } else { -1 };
stairs(&mut spec, [i as f64 * 2.0 * 2.0, j as f64 * 2.0 * 2.0], 4, direction, &format!("{base_name}{i}_{j}"));
}
}
spec.compile().expect("failed to compile")
}
fn stairs(spec: &mut MjSpec, grid_loc: [f64; 2] , num_stairs: u32, direction: i8, name: &str) {
const SQUARE_LENGTH: f64 = 2.0;
const V_SIZE: f64 = 0.076;
const H_SIZE: f64 = 0.12;
const H_STEP: f64 = H_SIZE * 2.0;
const V_STEP: f64 = V_SIZE * 2.0;
const BROWN: [f32; 4] = [0.460, 0.362, 0.216, 1.0];
let body_pos = [grid_loc[0], grid_loc[1], 0.0];
let world = spec.world_body_mut();
let body = world.add_body().with_pos(body_pos).with_name(name);
let [x_beginning, y_end] = [-SQUARE_LENGTH + H_SIZE; 2];
let [x_end, y_beginning] = [SQUARE_LENGTH - H_SIZE; 2];
let mut size_one = [H_SIZE, SQUARE_LENGTH, V_SIZE];
let mut size_two = [SQUARE_LENGTH, H_SIZE, V_SIZE];
let mut x_pos_l = [x_beginning, 0.0, direction as f64 * V_SIZE];
let mut x_pos_r = [x_end, 0.0, direction as f64 * V_SIZE];
let mut y_pos_up = [0.0, y_beginning, direction as f64 * V_SIZE];
let mut y_pos_down = [0.0, y_end, direction as f64 * V_SIZE];
for i in 0..num_stairs {
size_one[1] = SQUARE_LENGTH - H_STEP * i as f64 - H_STEP;
size_two[0] = SQUARE_LENGTH - H_STEP * i as f64 ;
[x_pos_l[2], x_pos_r[2], y_pos_up[2], y_pos_down[2]] = [direction as f64 * ( V_SIZE + V_STEP * i as f64); 4];
x_pos_l[0] = x_beginning + H_STEP * i as f64;
body.add_geom().with_rgba(BROWN).with_size(size_one).with_pos(x_pos_l);
x_pos_r[0] = x_end - H_STEP * i as f64;
body.add_geom().with_rgba(BROWN).with_size(size_one).with_pos(x_pos_r);
y_pos_up[1] = y_beginning - H_STEP * i as f64;
body.add_geom().with_rgba(BROWN).with_size(size_two).with_pos(y_pos_up);
y_pos_down[1] = y_end + H_STEP * i as f64;
body.add_geom().with_rgba(BROWN).with_size(size_two).with_pos(y_pos_down);
}
let size = [SQUARE_LENGTH - H_STEP * num_stairs as f64, SQUARE_LENGTH - H_STEP * num_stairs as f64, V_SIZE];
let pos = [0.0, 0.0, direction as f64 * (V_SIZE + V_STEP * num_stairs as f64)];
body.add_geom().with_pos(pos).with_size(size).with_rgba(BROWN);
}
fn connected_spheres(spec: &mut MjSpec) {
const GRID_LIMIT: i32 = 3;
let mut last_site_name = format!("ball_{}_{}", GRID_LIMIT-1, GRID_LIMIT-1);
for i in -GRID_LIMIT..GRID_LIMIT {
for j in -GRID_LIMIT..GRID_LIMIT {
let site_name = format!("ball_{i}_{j}");
let tendon = spec.add_tendon()
.with_range([0.0, 2.0]);
tendon.wrap_site(&site_name); tendon.wrap_site(&last_site_name);
let world = spec.world_body_mut();
let ball = world.add_body()
.with_pos([i as f64 * 0.5, j as f64 * 0.5, 5.0]);
ball.add_geom()
.with_type(MjtGeom::mjGEOM_SPHERE)
.with_size([0.1, 0.0, 0.0])
.with_mass(0.001);
ball.add_joint().with_type(MjtJoint::mjJNT_FREE);
ball.add_site().with_name(&site_name);
last_site_name = site_name;
}
}
}