"""Load the pinned kinematic model; no servos, policy weights or simulation steps.
python microduck-probe.py /path/to/microduck
Requires mujoco==3.3.7 and numpy==2.2.6.
"""
import json, pathlib, sys
import mujoco
import numpy as np
root = pathlib.Path(sys.argv[1])
model = mujoco.MjModel.from_xml_path(str(root / 'kinematics/assets/alpha/robot_walk.xml'))
data = mujoco.MjData(model)
mujoco.mj_forward(model, data)
hinges = [j for j in range(model.njnt) if model.jnt_type[j] == mujoco.mjtJoint.mjJNT_HINGE]
limits = {mujoco.mj_id2name(model, mujoco.mjtObj.mjOBJ_JOINT, j): model.jnt_range[j].tolist() for j in hinges}
assert len(hinges) == 14 and 'mouth' not in limits
assert np.isfinite(data.site_xpos).all()
test_angle = 1.0
hip_yaw_range = limits['left_hip_yaw']
assert not hip_yaw_range[0] <= test_angle <= hip_yaw_range[1]
assert -np.pi <= test_angle <= np.pi
print(json.dumps({'mujoco': mujoco.__version__, 'nq': model.nq, 'nv': model.nv,
 'hinges': len(hinges), 'geoms': model.ngeom, 'actuators': model.nu,
 'left_hip_yaw_range_radians': hip_yaw_range,
 'left_hip_yaw_range_degrees': np.rad2deg(hip_yaw_range).tolist(),
 'candidate_radians': test_angle, 'inside_generic_actuator_clamp': True,
 'inside_joint_range': False}, indent=2))
