CS 184: Computer Graphics and Imaging, Fall 2020

CS 184: Paper


Inverse Kinematics for 3D Skeletal Control

Jason Xu, Mae Wang, and Yowsean Li



Youtube: "Inverse Kinematics Project Video"

Slides

Abstract

A path-defined 3D robotic simulation utilizing inverse kinematics as a physics-based animation tool. The inverse kinematics function defines joint angles to achieve a desired skeletal pose, position, or rotation in a three-dimensional space to generate realistic movements. We developed and implemented on the Unity3D platform, overriding the development engine's current built-in functions for inverse kinematics.

Our topic involves implementing inverse kinematics (IK) on a real-time development platform to simulate movement for an articulated skeleton robot. We compare our IK implementation to another implementation approach to observe differences and evaluate the quality of our approach. Overall, our geometric approach is adequate, as comparisons reveal little performance differences for 2-chained systems.

With this mechanism implemented, we define animation as setting target points for the skeletal system rather than defining how the system should move (forward kinematics). This way, we can execute complex motions quickly and dynamically. IK is often used for real-time/pre-made simulations, movies, and graphical games.



Section I: Technical approach

Our inverse kinematics solver worked by providing three main functionalities—planar tracking, rotation and orientation—on a 2 rotational joint system to calculate the correct joint angles so that the system’s end effector reaches the target destination. We implemented each of the features on a robot arm first before applying constraints onto a humanoid body.

Planar Tracking

To achieve planar tracking, given a robot arm with 2-degrees of freedom on 2 rotational joints, we derived a formula using law of cosines to calculate joint angles given a target position. The formulas for the two joints are as follows:

gamma = atan(target.position.y - hinge.position.y , |target.position.x - hinge.position.x|)
jointangle0 = alpha + gamma
jointangle1 = beta

We also had to account for the case where the target point is out of reach of arm, in which case we fully extend the joint toward the target point. Furthermore, we encountered an issue due to a quirk of Unity's axes system so we had to offset our calculations by 90 degrees.

Rotation

With just planar tracking, the system has no awareness of a third dimension (i.e. depth) in space and would not be able to rotate itself to reach targets outside of x-y space. To allow for 3D rotation with the planar tracker, we rotate the arm so that it is planar with the target point. With the rotation, the planar tracker would then be able to adjust the joint angles.

theta = atan(target.position.z - hinge.position.z, target.position.x - hinge.position.x)

We calculate the amount of rotation needed by measuring the angle formed from the change in depth and the change in width. We also adjust the planar tracking to calculate the angles by using the length of change along the x-z dimension instead of just the x dimension and using xyz magnitude instead of xy since the x-y delta values only capture 2D length.

In our rotation design, a limitation is that only the hinge joint rotates. If we were to add rotational ability on both joints, we would have to slightly alter our planar tracking system to work with non-planar triangles. More troublesome for our solver, with bilateral 3D rotators, there is no clear deterministic method describing which joint should rotate first and how much it should rotate. Those variables would drastically alter the movement of the arm and would have to be highly tuned and dynamically dependent on specific positions and motions, significantly increasing complexity while adding very little to animating a humanoid walking.

Orientation

With planar tracking and rotation, our system can calculate the correct angles given that the target is within the bounding sphere of radius L, where L is the sum of the total length of the robot arm. However, in some circumstances, we need to be able orientate the joints into different configurations. For example, on a leg, the quadricep raises the leg with the calf pointing down. Meanwhile, on an arm, the bicep part points down with the forearm pointing up.

Solve Planar Tracker except replace `atan = Mathf.Atan2(diff.y, -xz.magnitude) * Mathf.Rad2Deg` (quadrant change)
Rotate to actual target `hinge.EulerAngle.y = [z - rotation] + 180`

We achieve orientability by creating a temporary point that is the target point flipped around the y-axis. We then rotate the arm by 180 degrees, giving us an arm that reaches its target except in a different orientation.

Why This Method?

There are multiple ways to solve inverse kinematics including using first order approximations and heuristic methods in addition to the geometric approach that we took. We researched each of those types of solvers and chose the geometric approach for its effectiveness and controllability.

The most common method of implementing IK is using a first order approximation with the Jacobian to calculate how each of the joint angles should change to reach the target point. Computationally, this method requires numerical techniques like calculating the pseudoinverse with the Jacobian’s SVD since it (3 x 2 in this case) is not invertible (nor is it usually invertible for IK) [9]. Implementing this method would allow us to add additional joints and degrees of freedom but is unclear as to exactly how to specify constraints and tie breakers, disqualifying it as solver for our use case.

Another technique is the use of constrained optimization programs to minimize the cost between our end effector with the target point with constraints. The optimization problem can then be solved using Lagrange multipliers, but the overhead cost of learning how to make these programs effectively on top of animation made it implementation-wise less attractive as a solution to our project [10].

Beyond numerical methods, we also researched into heuristic based methods like Cyclic Coordinate Descent and FABRIK. We were particularly interested in FABRIK, an iterative algorithm that would repeatedly adjust joint angles backwards and forwards until the end effector reached the target or for a limited number of iterations. FABRIK is interesting because it adjusts the joints closest to the end effector the most [3]. Indeed, we actually flipped this strategy for our IK solver and drew inspiration from FABRIK. FABRIK is also very fast, but since there was never a need for more than 2 joints, we felt that FABRIK was excessive in behavior and would not provide any better results.

