I sat down in late 2025 and decided I was going to get up to speed on the state-of-the-art in AI-driven software development. Despite my move into medical technology and business, AI is too exciting a world to leave behind. This chronicles my first experiment where I used AI to perform the bulk of the development but still kept the reins in my hands.

The problem I set out to solve is that of 2d inverse kinematics. Given a robot and a desired end position, we have to find its joint angles to reach that position. We’d also like to be able to respect our joint limits and avoid colliding with the world. Here’s an example of that:

jax solver driving the robot joints

The blue/green dot represents the desired end effector position. When the dot is blue, the end is locked in the horizontal position. When the dot is green, the end effector is allowed to reach the target point from any angle.

Full source code is on GitHub.

The Solvers

The final project implements five solvers for comparison. Each solver can solve with:

  1. arbitrary single-chain geometry
  2. angle limits on joints
  3. collision checking a. for joints and also links b. against halfspace, rectangle, and circular no-go zones.

The solvers are

Solver Algorithm Notes
jax gradient descent Solver is @jax.jit-ed
torch gradient descent With dynamic graph
sympy gradient descent sympy produces equations, scipy minimizer solves them
symbolic gradient descent sympy produces and solves equations
fabrik FABRIK Very cool algorithm!

Results

symbolic and sympy were not able to run with collision checking, so were omitted from these. I produces the same trajectory from jax, torch, and fabrik and was able to obtain these solution times, in log milliseconds:

Solve time per algorithm. Solve time per algorithm.

jax is incredibly fast, even on the CPU! I’ve been impressed with its speed in the past, but it still surprised me with its speed. Torch (without precompilation) is much slower, likely because of the overhead per operation. FABRIK runs very fast, but jax outstrips even that. The overhead from first compiling the function is only about 1000 ms and only has to be paid once.

FABRIK, being relatively new, has no widely-accepted standard for handling collisions. I got Claude to implement a relatively naive solution to no-go zones involving projection onto the boundary, and it sort-of works. FABRIK gracefully handles joint limits and end-effector angles, but remains a little vulnerable to degenerate/pathological cases. Here’s an example from our FABRIK implementation:

fabrik solver driving the robot joints

When it comes time to use this in a non-safety-critical robot, I’d be comfortable with deploying the jax solver with some added guardrails and sanity checks. This is what JAX looks like:

jax solver driving the robot joints

AI Use

All this was implemented with extensive use of Anthropic’s Claude Sonnet 4.5, which is incredible! It required a little strategic prompting, but generally acted like a mid-level developer with a caffeine addiction. It came up with the data model and forward kinematics easily, and was able to debug issues relatively reliably.

The general approach I followed in writing the code was to plan this myself and have Claude implement them. Instead of giving Claude an overall plan, I had it implement features or parts of roughly the size I would do myself, followed by testing and integration. Basically, I used Claude interactively in the way one might use a debugger or a fuzzer.

Problem Complexity

Claude occasionally stumbled but was easily prompted into correcting its mistakes. The most notable thing about the stumbles is that I would have easily made all these myself on the road to completing this project. Examples include:

  • matplotlib animations without rendering all artists in the initialization phase
  • creating unnecessary intermediate data types for jax, etc.
  • mistaking the jax line penalty subproblem as being impossible at first

The problem itself is only moderately difficult, and a lot of the key components are taught at the undergrad level. Claude was able to complete these tasks, and also harder ones that required significant generalization from its training corpus or abilities I didn’t think it had.

  • constructing penalties for violating the line boundary conditions.
  • figuring out parts of the penalty term is making the net effect non-convex.
  • visual intuition on the display area and animation keyframes.

The next step on this journey is to build a much bigger project with an AI-first approach, starting from the design document.