# Lula Kinematics Solver

## Learning Objectives

This tutorial shows how the Lula Kinematics Solver class is used to compute forward and inverse kinematics on a robot in Omniverse Isaac Sim.

## Getting Started

Prerequisites

In order to follow along with the tutorial, you may download a standalone Lula Kinematics example extension here: `Lula Kinematics Tutorial`. The provided zip file contains an example of the LulaKinematicsSolver being used to compute forward and inverse kinematics solutions for a specified target. This tutorial explains the contents of the file /Lula_Kinematics_python/scenario.py, which contains all LulaKinematicsSolver related code.

## Using the LulaKinematicsSolver to Compute Forward and Inverse Kinematics

The Lula Kinematics Solver is able to calculate forward and inverse kinematics for a robot that is defined by two configuration files (see Lula Kinematics Solver Configuration). The LulaKinematicsSolver may be paired with an Articulation Kinematics Solver to compute kinematics in a way that can be directly applied to the robot Articulation.

The file /Lula_Kinematics_python/scenario.py uses the LulaKinematicsSolver to generate inverse kinematic solutions to move the robot to a target.

``` 1import numpy as np
2import os
3import carb
4
5from omni.isaac.core.utils.extensions import get_extension_path_from_name
7from omni.isaac.core.articulations import Articulation
8from omni.isaac.core.utils.nucleus import get_assets_root_path
9from omni.isaac.core.prims import XFormPrim
10from omni.isaac.core.utils.numpy.rotations import euler_angles_to_quats
11
12from omni.isaac.motion_generation import ArticulationKinematicsSolver, LulaKinematicsSolver
14
15class FrankaKinematicsExample():
16    def __init__(self):
17        self._kinematics_solver = None
18        self._articulation_kinematics_solver = None
19
20        self._articulation = None
21        self._target = None
22
24        # Add the Franka and target to the stage
25
26        robot_prim_path = "/panda"
27        path_to_robot_usd = get_assets_root_path() + "/Isaac/Robots/Franka/franka.usd"
28
30        self._articulation = Articulation(robot_prim_path)
31
33        self._target = XFormPrim("/World/target", scale=[.04,.04,.04])
34        self._target.set_default_state(np.array([.3,0,.5]),euler_angles_to_quats([0,np.pi,0]))
35
36        # Return assets that were added to the stage so that they can be registered with the core.World
37        return self._articulation, self._target
38
39    def setup(self):
40        # Load a URDF and Lula Robot Description File for this robot:
41        mg_extension_path = get_extension_path_from_name("omni.isaac.motion_generation")
42        kinematics_config_dir = os.path.join(mg_extension_path, "motion_policy_configs")
43
44        self._kinematics_solver = LulaKinematicsSolver(
45            robot_description_path = kinematics_config_dir + "/franka/rmpflow/robot_descriptor.yaml",
46            urdf_path = kinematics_config_dir + "/franka/lula_franka_gen.urdf"
47        )
48
49        # Kinematics for supported robots can be loaded with a simpler equivalent
50        # print("Supported Robots with a Lula Kinematics Config:", interface_config_loader.get_supported_robots_with_lula_kinematics())
52        # self._kinematics_solver = LulaKinematicsSolver(**kinematics_config)
53
54        print("Valid frame names at which to compute kinematics:", self._kinematics_solver.get_all_frame_names())
55
56        end_effector_name = "right_gripper"
57        self._articulation_kinematics_solver = ArticulationKinematicsSolver(self._articulation,self._kinematics_solver, end_effector_name)
58
59
60    def update(self, step: float):
61        target_position, target_orientation = self._target.get_world_pose()
62
63        #Track any movements of the robot base
64        robot_base_translation,robot_base_orientation = self._articulation.get_world_pose()
65        self._kinematics_solver.set_robot_base_pose(robot_base_translation,robot_base_orientation)
66
67        action, success = self._articulation_kinematics_solver.compute_inverse_kinematics(target_position, target_orientation)
68
69        if success:
70            self._articulation.apply_action(action)
71        else:
72            carb.log_warn("IK did not converge to a solution.  No action is being taken")
73
74        # Unused Forward Kinematics:
75        # ee_position,ee_rot_mat = articulation_kinematics_solver.compute_end_effector_pose()
76
77    def reset(self):
78        # Kinematics is stateless
79        pass
```

The LulaKinematicsSolver is instantiated on lines 41-47 using file paths to the appropriate configuration files. The LulaKinematicsSolver uses the same robot description files as the Lula-based RMPflow Motion Policy Algorithm. The LulaKinematicsSolver can solve forward and inverse kinematics at any frame that exists in the robot URDF file. On line 54, the complete list of recognized frames in the Franka robot is printed:

```Valid frame names at which to compute kinematics:
'camera_bottom_screw_frame', 'camera_link', 'camera_depth_frame', 'camera_color_frame', 'camera_color_optical_frame', 'camera_depth_optical_frame',
'camera_left_ir_frame', 'camera_left_ir_optical_frame', 'camera_right_ir_frame', 'camera_right_ir_optical_frame', 'panda_face_back_left',
'panda_face_back_right', 'panda_face_left', 'panda_face_right', 'panda_leftfinger', 'panda_leftfingertip', 'panda_rightfinger', 'panda_rightfingertip', 'right_gripper', 'panda_wrist_end_pt']
```

Supported robots can be loaded directly by name as on lines 50-52. This is equivalent to lines 41-47.

On line 57, an Articulation Kinematics Solver is instantiated with the franka robot Articulation, the LulaKinematicsSolver instance, and the end effector name. The ArticulationKinematicsSolver class allows the user to compute the end effector position and orientation for the robot Articulation in a single line (line 75).

The ArticulationKinematicsSolver also allows the user to compute inverse kinematics. The current position of the robot Articulation is used as a warm start in the IK calculation, and the result is returned as an ArticulationAction that can be consumed by the robot Articulation to move the specified end effector frame to a target position (lines 67 and 70).

The LulaKinematicsSolver returns a flag marking the success or failure of the inverse kinematics computation. On line 67, the script applies the inverse kinematics solution to the robot Articulation only if the kinematics converged successfully to a solution, otherwise no new action is sent to the robot, and a warning is thrown. The LulaKinematicsSolver exposes settings that allow the user to specify how quickly it should terminate its search. These settings are outside the scope of this tutorial.

The LulaKinematicsSolver assumes that the robot base is positioned at the origin unless another location is specified. On lines 64-65, the LulaKinematicsSolver is given the current position of the robot base on every frame. This allows the forward and inverse kinematics to operate using world coordinates. For example, the position of the target is queried in world coordinates and passed to the LulaKinematicsSolver, which internally performs the necessary transformation to compute accurate inverse kinematics.

The LulaKinematicsSolver may be used on its own to compute forward kinematics at any position and to compute inverse kinematics with any warm start. A robot Articulation does not need to be present on the USD stage. Using the LulaKinematicsSolver in this way is outside the scope of this tutorial. See Kinematics Solvers for more details.

Additionally, the user should note that sending an inverse kinematic solution directly to the robot is not likely to be useful beyond simple demonstrations. In a realistic scenario, the user needs to determine not only the end position of the robot, but also the path to get there. An IK solver on its own can make for only a rudimentary trajectory thorugh space that is not likely to be optimal.

## Summary

This tutorial reviews how to load the LulaKinematicsSolver class and use it alongside the ArticulationKinematicsSolver helper class to compute forward and inverse kinematics at any frame specified in the robot URDF file.

### Further Learning

To understand the motivation behind the structure and usage of LulaKinematicsSolver in Omniverse Isaac Sim, reference the Motion Generation page.