Project — Robotics · Simulation · Math
A pick-and-drop simulation in MuJoCo, built from fundamentals. Jacobian calculation, damped least squares, and IK tuning.
A robotic arm simulation that solves inverse kinematics from scratch — computing the Jacobian, applying damped least squares, and tuning until pick-and-drop works reliably in a physics environment.
Most robotics tutorials hand you a working IK solver and ask you to configure it. This project went the other direction — implementing the math by hand in Python, inside MuJoCo's physics simulator, to understand what's actually happening when a robot arm reaches for an object.
The goal was a complete pick-and-drop task: the arm identifies a target, computes the joint angles needed to reach it, grasps it, moves to a drop position, and releases. Every step required the IK solution to be stable, accurate, and robust to the kinds of small numerical errors that real physics introduces.
Inverse Kinematics Simulation — Pick & Drop
Three concepts that had to work together for the arm to move correctly.
The Jacobian maps joint velocities to end-effector velocities — it describes how a small change in each joint angle affects the position and orientation of the arm's tip. Computing it correctly at every timestep is the foundation everything else depends on.
A naive Jacobian inverse breaks near singularities — configurations where the arm loses a degree of freedom and small movements in task space require impossibly large joint velocities. Damped least squares adds a regularization term λ that trades off accuracy for stability, keeping the arm from jerking unpredictably.
Choosing the right damping constant λ was an iterative process. Too low and the arm oscillates near singularities. Too high and it moves sluggishly, never quite reaching the target. Tuning λ by hand in MuJoCo made the tradeoff concrete and physical.
At each timestep, compute the difference between the current end-effector position (from forward kinematics) and the target position in world coordinates. This error vector is what the IK solver is trying to drive to zero.
For each joint, compute the partial derivative of the end-effector position with respect to that joint angle — stacking them into the Jacobian matrix J. This tells us how each joint contributes to moving the tip.
Compute Δq = Jᵀ(JJᵀ + λ²I)⁻¹ · Δx. The damping term λ²I prevents the inverse from blowing up near singularities, at the cost of slightly slower convergence. Tuning λ was the most time-intensive part of this project.
Apply the joint updates, step MuJoCo's physics engine, and check convergence. Once the error is below threshold, trigger the gripper, move to the drop target, and release. The full pick-and-drop cycle runs in a loop.
Every column is a joint. Every row is a direction in space. Once I could read the matrix and predict how the arm would move, the debugging became intuitive rather than trial-and-error.
Singularities are a design constraint, not just a math problem. Any robot arm operating near humans will encounter singular configurations. Handling them gracefully — through damping, null-space control, or trajectory planning — is a core engineering decision.
MuJoCo's physics engine adds a layer the math alone can't capture. Numerical drift, contact forces, and timestep size all interact with the IK solution. Bridging simulation and real hardware will require understanding these gaps intimately.
The natural next step is vision-based target detection, replacing the hardcoded target position with a camera feed that identifies objects in real time.