Level 8 (after Lessons 8.1 and 8.2) · Time 3 hours · Difficulty 2 of 5
Implement joint-space PD and PD with gravity compensation for models/arm7.xml (torque motors on all seven joints), design the gains from the arm’s own inertia, and characterize the step response. Then predict, without simulating, how far the arm sags when the compensation is switched off.
qfrc_bias).mj_fullM.starter.py asks for two constants and three functions:
OMEGA, ZETA: the natural frequency and damping ratio you design for.design_gains(model, data, omega, zeta): per-joint $k_p$ and $k_d$ that make each joint, taken alone, a second-order system with that $\omega$ and $\zeta$.pd_torque(model, data, q_des, kp, kd, compensate): the torque command, with gravity compensation when compensate is true, inside ctrlrange.predicted_steady_error(model, q_des, kp): the steady error $q_\text{des} - q$ without compensation, computed from statics alone.All results below are from the reference solution ($\omega$ = 18 rad/s, $\zeta$ = 1) starting at the home keyframe with a 0.3 rad step on every joint.
MJC_IMPL=starter pytest projects/p04_joint_pd
pytest projects/p04_joint_pd
Four tests: gains of the right shape and sign; the compensated step (overshoot under 5%, within 1% after 0.5 s, every command inside ctrlrange); the steady error without compensation within 10% of your prediction on every loaded joint; and the compensated steady error under $10^{-4}$ rad. The common failures are mutants in mutants.json. python tools/mutate_project.py p04_joint_pd checks that each one fails: the first-order prediction fails the third test, and $\omega$ = 12, unclipped torques and ignored armature fail the second.
qfrc_bias. After mj_step, data.qfrc_bias belongs to the state before the step. Here that changes the torque by at most 0.32 N m and the trajectory by at most 0.5 mrad, so the tests cannot see it. On a stiffer, faster or heavier system the stale term is a real error. Call mj_forward (or at least mj_kinematics plus mj_rne) first.zero keyframe (arm straight up) and the largest overshoot is 38%, and the arm has still not settled after 1.5 s. Shoulder yaw’s inertia grows from 0.065 to 0.49 kg m² as the arm tips over, so gains sized at the start leave the joint underdamped by a factor of about $\sqrt{7.6} \approx 2.8$. That factor is inferred from the inertia ratio.mj_fullM includes the 0.05 kg m² armature on every joint. On the wrist joints that is most of the inertia (0.05 of 0.0546 kg m² at j5), so gains computed from link inertia alone are about 12 times too small there.mj_fullM every step, and show the zero-pose step now meets the same criteria.solution.py, about 35 lines.