{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# PyCRAM Presentation" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2023-04-05T16:37:51.973404Z", "start_time": "2023-04-05T16:37:51.483749Z" } }, "outputs": [], "source": [ "import pycram" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Bullet World\n", "\n", "The BulletWorld is the internal simulation of PyCRAM. You can simulate different actions and reason about the outcome of different actions. \n", "\n", "It is possible to spawn objects and robots into the BulletWorld, these objects can come from URDF, OBJ or STL files. \n", "\n", "A BulletWorld can be created by simply creating an object of the BulletWorld class. " ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2023-04-05T16:37:59.788099Z", "start_time": "2023-04-05T16:37:57.586879Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Unknown tag \"material\" in /robot[@name='plane']/link[@name='planeLink']/collision[1]\n", "Unknown tag \"contact\" in /robot[@name='plane']/link[@name='planeLink']\n", "Unknown tag \"material\" in /robot[@name='plane']/link[@name='planeLink']/collision[1]\n", "Unknown tag \"contact\" in /robot[@name='plane']/link[@name='planeLink']\n" ] } ], "source": [ "from pycram.bullet_world import BulletWorld, Object\n", "from pycram.pose import Pose\n", "\n", "world = BulletWorld()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The world can also be closed with the 'exit' method" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "ExecuteTime": { "end_time": "2023-04-05T16:38:04.800655Z", "start_time": "2023-04-05T16:38:03.943911Z" } }, "outputs": [], "source": [ "world.exit()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The BulletWorld allows to render images from arbitrary positoins. In the following example we render images with the camera at the position [0.3, 0, 1] and pointing towards [1, 0, 1], so we are looking upwards along the x-axis. \n", "\n", "The renderer returns 3 different kinds of images which are also shown at the left side of the BulletWorld window. These images are:\n", "* A RGB image which shows everything like it is rendered in the BulletWorld window, just from another perspective. \n", "* A depth image which consists of distance values from the camera towards the objects in the field of view. \n", "* A segmentation mask image which segments the image into the different objects displayed. The segmentation is done by assigning every pixel the unique id of the object that is displayed there. " ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[array([[[255, 255, 255, 255],\n", " [255, 255, 255, 255],\n", " [255, 255, 255, 255],\n", " ...,\n", " [255, 255, 255, 255],\n", " [255, 255, 255, 255],\n", " [255, 255, 255, 255]],\n", " \n", " [[255, 255, 255, 255],\n", " [255, 255, 255, 255],\n", " [255, 255, 255, 255],\n", " ...,\n", " [255, 255, 255, 255],\n", " [255, 255, 255, 255],\n", " [255, 255, 255, 255]],\n", " \n", " [[255, 255, 255, 255],\n", " [255, 255, 255, 255],\n", " [255, 255, 255, 255],\n", " ...,\n", " [255, 255, 255, 255],\n", " [255, 255, 255, 255],\n", " [255, 255, 255, 255]],\n", " \n", " ...,\n", " \n", " [[239, 239, 239, 255],\n", " [239, 239, 239, 255],\n", " [239, 239, 239, 255],\n", " ...,\n", " [239, 239, 239, 255],\n", " [239, 239, 239, 255],\n", " [239, 239, 239, 255]],\n", " \n", " [[239, 239, 239, 255],\n", " [239, 239, 239, 255],\n", " [239, 239, 239, 255],\n", " ...,\n", " [239, 239, 239, 255],\n", " [239, 239, 239, 255],\n", " [239, 239, 239, 255]],\n", " \n", " [[239, 239, 239, 255],\n", " [239, 239, 239, 255],\n", " [239, 239, 239, 255],\n", " ...,\n", " [239, 239, 239, 255],\n", " [239, 239, 239, 255],\n", " [239, 239, 239, 255]]], dtype=uint8),\n", " array([[0.99999994, 0.99999994, 0.99999994, ..., 0.99999994, 0.99999994,\n", " 0.99999994],\n", " [0.99999994, 0.99999994, 0.99999994, ..., 0.99999994, 0.99999994,\n", " 0.99999994],\n", " [0.99999994, 0.99999994, 0.99999994, ..., 0.99999994, 0.99999994,\n", " 0.99999994],\n", " ...,\n", " [0.80473447, 0.80473447, 0.80473447, ..., 0.80473447, 0.80473447,\n", " 0.80473447],\n", " [0.8031688 , 0.8031688 , 0.8031688 , ..., 0.8031688 , 0.8031688 ,\n", " 0.8031688 ],\n", " [0.80160314, 0.80160314, 0.80160314, ..., 0.80160314, 0.80160314,\n", " 0.80160314]], dtype=float32),\n", " array([[-1, -1, -1, ..., -1, -1, -1],\n", " [-1, -1, -1, ..., -1, -1, -1],\n", " [-1, -1, -1, ..., -1, -1, -1],\n", " ...,\n", " [ 1, 1, 1, ..., 1, 1, 1],\n", " [ 1, 1, 1, ..., 1, 1, 1],\n", " [ 1, 1, 1, ..., 1, 1, 1]], dtype=int32)]" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from pycram.bullet_world_reasoning import _get_images_for_target\n", "\n", "_get_images_for_target(Pose([1, 0, 1], [0, 0, 0, 1]), Pose([0.3, 0, 1], [0, 0, 0, 1]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Objects\n", "Everything that is located inside the BulletWorld is an Object. \n", "Objects can be created from URDF, OBJ or STL files. Since everything is of type Object a robot might share the same methods as a milk (with some limitations).\n", "\n", "Signature:\n", "Object:\n", "* Name \n", "* Type\n", "* Filename or Filepath\n", "\n", " Optional:\n", " * Position\n", " * Orientation\n", " * World \n", " * Color \n", " * Ignore Cached Files\n", "\n", "If there is only a filename and no path PyCRAM will check in the resource directory if there is a matching file. \n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "milk = Object(\"Milk\", \"milk\", \"milk.stl\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Objects provide methods to change the position and rotation, change the color, attach other objects, set the state of joints if the objects has any or get the position and orientation of a link. \n", "\n", "These methods are the same for every Object, however since some Objects may not have joints or more than one link methods related to these will not work. " ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "milk.set_position(Pose([1, 0, 0]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To remove an Object from the BulletWorld just call the 'remove' method on the Object." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "milk.remove()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since everything inside the BulletWorld is an Object, even a complex environment Object like the kitchen can be spawned in the same way as the milk." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Scalar element defined multiple times: limit\n", "Scalar element defined multiple times: limit\n" ] } ], "source": [ "kitchen = Object(\"kitchen\", \"environment\", \"kitchen.urdf\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Costmaps\n", "\n", "Costmaps are a way to get positions with respect to certain criterias. \n", "The currently available costmaps are:\n", "* Occupancy Costmap\n", "* Visibility Costmap\n", "* Semantic Costmap \n", "* Gaussian Costmap\n", "\n", "It is also possible to merge multiple costmaps to combine different criteria." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Visibility Costmaps\n", "Visibility costmaps determine every position, around a target position, from which the target is visible. Visibility Costmaps are able to work with cameras that are moveable in height, for example if the robot has a movable torso. " ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "import pycram.costmaps as cm\n", "v = cm.VisibilityCostmap(1.27, 1.60, size=300, resolution=0.02, origin=Pose([0, 0, 0.1], [0, 0, 0, 1]))" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "v.visualize()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "v.close_visualization()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Occupancy Costmap\n", "Is valid for every position where the robot can be placed without colliding with an object." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "o = cm.OccupancyCostmap(0.2, from_ros=False, size=300, resolution=0.02, origin=Pose([0, 0, 0.1], [0, 0, 0, 1]))" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "s = cm.SemanticCostmap(kitchen, \"kitchen_island_surface\", size=100, resolution=0.02)\n", "\n", "g = cm.GaussianCostmap(200, 15, resolution=0.02)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can visualize the costmap in the BulletWorld to get an impression what information is actually contained in the costmap. With this you could also check if the costmap was created correctly. \n", "Visualization can be done via the 'visualize' method of each costmap." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "o.visualize()" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "o.close_visualization()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is also possible to combine two costmap, this will result in a new costmap with the same size which contains the information of both previous costmaps. Combination is done by checking for each position in the two costmaps if they are zero, in this case to same position in the new costmap will also be zero in any other case the new position will be the normalized product of the two combined costmaps." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "ov = o + v" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "ov.visualize()" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "ov.close_visualization()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Bullet World Reasoning \n", "Allows for geometric reasoning in the BulletWorld. At the moment the following types of reasoning are supported:\n", "* Stable\n", "* Contact\n", "* Visible \n", "* Occluding \n", "* Reachable \n", "* Blocking\n", "* Supporting\n", "\n", "To show the geometric reasoning we first a robot as well as the milk Object again." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Unknown attribute \"type\" in /robot[@name='pr2']/link[@name='base_laser_link']\n", "Unknown attribute \"type\" in /robot[@name='pr2']/link[@name='wide_stereo_optical_frame']\n", "Unknown attribute \"type\" in /robot[@name='pr2']/link[@name='narrow_stereo_optical_frame']\n", "Unknown attribute \"type\" in /robot[@name='pr2']/link[@name='laser_tilt_link']\n", "Unknown attribute \"type\" in /robot[@name='pr2']/link[@name='base_laser_link']\n", "Unknown attribute \"type\" in /robot[@name='pr2']/link[@name='wide_stereo_optical_frame']\n", "Unknown attribute \"type\" in /robot[@name='pr2']/link[@name='narrow_stereo_optical_frame']\n", "Unknown attribute \"type\" in /robot[@name='pr2']/link[@name='laser_tilt_link']\n" ] } ], "source": [ "import pycram.bullet_world_reasoning as btr\n", "milk = Object(\"Milk\", \"milk\", \"milk.stl\", pose=Pose([1, 0, 1]))\n", "pr2 = Object(\"pr2\", \"robot\", \"pr2.urdf\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We start with testing for visibility " ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Milk visible: True\n" ] } ], "source": [ "milk.set_position(Pose([1,0,1]))\n", "visible = btr.visible(milk, pr2.get_link_pose(\"wide_stereo_optical_frame\"))\n", "print(f\"Milk visible: {visible}\")" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Milk is in contact with the floor: False\n" ] } ], "source": [ "milk.set_position(Pose([1, 0, 0.05]))\n", "\n", "plane = BulletWorld.current_bullet_world.objects[0]\n", "contact = btr.contact(milk, plane)\n", "print(f\"Milk is in contact with the floor: {contact}\")" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Milk is reachable for the PR2: True\n" ] } ], "source": [ "milk.set_position(Pose([0.6, -0.5, 0.7]))\n", "\n", "reachable = btr.reachable(milk, pr2, \"r_gripper_tool_frame\")\n", "print(f\"Milk is reachable for the PR2: {reachable}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Designator\n", "Designator are symbolic descriptions of Actions, Motions, Objects or Locations. In PyCRAM the different types of designators are representet by a class which takes a description, the description then tells the designator what to do. \n", "\n", "For example, let's look at a Motion Designator to move the robot to a specific location. \n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Motion Designator\n", "\n", "When using a Motion Designator you need to specify which Process Module needs to be used, either the Process Module for the real or the simulated robot. This can be done either with a decorator which can be added to a function and then executes every designator in this function on the specified robot. The other possibility is a \"with\" scope which wraps a code piece. \n", "\n", "These two ways can also be combined, you could write a function which should be executed on the real robot and in the function is a \"with\" scope which executes something on the simulated robot for reasoning purposes. " ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "from pycram.designators.motion_designator import *\n", "from pycram.process_module import simulated_robot, with_simulated_robot\n", "\n", "description = MoveMotion(target=Pose([1, 0, 0], [0, 0, 0, 1]))\n", "\n", "with simulated_robot:\n", " description.resolve().perform()\n", " \n" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "scrolled": true }, "outputs": [], "source": [ "from pycram.process_module import with_simulated_robot\n", "\n", "@with_simulated_robot\n", "def move():\n", " MoveMotion(target=Pose([0, 0, 0], [0, 0, 0, 1])).resolve().perform()\n", "\n", "move()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Other implemented Motion Designator descriptions are:\n", "* Pick up\n", "* Place\n", "* Accessing\n", "* Move TCP\n", "* Looking\n", "* Move Gripper\n", "* Detecting\n", "* Move Arm Joint \n", "* World State Detecting " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Object Designator\n", "\n", "Object Designator represent objects, these objects could either be from the BulletWorld or the real world. Object Designator are used, for example, by the PickUpAction to know which object should be picked up." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "BelieveObject.Object(name='Milk', type='milk', bullet_world_object=Object(world=, \n", "name=Milk, \n", "type=milk, \n", "color=[1, 1, 1, 1], \n", "id=4, \n", "path=/home/jonas/workspace/ros/src/pycram-1/src/pycram/../../resources/cached/milk.urdf, \n", "joints: ..., \n", "links: ..., \n", "attachments: ..., \n", "cids: ..., \n", "original_pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205352\n", " nsecs: 248950242\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 1\n", " y: 0\n", " z: 1\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.0\n", " w: 1.0, \n", "base_origin_shift=[ 4.15300950e-04 -6.29518181e-05 8.96554102e-02], \n", "local_transformer=, \n", "tf_frame=Milk_4, \n", "urdf_object: ...), _pose=, \n", "name=Milk, \n", "type=milk, \n", "color=[1, 1, 1, 1], \n", "id=4, \n", "path=/home/jonas/workspace/ros/src/pycram-1/src/pycram/../../resources/cached/milk.urdf, \n", "joints: ..., \n", "links: ..., \n", "attachments: ..., \n", "cids: ..., \n", "original_pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205352\n", " nsecs: 248950242\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 1\n", " y: 0\n", " z: 1\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.0\n", " w: 1.0, \n", "base_origin_shift=[ 4.15300950e-04 -6.29518181e-05 8.96554102e-02], \n", "local_transformer=, \n", "tf_frame=Milk_4, \n", "urdf_object: ...)>)" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from pycram.designators.object_designator import *\n", "\n", "milk_desig = BelieveObject(names=[\"Milk\"])\n", "milk_desig.resolve()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Location Designator\n", "Location Designator can create a position in cartisian space from a symbolic desctiption" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Resolved: CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205407\n", " nsecs: 53105115\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.78\n", " y: -0.14\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.27958765375807687\n", " w: 0.9601201715754407, reachable_arms=None)\n", "\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205408\n", " nsecs: 363292217\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.78\n", " y: -0.14\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.27958765375807687\n", " w: 0.9601201715754407, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205408\n", " nsecs: 383865356\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.78\n", " y: -0.12\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.24708746132251994\n", " w: 0.968993181842469, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205408\n", " nsecs: 409863471\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.78\n", " y: -0.1\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.2116996959579716\n", " w: 0.9773347628787704, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205408\n", " nsecs: 439810991\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.78\n", " y: -0.08\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.17350299206578973\n", " w: 0.9848333421164306, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205408\n", " nsecs: 469390630\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.78\n", " y: -0.06\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.13273315102540856\n", " w: 0.9911518100769761, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205408\n", " nsecs: 498826742\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.78\n", " y: -0.04\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.08980559531591699\n", " w: 0.9959593139531121, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205408\n", " nsecs: 536117553\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.78\n", " y: -0.02\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.04531442117194118\n", " w: 0.9989727740203193, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205408\n", " nsecs: 615728139\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.78\n", " y: 0.0\n", " z: 0.0\n", " orientation: \n", " x: -0.0\n", " y: 0.0\n", " z: 1.2246467991473532e-16\n", " w: -1.0, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205408\n", " nsecs: 685858964\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.76\n", " y: 0.04\n", " z: 0.0\n", " orientation: \n", " x: -0.0\n", " y: 0.0\n", " z: 0.08248053154489343\n", " w: -0.9965926760297167, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205408\n", " nsecs: 819170713\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.76\n", " y: 0.0\n", " z: 0.0\n", " orientation: \n", " x: -0.0\n", " y: 0.0\n", " z: 1.2246467991473532e-16\n", " w: -1.0, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205408\n", " nsecs: 913299083\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.76\n", " y: -0.04\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.0824805315448933\n", " w: 0.9965926760297167, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205408\n", " nsecs: 991844177\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.76\n", " y: -0.08\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.1601822430069672\n", " w: 0.9870874576374967, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 26787519\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.78\n", " y: 0.02\n", " z: 0.0\n", " orientation: \n", " x: -0.0\n", " y: 0.0\n", " z: 0.045314421171941524\n", " w: -0.9989727740203193, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 69372415\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.78\n", " y: 0.04\n", " z: 0.0\n", " orientation: \n", " x: -0.0\n", " y: 0.0\n", " z: 0.08980559531591711\n", " w: -0.9959593139531121, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 115944147\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.78\n", " y: 0.06\n", " z: 0.0\n", " orientation: \n", " x: -0.0\n", " y: 0.0\n", " z: 0.13273315102540847\n", " w: -0.9911518100769761, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 185698986\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.78\n", " y: 0.1\n", " z: 0.0\n", " orientation: \n", " x: -0.0\n", " y: 0.0\n", " z: 0.21169969595797175\n", " w: -0.9773347628787704, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 223813772\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.8\n", " y: -0.16\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.3310069414355006\n", " w: 0.9436283191604177, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 257478475\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.8\n", " y: -0.14\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.30063938487909353\n", " w: 0.9537378886567945, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 403844594\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.74\n", " y: 0.02\n", " z: 0.0\n", " orientation: \n", " x: -0.0\n", " y: 0.0\n", " z: 0.03837651950358735\n", " w: -0.99926335004882, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 461148500\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.8\n", " y: -0.1\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.2297529205473612\n", " w: 0.9732489894677302, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 536622285\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.8\n", " y: -0.08\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.18910752115495127\n", " w: 0.9819563867314218, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 615195989\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.8\n", " y: -0.06\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.14521314468540483\n", " w: 0.9894003954974829, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 693008422\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.74\n", " y: -0.06\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.11315653826752592\n", " w: 0.9935771725675414, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 730560541\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.8\n", " y: -0.04\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.09853761796664222\n", " w: 0.9951333266680702, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 778785943\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.8\n", " y: -0.02\n", " z: 0.0\n", " orientation: \n", " x: 0.0\n", " y: 0.0\n", " z: 0.049813701880159676\n", " w: 0.998758526924799, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 814137697\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.8\n", " y: 0.0\n", " z: 0.0\n", " orientation: \n", " x: -0.0\n", " y: 0.0\n", " z: 1.2246467991473532e-16\n", " w: -1.0, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 854085445\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.8\n", " y: 0.02\n", " z: 0.0\n", " orientation: \n", " x: -0.0\n", " y: 0.0\n", " z: 0.0498137018801598\n", " w: -0.998758526924799, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205409\n", " nsecs: 891801834\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.8\n", " y: 0.04\n", " z: 0.0\n", " orientation: \n", " x: -0.0\n", " y: 0.0\n", " z: 0.09853761796664212\n", " w: -0.9951333266680702, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205410\n", " nsecs: 1260519\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.8\n", " y: 0.08\n", " z: 0.0\n", " orientation: \n", " x: -0.0\n", " y: 0.0\n", " z: 0.18910752115495139\n", " w: -0.9819563867314218, reachable_arms=None)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205410\n", " nsecs: 41796445\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.8\n", " y: 0.12\n", " z: 0.0\n", " orientation: \n", " x: -0.0\n", " y: 0.0\n", " z: 0.26693358189581157\n", " w: -0.9637149282107609, reachable_arms=None)\n", "CostmapLocation.Location(pose=header: \n", " seq: 0\n", " stamp: \n", " secs: 1690205410\n", " nsecs: 106158733\n", " frame_id: \"map\"\n", "pose: \n", " position: \n", " x: 0.8\n", " y: 0.1\n", " z: 0.0\n", " orientation: \n", " x: -0.0\n", " y: 0.0\n", " z: 0.22975292054736132\n", " w: -0.9732489894677301, reachable_arms=None)\n" ] } ], "source": [ "from pycram.designators.location_designator import *\n", "from pycram.designators.object_designator import *\n", "\n", "robot_desig = BelieveObject(types=[\"robot\"]).resolve()\n", "milk_desig = BelieveObject(names=[\"Milk\"]).resolve()\n", "location_desig = CostmapLocation(target=milk_desig, visible_for=robot_desig)\n", "\n", "print(f\"Resolved: {location_desig.resolve()}\")\n", "print()\n", "\n", "for pose in location_desig:\n", " print(pose)\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Action Designator\n", "Action Designator are used to describe high-level actions. Action Designator are usually composed of other Designators to describe the high-level action in detail. " ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "from pycram.designators.action_designator import *\n", "from pycram.enums import Arms\n", "\n", "with simulated_robot:\n", " ParkArmsAction([Arms.BOTH]).resolve().perform()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Making a simple plan\n", "To get familiar with the PyCRAM Framework we will write a simple pick and place plan. This plan will let the robot grab a cereal box from the kitchen counter and place it on the kitchen island. This is a simple pick and place plan." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [], "source": [ "from pycram.designators.object_designator import *\n", "cereal = Object(\"cereal\", \"cereal\", \"breakfast_cereal.stl\", pose=Pose([1.4, 1, 0.95]))\n" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "cereal_desig = ObjectDesignatorDescription(names=[\"cereal\"])\n", "kitchen_desig = ObjectDesignatorDescription(names=[\"kitchen\"])\n", "robot_desig = ObjectDesignatorDescription(names=[\"pr2\"]).resolve()\n", "with simulated_robot:\n", " ParkArmsAction([Arms.BOTH]).resolve().perform()\n", "\n", " MoveTorsoAction([0.3]).resolve().perform()\n", "\n", " pickup_pose = CostmapLocation(target=cereal_desig.resolve(), reachable_for=robot_desig).resolve()\n", " pickup_arm = pickup_pose.reachable_arms[0]\n", "\n", " NavigateAction(target_locations=[pickup_pose.pose]).resolve().perform()\n", "\n", " PickUpAction(object_designator_description=cereal_desig, arms=[pickup_arm], grasps=[\"front\"]).resolve().perform()\n", "\n", " ParkArmsAction([Arms.BOTH]).resolve().perform()\n", "\n", " place_island = SemanticCostmapLocation(\"kitchen_island_surface\", kitchen_desig.resolve(), cereal_desig.resolve()).resolve()\n", "\n", " place_stand = CostmapLocation(place_island.pose, reachable_for=robot_desig, reachable_arm=pickup_arm).resolve()\n", "\n", " NavigateAction(target_locations=[place_stand.pose]).resolve().perform()\n", "\n", " PlaceAction(cereal_desig, target_locations=[place_island.pose], arms=[pickup_arm]).resolve().perform()\n", "\n", " ParkArmsAction([Arms.BOTH]).resolve().perform()\n", " \n", " \n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Task Trees\n", "Task trees are a hirachical representation of all Actions involved in a plan. The Task tree can later be used to inspect and restructre the execution order of Actions in the plan." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "no_operation()\n", "├── perform(ParkArmsAction, )\n", "├── perform(ParkArmsAction, )\n", "├── perform(MoveTorsoAction, )\n", "├── perform(NavigateAction, )\n", "├── perform(PickUpAction, )\n", "├── perform(ParkArmsAction, )\n", "├── perform(NavigateAction, )\n", "├── perform(PlaceAction, )\n", "└── perform(ParkArmsAction, )\n" ] } ], "source": [ "import pycram.task\n", "import anytree\n", "tt = pycram.task.task_tree\n", "print(anytree.RenderTree(tt))" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "from anytree.dotexport import RenderTreeGraph, DotExporter\n", "RenderTreeGraph(tt).to_picture(\"tree.png\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# ORM\n" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Inserting TaskTree into database: 100%|██████████| 10/10 [00:00<00:00, 22.52it/s]\n" ] }, { "data": { "text/plain": [ "pycram.orm.task.TaskTreeNode(1, 2023-07-24 14:51:45.453499, None, TaskStatus.RUNNING, None, None, 1, 1)" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import sqlalchemy\n", "import sqlalchemy.orm\n", "import pycram.orm.base\n", "import pycram.orm.task\n", "import pycram.orm.object_designator\n", "import pycram.orm.motion_designator\n", "import pycram.orm.action_designator\n", "\n", "# set description of what we are doing\n", "pycram.orm.base.MetaData().description = \"Tutorial for getting familiar with the ORM.\"\n", "\n", "engine = sqlalchemy.create_engine(\"sqlite+pysqlite:///:memory:\", echo=False)\n", "session = sqlalchemy.orm.Session(bind=engine)\n", "pycram.orm.base.Base.metadata.create_all(engine)\n", "session.commit()\n", "\n", "\n", "tt.insert(session)" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pycram.orm.action_designator.NavigateAction(Navigate, 4, 4, 1, 4, 4)\n", "pycram.orm.action_designator.NavigateAction(Navigate, 7, 7, 1, 9, 9)\n" ] } ], "source": [ "navigations = session.query(pycram.orm.action_designator.NavigateAction).all()\n", "print(*navigations, sep=\"\\n\")" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(pycram.orm.action_designator.NavigateAction(Navigate, 4, 4, 1, 4, 4), pycram.orm.base.Position(0.5799999999999998, 0.7, 0.0, 4, None), pycram.orm.base.Quaternion(0.0, 0.0, 0.17446654103248407, 0.9846631028225646, 4, None))\n", "(pycram.orm.action_designator.NavigateAction(Navigate, 7, 7, 1, 9, 9), pycram.orm.base.Position(-1.8874999952316287, 0.959200015068054, 0.0, 9, None), pycram.orm.base.Quaternion(0.0, 0.0, 0.043989487236265, 0.9990319939885262, 9, None))\n" ] } ], "source": [ "navigations = session.query(pycram.orm.action_designator.NavigateAction, \n", " pycram.orm.base.Position, \n", " pycram.orm.base.Quaternion).\\\n", " join(pycram.orm.base.Position).\\\n", " join(pycram.orm.base.Quaternion).all()\n", "print(*navigations, sep=\"\\n\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.8.10" } }, "nbformat": 4, "nbformat_minor": 4 }