Search code examples
algorithminverse-kinematics

Is it a known issue that 2D inverse kinematics with FABRIK plus angle constraints often leads to a situation akin to gimbal lock?


I am implementing a 2D skeletal animation system that makes heavy use of inverse kinematics. I've decided to use FABRIK (Forward And Backward Reaching Inverse Kinematics) because of its robustness and the ease with which it can incorporate various kinds of constraints.

I have however run into a problem when adding angle constraints. The problem is something like gimbal lock. Basically in the presence of angle constraints it is easy for a system of bones and joints to get into a state in which it cannot find a valid solution to the inverse kinematics problem even though a solution exists. Further I believe this is not a problem with my implementation of FABRIK but is fundamental to the algorithm itself, at least in the 2D case.

The inverse kinematic problem is to find a configuration of bones and nodes such that some node, the effector, is at some target location, possibly given one or more root nodes that are pinned in place. FABRIK solves this problem (in the case of one root node) by iteratively reaching from the effector to the target, ignoring the root being pinned i.e. letting the root move. Then reaching from the from the root back to its pinned location, because the first pass may have moved it. We repeat these two phases until either the effector reaches the target or, in cases in which there is no solution, the effector has not moved (or has moved by less than some epsilon) since the last iteration.

Typically the algorithm works because the "reach" subroutine is defined such that it is guaranteed to succeed. Since reaching always succeeds after the two phases (1) the root is guaranteed to be at the pin location and (2) the effector is typically closer than it started to the target location. This is a heuristic algorithm that does converge in typical use cases, but my contention is that if we allow angle constraints there are non-pathological cases in which it does not converge even though the reach subroutine is still guaranteed to succeed. What happens is that given angle constraints there are non-pathological cases such that (2) above is no longer true. After the two phases the effector may be further from the target than before. I describe an example below.

I am posting here because I'd like to know if anyone knows if this problem has been described or dealt with in the literature. I have only found various claims that FABRIK behaves well with constraints, for example "Extending FABRIK with model constraints". But I have found this kind locking behavior happens often in the presence of at least two parent-child angle constraints and at least one pinned node.

example below:

The effector is the upper rightmost node; red circle is the target. All of the joints have an angle constraint on them like the one indicated in cyan: the rotation of each bone relative to its parent must be greater than or equal to zero and less than or equal to 90 degrees.

enter image description here

We note that this inverse kinematics problem does have a solution:

enter image description here

After the forward reaching phase, we will get the following:

enter image description here

After the backwards reaching phase, we note that the effector is now further from the target than when we began:

enter image description here

And further I think it is intuitively clear that continuing to iterate is not going to help matters. Basically angle constraints make it such that reaching from the effector to the target may move the root from the pinned location dramatically and chaotically whereas the heuristic algorithm needs it to move it only a little, close to where it needs to be.


Solution

  • I have found a solution to this problem, or at least a way of ameliorating the issue such that it no longer bothers me because I feel the algorithm performs reasonably rather than then just seeming broken.

    My solution is to only apply constraints during the backward reaching phase of the FABRIK algorithm.

    Two key insights led me to this idea

    1. The forward reaching phase of the basic algorithm already invalidates constraints even if there are no extra angle etc. constraints in that it moves the root node away from its pinned position.
    2. The output of the algorithm will always be the output of the second phase, so constraint satisfaction only matters during the second phase.

    That is, only the output of the backward-reaching phase must satisfy all constraints including the constraints of pinned root nodes. The forward-reaching phase's output is essentially internal state that is never passed on to code external to the FABRIK implementation. Allowing forward-reaching to ignore constraints means that its output will have the same heuristic properties that make the algorithm so robust when we do not use angle constraints.

    Example below:

    A screen cap video of the bad behavior, when constraints are applied during both phases of FABRIK: link.

    Fixing the problem by only applying constraints during backward reaching: link