{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f96fd41d",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "# Robotics Algorithms\n",
    "The purpose of this notebook is to demonstrate how **kdflex**'s various algorithms can be used. This notebook uses the Barret WAM arm to showcase these algorithms.\n",
    "\n",
    "Resources\n",
    "- [Other notebook examples](https://portal.karanadyn.com/docs/examples_page.html) \n",
    "- [kdFlex Documentation](https://portal.karanadyn.com/docs/index.html)\n",
    "\n",
    "**Acknowledgements**\n",
    "The Barret WAM urdf is sourced from the public repository [barrett-ros2-pkg](https://git.barrett.com/software/barrett-ros2-pkg.git). Thank you to the authors and contributors."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5978859c",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "Import **kdFlex** Python modules objects for use later"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "dce602b8",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "import atexit\n",
    "import numpy as np\n",
    "from pathlib import Path\n",
    "\n",
    "import Karana.Core as kc\n",
    "import Karana.Frame as kf\n",
    "import Karana.Dynamics as kd\n",
    "from Karana.KUtils.BasicPrefab import BasicPrefabDS\n",
    "import Karana.Dynamics.SOADyn_types as kdt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bcb35c5b",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "Build the filepath to the URDF file we will import"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "fd13f1bc",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "resources = Path().absolute().parent / \"resources\"\n",
    "urdf_file = resources / \"wam7dof\" / \"wam7dof_hand.urdf\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "64ddd559",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "Import the URDF file to create a SOADyn_types.MultibodyDS. The \"DS\" is short for \"Data Structure\". This is kdFlex's native, file-format agnostic way of specifying a multibody. We'll use this later on to instantiate the multibody."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "8e99d2b9",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "LEGEND: [<hinge type[/dofs]> <prescribed subhinges>] <body name>[/num embedded bodies > 0] <flex dofs > 0>\n",
      "|-wam7dof_MBVROOT_\n",
      "   |-[REVOLUTE] FirstLink\n",
      "      |-[REVOLUTE] SecondLink\n",
      "         |-[REVOLUTE] ThirdLink\n",
      "            |-[REVOLUTE] FourthLink\n",
      "               |-[REVOLUTE] FifthLink\n",
      "                  |-[REVOLUTE] SixthLink\n",
      "                     |-[REVOLUTE] SeventhLink\n",
      "                        |-[LOCKED] bhand_base\n",
      "                           |-[REVOLUTE] bhand_link11\n",
      "                              |-[REVOLUTE] bhand_link12\n",
      "                                 |-[REVOLUTE] bhand_link13\n",
      "                           |-[REVOLUTE] bhand_link21\n",
      "                              |-[REVOLUTE] bhand_link22\n",
      "                                 |-[REVOLUTE] bhand_link23\n",
      "                           |-[REVOLUTE] bhand_link32\n",
      "                              |-[REVOLUTE] bhand_link33\n",
      "\n"
     ]
    }
   ],
   "source": [
    "sg_ds = BasicPrefabDS.fromFile(urdf_file).params.subtree\n",
    "\n",
    "frame_container = kf.FrameContainer(\"root\")\n",
    "sg_ds2 = kdt.SubGraphDS(name=sg_ds.name, base_bodies=sg_ds.base_bodies)\n",
    "multibody = sg_ds2.toMultibody(frame_container)\n",
    "\n",
    "# print(multibody_info)\n",
    "\n",
    "multibody.ensureHealthy()\n",
    "multibody.resetData()\n",
    "multibody.dumpTree()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "97db71f8",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "Set up the 3D graphics."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "024e4376",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "        <div style=\"height:300px; resize:vertical; overflow: auto;\">\n",
       "          <iframe src=\"http://localhost:38295\" style=\"width:100%; height:100%; border:0; display:block;\"></iframe>\n",
       "        </div>\n",
       "        "
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "cleanup_graphics, web_scene = multibody.setupGraphics(port=0)\n",
    "web_scene.defaultCamera().pointCameraAt(\n",
    "    offset=[0.2, 0.5, 1.7],\n",
    "    target=[0, 0, 1],\n",
    "    up=[1, 0, 0],\n",
    ")\n",
    "proxy_scene = multibody.getScene()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b90d05e",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "Display the bodies in the multibody model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "e9ab8bad",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[WebUI] Web server is running on port 38295\n",
      "You may be able to connect in your browser at:\n",
      "\t\u001b[1mhttp://localhost:38295\u001b[0m\n",
      "\n",
      "LEGEND: <body number> <body name> <parent body> <hinge type> [prescribed subhinges] <U dofs/offset> [flex dofs/offset]\n",
      "\n",
      "      Body           Parent               Hinge    Dofs          \n",
      "      ____           ______               _____    ____          \n",
      "   1. FirstLink      wam7dof_MBVROOT_    REVOLUTE  1/0           \n",
      "   2. SecondLink     FirstLink           REVOLUTE  1/1           \n",
      "   3. ThirdLink      SecondLink          REVOLUTE  1/2           \n",
      "   4. FourthLink     ThirdLink           REVOLUTE  1/3           \n",
      "   5. FifthLink      FourthLink          REVOLUTE  1/4           \n",
      "   6. SixthLink      FifthLink           REVOLUTE  1/5           \n",
      "   7. SeventhLink    SixthLink           REVOLUTE  1/6           \n",
      "   8. bhand_base     SeventhLink          LOCKED   0/7           \n",
      "   9. bhand_link11   bhand_base          REVOLUTE  1/7           \n",
      "  10. bhand_link12   bhand_link11        REVOLUTE  1/8           \n",
      "  11. bhand_link13   bhand_link12        REVOLUTE  1/9           \n",
      "  12. bhand_link21   bhand_base          REVOLUTE  1/10          \n",
      "  13. bhand_link22   bhand_link21        REVOLUTE  1/11          \n",
      "  14. bhand_link23   bhand_link22        REVOLUTE  1/12          \n",
      "  15. bhand_link32   bhand_base          REVOLUTE  1/13          \n",
      "  16. bhand_link33   bhand_link32        REVOLUTE  1/14          \n",
      "                                                   ____          \n",
      "                                                   15            \n",
      "\n"
     ]
    }
   ],
   "source": [
    "multibody.displayModel()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "77a82391",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "Display the topological structure of the multibody system"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f4914aa3",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "# Testing robotics algorithms"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "0ada5435-e53b-4018-b1e6-7d9b57b5f716",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Uniform Gravity Acceleration Set\n",
      "Udot: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n"
     ]
    }
   ],
   "source": [
    "multibody.setUniformGravAccel([0, 0, 9.8])\n",
    "\n",
    "print(\"Uniform Gravity Acceleration Set\")\n",
    "print(f\"Udot: {multibody.getUdot()}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "ca165b01-b2aa-4485-86c8-b440be76cfb0",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Without Gravity Compensation\n",
      "Udot: [-1.25788279e-04 -1.24733017e+01  3.58365891e-02  4.93454986e+01\n",
      " -8.47109747e+01 -3.70940309e+01  8.46752641e+01  4.09569893e-07\n",
      " -1.68881352e-01 -5.29529891e-02  4.09569893e-07 -1.68881352e-01\n",
      " -5.29529892e-02  2.74942539e-01 -5.31081971e-02]\n"
     ]
    }
   ],
   "source": [
    "print(\"Without Gravity Compensation\")\n",
    "multibody.setUdot(0)\n",
    "kd.Algorithms.evalForwardDynamics(multibody)\n",
    "print(f\"Udot: {multibody.getUdot()}\")\n",
    "assert not np.allclose(multibody.getUdot(), 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "7a490185-2e1b-4f06-a452-e1871b9236a8",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "With Gravity Compensation\n",
      "Gravity Compensation Torque: [ 8.91121417e-05  4.24085429e-01 -2.44276030e-07 -2.63264584e+00\n",
      "  3.16021202e-06  1.66622295e-01  6.11944300e-07 -6.11951481e-07\n",
      " -6.86000000e-02  0.00000000e+00 -6.11951481e-07 -6.86000000e-02\n",
      "  0.00000000e+00 -6.86000000e-02  0.00000000e+00]\n",
      "Udot: [ 0.00000000e+00  0.00000000e+00  3.11755858e-15 -9.76298595e-19\n",
      " -3.09934158e-15 -8.18770417e-18 -1.82169618e-17  7.78027041e-23\n",
      " -9.18981707e-18  2.91143785e-21  7.78027041e-23 -9.18980914e-18\n",
      "  2.90350589e-21  9.19042584e-18 -3.52021250e-21]\n"
     ]
    }
   ],
   "source": [
    "print(\"With Gravity Compensation\")\n",
    "multibody.setUdot(0)\n",
    "T = kd.Algorithms.evalGravityCompensation(multibody)\n",
    "print(f\"Gravity Compensation Torque: {T}\")\n",
    "multibody.setT(T)\n",
    "kd.Algorithms.evalForwardDynamics(multibody)\n",
    "print(f\"Udot: {multibody.getUdot()}\")\n",
    "assert np.allclose(multibody.getUdot(), 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "29e06a59",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Evaluated the Computed Torque\n",
      "Reset Q, U, and Udot\n",
      "Computed Torque: [ 8.91121417e-05  4.24085429e-01 -2.44276030e-07 -2.63264584e+00\n",
      "  3.16021202e-06  1.66622295e-01  6.11944300e-07 -6.11951481e-07\n",
      " -6.86000000e-02  0.00000000e+00 -6.11951481e-07 -6.86000000e-02\n",
      "  0.00000000e+00 -6.86000000e-02  0.00000000e+00]\n",
      "Udot: [ 0.00000000e+00  0.00000000e+00  3.11755858e-15 -9.76298595e-19\n",
      " -3.09934158e-15 -8.18770417e-18 -1.82169618e-17  7.78027041e-23\n",
      " -9.18981707e-18  2.91143785e-21  7.78027041e-23 -9.18980914e-18\n",
      "  2.90350589e-21  9.19042584e-18 -3.52021250e-21]\n"
     ]
    }
   ],
   "source": [
    "print(\"Evaluated the Computed Torque\")\n",
    "print(\"Reset Q, U, and Udot\")\n",
    "multibody.setUdot(0)\n",
    "multibody.setQ(0)\n",
    "multibody.setU(0)\n",
    "multibody.setT(0)\n",
    "T = kd.Algorithms.evalComputedTorque(multibody)\n",
    "print(f\"Computed Torque: {T}\")\n",
    "multibody.setT(T)\n",
    "kd.Algorithms.evalForwardDynamics(multibody)\n",
    "print(f\"Udot: {multibody.getUdot()}\")\n",
    "assert np.allclose(multibody.getUdot(), 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0841ae40",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "# Testing other control related algorithms"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "37fa9e56",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "0ec19236",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "Cleanup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "136c1c30",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function __main__.cleanup()>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def cleanup():\n",
    "    \"\"\"Cleanup the simulation.\"\"\"\n",
    "    global sg_ds, sg_ds2, web_scene, proxy_scene\n",
    "    del sg_ds, sg_ds2, web_scene, proxy_scene\n",
    "\n",
    "    cleanup_graphics()\n",
    "\n",
    "    kc.discard(multibody)\n",
    "    kc.discard(frame_container)\n",
    "\n",
    "\n",
    "atexit.register(cleanup)"
   ]
  }
 ],
 "metadata": {
  "docs": {
   "tags": [
    "import",
    "math",
    "robot"
   ]
  },
  "kernelspec": {
   "argv": [
    "python",
    "-m",
    "ipykernel_launcher",
    "-f",
    "{connection_file}"
   ],
   "display_name": "Python 3 (ipykernel)",
   "env": null,
   "interrupt_mode": "signal",
   "kernel_protocol_version": "5.5",
   "language": "python",
   "metadata": {
    "debugger": true
   },
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  },
  "name": "notebook.ipynb"
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
