# Design of a Digital Twin Training Centre for an Industrial Robot Arm
## 4 KUKA KR5 Robot Unit Re-Creation and Control
\[y=\left(\frac{\overline{v}}{\omega}\right),\text{ }\text{ }\text{where }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }=\begin{pmatrix}\text{v}_{x}\\ \text{  
The Event Graph of Animation Blueprint contains a special event called \"Event Blueprint Update Animation\" which runs in every frame. Therefore, from the user's perspective, it happens instantly. Using the AnimGraph, the control rig is also available, which is a node-based rigging system capable of creating the necessary inverse kinematics virtually. Figure 12 shows the AnimGraph, which can communicate with the control rig. The input values of the control rig are read by the Animation Blueprint in every frame. The Output pose is basically the appearance of the KUKA KR5 with the current axis rotations.  
When pressing one of buttons responsible for movement, the \"Set Timer by Event\" node causes the Custom Event to run, repeatedly, until we release the button, which calls the \"Clear and Invalidate Timer by Handle\" function. The time input is a numerical value in seconds, which shows us the time spent between two executions. Changing this value can be used to make the robot move faster [55].  
The custom event that belongs to the free kinematics changes the value of \"Axis Rotations\", which is an 1D float array created in the KUKA KR5's blueprint. When the buttons controlling the movement are pressed, an integer's value instantly changes to an integer between 0 and 5, and a float variable gets a \(-1\) or \(+1\) value, which is responsible for the direction of rotating.  
The FK event changes the value of one of the elements of \"Axis Rotations\" float 1D array by adding the multiplication of a pre-defined \"FKAdding Value\" variable and with \(-1\) or \(+1\) depending on the direction of rotation. By using the \"Clamp float\" node, the rotation can be confined between join limits.  
The value of \"Axis Rotations\" array found in the KUKA KR5'S blueprint is changed through the Animating Blueprint's AnimGraph, which are sent to the Control Rig, where the current value of \"Bone\" rotation is overwritten by the new value. Figure 13 shows a part of the control rig, when the Axis 1 of KUKA KR5 is rotating. First it checks if currently the user is controlling in the joints coordinate system. If so, then the program with the \"Set Transform--Bone\" will change the Z rotation, while the X and Y stay constant. The new value of Z rotation is given by the AnimGraph as an input for control rig.  
To change the TCP world coordinates, inverse kinematics is required, which is created in the Control Rig. In Unreal Engine 4, since version 4.26 the full-body IK node is present, based on Jacobian Pseudoinverse Damped Least Squares. The full-body IK gives numerous opportunities to change settings during runtime and has other options as well. Multiple controls can be created, which can be moved and rotated using variables. One of these controls can be used as the FBIK effector [56].  
Figure 12: AnimGraph in the Animation Blueprint.  
The position of the IK control gets to the Control Rig via AnimGraphs. In the case of joints A1, A2, A3, overwriting the FBIK with limiting the rotation to only one axis is enough. However, in the case of A4, A5, A6, an \"Aim Math\" node is required, along with helper controls, to keep the desired orientation.  
For controlling the TCP in the world coordinate system, a helper actor must be added, which is invisible to the user. Pressing the movement buttons of the user interface, the IK actor's position changes, and this position is given to the IK Control found in the Control Rig. Changing the position works similarly to FK movement, however in this case, a custom event tied to a timer adds or subtracts a given value to one of the coordinates of the IK actor.  
After the controlling of KUKA KR5 is finished, the previously created program can be expanded with the HMI. Every time the motion button is pressed, a text appears in the next row that contains the type of movement and status of the gripper (open/closed). As this happens, temporary variables store the program line, joint rotations, and the position of the IK actor. Pressing CMD OK, these temporary values are added to the chosen element of the ProgramStructArray, then SaveEvent is executed. Before pressing CMD OK, it is possible to choose the movement type, which is stored in an ENUM variable. This is relevant while playing back the program, however, choosing the CIRC Motion option makes it necessary to add the coordinates of Aux and End points. To achieve easier playback, after every addition, regardless of movement type, joint rotation values and TCP vector coordinates are saved. Aux and End vectors are added for LIN and PTP movements as well, despite not using them--this is mostly to keep index values in the array consistent [57] (shown in Figure 14).  
Figure 14: PTP, LIN, CIRC—axis specific movement.  
Figure 13: Axis rotation value overwrite in Control Rig.  
To run the program, the G button must be pressed on the keyboard to start the \"Play Program\" Custom Event, which has an integer input that is the initial index of elements related to motion arrays. This value is sent to the \"Motion Index\" integer variable inside the KUKA KRS\({}^{\prime}\)s blueprint. \"Switch on Enum\" node calls the event related to the motion type. \"FKMovement\" custom event starts in case of PTP motion, \"Simple Movement\" custom event is called in case of LIN, and \"Circular Movement\" in case of CIRC motion type. At the end of each movement type, an \"EndOfMotion\" Custom Event is called, which first opens or closes the gripper with an event, if necessary. After the Gripper Event, if the value of \"Motion Index\" is not equal with the \"length of matrixes assigned to the movement\" \(-1\), the \"Play Program\" custom event is called again with an index value that is increased by one. This is repeated until the program is finished.  
The basis of the movements is given by the combination of a timeline and a lerp. In the timeline, with a float track two points are added: at 0 s a 0 value and at 1 s a 1 value. The Lerp node has three inputs: A, B, Alpha. In case of Alpha = 0, the output gives back 100% of value A, in case of Alpha = 1, the output gives 100% of value B. Between 0 and 1, a linear combination of A and B is returned. The value of alpha is provided by the timeline's float track, which increases from 0 to 1 in one second.  
To avoid the movement happening within a single second, changing the value of Play Rate is necessary. In case of PTP and CIRC motion type this value depends on the rotation angle, while in case of Lin movement it depends on the distance between the start and end points.  
During PTP movement, 6 custom events are called with their timelines and lerps. To the A value of the lerps, the KR5\({}^{\prime}\)s rotational values are sent, meanwhile to the B value, the rotation values saved in the Program Structure are sent. This makes it so that all joints start rotating at the same time, and when every timeline is done, the \"EndOfMotion\" Custom Event is called.  
In case of LIN movements, the lerp uses vector coordinates. The moment the movement starts, the IK actor's position is read, which then sent to the lerp's A input, meanwhile the IK vector array's value is sent to the B input from the Program Structure.  
In the case of CIRC movement, the origin of the circle has to be defined by the Start, Aux and End points.  
Supposing that \(a\), \(b\), \(c\) letters represent the Start, Aux, and End points. \(P_{1}\) is the [\(ab\)] line's half point, \(P_{2}\) is the [\(bc\)] line's half point, d is the origin of the circle. Multiplying the vectors that point from b to \(P_{1}\) and \(P_{2}\), we get a vector that is perpendicular to the plane, and is defined by points \(a\), \(b\), \(c\)[58].  
\[\overset{\rightarrow}{S}=\frac{b\overset{\rightarrow}{P_{1}}}{2}\times\frac{ b\overset{\rightarrow}{P_{2}}}{2} \tag{6}\]  
\(O_{1}\) and \(O_{2}\) vectors point from \(P_{1}\) and \  
Then the origin of the circle is:  
\[d=P_{1}+O_{1}*\frac{p}{1-q} \tag{11}\]  
These equations can be entered into Unreal Engine 4 by using a Math Expression Node.