Inverse Kinematics with more than 2 segments I'm building a 2D inverse kinematics system and can't figure out how to find all the joint positions. I have the math to make a typical IK set up with a single bend (e.g. arm, leg), but I get stuck when adding another bend.

How do I find the position of all joints for an inverse kinematic chain that is longer than 2 segments?

Here's an example of the planar solution I'm looking for: https://youtu.be/3sqd_CZNq7s?t=6s

I'm building this in Adobe After Effects so using an existing IK solver isn't going to work.

Here's my visual setup for reference:



What I'm aiming for is that when the blue box is moved (target) joints 2 and 3 bend appropriately to maintain their length. Joint 1 is static and doesn't move.

To make this work, I need x,y coordinates to be calculated in real time. No need to render anything on screen—just the position values for each joint.

Here's my javascript so far:

var angle1, angle2, angle3, theta1, theta2, theta3, targetSqrDist;

// joints
var joint1 = thisComp.layer("joint 1");
var joint2 = thisComp.layer("joint 2");
var joint3 = thisComp.layer("joint 3");
var joint4 = thisComp.layer("joint 4");

// segment lengths
var segment1Len = length(joint2.transform.position, joint1.transform.position);
var segment2Len = length(joint3.transform.position, joint2.transform.position);
var segment3Len = length(joint4.transform.position, joint3.transform.position);

// target position
var target = thisComp.layer("target");
var ix = target.transform.position[0] - joint1.transform.position[0];
var iy = target.transform.position[1] - joint1.transform.position[1];

// target square distance
targetSqrDist = ix * ix + iy * iy;


// Segment 1
angle1 = Math.max(-1, Math.min( 1, 
    (targetSqrDist + (segment1Len*segment1Len) - (segment2Len*segment2Len)) / (2 * segment1Len * Math.sqrt(targetSqrDist))
));

theta1 = Math.atan2(iy, ix) - Math.acos(angle1);

var s1X = joint1.transform.position[0] + segment1Len * Math.cos(theta1);
var s1Y = joint1.transform.position[1] + segment1Len * Math.sin(theta1);


// Segment 2
angle2 = Math.max(-1, Math.min( 1, 
    (targetSqrDist - (segment1Len*segment1Len) - (segment2Len*segment2Len)) / (2 * segment1Len * segment2Len)
));

theta2 = Math.acos(angle2);

var s2X = s1X + segment2Len * Math.cos(theta2 + theta1);
var s2Y = s1Y + segment2Len * Math.sin(theta2 + theta1);


// Segment 3
angle3 = Math.max(-1, Math.min( 1, 
    (targetSqrDist - (segment2Len*segment2Len) - (segment3Len*segment3Len)) / (2 * segment2Len * segment3Len)
));

theta3 = Math.acos(angle3);

var s3X = s2X + segment3Len * Math.cos(theta3 + theta2);
var s3Y = s2Y + segment3Len * Math.sin(theta3 + theta2);


This code would be applied to each joint with a unique position value assigned to it, depending on the joint's location.
What you have here is an underconstrained problem*. To solve this problem you do what you do to any other underconstrained system. This is also why you mostly only see the 2 joint version as it is not underconstrained in the planar solution, and in any case the preregistration is trivial.

Basically you have 2 options:


Add more constraints
Deal with the freedom


Adding more constraints to the system reduces the degrees of freedom. For example if you only permit one of the joints to rotate about its z axis and the another around its x axis then y then you have reduced the problem to the same 2 member problem. Another way to constrain it is to force the orientation of the last link. This also reduces it to the same case as 2 links. But there are other meaningful ways to reduce complexity that depend on your application.



Image 1: Constraining one member reduces the problem to a 2 member problem. In the planar case that means 2 solutions (other in blue).

Dealing with the freedom just means that your answer is going to be a family of answers. Then you develop a way to choose the solution from that family. Letting the user adjust the parameter is equivalent to adding one more constraint. But there are other methods such as least squares, or energy methods that yield different results. Sky is the limit here. For example I have worked with robot controllers that decided the parameter based on what was the least amount of rotation on joints. The problem was that this wasn't entirely deterministic so over time the robot ended up doing things differently...

* This is more suited to Engineering.SE but since IK is a common graphics problem lets deal with it here.