An analytic method through geometry was particularly attractive for this project because it is a good primer to get orientated around animation and kinematics without imposing secondary implementation issues that might restrict project progress. In addition, an analytic method is deterministic, and with a comprehensive understanding of how the system worked, we were able to write constraints and specify more precise behavior—something we might not have been able to do with numerical methods that might’ve chosen any number of configurations as the solution [1]. A downside with taking the analytic approach is that it is impractical if we wanted to extend the system to more joints. We did notice that there were many resources on 2D inverse kinematics using this method but not with 3D kinematics and so had to derive formulas that we belived best suited the system.

General Implementation Challenges

We found it quite difficult to debug our code since we had to consider faults in our environment setup on top of implementation errors in our script. One specific challenge we had was with object hierarchies within Unity. When testing our fully controllable humanoid with its walk cycle animation, we discovered that upon rotating the character, our IK system started to behave unexpectedly. It turned out that our implementation was working properly but an incorrect hierarchy of our target points was causing the coordinate systems to be out of sync relative to the character when it was rotated. To solve this issue, we needed to reorganize the hierarchies of our objects in Unity and use local positions (which use coordinates relative to our primary object) in our calcuations.

Another frequent challenge we encountered was verifying that our solution at any given time worked. We implemented each of the features without considering how it might impact the next feature. As a result, we were not able to abstract each of the features and instead had to frequently modify previously written code for another feature. To insure that the system would not break with new features, with every modification, we manually tested positions across 3D while also physically adjusting the entire model space to ensure that the correct coordinates were used. This method of constant back and forth slowed us down but helped insure correctness throughout the process. In addition, whenever our system did break, it was a helpful reminder to go back to the drawing board and consider factors we did not consider. As a result, we were able to capture a lot of geometric errors.

Lessons Learned

From our work for this project we learned several things. Firstly, animation is difficult, especially with precise movements. It was particularly difficult to get our animation to look realistic since we had to animate our target points by hand in Unity, rather than having a reference from actual real-world movements. We also learned that inverse kinematics is great for automating generic movements as in a robotic arm with full freedom, but is less appropriate for specialized, constrained movement without adding much more complexity. Lastly, we discovered that our analytical geometry approach for deriving the joint parameters was great for our use case since it was very conceptually straightforward, but may be limited in its extension to appendages with more than two joints.



Section II: Results

Application to Walking

For our humanoid walk animation, we created a pair of arms and legs and attached them on a body. The arms were set up with rotation and orientation on because arms can freely rotate about when in front of the body and have a different orientation from legs. However, since shoulder joints cannot freely move past a certain point, we added constraints to stop rotation and movement of the arm. The legs were configured with rotation and orientation off. While feet do not have to move in a parallel line while walking, we found the rigging for the animation to be easier and imposed the rotation restriction.

Full walk cycle

In the video above, we see our humanoid with a fully animated walk cycle, controlled using WASD keys in Unity. The walk cycle is animated using four red spheres which are the end effectors for each of the limbs. Colliders are enabled on the objects to allow the humanoid to interact with the environment.

Manual arm control

The demo above shows a manual manipulation of the arm by controlling the end effector (red sphere). As we can see, the arm has a full range of motion and the elbow bends accordingly. We also incorporated Unity's physics engine, allowing the humanoid to push the capsule away.

Our IK implementation
FastIKFabrik Implementation

Above, we have a side-by-side comparison of the humanoid's walk cycle controlled using our IK system and FastIKFabrik, an existing IK library based on this paper which we used as a baseline. The primary difference we can see is that the leg positions are inverted in the FastIKFabrik example due to implementation differences. However, other than that, the two simulations are quite similar which was our ultimate goal.

Our IK implementation
FastIKFabrik Implementation

Here, we have a comparison of arm movement between our IK system and FastIKFabrik. As we can see, the constraint options that we added to our system greatly improve the realism of the elbow movements as it simulates the constraints of the human elbow. With FastIKFabrik, we have a completely free joint which moves awkwardly in certain positions with regards to the mechanical feasibility of an actual human arm.



Section III: Resources

Our resource links distill into two categories: practical and theoretical information. YouTube videos gave us a practical sense of how to approach Unity and use its platform while the papers and articles gave us a more solid theoretical understanding in how to perform the joint calculations.



Section IV: Contributions


Jason Xu:

  • Researched IK solvers
  • Designed rotation and orientation
  • Designed constraint system
  • Coding and Debugging designs
  • Parts of final report, milestone slides

  • Mae Wang:

  • Introduced and implemented the current geometric approach for IK.
  • Animated all target objects in Unity3D.
  • Took charge of all Unity3D-related functionalities, such as setting up the Unity platform with needed assets and scripts/Unity "Git" collaboration, manual arm movement (WASD) for red object targets, basic input movement (arrow keys), building the robot's hierarchy and collision physics, and constructing environment and cameras.
  • Debugged tricky constraint bugs in 3D.
  • Produced and voiced all youtube videos for the project.

  • Yowsean Li:

  • Debugging code/Unity issues
  • Creating demo videos
  • Milestone report
  • Parts of final report