This capstone implements a Gymnasium environment and evaluation suite for 7-DOF manipulation on models/articulated.xml. The task requires a robotic manipulator with a parallel gripper to approach, grasp, and pull open a cabinet slide drawer past a 0.10 m threshold under physical contact.
The environment adheres to the course instrument specification (mjcourse.capstone):
check_env);Three control representations are provided: Cartesian end-effector deltas (ee_delta), joint angle target deltas (joint_delta), and direct joint torques (torque).
| Axis | Choice in Capstone A |
|---|---|
| Task | Cabinet drawer opening on models/articulated.xml (MuJoCo 3.14.0). Lower slide drawer (range="0 0.2" m, damping 5 N s/m, frictionloss 0.5 N m). Target displacement threshold is 0.10 m. |
| Observation | 23-dimensional float32 vector: 7 joint positions (joint encoders), 7 joint velocities (joint encoders, differentiated), 3 TCP Cartesian coordinates (forward kinematics of the joint encoders), 1 gripper opening (joint encoders), 3 handle coordinates (camera tracker), 1 drawer slide coordinate (joint encoders), 1 target opening distance (task specification). |
| Action | Three operational spaces at 20 Hz control rate (0.002 s timestep, frame skip 25): ee_delta (4D: dx, dy, dz translation in meters, gripper command), joint_delta (8D: joint displacement deltas in radians, gripper command), torque (8D: joint torques in N m with gravity compensation, gripper command). |
| Episode | Horizon is 100 steps (5.0 seconds). Early termination occurs upon opening the drawer to 0.10 m. Step expiration is reported as truncation (truncated=True, terminated=False). |
| Initialization | Robot arm initialized at collision-free pre-grasp pose 12 cm ahead of the handle, perturbed with uniform noise in [-0.01, 0.01] rad from self.np_random. Initial drawer slide position is randomized in [0.0, 0.015] m. |
| Evaluation | 200 independent held-out evaluation seeds (1000 to 1199). Zero evaluation data used for tuning. |
| Metric | Binomial success rate with exact two-sided 95% Wilson score confidence interval. |
Running the acceptance checker across all three action representations:
python -m mjcourse.capstone capstones.a_drawer.env:DrawerEnv --kwargs '{"action_mode": "ee_delta"}' --object drawer
python -m mjcourse.capstone capstones.a_drawer.env:DrawerEnv --kwargs '{"action_mode": "joint_delta"}' --object drawer
python -m mjcourse.capstone capstones.a_drawer.env:DrawerEnv --kwargs '{"action_mode": "torque"}' --object drawer
Each mode passes all six criteria:
PASS gymnasium check_env
PASS observations are copies
PASS time limit reported as truncation
PASS reproducible with a seed
PASS observation sources are sensors
PASS no privileged quantity leaks
PASS model fingerprint: a113e5528ae5a96643342c88a428d9a9a729e62f7c043db75c71021adf67a586
When privileged quantities are introduced (for example extra_observations=("drawer_velocity",)), the checker halts with exit code 1, isolating both the undeclared sensor provenance and the parameter leak.
Evaluated across the 200 held-out evaluation seeds (seeds 1000 through 1199):
| Policy | Control Representation | Success Count | Success Rate | 95% Wilson Score Interval |
|---|---|---|---|---|
| Scripted finite-state | ee_delta (4D) |
200 / 200 | 100.0% | [98.1%, 100.0%] |
| Constant pull | ee_delta (4D) |
0 / 200 | 0.0% | [0.0%, 1.9%] |
| Constant push | ee_delta (4D) |
0 / 200 | 0.0% | [0.0%, 1.9%] |
| Zero action | ee_delta (4D) |
0 / 200 | 0.0% | [0.0%, 1.9%] |
The scripted policy exceeds the 90.0% threshold mandated by the rubric. Open-loop constant action baselines fail completely (0.0%), confirming that the task cannot be solved by open-loop drift or static commands.
While the scripted policy achieves 100% on the nominal held-out distribution, stress-testing under extreme out-of-distribution perturbations identifies four distinct failure classes:
To execute the test suite and evaluation protocol:
# Run acceptance test suite
pytest tests/test_capstone_a.py
# Run preregistered evaluation and generate run_record.json
python capstones/a_drawer/eval.py