{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "b44d1ce7-186f-4603-8363-cdd60f41bcfb",
   "metadata": {},
   "source": [
    "# Day 01 - Creating an Environment URDF\n",
    "\n",
    "In this hands-on tutorial, you'll learn how to create a simulation environment in URDF (Unified Robot Description Format).\n",
    "\n",
    "This tutorial is also intended to familiarize you with the JupyterLab interface, which will be used in subsequent hands-on tutorials at Fallschool.\n",
    "\n",
    "<!-- > Note: This tutorial assumes you know how to write well-formatted XML code -->"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dac4f0b7-4efe-4896-8294-cbb521279e17",
   "metadata": {},
   "source": [
    "## 0. Open an empty URDF: 👉 [empty.urdf](../empty.jupyterlab-workspace)\n",
    "\n",
    "You will see a `URDF` file and a 3D scene on the right. \n",
    "\n",
    "### What is URDF?\n",
    "\n",
    "URDF is an XML file format for specifying the geometry and organization of 3D robots. The three primary elements in a URDF file are `<robot>`, `<link>`, and `<joint>`.\n",
    "\n",
    "It was originally designed to describe robots, so the root element is called `<robot>`. However, here, we use it to describe the environments in which the robot interacts."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6087bb00-56cd-4f1d-9097-efb59c1dad0f",
   "metadata": {},
   "source": [
    "## 1.What is `<link>`?\n",
    "\n",
    "A `<link>` element represents a physical part of the environment, which could be as simple as a box or as complex as a piece of furniture.\n",
    "\n",
    "### Three basic shapes\n",
    "\n",
    "First, let's take a look at three basic geometry shapes: box, cylinder, and sphere. Each shape is defined as a `<link>` element in URDF. Different shapes use different properties to define their size.\n",
    "\n",
    "The `<origin>` element defines the orientation and position of the shape in the 3D environment. The `rpy` specifies the orientation in terms of roll, pitch, and yaw angles, defining the rotation around the x, y, and z axis respectively. The `xyz` specifies the positions.\n",
    "\n",
    "```xml\n",
    "<origin rpy=\"r p y\" xyz=\"x y z\"/>\n",
    "```\n",
    "\n",
    "**Copy the following XML code to the URDF file.**  Change their properties to see what will happen!\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d1e756e2-fbd9-4832-a412-7123f6eb5fe9",
   "metadata": {},
   "source": [
    "\n",
    "**Box**\n",
    "```xml\n",
    "<link name=\"box_1\">\n",
    "    <visual>\n",
    "        <geometry>\n",
    "            <box size=\"0.5 0.5 0.5\"/>\n",
    "        </geometry>\n",
    "        <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n",
    "    </visual>\n",
    "</link>\n",
    "```\n",
    "\n",
    "**Cylinder**\n",
    "```xml\n",
    "<link name=\"cylinder_1\">\n",
    "    <visual>\n",
    "        <geometry>\n",
    "            <cylinder length=\"1.5\" radius=\"0.1\"/>\n",
    "        </geometry>\n",
    "        <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n",
    "    </visual>\n",
    "</link>\n",
    "```\n",
    "\n",
    "**Sphere**\n",
    "```xml\n",
    "<link name=\"sphere_1\">\n",
    "    <visual>\n",
    "        <geometry>\n",
    "            <sphere radius=\"0.3\"/>\n",
    "        </geometry>\n",
    "        <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n",
    "    </visual>\n",
    "</link>\n",
    "```"
   ]
  },
  {
   "attachments": {
    "b96896d2-25e0-4365-a91c-d9c9effa335f.png": {
     "image/png": "iVBORw0KGgoAAAANSUhEUgAAAOQAAACoCAYAAADwzUKaAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAA5KADAAQAAAABAAAAqAAAAAC50hBzAAAqy0lEQVR4Ae2dB5gU1dKGixyVjATJWZJiAAUVkJy5oIBZAfX6my9BwHC9mEVUTJgFFBEQRECCoKACkpG85MySlSzJv96Cwdlll52Z3dnpWU75tDvMdJ8+Xd1fV52K6f5WEkeOA44DnuBAek/Mwk3CccBxwDjgAOkeBMcBD3HAAdJDN8NNxXHAAdI9A44DHuKAA6SHboabiuOAA6R7BhwHPMQBB0gP3Qw3FccBB0j3DDgOeIgDDpAeuhluKo4DDpDuGXAc8BAHHCA9dDPcVBwHHCDdM+A44CEOOEB66Ga4qTgOOEC6Z8BxwEMccID00M1wU3EccIB0z4DjgIc44ADpoZvhpuI44ADpngHHAQ9xwAHSQzfDTcVxIKNjQfRz4NixY3LixAk5cuSIHD16NMELypw5s+TIkUMyZswomTJlknTp0iW4n/syshxwgIws/4M+O8DbunWrbFi/XpYvWyZr16yVv/76S06cPCGHDx+Wo0cSBmSWLAAypwEyS9asUrRoUSlXvpyUKVtWSpYsKdmyZQt6Lu6AlOeAA2TK8zTFRvz71CnZt2+fbN+2XRYuXCC//vKLLFq0yEAHMI8fP26SEWmXI2cOyZQxk2TMlFGyZ8seZw7sh/Q8peMdOnTIjsmQIYNJSiQmW5WqVaVu/XpSqVIlKV2mjOTJk8d+jzOQ+0fYOZDOlYEMO4+DPgFgWxWzSqb/9JMsUCDOnT1HDhw4YOMAvgIFCxpwkHK5cueW7NmzS+Eihe0vamlB/d2fDh48KLt27TIgxm7fLgcPHJR9f/whfyjYFy9eLNtU4gJaiPGvq32dVKhQURo1aSzVqleXLFmy+A/nPoeRAw6QYWRusEOzFly3dq28PWCALF28RGJjYw0ggAwJdsONN0qValUlf758khsg6vesDZF2wRCleDkXqu7evXtl/59/yprVq2XKlCmycP4C2b9/v/1W8JKCdt577r1Xql9+uam1bu0ZDKeD39cBMnieheWITZs2yeeffiZjx4wxkOTKlUsuv+IKqVmrljRt1lSKFy+h4issp44z6J49e2SqAnP2b7/JvDlzZcuWLQZ4pOXdCswrr7zSGYTicCxl/+EAmbL8DGm0xb//Lq+/1s/WiAzAWq5jp05SQx/+fCoNI0FYa5cuWSJjv/tOvh01WlB7S5UuJd179pRGjRs7UIbppjhAhomxgQ778/Tp0qNbN9mze49cVrmyPPTIw3Jj3bqecU2cPHnSpGS3x5+QJbrexBrLHO+4807J7NaWgd7mgPdzgQEBsyrld9yuBpY3Xu8vu3bukmtq1ZTXXu8nDRo2tHWhV9ZqrE9LlCghbw54Szp07GiulU8++ljmzZuX8gxxI4oDZIQeAiypn33yqfkSMZj0efppKV+hgmdVwaKXXio9ej2pFtjasnPnTvng/YFy4oxlNkIsTJOndYCM0G3FuhmzcqWpgHfdc7dcpv4/rxPW3m49ukuhQoVk2bKlsnnzZq9POerm5wAZoVu2S6XMZrWs4ke8okYNHIARmklwpy1QoKAFDhw5fERmzZoV3MFu7yQ54ACZJIvCs8NOXTdu3LjR1L4/1Q8YLXTixHGLl0Xl3rN7d7RMO2rm6QAZ4VtFaNzMX2cI1sxooLUauLBq1SrzTV588cXRMOWomqMDZIRvF9Eygwd9ftYHGeHpJHp6ont2a/jdi32flwMayYMVOKsGqTtKWQ44QKYsP0MaLXZ7rDzz1NPy45SpZ2NKQxooTAcBxt81qL1Ht+6yZs2af84SJevefybs/U8OkBG+Rzjai5cobgHevTQK5uMPP7RYUjIzIk0AkeyQcWPHyhOPPia//PyzBrYXsLStSM8trZ7fATLCd7ZQ4UIy8KOPzOnOw9/v1dekdfMWGtf6qaxYvtwyNFJ7ihhstmoM6zcjRkj7tv+Sxx5+RLZt22YB5p8OGmTxtak9pwvlfC4f0gN3Gr9e76f6SKXLLpNhQ4fKihUr5JWXXpbSpUtLjauulFrXXiv1b7rJMv7DOV1SsJYtXSbDvx5mic8kQJP0TKD7PZ3vlTZt20rBSy4J5xQu+LEdID3yCJBK1em2W6Vlq5Yy4fsJCoqvzU/59VfDLLg750UXWQ5k3Xr1NKKnvOQvUECwcqLyYlwhyTipNCxUUEB3TA1JhzVhGYlMDO3mzZtk1sxZMmvGDFOX+Z4ggGLFip0NdC+iuZecg7QtR+HjgANk+Hgb9Mjp06eXi1UadejUUZo1b2bxolQJWKA5igR2s4ZjgwooIEupBGVNR0ZI1qwA83QicebMWWxdCkB3aE7lH5qMDJ08cVIOHT5k/965Y6epoZQC8afixYtL23b/ssTk6667Ti5R6e2VuFr/eabVzw6QHr2zF6n0q1e/vtSuU8ey/bdu3mKq7Jw5s2XOb7PlmKmXS81/yZqPzUcAMWfOnJIufTohogbXio/4zSdNKXZFqY6SpUpJg0YNTQIjFalEQN0dR6nPAQfI1Oe5nXHfvr0BnZmKAACEjYwQ4l5RO/9Uqbdu3ToreEXWyIZ1pyXdIV3zxaf06p6gDAcSuHDRIlKkcGEhWBwJmy+vStdsgYMP6y9BDGxIWeYCsB2lDAccIFOGjwGPwoNMRv6HAz8I+Jj4OwIA1pBs8YliVvEJlRNgA8iUoXQGxOHDhtmYD/z7Acmg60tHyeeA42LyeRjwCIcOHpJ33h4gQwYNtipwAR8YxI7hLucIqDNkSG/ryh07dshbb7yhlQUWS68+T0mx4sXcejOIe5XQrin1ykxobPedHweOHzsuH334gdXNQYrVuf56v1+j7yPr0Np1aptxaapGGP33mWc0tM4Fmyf3TjpAJpeDARx/Ug0ugz7/TD75+BNzTTz6+GNy2+23n3FTREfalf9lIiUBZOMmTaT/W2+anxLr7/N9/2eqrP++7nNwHHCADI5fIe29XCNu8Cee0vXjgw/9n3S9/34rGFW2XFnJqsaWaDKKAMaL1CeKalyhYkWL2nnplVckb768Wkd2mvwwabLg73QUGgccIEPjW1BHvfzii2YRxaF/+x132MOMoYXtqLok9mn1gGghggY2b9psktDn30R1bdSosUX1TNPizkT3OAqNAw6QofEtqKMo/w8hGXH8Q/gZ8+XLrwWudsrMGTOjRqps3LDBAhYyqqUX/yWUTSunE8yAlPxdS1pSCd1RaBxwgAyNb8EddUaDw+nuo7x586rKV8GsrcSObomC+jT0GqHiHIBD3S5SpIjvcuxzFo0Q4rd9+05HBp390X0ImAMOkAGzKvk70l/DR6wbqW1aslRJWbRwkfTp1Vvou+GFtCvfHP3/YkF9U10ckydNsjXkw5oB4t/zg4rnBAmgrh479k9kkP8Y7nPSHHCATJpHKbYH6yt/g0dxrXfaq08fbZRTRGb8+qvc16WrTJ82LU4YXIqdPMSBeEFQwbxPr14y8L33LcDg4UcfkauuuTrOiIsWLrTq5nG+dP8ImgMOkEGzLPQDpvwwRbMq4q4X8Ue+oEafMmXLWI3WPk/2kqd795HVWrcGieMP4NDPHPyRRBTR1+OF//WVR1UaEl1EBsjT/31WbtGCyf7SkQD1EcOHO2NO8Gw+5wjXSuAclqT8F5W1tZuvs/GVV10l/3u+r1SMV4cVle+l559XSTnDgskJdQOszVu20NZwFaRMmbKSKXN4Y0YB4XZNRMYINV8rk3897Gv5S3t8kN51rWZ+/PvBBy0/E+uwj+ic1VtfIhO+/973lQz6YkjUBz6cvZhU/uAAmQoM9wES3x35hNWqV5OnNLKF7lb+hEth4YIFMlIz9SdPnGRZGgCzRMmSUqVKFUtgrnVtLQsKpydkShBSmOD0BfPny1ztdrV6VYws/n2xSWcyQ6pfXl3a33yztTiwxj9+YEQyUsEc6cg8GQsV1wEy9DvjABk67wI+0gfIV/v1s5o5azVLo6AGht/3wAPSsnUrS4HyH4zQui3q6xs/fpwZUTCoUOmc6BikFQahEiVLWOsBnPNkgpBuhUrpI3OvnKmJg+SDjv11TPZr49edO3dYS3S6bq1etdrWrKRosZH0fIlWBeBlQV4kHZVz6Nj+gemH9cUxf958efmll0y1pkHsQ488Iu+/955Zix0gfXch+L8OkMHzLOgjfICcMHmyRet88MFA+e7bMSZVbmrYQFq0bCnX33BDHED5TkKa1XxNUJ4/b6455KmJyvoyKSpTtqzoAlQ26zqQCgGJEVLwkkKXSOXKVSw4nD4jJCbnUbeMv2rK8axnkeDfjh4tY0Z/a0acyiq5aS9AmZEmDRsJfkoHyMS4nfT3LtsjaR6l2B47dsQa8J559llrOz76m1EyacJE+U3LZ1SsVNGieK6uWdOklC+cjlYD9W+qry3qbjQA0IacqucHDx5Q6+dS2bRpo0qlLWdBeupvrVanfk9qqELZVKKypdOQN1Z+ZGTQ/LWM+hFLqiqMdKVmDuooZUJ857WD9X8kPuPKWLZ0qXz15VADJFkeqMw3d7hFOnfpolXoylskEutNwuqoXuAoNA44CRka34I6yichb+nQQV585WWTPEgbqoB/oK6EuXPmWKIx6y9KZrRu09pKaCDlCCYIJqWKduT+1QOYaIb0GVTtzGEqbyATP67rXHymxOBS9GrShAkSExNjhyI5Wcd2uvVWk6QAnWsZMniwvKqFuVC3nYQMhMsJ7+MkZMJ8Ccu3P/74o7UKR71DHSyrgOv74gvm7sCg8oU+1JRbJHkZCYSfEglGI1dAULpMGcmfP3+c9Vz8iYZa3h8gY6RZoCrpHG1nvluLX6Ea8z1EWFyTpk2te/LlqtYS+ucjumCN+27sWUuy73v3N3gOOAkZPM+CPsInIRWFcvXVV8tzmqaEMcafkI4kMC9dusTqoVIhHGMOvRiJvMukBh0MK/j/AChuE2q6Er6GypkxYyaGV+Ak3AL9oBpz/lKjzt+q0tLcByMRjWKp0bN29Ro5oL+fPKWlObQQFnMx445Ka0pRtm7TRmrqC4GXBIYlfyLA/Nmnn5HxWkzZ5zN1EtKfQ8F9doAMjl8h7X0WkGeOvvqaa+TJ3r3NpRDfcMIuPNisFWNiVmm1ud+1TOMWWaUqI2ojfr/EiLHMmJPADrFafQ5QJkasHQF6eV0Pss5EGletVs0A729h9T8eA87A99+XEV8PPwtGfneA9OdScJ+jHpA8vLzR8e9h3scXxme6+x7TLH2kSDBrsODYF9jePkDiq/PVNQU4ONqxsp5PzeT6CCoATEixPzRwe4e6LUiBiolZqWrmBsHIoogwPpwvExFgAVoqzZEKVliLXZUsWUpKli4lF6sxBkmLYQd+JQZCrhj3yJLFS+QpfamsVxcOa1aujb/ci0gBkvu/W1vkHdV1LJoEc0KiZzrzF4vy+a4rsLsZ3r3i6h/hPVeyRuehZKPzEmoSGQX403hQKfpLtgTfxW7fJhv0zb3/z/32YD3w4L8t7ck/1CtZE0nGwXfcdadgWUVdXKsqabcnnrCs+463dpIaV15pvsT4wwMgAMJWQP19iREvIqyhACIxwlcZ34qa2L4Jfc8DTwABUTmjRn5jLwj2Y9xOt91m7hDSySJF+FV7du8u69auMyASUFFQ69YWvbSY/WXdmyN7DnXp5JF8uhantm1O9d3iZ4W/8DrS5GlAku4zWAtCEXiNZGHjocPkf/DAQQXgvnMsiv4MxeI3+PNBUr9BA7lMy/RHmtpon4xq1atLv1dePdsOnOyJBQvmS8WKlaTLfV0NmKFE4QA0JFw4CJDT/WrkiJHyq5bqIMbVn7r17CGtWreWKepn/SefxX+P8H/mWXn/3fesBQJn4wW1ZvVq2+KfnRcIvMKlBBAJtsiiRabz6/qbYl0X5/rHYBX/2HD/29OAnDt3nmYYvGeGjVAZQYzos089JZ9pkxjUsUhSliyZLQjgGtaQPXqatEENxbjCRpVy/IGt1IhS5/o6upYrLvT9SO23NyopVQwwLC1csFDGfDtaHf4b40hf1D9eLt179LB6sZGULkju4Rp3O10zZQKhgwcPmk93q+ZuxicinFjfR+p6PA3IGjVqWEjWT+ouwFcHI0OhFctXmDp1qxaW8sIagoY1bwx4y8Livhg8xNKbuC7Wi6yBPv34Y3XCf2kZIGXLljMjC6FsBJmjtsa3dIbCE/9jOC8AJAooZuVKq5C+dctWk4rE18anS9U3SlAA1tdiWnDZzLvxd0rFf69WSThYX7jx/a+BToGXCwasqtWqqpZyX8TAyHw9DciMmTJKx06dpIU2oDmw/4CsW79O5ikwp0z+QQ6o2nr40OGAeimiug7RB5+HukrVqoHep7Duh8rUrn17jcCpa5kVgz77zNQt1seoiMyZSBw2AEicKqUyWAuX0H6SuD0ooQG4McjkVvUrXbrT2XS8dLJlP70mInrm+PHTbQaI4uGlRnuBbVu3yE51/i9e9LusXLlCjWAn7JyHjxzWDI+4oXZICwxPnOPOu++Sho0bW7xrSr8YQmG4LUs++9zW5IEcD/98qiqZNzdoyCJRUriL4DHqayQpKq2sqCg40Fdq27Z3Bgywh5aHhu18Ro2mzZrJ2++9m+pvQJ+VdfLUKYm6JbimObNny8/Tp6uUijmrzobycPDQlVLLKW9++LRv775QhjEDUOUqlaVylapyw403yrXqi8QAkhg1qFtP1mtwQWpaWX/QdeujDz1slt/E5uX7nrUjL5SmzZtLKTX48ILzGnlaQibGLB40QspY69BfAiA2btJY04RukdWrV2ky7VSLfsEIBEB9IP1x6lRTyeLnIiZ2ntT8nmsi5/AajWXdq+teHuxV6odkXTR//jzTBrgOn5vnfHODLytXrDzfLnF+g39IVd9GJNG1111r6V50wyqk7hFcCF4j1OlPtdYt1wv5Xwdr73oaA1yzVi3Trl5+6UXTDDJpAAUZLOzrRYpKQMJI3vw9tec9kSwYQPr1729vPG4CaU1Hjxw1cM6aNcsComO3x+oa43jI64zUunkAk3UiG+C8/c47BAviNs1ZRH3dqC4drLK8bPC3obLt2bPXskiwLLIGTYhy51GL4pmgb+JRs2mDnezqAsBgRCoXWR68qC7VNWFyXCMJnTtc31Hnlkil8rq2JgWsdJnSxjNUUf7tT0QhUf3gvXfflSq6VqQBrhcpKgHJgzdGU4Bo+U1EyWPqz4uvftDR6fRCvZo9vESq4MckEiXaiABuYlrZICQlUgEJwbZTAwNQeQmNi43dnuDlEQPry5fE/8ZnrM789aq0SPBC/L7Er9j76aeslCbdvMg0SYyaqZq6SC3Go0eNMqmKlKSWkdcoKgGJOR7rJOrbfQ/cb2/38zEWdQvVK62QGW1UsiHdAFoJDUK/UAk3EVtShFGq6/33ybJlS81iP1aD4Tt37XKmnUNSR6fe71FZ5Grcd9+pJIg1PxjJvTygjhwHkuIA4YqkwOEe+WroUAuyT+qY1P496p7kQ2q2Hz9uvIGQkDOkhCPHgUA50FIjigoXKSybNm7UergLAz0s1faLOkBipMEKWaVqFblKU5kcOQ4EwwFU11s6dLRDiMdl2eMlijpAEtyMcaZq1WoWHOwlZrq5eJ8DLG8uq3yZ5XaSkH2+lLRIXE1UARIgEn+IawDHd6SjKiJxw9w5k88BQv/wY2Ohxn3mJYoqQGLqB5SsG6k948hxIBQOWO5n7lxy5OgRqx0UyhjhOiaqAIkTnJqgjhwHksMB/K8XXXSxpWiFmrCQnPOf79ioAiQqarZs2eWULsRDjew/HzPcbxcGB05XX9ivQfuZbC3ppauOKkCiqhLcfESTlF1TUC89RtE1lz+0LhEB94QPErXkJYoqQFrqjGZzEyYGQ52U9NKjFD1zoZrfLo35JZaXwHkvUVQBEsaR04jqSocmAssdOQ4EwwHigGM0/5OqftTbOV/8azDjptS+UQfIuvXqac2TXBZlQaEoR44DwXAAKz3lPqDmGnbphSRr//lHHSDJWq9dp7apq0RaoL46chwIlAOztSr7Oi1dyXNUr379QA9Ltf2iDpBwpk3btuaLJOGYinSOHAcC4QAFzz7/9FNLN2ul/VPOVw83kPHCsU9UApIaprfdcbsFCbz79juyNV5ZwnAwyo0Z3Rwgh3aIlhT9bdZv2sahgnTUZkFerIIQlYDE/dG2XTvLbqc47iAtcgTDHTkOJMYBnpNR33xjP1N90KuJ6lEJSLhKScRHn3jc1I8hQ4ZoQWQHysQexgv5e7I5Vmppy+7/6SbbNW6VKn+0aPdqlYSoBSQMpT1ap9tulYwabP7RBx/K5ImTnKS8kNGXwLVTvfx/zzxr+Y/UDerZq5eV0kxgV098FbWAhHusAR7W3vaNtE4o/TL6PvecTNOiys7y6olnK6KTQDJixOn+xH9k7ty5Vmy6j9bfoRCWlymqAQljc2snpxdefsmkJb0+nnjscRmqVb8p0e/owuQAzv8F8xdI57vvkSVLlmiqXml5R1tSXKGV8L2qqvruVNQDkgshcqe39u9o0LChVWN78/X+8vqrr52t1+m7WPc37XMAyUjx5F49e2rLvMVCdXca5FbyQLOlQLifJgDJhdIHst8b/eV+rcn6t/6HlOx8993arekXB8xAnoQ0sA/rxVdffkWe7N5D+2duElqvf/HVUG0Hf23UFEKLyjKQiT07uEMeevQRKa5lET/8YKDMmjlLFv++2IoN36XgdEnNiXEuur8ncZ22fu8MeNvaz6Ex3dKxg3Tp2tWa0kbT1aUpQMJ4MkLatjvdh/EBvSGUaPjko4/lF5WUSE8qm/sKBkfTjXJzPZcD+J7pVdlPlyczNWILuwHRN1hSW7RsEfH2g+fOOOlv0hwguWQChonGGK6O4EHqnxw+bJj1+nhMLbL1G9xkHbVq16njafN30rfuwt5j2dKl8r12cv7qS62vqh3DKF7VsFEjK35MKwGvG28Su3tpEpC+iy2g6TWPPv6Ylou8yrrrzp83T6b+MEUWqgWuzvXXy1333G1Vz6P15vmu80L6u0tb6NEVe/Kkida+DyMOjXXuvvde+Vf7dgFVMfcyv9I0IGE8jWNI2bqudm2zvn3y0UfWVWqsVj+foG9YOk7RnKdcuXKSv0B+L9+rC3ZurBFXxcTIj1N/lA8HDjQjHS9RenM0btLEXrq0mksLL9Y0D0jfU0wQQfMWLaw70tQpU2SYlpKnmxT9GOnOTNsypGbTZk09l0Xuu4YL7S8dvmbNnGkvUloM0lQIyq59HTt06mgBIfgWo6VbVyD374IBpI8Z1FDp0LGj5cJxswd9+pnlx0376SfNBJhl6Tm1VGrSBq6IlnegdZvrHeLjXvj/HjxwUPbt22tpdZ9r0sBuVVHpKg3oimj3r2badLd12zbW9QxralqjCw6Q3EBUm0u0FTh5lS1Uak6cONEao+KzxGo3cvhw+VbbllHhuok+AKizV19zjefKPaSlh5Fu2DjysYajtfgirTDQ4Uekg3NLbW3vxRZyKXkfLkhA+jMwo7556aB1kzbwJCvgN80o/3LIFxKrDVLxYS5ZvET7z+eVsmXLmaO5RetWUrFiRQN1oGsW6rYQ4odLJi1TzotyWnu8nDkT79PI9WOIYQN047Qt3IwZv8ra1Wtk8+bNZ9eHALFFq1bSrHkzfTFWNsNNoPyOZh6nU8Z4q9uIB7hJLCQByWNGjZYYNSasXrXKys77pkY/QgxFN9ara5KW/ox0PE6MNm7YKIcPH4qa8K3EriOp73dp0TFAlVDM6GEt3Qkfdu3aKVi7J2lmDjWR4DWESkr35jLlylp346aqmXgxoz8pHiT3dwfIJDhIYAGdd5GekyZMkPXaoMWXTcIbG3BWuqySlC5dRugZQb0fgpm9mI2exKWm+M9kW+CwX7F8hQVoLF+2zACLscZH1LZBJSVgg9bklVT7yKQGuAuVHCADvPNEhezfv1/LB/4h348frzGyP2ttz12yZ/ees9ITEBIFRAhfETXJ176+jllvUVexDGKa5/e0YhVEutHeAb5QvPrw4SOyYMF8mTdnrizXdvP08qShDZXeeInBnzzKC7o+V1DgYZwhcz+78gTeOFL7hlNZQ38MYrfHyqxZM2X9uvWyYcN6daMs0fo+W88p4Mx6qJi2VC+rHXzJPsina1JAisWXrr5ICa/VB43PFaQa1k4anbK+3q0voj///EO2Kw+Wa9QMqiprQv8VEBoE10Yvz3LlyptBBnW2+uXVneU6PoPP/NsBMhHGBPv1fi1Pv0PXUIRx8dAS2D5T3Sr0kaDCOhsShY0HFSmK1MRghPk+S5as+vDmsgD4IkWKaoB8cQuMBrS59KGGOM73NwNt3M/8277U/9Gmz7eP7zv+Ip38gcJ3vrnwWZNjLEOGOaKi/6lawNq1axV0u2W1rqH3H1AJeOSoSTpAiGuCNSH7cz7cQrx0MujGNfHiuf6GG8xKnTdvPil4SUHJp+4jfnd0fg44QJ6fP8n+FTAQdzlPDRmkBO3auUvouLRdpcw+rXLgU+mSOhEPvM/IwUNfVA0g/utUwFi2XNlzAucB3mq1YKI++ghwEoKGEQYCXKiVSRHAQ+VG6tEWnILVuS7OZWtnpF7lKlVMHU1qHPd74hxwgEycN2H5BYCi2tEsCKPHoYOHrE8haiAg2bB+g0kpHOLshxRKbWKdB9hLqXqN9RhpXaJESTW2ZDJA8ntRddIjudOicz61+e1/PgdIf26E6TO5ehg+8Hcm9gAD1FO6ndDtpILwpEq2v9l0ThhOqD2LZNuo6vCO2NMhZEyX/iY7Yrfrvkl7r7KpZKWmTIYMp1VHpG6NK2vYVSPtCJaAkISoovzuU0f5fD5ibqjouDKo6oYUdxQ8Bxwgg+dZ0Ec0uqmBqasjRo+SKqrWpUVC/W7TqrVK9OMyUAP4q1atmhYvM+zXlGZKeISdU8k4Ac5wrJT4M9MqEdWEAWvvHl0X+61X0+r1huu6HCDDxVm/cY/9ddoR/tXQLzVwep/fL2njI0Yq8hNZ8/LiicS6N21wUpcLaeVCouE61q1dJ18MHpzmijn/PG26TJww8WwEUzTcC6/O8fwrda/OOkrnhfT44P2BaijJYNUKoj06BVcJKWzPaAlOggYcJZ8DDpDJ52FQI2Ax7d+vn6mu93bpbCF2QQ3gkZ2P6nV8rvWKPvv4kzSphkeKzU5lTUXOF9Pgc9wIEKrrv++73/IwWYPFj6RJxWkFdSqCCBZr3uLD//eQvPPWAIvmwUVSWJO5/QMVghrU7XyWAw6QZ1kR/g/PPd/XKhWQF0mwOrGvD97/gPR5speM1oToPzX8TpEZ/omEcIbDGiROc9zntHHN7R07aX2bqeYfZShcHK+9/nqaTx4OgW1BH+JU1qBZFsIBZ2JOkSJ9X3hevtD2ee+/+55JRdZh48aOtQd89DejtK5PHQsgoFxFQnGpIZw95EOQ2gc0oGHmjBkyZPAQSz2jro2/NCcntHefpzR87lK/l8npmNuQT3wBH+gCA1Lh5rdr01YWLVwob7/7jjTTkiHQhPHf60M+WJvCzD/H6kpcKgEENzVsINWqV7daMgU1yDxHjpySPkN4lBpAhhSkixjRQATI/zD5B5kze/Y5ca7Mj7ImN3e4xWrcZtVAeRqi3te5i8XbvvP+e5bbmAqsTXOncBIyFW4p9XgAJK6Bps2bm+RrqqUpCFsbN26clbEgAJ3wOYi/v+sDzkZWSOkyZaS4pm/l0mwQylmwFiWNi5hSgr1969JALwXwYVzCMkpIHknX1LQht5OmpitjVlqMbULjIQnbtb9Zyy82NtAhxQlgnzd3nvkhL69xxXmrJyQ0pvvuHw44CfkPL8L2CdfA/V26WnrUc337SnMtc4+UgQAfKVsYSoYMGmzlQkh7ohZpQkQsLMYT1qGMkV43QFutejXbPWPGTAbeiy4+XdeG8ddotsfRo0fs982bNhvoABFxs8fVFcO5UJ39VVHfuUmmBvi8FFq3aWNpVdSv9U+ypoxmz27dLa62e88ecsdddwX9kvCd70L/6wCZCk8AKVZvv/WWDNKyhiQqP/PfZ60GbPxTAx6yPaZN+0mBudqKA6/QzHv8l6lJAJ36NlXUWEN5kppaYqO6qs6+l4j/XDZpShlNUedpDSLaM6CW+/I3/fdznwPjgANkYHxK9l47YmPlga73WQNRchmf7N1bGuoakap38QlJhcQiHWubViBApaQwFA890hPpxj4A2Pc5/hhJ/dukq7pgUHfZkLhXXX21tV2gvAbl+ekWRg5mQsYlzrtwwQLzqc7+bbZVP2DtSF8NR6FzwAEydN4FfSQWym602FYVj0JObbUubCtVA1lLJvTQJ3QCX3IzY9EPEQlFCtapk6dMkiakdvrGQc3MmCmjqbxVq1Uz0CGxkYaUEAlkLcr4O/TcY8d8J2/2728vDub/RLduVqwq0Ovwzcn9jcsBB8i4/Aj7v0hMxoVAjwqIEpJ33n2XtGzdOlmNYpCWrAXPB8jMmTJbknGoF0nQ+NgxY2TkiJEmHTkfBYx7P/2UlNOyHfpWCXVod9wZDjhARuBRYE044uuvNQb0aTs7RhokFKF0lESk4SxlMgKRWOGcPuBGIvMSoUbQyBEjtKDXOpOKqLwdb71VJeN/bK7hnMeFNLZze0TgbgPAIkXVka6E2wKVcY1m2r/2yqvaZDSn1KqlRhRtx43lFDdHaoMTEG7csEEDAmZqPdoVWlt1hqnFzLdY8WIqCNNb45vKVU7Pje8dpQwHHCBTho8hj5JPa5T2e6O/GW6+UVUQf+W0adOE5j958uaRvHnzWkjaTQ0aSMVKlaSo1nvFzYExiLIaSCrWbYFKU6QeBhmfQYgQPiT2zh075fdFi2ThwgValGuZ+hT3W6kQ9sfVwouh3c3tpWbNmjJIg8pZQzpKeQ44QKY8T4MaMYNG3mB15YGnfD6OeXpX0iqPWqdr166RmJUxMu3Hn2xcgEcRZkruWwsDjeDJmjXbaWto+tNrOABLRXWAirQ7mxSt4CI4nILGWH0psrVK2yRsUCuuv2sF4w+hezfWrWuV5OpqeBzxqun03OyX1nuUBHUDU3hnB8gUZmhyhgNsgPOBBx+0SBpqpK7XpGb+Ll++zMLYcOzToYstMcqaLavkyZ1HAZTOIm4saD2xnc98jyS+6pqrNWSvqpQsVdKigWiJkFYaoSZx+Z752QHSM7ci7kSQcmU0OoYNtREVEysnkTVbFaC4PTboOg+JunzZcouHRRVFBY1DZ3oAodpmzEh0UDorZHyprgVLqMsDA1JBLfVIOX+fChyo+hvnPO4fKcIBB8gUYWN4B0H1BCxsrOcqqrOelni4HPwJwBKjmhD5wu0S+s195x0OOEB6514keyYA1us9QpJ9kWl8gPDk8qRxprnLcxwIFwccIMPFWTeu40AIHHCADIFpF/IhGJhoW0ChEQxNjlKWAw6QKcvPgEcjXxFfIUHhf2lmR7QQc/1DW9LRd4SMFEcpywEHyJTlZ8CjFdbUJhrfUO2bbsNInmggMj2oLoBb5oorTjfqiYZ5R8scHSAjdKfyqnQsp+286Yo1bOhXlvsYoakEfFpeGl99OVQ7XK21cL6KlSoGfKzbMTAOOEAGxqcU3wsJ0659ewsc/3n6dPlEO0Yd03QmrxI+zm9GjpQRw4db/Ow9nTublPTqfKN1Xhn+qxStk4/2eRfSspC0MaeyG3V3UF1LlSptXYg9Ey2jUjFW415fffkVeWfA2xbP2vW+rnLrbbfFqasT7ffCK/N3+ZARvhNE1owa+Y0MePNNCwKnmFSTJk0017CTANhIErWAxmtVvPFjx8mvv/xiU3nkscfktjtud63Lw3RjHCDDxNhghkUdXBUTI3169baqc8SjFilaRBo3bSrNm7fQ9VphS8MKt9RkjWi5kFqTlVQsquBRn5UY2TJly0jnLl2kRatWrmVAMDc3yH0dIINkWDh3pzbOxO8nyJjRo2WRAgIigZniU1fUqKGpUJWtgDI5lASLpwThdqE+6+rVq2TJ4iWyQi2oP06ZYsYmXgAYnpo0bSLtb7nF+ncQV+sofBxwgAwfb0MaGSlFyQzyIb9VYM6aNUvoNIUTnvqo+fLn09zHXFqkuLxVeLtUiyaTOpU7Vy5b3xHPGl+SWkKySmHGRg09oDmSuC6QftOnTTc/6D4F5V7Njzx56qRVSKcYcydVmyntSEoY4zoKPwccIMPP45DPAIBIUkZizdeWA7HbYy0PktSrhAjpRS5jbs2F9Cey/zdu2HhuataZnch5PF19rqiUKFlS14h3WFmR+MD2H9N9Dg8HHCDDw9cUH5UKb7tUpd2q0nOzln7cunWbbFGwbty4waQpvwdCZPujhhYqXEjKl69ga1WaACEFqUSQPXt2qzQQyFhun5TngANkyvM07CMiOVFDfRvqLN9RGeCcBGW/2RCqh9TzbaxD+ezWhX5MivBHB8gI3wB3escBfw64SB1/brjPjgMR5oADZIRvgDu944A/Bxwg/bnhPjsORJgDDpARvgHu9I4D/hxwgPTnhvvsOBBhDjhARvgGuNM7DvhzwAHSnxvus+NAhDngABnhG+BO7zjgzwEHSH9uuM+OAxHmgANkhG+AO73jgD8HHCD9ueE+Ow5EmAMOkBG+Ae70jgP+HHCA9OeG++w4EGEOOEBG+Aa40zsO+HPAAdKfG+6z40CEOfD/KqY2M7fTCmoAAAAASUVORK5CYII="
    }
   },
   "cell_type": "markdown",
   "id": "9769a85d-0412-4742-8f6c-4080c1790397",
   "metadata": {},
   "source": [
    "## 2. What is `<joint>`?\n",
    "\n",
    "In the previous step, we created some components in the scene, but they are not connected to each other. To enable movement and define the relationship between components (`links`), we need to define `joints`. Here, we introduce two types of joints: `revolute` (rotational) joint and `prismatic` (linear sliding) joint.\n",
    "\n",
    "\n",
    "### A revolute joint allows rotational movement around a specified axis.\n",
    "\n",
    "![image.png](attachment:b96896d2-25e0-4365-a91c-d9c9effa335f.png)\n",
    "\n",
    "* Parent link: The stationary or base link.\n",
    "* Child link: The link that moves relative to the parent.\n",
    "* Limit: Specifies the minimum and maximum rotation angles in radians.\n",
    "* Axis: Specifies the axis of rotation.\n",
    "\n",
    "**Rotational joint**\n",
    "```xml\n",
    "<joint name=\"joint_rev\" type=\"revolute\">\n",
    "    <parent link=\"cylinder_1\"/>\n",
    "    <child link=\"box_1\"/>\n",
    "    <limit lower=\"0\" upper=\"1.57\"/>\n",
    "    <axis xyz=\"0 0 1\" /> \n",
    "    <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n",
    "</joint>\n",
    "```\n",
    "\n",
    "The `limit` requires angles in radians, so we need to convert degrees to radians using the following Python function. Once we have defined the joint, we can test the movement in the right panel of the 3D scene."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "92c49402-4a33-47de-8d53-4865fae9f521",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.5707963267948966"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import math\n",
    "math.radians(90)"
   ]
  },
  {
   "attachments": {
    "10d60461-1c56-47f5-aec6-f70eaa5c5dbc.png": {
     "image/png": "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"
    }
   },
   "cell_type": "markdown",
   "id": "1297e0fb-18f8-4899-8d6f-df4584899345",
   "metadata": {},
   "source": [
    "### A prismatic joint allows linear movement along a specified axis.\n",
    "\n",
    "![image.png](attachment:10d60461-1c56-47f5-aec6-f70eaa5c5dbc.png)\n",
    "\n",
    "* Limit: Sets the range of movement along the axis.\n",
    "* Axis: Defines the direction of sliding.\n",
    "\n",
    "\n",
    "**Linear sliding**\n",
    "```xml\n",
    "<joint name=\"joint_pri\" type=\"prismatic\">\n",
    "    <parent link=\"cylinder_1\"/>\n",
    "    <child link=\"sphere_1\"/>\n",
    "    <limit lower=\"-0.5\" upper=\"0.5\"/>\n",
    "    <axis xyz=\"0 0 1\" /> \n",
    "    <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n",
    "</joint>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b7ba6e48-747d-40a7-ba43-8882fdf5ddc5",
   "metadata": {},
   "source": [
    "## 3. Add Visual Material\n",
    "\n",
    "We can colors to a links using the `<material>` elements.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76a505fd-3f5a-47f6-8ecc-fe99c0243049",
   "metadata": {},
   "source": [
    "```xml\n",
    "<material name=\"yellow\">\n",
    "    <color rgba=\"0.6 0.396 0.082 1\"/>\n",
    "</material>\n",
    "```\n",
    "\n",
    "```xml\n",
    "<link name=\"sphere_1\">\n",
    "    <visual>\n",
    "        <geometry>\n",
    "            <sphere radius=\"0.3\"/>\n",
    "        </geometry>\n",
    "        <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n",
    "        <material name=\"yellow\"/>\n",
    "    </visual>\n",
    "</link>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b655549-6997-4929-a0c4-9f237f7c94d4",
   "metadata": {},
   "source": [
    "## 4. Collision and Physics\n",
    "\n",
    "Up to this point, we have only defined the visual properties of the components. In URDF, physics properties provide essential details to accurately simulate how links and joints behave under physical forces.\n",
    "\n",
    "Below is a simple example, compared to the previous examples, it also defines a collision shape and inertial properties of the component. Since we are not using any physics engine in this tutorial, these properties will not take effect in the visualizaion. This part will be covered in more detail later in the hands-on tutorial."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "91e32e12-f0a1-4129-b735-558e1b55d713",
   "metadata": {},
   "source": [
    "```xml\n",
    "<link name=\"box_2\">\n",
    "    <visual>\n",
    "        <geometry>\n",
    "            <box size=\"0.5 0.5 0.5\"/>\n",
    "        </geometry>\n",
    "        <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>\n",
    "        <material name=\"yellow\"/>\n",
    "    </visual>\n",
    "    <collision>\n",
    "        <geometry>\n",
    "            <box size=\"0.5 0.5 0.5\"/>\n",
    "        </geometry>\n",
    "    </collision>\n",
    "    <inertial>\n",
    "        <mass value=\"10\"/>\n",
    "        <inertia ixx=\"1e-3\" ixy=\"0.0\" ixz=\"0.0\" iyy=\"1e-3\" iyz=\"0.0\" izz=\"1e-3\"/>\n",
    "    </inertial>\n",
    "</link>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "58c9f3e8-b2ac-49d7-af41-b71d77296cde",
   "metadata": {},
   "source": [
    "## 5. Import complex 3d objects\n",
    "\n",
    "It is difficult to describe realistic objects using only basic geometric shapes. Therefore URDF supports the import of complex 3D shapes from external files. These 3D models are usually created using modeling tools such as blender.\n",
    "\n",
    "```xml\n",
    "<link name=\"cup\">\n",
    "    <visual>\n",
    "        <origin xyz=\"1 -1 0\" rpy=\"0 0 0\"/>\n",
    "        <geometry>\n",
    "            <mesh filename=\"/cup.obj\" scale=\"5 5 5\"/>\n",
    "        </geometry>\n",
    "    </visual>\n",
    "</link>\n",
    "\n",
    "<link name=\"spoon\">\n",
    "    <visual>\n",
    "        <origin xyz=\"1 0 0\" rpy=\"0.1 0.1 0.1\"/>\n",
    "        <geometry>\n",
    "            <mesh filename=\"package://iai_kitchen/meshes/racks/BoxyToolholder/Spoon.stl\" scale=\"0.1 0.1 0.1\"/>\n",
    "        </geometry>\n",
    "    </visual>\n",
    "</link>\n",
    "\n",
    "<link name=\"milk_box\">\n",
    "    <visual>\n",
    "        <origin xyz=\"1 1 0\" rpy=\"0 0 0\"/>\n",
    "        <geometry>\n",
    "            <mesh filename=\"/milk_box/milk_box.dae\" scale=\"5 5 5\"/>\n",
    "        </geometry>\n",
    "    </visual>\n",
    "</link>\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1d6764e-34f1-4cf8-9589-bbc84be49e22",
   "metadata": {},
   "source": [
    "## 6. Let's build a kitchen\n",
    "\n",
    "Xacro is a macro language for XML. With it, we can define URDF fragments in different files so that we can reuse designed components.\n",
    "\n",
    "Next, we will quickly build a kitchen scene with some predefined kitchen furniture URDF.\n",
    "\n",
    "### Open the kitchen scene: [kitchen.urdf.xarco](../kitchen.jupyterlab-workspace)\n",
    "\n",
    "You will see some kitchen furniture. Try to arrange them in a way that makes sense. If you duplicate some components, remember to change the name of each component; each component needs to have a unique name."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf215b34-fa14-4c8c-a706-4d929acf0cf3",
   "metadata": {},
   "source": [
    "### Kitchen Furniture List\n",
    "\n",
    "If you want to checkout the details of these components, You can find the source URDF files in the file browser on the left panel.\n",
    "\n",
    "**Table**\n",
    "\n",
    "Source File: `iai_kitchen/urdf_obj/IAI_tables.urdf.xacro`\n",
    "```xml\n",
    "<xacro:iai_table_1 name=\"table_1\" parent=\"room_link\">\n",
    "    <origin xyz=\"1.5 0.75 0\" rpy=\"0 0 ${pi/2}\" />\n",
    "</xacro:iai_table_1>\n",
    "```\n",
    "\n",
    "**Chair**\n",
    "\n",
    "Source File: `iai_kitchen/urdf_obj/IAI_tables.urdf.xacro`\n",
    "```xml\n",
    "<xacro:jokkmokk_chair name=\"chair_1\" parent=\"room_link\">\n",
    "    <origin xyz=\"1.5 -0.75 0.5535\" rpy=\"0 0 0\" />\n",
    "</xacro:jokkmokk_chair>\n",
    "```\n",
    "\n",
    "**Fridge**\n",
    "\n",
    "Source File: `iai_kitchen/urdf_obj/IAI_tables.urdf.xacro`\n",
    "```xml\n",
    "<xacro:iai_fridge_area name=\"fridge_1\" parent=\"room_link\">\n",
    "    <origin xyz=\"-1 0 0\" rpy=\"0 0 0\" />\n",
    "</xacro:iai_fridge_area>\n",
    "```\n",
    "\n",
    "**Oven**\n",
    "\n",
    "Source File: `iai_kitchen/urdf_obj/IAI_oven_area.urdf.xacro`\n",
    "```xml\n",
    "<xacro:iai_oven_area name=\"oven_1\" parent=\"room_link\">\n",
    "    <origin xyz=\"-1 -1.6 0\" rpy=\"0 0 0\" />\n",
    "</xacro:iai_oven_area>\n",
    "```\n",
    "\n",
    "**Stove**\n",
    "\n",
    "Source File: `iai_kitchen/urdf_obj/IAI_kitchen_island.urdf.xacro`\n",
    "```xml\n",
    "<xacro:iai_kitchen_island name=\"stoves_1\" parent=\"room_link\">\n",
    "    <origin xyz=\"0 0 0\" rpy=\"0 0 0\" />\n",
    "</xacro:iai_kitchen_island>\n",
    "```\n",
    "\n",
    "**Sink**\n",
    "\n",
    "Source File: `iai_kitchen/urdf_obj/sink_area.urdf.xacro`\n",
    "```xml\n",
    "<xacro:iai_sink_area name=\"sink_area\" parent=\"room_link\">\n",
    "    <origin xyz=\"0 -2.5 0\" rpy=\"0 0 0\" />\n",
    "</xacro:iai_sink_area>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7d2aa228-e342-44b4-8da5-09d610efb2e4",
   "metadata": {},
   "source": [
    "# Checkout IAI labs Digital Twins: \n",
    "- [iai_kitchen.urdf.xacro](./iai_kitchen.urdf.xacro)\n",
    "- [iai_apartment.xacro](./iai_apartment.xacro)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dd6cef1d-0cc1-4779-bcf8-96441646c8d6",
   "metadata": {},
   "source": [
    "# Appendix: Kitchen assets and robots\n",
    "Assets source: https://github.com/Multiverse-Framework/Multiverse-Assets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "3558a976-c891-4c1f-8796-185a4d94b478",
   "metadata": {
    "jupyter": {
     "source_hidden": true
    }
   },
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "| Kitchen Assets(84) | Robots(26) |\n",
       "|---|---|\n",
       "| [beer_bottle.urdf](Assets/objects/beer_bottle/beer_bottle.urdf) | [cassie.urdf](Assets/robots/agents/agility_robotics/cassie/cassie.urdf) |\n",
       "| [black_towel.urdf](Assets/objects/black_towel/black_towel.urdf) | [anymal_b.urdf](Assets/robots/agents/anyrobotics/anymal_b/anymal_b.urdf) |\n",
       "| [blue_vase.urdf](Assets/objects/blue_vase/blue_vase.urdf) | [anymal_c.urdf](Assets/robots/agents/anyrobotics/anymal_c/anymal_c.urdf) |\n",
       "| [bread_1.urdf](Assets/objects/bread_1/bread_1.urdf) | [panda.urdf](Assets/robots/agents/franka_robotics/panda/panda.urdf) |\n",
       "| [bread_2.urdf](Assets/objects/bread_2/bread_2.urdf) | [barkour v0.urdf](Assets/robots/agents/google/barkour%20v0/barkour%20v0.urdf) |\n",
       "| [bread_knife.urdf](Assets/objects/bread_knife/bread_knife.urdf) | [barkour_vb.urdf](Assets/robots/agents/google/barkour_vb/barkour_vb.urdf) |\n",
       "| [bread_roll_1.urdf](Assets/objects/bread_roll_1/bread_roll_1.urdf) | [arm.urdf](Assets/robots/agents/heavyrobo/arm/arm.urdf) |\n",
       "| [bread_roll_2.urdf](Assets/objects/bread_roll_2/bread_roll_2.urdf) | [armar6.urdf](Assets/robots/agents/kit/armar6/armar6.urdf) |\n",
       "| [bread_roll_3.urdf](Assets/objects/bread_roll_3/bread_roll_3.urdf) | [iiwa14.urdf](Assets/robots/agents/kuka/iiwa14/iiwa14.urdf) |\n",
       "| [brown_banana.urdf](Assets/objects/brown_banana/brown_banana.urdf) | [tiago_dual.urdf](Assets/robots/agents/pal_robotics/tiago_dual/tiago_dual.urdf) |\n",
       "| [brush.urdf](Assets/objects/brush/brush.urdf) | [sawyer.urdf](Assets/robots/agents/rethink_robotics/sawyer/sawyer.urdf) |\n",
       "| [butter.urdf](Assets/objects/butter/butter.urdf) | [robotis_op3.urdf](Assets/robots/agents/robotis/robotis_op3/robotis_op3.urdf) |\n",
       "| [butter_knife.urdf](Assets/objects/butter_knife/butter_knife.urdf) | [Skydio X2.urdf](Assets/robots/agents/skydio/Skydio%20X2/Skydio%20X2.urdf) |\n",
       "| [cactus.urdf](Assets/objects/cactus/cactus.urdf) | [hsrb.urdf](Assets/robots/agents/toyota/hsrb/hsrb.urdf) |\n",
       "| [cheese.urdf](Assets/objects/cheese/cheese.urdf) | [vx300s.urdf](Assets/robots/agents/trossen_robotics/vx300s/vx300s.urdf) |\n",
       "| [cheese_2.urdf](Assets/objects/cheese_2/cheese_2.urdf) | [ufactory_lite6.urdf](Assets/robots/agents/ufactory/ufactory_lite6/ufactory_lite6.urdf) |\n",
       "| [cheese_3.urdf](Assets/objects/cheese_3/cheese_3.urdf) | [xarm7.urdf](Assets/robots/agents/ufactory/xarm7/xarm7.urdf) |\n",
       "| [cherry.urdf](Assets/objects/cherry/cherry.urdf) | [a1.urdf](Assets/robots/agents/unitree/a1/a1.urdf) |\n",
       "| [coke_can.urdf](Assets/objects/coke_can/coke_can.urdf) | [go1.urdf](Assets/robots/agents/unitree/go1/go1.urdf) |\n",
       "| [cold_cutting_1.urdf](Assets/objects/cold_cutting_1/cold_cutting_1.urdf) | [h1.urdf](Assets/robots/agents/unitree/h1/h1.urdf) |\n",
       "| [cold_cutting_2.urdf](Assets/objects/cold_cutting_2/cold_cutting_2.urdf) | [z1.urdf](Assets/robots/agents/unitree/z1/z1.urdf) |\n",
       "| [cold_cutting_3.urdf](Assets/objects/cold_cutting_3/cold_cutting_3.urdf) | [ur10e.urdf](Assets/robots/agents/universal_robot/ur10e/ur10e.urdf) |\n",
       "| [cucumber.urdf](Assets/objects/cucumber/cucumber.urdf) | [ur5e.urdf](Assets/robots/agents/universal_robot/ur5e/ur5e.urdf) |\n",
       "| [cutting_board.urdf](Assets/objects/cutting_board/cutting_board.urdf) | [left_shadow_hand.urdf](Assets/robots/grippers/shadow_robot/left_shadow_hand/left_shadow_hand.urdf) |\n",
       "| [dark_brown_avocado.urdf](Assets/objects/dark_brown_avocado/dark_brown_avocado.urdf) | [right_shadow_hand.urdf](Assets/robots/grippers/shadow_robot/right_shadow_hand/right_shadow_hand.urdf) |\n",
       "| [flowerpot.urdf](Assets/objects/flowerpot/flowerpot.urdf) | [d435i.urdf](Assets/robots/sensors/realsense/d435i/d435i.urdf) |\n",
       "| [fork.urdf](Assets/objects/fork/fork.urdf) | []() |\n",
       "| [garlic.urdf](Assets/objects/garlic/garlic.urdf) | []() |\n",
       "| [gerbera.urdf](Assets/objects/gerbera/gerbera.urdf) | []() |\n",
       "| [grain_buckwheat.urdf](Assets/objects/grain_buckwheat/grain_buckwheat.urdf) | []() |\n",
       "| [green_avocado.urdf](Assets/objects/green_avocado/green_avocado.urdf) | []() |\n",
       "| [green_banana.urdf](Assets/objects/green_banana/green_banana.urdf) | []() |\n",
       "| [green_grape.urdf](Assets/objects/green_grape/green_grape.urdf) | []() |\n",
       "| [green_orange.urdf](Assets/objects/green_orange/green_orange.urdf) | []() |\n",
       "| [green_pineapple.urdf](Assets/objects/green_pineapple/green_pineapple.urdf) | []() |\n",
       "| [green_tomato.urdf](Assets/objects/green_tomato/green_tomato.urdf) | []() |\n",
       "| [honey_peach.urdf](Assets/objects/honey_peach/honey_peach.urdf) | []() |\n",
       "| [horticultural_scissors.urdf](Assets/objects/horticultural_scissors/horticultural_scissors.urdf) | []() |\n",
       "| [kitchen_knife_1.urdf](Assets/objects/kitchen_knife_1/kitchen_knife_1.urdf) | []() |\n",
       "| [kitchen_knife_2.urdf](Assets/objects/kitchen_knife_2/kitchen_knife_2.urdf) | []() |\n",
       "| [kitchen_pliers.urdf](Assets/objects/kitchen_pliers/kitchen_pliers.urdf) | []() |\n",
       "| [kiwi_1.urdf](Assets/objects/kiwi_1/kiwi_1.urdf) | []() |\n",
       "| [kiwi_2.urdf](Assets/objects/kiwi_2/kiwi_2.urdf) | []() |\n",
       "| [ladle.urdf](Assets/objects/ladle/ladle.urdf) | []() |\n",
       "| [large_bowl.urdf](Assets/objects/large_bowl/large_bowl.urdf) | []() |\n",
       "| [large_plate.urdf](Assets/objects/large_plate/large_plate.urdf) | []() |\n",
       "| [lemon.urdf](Assets/objects/lemon/lemon.urdf) | []() |\n",
       "| [lime.urdf](Assets/objects/lime/lime.urdf) | []() |\n",
       "| [long_saussage.urdf](Assets/objects/long_saussage/long_saussage.urdf) | []() |\n",
       "| [medium_bowl.urdf](Assets/objects/medium_bowl/medium_bowl.urdf) | []() |\n",
       "| [medium_plate.urdf](Assets/objects/medium_plate/medium_plate.urdf) | []() |\n",
       "| [mixer.urdf](Assets/objects/mixer/mixer.urdf) | []() |\n",
       "| [oven_mitt.urdf](Assets/objects/oven_mitt/oven_mitt.urdf) | []() |\n",
       "| [paicha.urdf](Assets/objects/paicha/paicha.urdf) | []() |\n",
       "| [pan.urdf](Assets/objects/pan/pan.urdf) | []() |\n",
       "| [peeler.urdf](Assets/objects/peeler/peeler.urdf) | []() |\n",
       "| [pepper_black.urdf](Assets/objects/pepper_black/pepper_black.urdf) | []() |\n",
       "| [pepper_brown.urdf](Assets/objects/pepper_brown/pepper_brown.urdf) | []() |\n",
       "| [pepper_white.urdf](Assets/objects/pepper_white/pepper_white.urdf) | []() |\n",
       "| [pickled_cucumber.urdf](Assets/objects/pickled_cucumber/pickled_cucumber.urdf) | []() |\n",
       "| [pie_fork.urdf](Assets/objects/pie_fork/pie_fork.urdf) | []() |\n",
       "| [red_apple.urdf](Assets/objects/red_apple/red_apple.urdf) | []() |\n",
       "| [rose.urdf](Assets/objects/rose/rose.urdf) | []() |\n",
       "| [round_red_onion.urdf](Assets/objects/round_red_onion/round_red_onion.urdf) | []() |\n",
       "| [round_white_onion.urdf](Assets/objects/round_white_onion/round_white_onion.urdf) | []() |\n",
       "| [scissors_1.urdf](Assets/objects/scissors_1/scissors_1.urdf) | []() |\n",
       "| [scissors_2.urdf](Assets/objects/scissors_2/scissors_2.urdf) | []() |\n",
       "| [short_sausage.urdf](Assets/objects/short_sausage/short_sausage.urdf) | []() |\n",
       "| [small_bowl.urdf](Assets/objects/small_bowl/small_bowl.urdf) | []() |\n",
       "| [small_plate.urdf](Assets/objects/small_plate/small_plate.urdf) | []() |\n",
       "| [table_knife.urdf](Assets/objects/table_knife/table_knife.urdf) | []() |\n",
       "| [target.urdf](Assets/objects/target/target.urdf) | []() |\n",
       "| [teaspoon.urdf](Assets/objects/teaspoon/teaspoon.urdf) | []() |\n",
       "| [tomato.urdf](Assets/objects/tomato/tomato.urdf) | []() |\n",
       "| [tulip.urdf](Assets/objects/tulip/tulip.urdf) | []() |\n",
       "| [watermelon.urdf](Assets/objects/watermelon/watermelon.urdf) | []() |\n",
       "| [white_towel.urdf](Assets/objects/white_towel/white_towel.urdf) | []() |\n",
       "| [yellow_apple.urdf](Assets/objects/yellow_apple/yellow_apple.urdf) | []() |\n",
       "| [yellow_banana.urdf](Assets/objects/yellow_banana/yellow_banana.urdf) | []() |\n",
       "| [yellow_orange.urdf](Assets/objects/yellow_orange/yellow_orange.urdf) | []() |\n",
       "| [yellow_peach.urdf](Assets/objects/yellow_peach/yellow_peach.urdf) | []() |\n",
       "| [yellow_pineapple.urdf](Assets/objects/yellow_pineapple/yellow_pineapple.urdf) | []() |\n",
       "| [yellow_tomato.urdf](Assets/objects/yellow_tomato/yellow_tomato.urdf) | []() |\n",
       "| [yellow_vase.urdf](Assets/objects/yellow_vase/yellow_vase.urdf) | []() |\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import os\n",
    "from IPython.display import display, Markdown\n",
    "from urllib.parse import quote\n",
    "\n",
    "def find_urdf_files(directory):\n",
    "    # Store URDF file paths\n",
    "    urdf_files = []\n",
    "    \n",
    "    # Walk through the directory recursively\n",
    "    for root, _, files in os.walk(directory):\n",
    "        for file in files:\n",
    "            if file.endswith('.urdf'):\n",
    "                # Build the full path\n",
    "                full_path = os.path.join(root, file)\n",
    "                urdf_files.append(full_path)\n",
    "    \n",
    "    urdf_files.sort()\n",
    "    return urdf_files\n",
    "\n",
    "def markdown_links(file):\n",
    "    return f\"[{os.path.basename(file)}]({quote(file)})\"\n",
    "\n",
    "def markdown_table(array1, array2, col1_name=\"Kitchen Assets\", col2_name=\"Robots\"):\n",
    "    # Determine the maximum length of the arrays\n",
    "    max_length = max(len(array1), len(array2))\n",
    "    \n",
    "    # Pad the shorter arrays with empty strings\n",
    "    padded_array1 = array1 + [\"\"] * (max_length - len(array1))\n",
    "    padded_array2 = array2 + [\"\"] * (max_length - len(array2))\n",
    "    \n",
    "    # Create the Markdown table\n",
    "    markdown_table = f\"| {col1_name}({len(array1)}) | {col2_name}({len(array2)}) |\\n\"\n",
    "    markdown_table += \"|---|---|\\n\"  # Header separator\n",
    "    for val1, val2 in zip(padded_array1, padded_array2):\n",
    "        markdown_table += f\"| {markdown_links(val1)} | {markdown_links(val2)} |\\n\"\n",
    "    \n",
    "    # Display the table as Markdown\n",
    "    display(Markdown(markdown_table))\n",
    "\n",
    "\n",
    "# Index All URDF\n",
    "objects_urdf = find_urdf_files(\"Assets/objects\")\n",
    "robots_urdf = find_urdf_files(\"Assets/robots\")\n",
    "\n",
    "markdown_table(objects_urdf, robots_urdf)"
   ]
  }
 ],
 "metadata": {
  "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.10.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}