Target
The cube position from the camera.
p* = (x, y, z)
Personal project / PyTorch / Webots / Aug to Sep 2026
I trained an MLP that solves IK for a UR5e with the tool pointing down. The loss runs the predicted angles through a PyTorch copy of the robot's forward kinematics, and the model drives a camera-guided pick-and-place loop in Webots.
The error is on 2,021 test targets the network never saw. Time is on one thread, and IKPy gets the same pose problem. The 0.33 mm is the gap at the grasp point in Webots between the pose reached with the network and with the closed-form IK (one run; 4.8 mm mean over the scenario's 4 targets). The closed-form solver is still 2.3x faster.
A multi-head version trained without branch labels finds about half of the 8 IK branches, but with about twice the error, so I kept one branch.
The cube position from the camera.
p* = (x, y, z)
3 layers of 512, SiLU, 530k parameters.
q = f(p*)
The DH chain in PyTorch, so pose error has a gradient.
p(q), R(q)
Position and orientation error, plus a small data term that holds one branch.
|p - p*|² + ...
FK is only used in training. At run time it's one forward pass. The camera side is a color threshold plus a homography I fit on a calibration grid (1.1 mm median residual, on the calibration points themselves).
Solver benchmark
Same 200 pose targets for every solver, 200 warm-up calls on other targets, one thread. From the rest configuration IKPy fails on 58% of targets. The network had no failures inside its training box.
Checks
What didn't work
Outside the training box the error grows: 14.3 mm median on a z = 0.25 m slice, 7 to 11 mm above the tray. Past the reach limit it still returns six angles, up to 1.78 m off, with no warning, so it needs a reachability check in front. One tool orientation, one IK branch, simulation only.
The Webots scene, the NumPy FK and the closed-form IK come from allan-almeida1/ur5-pick-and-place-webots (MIT). CREDITS.md lists what I inherited and what I wrote.