{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f96fd41d",
   "metadata": {},
   "source": [
    "# Importing a robot arm multibody model from a URDF file\n",
    "The purpose of this notebook is to\n",
    "- demonstrate the creation of a {py:class}`Karana.Dynamics.Multibody` instance for a robot arm from a URDF model file \n",
    "- show the structure of the loaded model\n",
    "- show a 3D visualization of the robot arm\n",
    "- serve as a `hello world` script for verifying a proper `kdFlex` installation\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 Barrett 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": {},
   "source": [
    "Import **kdFlex** Python modules objects for use later"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "dce602b8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pathlib import Path\n",
    "import atexit\n",
    "\n",
    "import Karana.KUtils.BasicPrefab as kub\n",
    "from Karana.KUtils.Sim import Sim"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bcb35c5b",
   "metadata": {},
   "source": [
    "Build the filepath to the URDF file we will import"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "fd13f1bc",
   "metadata": {},
   "outputs": [],
   "source": [
    "resources = Path().absolute().parent / \"resources\"\n",
    "urdf_file = resources / \"wam7dof\" / \"wam7dof_hand.urdf\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c8b05075",
   "metadata": {},
   "source": [
    "Import the URDF file to create a BasicPrefabDS. The \"DS\" is short for \"Data Structure\". This is kdFlex's native, file-format agnostic way of specifying a multibody and associated KModels. We'll use this next to create our simulation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "c6ce1a4a",
   "metadata": {},
   "outputs": [],
   "source": [
    "basic_prefab_ds = kub.BasicPrefabDS.fromFile(urdf_file)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4fd06632",
   "metadata": {},
   "source": [
    "Instantiate and configure the {py:class}`Karana.Dynamics.Multibody` based on the BasicPrefabDS description."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "8e99d2b9",
   "metadata": {},
   "outputs": [],
   "source": [
    "sim, prefab = Sim.fromBasicPrefabDS(basic_prefab_ds)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3c4aeea4",
   "metadata": {},
   "source": [
    "Finalize the model to get it ready for use."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "115f56a0",
   "metadata": {},
   "outputs": [],
   "source": [
    "sim.mb.ensureHealthy()\n",
    "sim.mb.resetData()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "97db71f8",
   "metadata": {},
   "source": [
    "Set up the 3D graphics."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "024e4376",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "        <div style=\"height:300px; resize:vertical; overflow: auto;\">\n",
       "          <iframe src=\"http://newton:33661\" 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": [
    "_, graphics = sim.setupGraphics(port=0)\n",
    "graphics.defaultCamera().pointCameraAt(\n",
    "    offset=[0.2, 0.5, 1.7],\n",
    "    target=[0, 0, 1],\n",
    "    up=[1, 0, 0],\n",
    ")\n",
    "del graphics"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b90d05e",
   "metadata": {},
   "source": [
    "Display the bodies in the multibody model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "e9ab8bad",
   "metadata": {},
   "outputs": [],
   "source": [
    "sim.mb.displayModel()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "77a82391",
   "metadata": {},
   "source": [
    "Display the topological structure of the multibody system"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "e88214b0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[WebUI] Web server is running on port 33661\n",
      "You may be able to connect in your browser at:\n",
      "\t\u001b[1mhttp://newton:33661\u001b[0m\n",
      "\n",
      "               ===== Bodies for 'wam7dof' Multibody =====\n",
      "Legend:\n",
      "  No.              topological body number\n",
      "  Hinge            hinge type followed by one prescribed optional marker per subhinge\n",
      "  P                prescribed subhinge; blank means unprescribed\n",
      "  DOFs             hinge-local / DOFs accumulated before this body\n",
      "========================================================\n",
      "No.     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",
      "Totals                                                15\n",
      "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": [
    "sim.mb.dumpTree()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "df73d006",
   "metadata": {},
   "source": [
    "Animate the graphics by articulating the individual joints."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "8f575fb9",
   "metadata": {},
   "outputs": [],
   "source": [
    "sim.mb.articulateBodies()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0ec19236",
   "metadata": {},
   "source": [
    "Cleanup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "136c1c30",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function __main__.cleanup()>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def cleanup():\n",
    "    \"\"\"Cleanup the simulation.\"\"\"\n",
    "    global basic_prefab_ds, prefab, sim\n",
    "    del basic_prefab_ds, prefab, sim\n",
    "\n",
    "\n",
    "atexit.register(cleanup)"
   ]
  }
 ],
 "metadata": {
  "docs": {
   "recording": "https://portal.karanadyn.com/tutorial_videos/example_urdf.mp4",
   "tags": [
    "dynamics",
    "urdf",
    "import",
    "robot",
    "WAM"
   ]
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "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
}
