#!/usr/bin/env python3 """Generate symmetric box-geom stairs XML for MuJoCo sim2sim. The course is a flat approach, ascending stairs, a top platform, and matching descending stairs. Each tread is a solid box rising from the ground. Usage: uv run scripts/gen_stairs_box.py # default: 10 steps × 6cm = 60cm uv run scripts/gen_stairs_box.py --step-height 0.04 --num-steps 5 uv run scripts/gen_stairs_box.py --step-height 0.10 --num-steps 8 --step-depth 0.4 """ import argparse, os TPL = ''' {steps} ''' STEP_TPL = ' \n' PLAT_TPL = ' \n' def main(): p = argparse.ArgumentParser() p.add_argument("--step-height", type=float, default=0.06, help="rise per step [m]") p.add_argument("--step-depth", type=float, default=0.30, help="tread depth per step [m]") p.add_argument("--num-steps", type=int, default=10, help="number of steps") p.add_argument("--platform-depth", type=float, default=1.0, help="top platform depth [m]") args = p.parse_args() h = args.step_height d = args.step_depth n = args.num_steps platform_depth = args.platform_depth steps_xml = "" for i in range(n): top = (i + 1) * h steps_xml += STEP_TPL.format( name=f"step_up_{i}", sx=d / 2, sz=top / 2, x=(i + 0.5) * d, z=top / 2, ) # Platform at top total_height = n * h platform_start = n * d platform_end = platform_start + platform_depth steps_xml += PLAT_TPL.format( sx=platform_depth / 2, sz=total_height / 2, x=platform_start + platform_depth / 2, z=total_height / 2, ) for i in range(n): top = (n - i - 1) * h if top <= 0: continue steps_xml += STEP_TPL.format( name=f"step_down_{i}", sx=d / 2, sz=top / 2, x=platform_end + (i + 0.5) * d, z=top / 2, ) out = TPL.format(steps=steps_xml.rstrip()) out_dir = os.path.join(os.path.dirname(__file__), "..", "motrix_envs", "src", "motrix_envs", "locomotion", "go1", "xmls") out_path = os.path.join(out_dir, "scene_stairs_box.xml") with open(out_path, "w") as f: f.write(out) max_h = n * h finish_x = platform_end + n * d print(f"Generated {n} steps up/down x {h*100:.0f}cm = {max_h*100:.0f}cm total") print(f" step depth: {d*100:.0f}cm platform: {platform_depth:.2f}m") print(f" course: x=0.00m to x={finish_x:.2f}m") print(f" saved: {out_path}") if __name__ == "__main__": main()