We are so accustomed to interacting with the world around us, that we do not think about how difficult our arms and legs move. In the academic literature, the task of controlling a robot arm is called inverse kinematics. Kinematics means " movement ", and the concept of " inverse " is due to the fact that we usually do not control the hand itself. We drive βenginesβ that turn every single part. Inverse kinematics is the task of determining how to move these engines in order to move the arm to a specific point. And in its general form, this task is extremely difficult. So that you understand how difficult it is, you can think of games such as QWOP , GIRP, or even Lunar Lander , in which you choose not where to move, but which muscles (or accelerators) to put into action.
The task of controlling movable drives extends even to the field of robotics. You should not be surprised that over the centuries maths and engineers have been able to develop many solutions. Most 3D editors and game engines (including Unity) have a set of tools that allow you to rivet humanoid and animal-like creatures. For various schemes (robot manipulators, tails, tentacles, wings, etc.), embedded solutions usually do not exist.
That is why in the previous series of articles on procedural animations and inverse kinematics, I proposed a very general and effective solution that can work with any scheme. But such power has a compromise: efficiency. One of the most important reasons for criticizing my article was that the method turned out to be too long and costly, while being used for hundreds of characters. Therefore, I decided to write a new article on the inverse kinematics of a manipulator in two degrees of freedom. The technique described in this tutorial is extremely effective and can be used for dozens (if not hundreds!) Of characters simultaneously.
Inverse kinematics
Let's imagine a robotic arm with two segments and two hinges, similar to the diagram below. At the end of the manipulator there is a final link that we want to control. We have no direct control over the position of the final link and can only rotate the hinges. The task of inverse kinematics is to find the best way to turn the connections to move the final link to the desired position. ')
The solution proposed in this tutorial will work only for manipulators with two hinges. In academic literature it is often written that such manipulators have two degrees of freedom . And the reason for this is perfectly clear from the diagram below. The manipulator of a robot with two degrees of freedom can be modeled as a triangle, which is one of the most well-studied shapes in geometry.
Let's start by formalizing the task a bit. Two hinges A and B (both highlighted in black) can be rotated at corners A (blue) and B (green). This will cause the final link to move to position. C .
Inside corners
We can use three points. A , B and C to build a triangle with internal angles alpha , beta and gamma as in the example below.
Although all three corners are unknown to us, we know the length of all the edges.
Section overlineAB denotes a hand and has a length c ;
Section overlineBC denotes the forearm and has a length a ;
Section overlineca denotes the distance between the hinge of the shoulder and the brush, and has a length b .
Knowledge of the three sides of the triangle is enough to find all three corners. This is possible thanks to the cosine theorem , which is a generalization of the Pythagorean theorem for triangles, which are not necessarily correct.
The two angles necessary to control the manipulator are alpha and beta . Let's start with alpha , which can be calculated using the cosine theorem:
$$ display $$ \ begin {equation *} a ^ 2 = b ^ 2 + c ^ 2 - 2 bc \ cos {\ alpha} \ end {equation *} $$ display $$
We can transform the equation to translate cosalpha :
\ begin {split} \ cos {\ alpha} & = \ frac {a ^ 2-b ^ 2-c ^ 2} {- 2bc} = \\ & = \ boxed {\ frac {b ^ 2 + c ^ 2-a ^ 2} {2bc}} \ end {split}
\ begin {split} \ cos {\ alpha} & = \ frac {a ^ 2-b ^ 2-c ^ 2} {- 2bc} = \\ & = \ boxed {\ frac {b ^ 2 + c ^ 2-a ^ 2} {2bc}} \ end {split}
Now we need to apply the inverse cosine function cosβ1 (also known as arccosine ) to find alpha :
$$ display $$ \ begin {equation *} \ alpha = \ cos ^ {- 1} {\ left (\ boxed {\ frac {b ^ 2 + c ^ 2-a ^ 2} {2bc}} \ right) } \ end {equation *} $$ display $$
Using the same procedure, we can again apply the cosine theorem to find beta :
b2=a2+c2β2accosbeta
cosbeta=fraca2+c2βb22ac
$$ display $$ \ begin {equation *} \ beta = \ cos ^ {- 1} {\ left (\ frac {a ^ 2 + c ^ 2 -b ^ 2} {2ac} \ right)} \ end { equation *} $$ display $$
Derivation of the cosine theorem
Section h divides a triangle oversettriangleABC into two right triangles: oversettriangleABH and oversettriangleBCH . This proof is a natural consequence of applying the Pythagorean theorem to both triangles:
$$ display $$ \ begin {equation *} \ begin {split} \ overset {\ triangle} {ABH}: & \\ & c ^ 2 = h ^ 2 + \ left (bd \ right) ^ 2 \\ & h ^ 2 = \ boxed {c ^ 2 - \ left (bd \ right) ^ 2} \ end {split} \ end {equation *} $$ display $$
$$ display $$ \ begin {equation *} \ begin {split} \ overset {\ triangle} {BCH}: & \\ & a ^ 2 = d ^ 2 + h ^ 2 \\ & h ^ 2 = \ boxed {a ^ 2 -d ^ 2} \ end {split} \ end {equation *} $$ display $$
Both equations are now relatively h2 . We can equate them both to get the following:
\ begin {split} \ boxed {a ^ 2 -d ^ 2} & = \ boxed {c ^ 2 - \ left (bd \ right) ^ 2} \\ a ^ 2 - d ^ 2 & = c ^ 2 - \ left (b ^ 2 + d ^ 2 - 2 bd \ right) \\ a ^ 2 - d ^ 2 & = c ^ 2 - b ^ 2 - d ^ 2 + 2 bd \ a ^ 2 \ xcancel { - d ^ 2} & = c ^ 2 - b ^ 2 \ xcancel {- d ^ 2} + 2 bd \\ a ^ 2 & = c ^ 2 - b ^ 2 + 2 bd \\ \ end {split}
what can be converted to:
$$ display $$ \ begin {equation *} c ^ 2 = a ^ 2 + b ^ 2-2bd \ end {equation *} $$ display $$
In this form, the cosine theorem is presented in the Euclidean Principles.
To get the modern look of the equation, we need to apply trigonometry. Since (5) is a regular triangle, we can express the segment d as:
$$ display $$ \ begin {equation *} d = a \ sin {\ delta} \ end {equation *} $$ display $$
Where delta can be found by remembering that the sum of the angles of a triangle is 180circ (or, similarly, pi radians):
$$ display $$ \ begin {equation *} \ begin {split} d & = a \ sin {\ delta} \\ d & = a \ boxed {\ sin {\ left (\ frac {\ pi} {2} - \ gamma \ right)}} \\ d & = a \ boxed {\ cos {\ gamma}} \ end {split} \ end {equation *} $$ display $$
The final step is a well-known property:
sinleft(fracpi2βgammaright)=cosgamma
Now we can substitute this, which gives us a modern view of the cosine theorem :
$$ display $$ \ begin {equation *} \ begin {split} c ^ 2 & = a ^ 2 + b ^ 2-2b \ boxed {d} \\ c ^ 2 & = a ^ 2 + b ^ 2-2b \ boxed {a \ cos {\ gamma}} \\ c ^ 2 & = a ^ 2 + b ^ 2-2ab \ cos {\ gamma} \ end {split} \ end {equation *} $$ display $$
Hinge angles
Using the cosine theorem, we calculated the values alpha and beta which are the inner corners of the triangle formed by the manipulator. However, we actually need angles A (blue) and B (green).
Let's start by calculating B that will be easier. From the picture shown above it is obvious that beta and B total give 180circ (which is equal to pi radians). It means that:
$$ display $$ \ begin {equation *} \ begin {split} \ beta + B = \ pi \\ B = \ pi - \ beta \ end {split} \ end {equation *} $$ display $$
Calculation A not much different. The only difference here is that we need to consider Aβ² (purple) which is the cut angle overlineac . It can be calculated using the arc cotangent function tanβ1 :
$$ display $$ \ begin {equation *} A '= \ tan ^ {- 1} {\ left (\ frac {C_Y-A_Y} {C_X-A_X} \ right)} \ end {equation *} $$ display $$
What gives us:
$$ display $$ \ begin {equation *} A = \ alpha + A '\ end {equation *} $$ display $$
Sign of angles A , Aβ² and B basically arbitrary and depends on the method of movement of each hinge.
Multiple solutions?
The problem of inverse kinematics usually involves several solutions. Even in our case, with only two degrees of freedom, we have two different solutions.
Although the corners A and B actually different, the output essentially remains the same, with a few exceptions.
Part 2. Code
Introduction
In the previous part, we considered the problem of inverse kinematics for a robot manipulator with two degrees of freedom.
In this case, the length of the manipulators is usually known. cc and a . If the point we want to reach is C , the configuration becomes a triangle, all sides of which are known.
Then we derived equations for the angles A and B controlling the pivot of the manipulator hinges:
$$ display $$ \ begin {equation *} A = \ underset {\ alpha} {\ underbrace {\ cos ^ {- 1} {\ left (\ frac {b ^ 2 + c ^ 2-a ^ 2} { 2bc} \ right)}}} + \ underset {A '} {\ underbrace {\ tan ^ {- 1} {\ left (\ frac {C_Y-A_Y} {C_X-A_X} \ right)}}} \ end {equation *} $$ display $$
$$ display $$ \ begin {equation *} B = \ pi - \ underset {\ beta} {\ underbrace {\ cos ^ {- 1} {\ left (\ frac {a ^ 2 + c ^ 2 -b ^ 2} {2ac} \ right)}}} \ end {equation *} $$ display $$
At first glance, they can look pretty frightening; on the other hand, their geometric interpretation is quite intuitive from the figure shown above.
Creating a robot manipulator
The first step in implementing this solution is to create a robot arm. The concept of "hinges" is unknown to the Unity engine. However, the parent element system in the engine can be used to create a hierarchy of components that will behave exactly like a robot manipulator.
The idea is to use a GameObject for each hinge so that the rotation of its transform makes it rotate and a manipulator attached to it. Having made the second hinge a child of the first hinge, we will make them turn as in the first drawing.
As a result, we get the following hierarchy:
Root
Hinge A
Bone A
Hinge B
Bone B
Arm
Then we can add a script with the name SimpleIK to the root object, which will perform hinge turns to reach the desired point.
using System.Collections; using UnityEngine; namespaceAlanZucconi.IK { publicclassSimpleIK : MonoBehaviour { [Header("Joints")] public Transform Joint0; public Transform Joint1; public Transform Hand; [Header("Target")] public Transform Target; ... } }
The equations derived in the previous part of the tutorial require knowledge of the length of the first two bones (called respectively c and a ). Since the length of the bones should not change, they can be calculated in the Start function. However, this requires the paddle to be in a good configuration when you start the game.
Before showing the finished version of the code, let's start with a simplified. If we transfer equations (1) and (2) directly into the code, then as a result we get something like this:
Mathematical functions cosβ1 and tanβ1 called in Unity Mathf.Acos and Mathf.Atan2 . In addition, the final angles are converted to degrees using Mathf.Rad2Deg , because the Transform component should receive angles, not radians.
Target unreachable goals
Although the code shown above seems to work, there is a condition under which it fails. What happens if the goal is unattainable? This is not taken into account in the current implementation, which leads to undesirable behaviors.
A common solution would be to completely stretch the arm towards the target. This behavior is consistent with the pullout movement that we seek to pretend.
The code shown below recognizes unattainable targets by checking whether the distance from the root to it is greater than the total length of the manipulator.
Now we have to learn how to turn the hinges. This is done by accessing the localEulerAngles property of the Transform hinge component. Unfortunately, we cannot change the angle z directly, so the vector needs to be copied, modified, and pasted.