From 9bcb9c5165e3c6674c9bd68d0d4d0a47381fd430 Mon Sep 17 00:00:00 2001 From: lihinw <115400439+lihinw@users.noreply.github.com> Date: Tue, 30 May 2023 21:37:41 +0200 Subject: [PATCH] assignment03 --- lecture_04/assignment_03/assignment_03.ghx | 6005 +++++++++++++++++ .../assignment_03_Lihin_weera.3dm | Bin 0 -> 66017 bytes 2 files changed, 6005 insertions(+) create mode 100644 lecture_04/assignment_03/assignment_03.ghx create mode 100644 lecture_04/assignment_03/assignment_03_Lihin_weera.3dm diff --git a/lecture_04/assignment_03/assignment_03.ghx b/lecture_04/assignment_03/assignment_03.ghx new file mode 100644 index 0000000..8235b15 --- /dev/null +++ b/lecture_04/assignment_03/assignment_03.ghx @@ -0,0 +1,6005 @@ + + + + + + + + 0 + 2 + 2 + + + + + + + 1 + 0 + 7 + + + + + + c4f913db-409d-41a9-88e1-f6f90989047d + Shaded + 1 + + 100;150;0;0 + + + 100;0;150;0 + + + + + + 637527254194888879 + + assignment_03.ghx + + + + + 0 + + + + + + 342 + -142 + + 0.85 + + + + + 0 + + + + + + + 0 + + + + + 2 + + + + + GhPython, Version=7.28.23058.3001, Culture=neutral, PublicKeyToken=null + 7.28.23058.3001 + + 00000000-0000-0000-0000-000000000000 + + + + + + + Pufferfish, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null + 3.0.0.0 + Michael Pryor + 1c9de8a1-315f-4c56-af06-8f69fee80a7a + Pufferfish + 3.0.0.0 + + + + + + + 58 + + + + + c552a431-af5b-46a9-a8a4-0fcbc27ef596 + Group + + + + + 1 + + 150;170;135;255 + + A group of Grasshopper objects + bfe572e7-d997-4c3c-8488-4e03d01804ea + b278407c-79b3-49ef-a2c8-ee682b33d9ef + 6fe2e9d2-130c-4a02-b347-a1c6b831fc5a + 9a4be73c-3082-4c74-be27-41c7c1688c53 + 4 + 3dd78fb5-3c65-4715-b2db-b9489d44fd71 + Group + + + + + + + + + + + c552a431-af5b-46a9-a8a4-0fcbc27ef596 + Group + + + + + 1 + + 150;170;135;255 + + A group of Grasshopper objects + d5ffda3e-a3ab-4688-9de8-1d9d9e2789e3 + 4b0a07e0-a378-4f92-8f0a-6c1f1fb427f2 + 1d31a79f-b7ba-423f-944c-23f606999dae + eaec99d4-5f03-4209-953f-02aee1235de3 + 4a5bf47a-b0af-4831-a451-6b776364bb7e + 5 + 5a4ca04f-0f26-4978-bcce-92edaa3c4b8e + Group + + + + + + + + + + + c552a431-af5b-46a9-a8a4-0fcbc27ef596 + Group + + + + + 1 + + 150;170;135;255 + + A group of Grasshopper objects + 781a5de8-c54c-4805-927f-519a45da032f + 4b0a07e0-a378-4f92-8f0a-6c1f1fb427f2 + 1d31a79f-b7ba-423f-944c-23f606999dae + eaec99d4-5f03-4209-953f-02aee1235de3 + 4a5bf47a-b0af-4831-a451-6b776364bb7e + 20c7f0ab-fd13-4bd7-a130-c6fe893d2a0b + 47c152bc-c823-4835-aad3-3bf5c281e892 + d19cf29a-0512-4632-b4e0-ecc00c5b8487 + 2ceac33a-a5ff-4a42-8067-32e6a2c7fbee + ac227038-eb23-4cb5-94d8-f63bb92375a4 + b3787c61-219b-4ed9-b49f-1e7dd56236b1 + b395bfb0-5717-46c4-924c-a3ba167b1e0d + 4e66fe1b-29b3-4955-9524-ca986decd9ac + 78471367-17af-4599-8661-808ba87f82a6 + bfa816f1-e4c0-482e-9515-4b540fd2f427 + 82091d9c-f1c0-4207-8d3d-b1dca673d5df + 5d051c72-528a-498d-a91b-f91e344562b4 + baea3a7f-42ad-4480-b62c-39cd2f8c2e8a + 18 + 8b8d6fbf-db19-4267-9188-c4fdd76620b6 + Group + + + + + + + + + + + 8ec86459-bf01-4409-baee-174d0d2b13d0 + Data + + + + + Contains a collection of generic data + 4e66fe1b-29b3-4955-9524-ca986decd9ac + Data + Robot + false + 846547a4-0964-4bea-b2e5-d3fd03e0ff69 + 1 + + + + + + 1254 + 168 + 50 + 24 + + + 1279.353 + 180.9772 + + + + + + + + + + 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe + Scribble + + + + + false + + 46.70692 + 119.7138 + + + 272.0458 + 119.7138 + + + 272.0458 + 139.8124 + + + 46.70692 + 139.8124 + + A quick note + Cambria + 82091d9c-f1c0-4207-8d3d-b1dca673d5df + false + Scribble + Scribble + 22 + 1) Load robot from ROS + + + + + + 41.70692 + 114.7138 + 235.3389 + 30.09864 + + + 46.70692 + 119.7138 + + + + + + + + + + 8ec86459-bf01-4409-baee-174d0d2b13d0 + Data + + + + + Contains a collection of generic data + aacb02be-ffde-4997-b910-3a5670a6e5b1 + Data + Target planes + false + 44d4a187-3a93-413f-992e-d4cc7e2e19ad + 1 + + + + + + 1240 + 476 + 50 + 24 + + + 1265.041 + 488.8133 + + + + + + + + + + c552a431-af5b-46a9-a8a4-0fcbc27ef596 + Group + + + + + 1 + + 150;240;218;146 + + A group of Grasshopper objects + 0c3c0677-cbf3-46be-b539-e48399697bc7 + de6b7a53-8f17-48cc-bb14-1aedc473dd1c + 04770360-9eb5-44e4-911f-142deec44bdc + aacb02be-ffde-4997-b910-3a5670a6e5b1 + 50ee1702-2c6a-4092-b68b-7fd9ec30c129 + 9dbe68e7-ae2d-4df4-89a9-ae0ec5759854 + d17c9d6f-7bf6-411c-816c-4c1caad151b9 + 37fef6aa-0c60-4da4-9d31-1ae0bdd95cd2 + d6cabb95-93fe-48fe-9b1b-2070fdd10e56 + 3974a64b-9fea-4aa6-a9ad-21315ef8260a + b171143f-e5e1-4bc8-92f7-eb329037f691 + 11 + cf91e427-c398-45be-b915-f55275cc67b7 + Group + + + + + + + + + + + 8ec86459-bf01-4409-baee-174d0d2b13d0 + Data + + + + + Contains a collection of generic data + d385349b-7e03-4362-b9d0-eacd34e2562b + Data + Pickup plane + false + 3a86f18b-7506-4d48-8a5c-6048a1108886 + 1 + + + + + + 1242 + 320 + 50 + 24 + + + 1267.779 + 332.6416 + + + + + + + + + + c552a431-af5b-46a9-a8a4-0fcbc27ef596 + Group + + + + + 1 + + 150;240;218;146 + + A group of Grasshopper objects + d385349b-7e03-4362-b9d0-eacd34e2562b + 66c3b06d-1415-476b-875b-53498de1860a + c9e84bc7-5f07-46ef-9e42-32f7d85d0c13 + 39a429c7-2480-4ff8-8f4c-5bd8a47369a7 + 224add91-1cc7-47af-8c77-af2d42147144 + ff0bbdd7-eb5b-4ed6-a652-505db2c0ac8c + 13d747bd-3e05-4a41-8ea0-75bad3d5248b + dd675efd-9233-4ad4-bb47-4b8f4932cc90 + 68575641-3532-400d-95f0-a0242e51e625 + eb5acce9-f665-4261-a8bc-ffd4947a64da + 0bd900d0-2016-4c53-af3b-1c52cf194064 + 11 + 3c032157-3bf9-40ee-9b12-e4e807d15ccc + Group + + + + + + + + + + + 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe + Scribble + + + + + false + + 46.70692 + 281.4785 + + + 269.3387 + 281.4785 + + + 269.3387 + 301.5771 + + + 46.70692 + 301.5771 + + A quick note + Cambria + ff0bbdd7-eb5b-4ed6-a652-505db2c0ac8c + false + Scribble + Scribble + 22 + 2) Define pick-up plane + + + + + + 41.70692 + 276.4785 + 232.6318 + 30.09863 + + + 46.70692 + 281.4785 + + + + + + + + + + 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe + Scribble + + + + + false + + 46.70692 + 431.5476 + + + 263.9891 + 431.5476 + + + 263.9891 + 451.7751 + + + 46.70692 + 451.7751 + + A quick note + Cambria + 9dbe68e7-ae2d-4df4-89a9-ae0ec5759854 + false + Scribble + Scribble + 22 + 3) Define target planes + + + + + + 41.70692 + 426.5476 + 227.2822 + 30.22754 + + + 46.70692 + 431.5476 + + + + + + + + + + 410755b1-224a-4c1e-a407-bf32fb45ea7e + 00000000-0000-0000-0000-000000000000 + Robot Visualize + + + + + """ +Visualizes the robot. + +COMPAS FAB v0.27.0 +""" +from compas.artists import Artist +from compas.geometry import Frame +from compas.geometry import Transformation +from compas_fab.robots import PlanningScene +from ghpythonlib.componentbase import executingcomponent as component + + +class RobotVisualize(component): + def RunScript( + self, + robot, + group, + configuration, + show_visual, + show_collision, + show_frames, + show_base_frame, + show_end_effector_frame, + show_cm, + show_acm, + ): + + visual = None + collision = None + collision_meshes = None + attached_meshes = None + frames = None + base_frame = None + ee_frame = None + + if robot: + show_visual = True if show_visual is None else show_visual + show_cm = True if show_cm is None else show_cm + show_acm = True if show_acm is None else show_acm + configuration = configuration or robot.zero_configuration() + + robot.update(configuration, visual=show_visual, collision=show_collision) + compas_frames = robot.transformed_frames(configuration, group) + + if show_visual: + visual = robot.artist.draw_visual() + + if show_collision: + collision = robot.artist.draw_collision() + + if show_base_frame: + base_compas_frame = compas_frames[0] + artist = Artist(base_compas_frame) + base_frame = artist.draw() + + if show_end_effector_frame: + ee_compas_frame = robot.forward_kinematics( + configuration, group, options=dict(solver="model") + ) + artist = Artist(ee_compas_frame) + ee_frame = artist.draw() + + if show_frames: + frames = [] + for compas_frame in compas_frames[1:]: + artist = Artist(compas_frame) + frame = artist.draw() + frames.append(frame) + + if show_cm or show_acm: + scene = PlanningScene(robot) + scene = robot.client.get_planning_scene() + + collision_meshes = [] + attached_meshes = [] + + if show_cm: + for co in scene.world.collision_objects: + header = co.header + frame_id = header.frame_id + cms = co.to_collision_meshes() + + for cm in cms: + if cm.frame != Frame.worldXY(): + t = Transformation.from_frame(cm.frame) + mesh = cm.mesh.transformed(t) + else: + mesh = cm.mesh + + collision_meshes.append(Artist(mesh).draw()) + + if show_acm: + for aco in scene.robot_state.attached_collision_objects: + for acm in aco.to_attached_collision_meshes(): + frame_id = aco.object["header"]["frame_id"] + frame = robot.forward_kinematics( + configuration, options=dict(link=frame_id) + ) + t = Transformation.from_frame(frame) + + # Local CM frame + if ( + acm.collision_mesh.frame + and acm.collision_mesh.frame != Frame.worldXY() + ): + t = t * Transformation.from_frame( + acm.collision_mesh.frame + ) + + mesh = acm.collision_mesh.mesh.transformed(t) + + attached_meshes.append(Artist(mesh).draw()) + + return ( + visual, + collision, + collision_meshes, + attached_meshes, + frames, + base_frame, + ee_frame, + ) + + Visualizes the robot. +COMPAS FAB v0.27.0 + true + true + 2 + + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDgAACw4BQL7hQQAAAdhJREFUSEu1lLFKA0EQhlUIQVBMOhGLgGAtxAcIYmmRJpWNrZ2dhSCWqURtxC6VRSofIYWlhS8QyBMEOzvP/zt2jtm9VSLEg+9ud2bnn9nZu1spiuJfyRqXSdb4F3ZvX1vigmfOXzP8FQm/iEJ8iH7qjyZUIUZiIgjseb9HvjMxE4jbE4jt2Lo0CGca0BOI3Ti8nzGFdYTFv9cShAWlUzyK6zC/E9aGHFFbND8Q1c5TBwHPgiQPYU4C2uZFPVEbNa/aA9wqg5wIE2RP6AuSsH2DAzV/2Q49aRPtwzYzTW5VBXKwC+sjIvQ+qiiso52IWSG00B941CKfwA7UDs0qqiUJ61nnD5z10ffALe2hb48x8Ws88lEIhWWLqBnC4jQBRIUsStYosdxbUx6croFgAJcWo6st5sE+ruw28EiMbfs3xbjBnxWKEw8quw1SEEvEgaQtCQydWJv1zjb3OpFoisT8G2KMJNINYlBWq8t2NfQakWCKxH48cAlNg+CT8AmPvUYkCArmq82JRmydnJeCa+sbX42dvfsgPk31ogko2L7kX9m+GpcJYLXR/AzjqD0QTUDBCyWA5v5hlSTQTfWiCSiQX4X91H5l8+jUzgHeUi2oGZZN1rg8ipVvhzuVIxcFIsQAAAAASUVORK5CYII= + + false + 7a58f25a-3dc8-4dfa-bf0f-35404273569e + true + true + Robot Visualize + Robot Visualize + + + + + + 2220 + 498 + 257 + 204 + + + 2367 + 600 + + + + + + 10 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 7 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + + + + + true + The robot. + 439bbb30-bb2a-4f39-bfd6-8205cd93fd09 + robot + robot + true + 0 + true + 619d4216-bdfd-4395-b679-83b02e397c53 + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + 2 + + + + + + 2222 + 500 + 130 + 20 + + + 2288.5 + 510 + + + + + + + + true + The planning group used for end-effector and base visualization. + ad36f822-0439-4ba3-b51a-c348f6f591ec + group + group + true + 0 + true + 0 + 37261734-eec7-4f50-b6a8-b8d1f3c4396b + + + + + + 2222 + 520 + 130 + 20 + + + 2288.5 + 530 + + + + + + + + true + The robot's full configuration. + 9fb95b19-f673-4906-9998-b63a5811ea88 + configuration + configuration + true + 0 + true + 4ca3f55b-10fb-41c3-9f24-2b4809b96eeb + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 2222 + 540 + 130 + 20 + + + 2288.5 + 550 + + + + + + + + true + Whether or not to show the robot's visual meshes. + 22d8ace2-7a15-4a22-9430-2f721280765e + show_visual + show_visual + true + 0 + true + 0 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 2222 + 560 + 130 + 20 + + + 2288.5 + 570 + + + + + + + + true + Whether or not to show the robot's collision meshes. + ad827435-eaa9-47db-8456-0f04c22dde3a + show_collision + show_collision + true + 0 + true + 0 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 2222 + 580 + 130 + 20 + + + 2288.5 + 590 + + + + + + + + true + Whether or not to show the robot's joint frames. + 35824dc3-741e-4a85-9d9f-f350f6328850 + show_frames + show_frames + true + 0 + true + 0 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 2222 + 600 + 130 + 20 + + + 2288.5 + 610 + + + + + + + + true + Whether or not to show the robot's base frame. + 5c36de85-2908-4ed4-8bfb-be05a5fc15a0 + show_base_frame + show_base_frame + true + 0 + true + 0 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 2222 + 620 + 130 + 20 + + + 2288.5 + 630 + + + + + + + + true + Whether or not to show the robot's end-effector frame. + 43679585-4dff-44fc-8144-04d51b6597a3 + show_end_effector_frame + show_end_effector_frame + true + 0 + true + 0 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 2222 + 640 + 130 + 20 + + + 2288.5 + 650 + + + + + + + + true + Whether or not to show the collision meshes (if any). + b0245b8b-4b25-480e-8434-34500dd361dd + show_cm + show_cm + true + 0 + true + 0 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 2222 + 660 + 130 + 20 + + + 2288.5 + 670 + + + + + + + + true + Whether or not to show the attached collision meshes (if any). + c258dd5f-afd6-4742-9840-e8ae6df45c59 + show_acm + show_acm + true + 0 + true + 0 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 2222 + 680 + 130 + 20 + + + 2288.5 + 690 + + + + + + + + Rhino meshes of the robot's visual geometry (if any). + b51fd205-41de-4772-b77b-54118aa40c2c + visual + visual + false + 0 + + + + + + 2382 + 500 + 93 + 28 + + + 2428.5 + 514.2857 + + + + + + + + Rhino meshes of the robot's collision geometry (if any). + 3fd4309e-805a-4b2a-8b39-fb39cda51d21 + collision + collision + false + 0 + + + + + + 2382 + 528 + 93 + 29 + + + 2428.5 + 542.8571 + + + + + + + + Rhino meshes of the scene's collision meshes (if any). + ba8f5aaf-7d4f-4021-b0f3-328651e5f766 + collision_meshes + collision_meshes + false + 0 + + + + + + 2382 + 557 + 93 + 28 + + + 2428.5 + 571.4286 + + + + + + + + Rhino meshes of the scene's attached collision meshes (if any). + 00b4652c-1968-4bef-b124-5b86f4dc25bc + attached_meshes + attached_meshes + false + 0 + + + + + + 2382 + 585 + 93 + 29 + + + 2428.5 + 600 + + + + + + + + The robot's joint frames as Rhino planes (if any). + 243eeb3c-e1ad-4233-9a1a-b0ec9fd1c962 + frames + frames + false + 0 + + + + + + 2382 + 614 + 93 + 28 + + + 2428.5 + 628.5714 + + + + + + + + The robot's base frame as a Rhino plane (if any). + 91fd1995-e0da-4f23-a4c6-afeefc044dee + base_frame + base_frame + false + 0 + + + + + + 2382 + 642 + 93 + 29 + + + 2428.5 + 657.1429 + + + + + + + + The robot's end-effector frame as a Rhino plane (if any). + 5a2c4711-ae2f-4f0f-b633-afc7c8fccfd2 + ee_frame + ee_frame + false + 0 + + + + + + 2382 + 671 + 93 + 29 + + + 2428.5 + 685.7143 + + + + + + + + + + + + + + 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe + Scribble + + + + + false + + 46.70692 + 651.1613 + + + 317.5712 + 651.1613 + + + 317.5712 + 671.2599 + + + 46.70692 + 671.2599 + + A quick note + Cambria + fccb98c9-c6e5-4caa-8384-ca0ddf85fd1f + false + Scribble + Scribble + 22 + 4) Solve IK for pick-up plane + + + + + + 41.70692 + 646.1613 + 280.8643 + 30.09863 + + + 46.70692 + 651.1613 + + + + + + + + + + 8ec86459-bf01-4409-baee-174d0d2b13d0 + Data + + + + + Contains a collection of generic data + 02bc89eb-6961-419b-a5c7-ecf1d7beb296 + Data + Pickup config + false + 1d8af690-69c5-4c9f-b553-1a05f97e8281 + 1 + + + + + + 1242 + 734 + 50 + 24 + + + 1267.176 + 746.6949 + + + + + + + + + + 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe + Scribble + + + + + false + + 73.59002 + 675.2849 + + + 238.8635 + 675.2849 + + + 238.8635 + 689.9958 + + + 73.59002 + 689.9958 + + A quick note + Cambria + 6e5b9db8-970d-4e5b-bf3d-6ec1c492b072 + false + Scribble + Scribble + 16 + Results in pickup config + + + + + + 68.59002 + 670.2849 + 175.2734 + 24.71094 + + + 73.59002 + 675.2849 + + + + + + + + + + c552a431-af5b-46a9-a8a4-0fcbc27ef596 + Group + + + + + 1 + + 150;240;218;146 + + A group of Grasshopper objects + fccb98c9-c6e5-4caa-8384-ca0ddf85fd1f + 02bc89eb-6961-419b-a5c7-ecf1d7beb296 + 6e5b9db8-970d-4e5b-bf3d-6ec1c492b072 + fb4c5d39-e0a5-4c45-b606-72de43c589ac + b96209a7-93e4-4212-b096-c83e82b4da7b + 98209ace-c305-4683-b351-d9b9daf31e36 + df49cbca-ec61-4dc7-8c55-18e7e63a3700 + 5c90bf29-e6aa-4294-8822-68408c74406a + 8 + 3962a36b-d451-45d1-acb9-c99a5708db90 + Group + + + + + + + + + + + 00027467-0d24-4fa7-b178-8dc0ac5f42ec + Value List + + + + + Provides a list of preset values to choose from + 137a3255-a54e-4e4c-a9c3-e6d902b2a8bb + 2 + 3 + Value List + List + false + 0 + + + + + 0 + Pickup config + false + + + + + 1 + Trajectory + true + + + + + + 1455 + 530 + 123 + 22 + + + + + + + + + + eeafc956-268e-461d-8e73-ee05c6f72c01 + Stream Filter + + + + + Filters a collection of input streams + 471af287-d88e-43f4-9bb2-98daa088f633 + Stream Filter + Filter + + + + + + 1910 + 529 + 77 + 64 + + + 1942 + 561 + + + + + + 3 + 2e3ab970-8545-46bb-836c-1c11e5610bce + 8ec86459-bf01-4409-baee-174d0d2b13d0 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + 1 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + + + + + Index of Gate stream + fde7ac2c-1b3d-473c-8b2b-4addc4d52e1a + Gate + G + false + 137a3255-a54e-4e4c-a9c3-e6d902b2a8bb + 1 + + + + + + 1912 + 531 + 15 + 20 + + + 1921 + 541 + + + + + + 1 + + + + + 1 + {0} + + + + + 0 + + + + + + + + + + + 2 + Input stream at index 0 + e6a67ce5-d55f-4ec2-a44c-573291be81a5 + false + Stream 0 + 0 + true + a38644b3-ef3b-4bc2-bf1d-8843907a4a1f + 1 + + + + + + 1912 + 551 + 15 + 20 + + + 1921 + 561 + + + + + + + + 2 + Input stream at index 1 + 14985ec3-7977-426f-bc6b-ad27afc61e04 + false + Stream 1 + 1 + true + a4b043bc-8e30-4b4c-bb40-e7f42497696d + 1 + + + + + + 1912 + 571 + 15 + 20 + + + 1921 + 581 + + + + + + + + 2 + Filtered stream + ddfd1927-535b-4f08-acf1-f1762fa62a54 + false + Stream + S(1) + false + 0 + + + + + + 1957 + 531 + 28 + 60 + + + 1971 + 561 + + + + + + + + + + + + + + c552a431-af5b-46a9-a8a4-0fcbc27ef596 + Group + + + + + 1 + + 150;0;155;194 + + A group of Grasshopper objects + 7a58f25a-3dc8-4dfa-bf0f-35404273569e + 137a3255-a54e-4e4c-a9c3-e6d902b2a8bb + 471af287-d88e-43f4-9bb2-98daa088f633 + 766f518e-d29b-4814-a406-a45e5ded4a64 + e4b338fe-125d-4929-92e1-4e17c08f9b3b + f53212f5-507f-4bda-b372-34bf2b7020a3 + a38644b3-ef3b-4bc2-bf1d-8843907a4a1f + e9d20ac9-0dbc-44cb-9f48-878ae446678f + 619d4216-bdfd-4395-b679-83b02e397c53 + df7fb28b-31b3-40c8-ab8a-ec66c12ea055 + 10 + ca0ff086-508f-4122-8664-195d1a456efe + Group + + + + + + + + + + + 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe + Scribble + + + + + false + + 1448 + 480.4395 + + + 1572.363 + 480.4395 + + + 1572.363 + 495.9834 + + + 1448 + 495.9834 + + A quick note + Cambria + 766f518e-d29b-4814-a406-a45e5ded4a64 + false + Scribble + Scribble + 22 + Visualization + + + + + + 1443 + 475.4395 + 134.3623 + 25.54395 + + + 1448 + 480.4395 + + + + + + + + + + 8ec86459-bf01-4409-baee-174d0d2b13d0 + Data + + + + + Contains a collection of generic data + b96209a7-93e4-4212-b096-c83e82b4da7b + Data + Pickup plane + false + d385349b-7e03-4362-b9d0-eacd34e2562b + 1 + 2 + + + + + + 77 + 724 + 50 + 24 + + + 102.6684 + 736.2081 + + + + + + + + + + 8ec86459-bf01-4409-baee-174d0d2b13d0 + Data + + + + + Contains a collection of generic data + 98209ace-c305-4683-b351-d9b9daf31e36 + Data + Robot + false + 4e66fe1b-29b3-4955-9524-ca986decd9ac + 1 + 2 + + + + + + 77 + 696 + 50 + 24 + + + 102.0198 + 708.5996 + + + + + + + + + + 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe + Scribble + + + + + false + + 46.70692 + 861.2363 + + + 379.9403 + 861.2363 + + + 379.9403 + 881.4102 + + + 46.70692 + 881.4102 + + A quick note + Cambria + ba94b074-3f68-4274-8b84-f87aa5c4cb3e + false + Scribble + Scribble + 22 + 5) Plan trajectory to selected plane + + + + + + 41.70692 + 856.2363 + 343.2334 + 30.17383 + + + 46.70692 + 861.2363 + + + + + + + + + + 7f5c6c55-f846-4a08-9c9a-cfdc285cc6fe + Scribble + + + + + false + + 75.11641 + 888.1221 + + + 314.8351 + 888.1221 + + + 314.8351 + 902.833 + + + 75.11641 + 902.833 + + A quick note + Cambria + 01b0a494-be40-47b6-bdc4-7c92967b9f38 + false + Scribble + Scribble + 16 + From pickup config to target plane + + + + + + 70.11641 + 883.1221 + 249.7187 + 24.71094 + + + 75.11641 + 888.1221 + + + + + + + + + + 8ec86459-bf01-4409-baee-174d0d2b13d0 + Data + + + + + Contains a collection of generic data + 55db7485-e593-4762-a166-64303d976c7a + Data + Target planes + false + aacb02be-ffde-4997-b910-3a5670a6e5b1 + 1 + 2 + + + + + + 81 + 988 + 50 + 24 + + + 106.0911 + 1000.628 + + + + + + + + + + 8ec86459-bf01-4409-baee-174d0d2b13d0 + Data + + + + + Contains a collection of generic data + 538c02c6-6b3b-4712-a784-dda0bc63f847 + Data + Robot + false + 4e66fe1b-29b3-4955-9524-ca986decd9ac + 1 + 2 + + + + + + 82 + 931 + 50 + 24 + + + 107.0106 + 943.0975 + + + + + + + + + + 8ec86459-bf01-4409-baee-174d0d2b13d0 + Data + + + + + Contains a collection of generic data + c666c109-2ccb-4c50-90cd-00130af76eaa + Data + Pickup config + false + 02bc89eb-6961-419b-a5c7-ecf1d7beb296 + 1 + 2 + + + + + + 81 + 959 + 50 + 24 + + + 106.6234 + 971.4724 + + + + + + + + + + 57da07bd-ecab-415d-9d86-af36d7073abc + Number Slider + + + + + Numeric slider for single values + e4b338fe-125d-4929-92e1-4e17c08f9b3b + Number Slider + + false + 0 + + + + + + 1456 + 565 + 160 + 20 + + + 1456.641 + 565.639 + + + + + + 3 + 1 + 1 + 100 + 0 + 0 + 21 + + + + + + + + + 59daf374-bc21-4a5e-8282-5504fb7ae9ae + List Item + + + + + 0 + Retrieve a specific item from a list. + df7fb28b-31b3-40c8-ab8a-ec66c12ea055 + List Item + Item + + + + + + 2027 + 549 + 64 + 64 + + + 2061 + 581 + + + + + + 3 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + 2e3ab970-8545-46bb-836c-1c11e5610bce + cb95db89-6165-43b6-9c41-5702bc5bf137 + 1 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + + + + + 1 + Base list + 39c89e61-bc93-43d0-a501-c5bba7a3da6e + List + L + false + ddfd1927-535b-4f08-acf1-f1762fa62a54 + 1 + + + + + + 2029 + 551 + 17 + 20 + + + 2039 + 561 + + + + + + + + Item index + 83d287eb-3d9d-4785-b735-156766b364e7 + Index + i + false + e4b338fe-125d-4929-92e1-4e17c08f9b3b + 1 + + + + + + 2029 + 571 + 17 + 20 + + + 2039 + 581 + + + + + + 1 + + + + + 1 + {0} + + + + + 0 + + + + + + + + + + + Wrap index to list bounds + 60da4aea-66d4-49fc-8aa9-a5189edc913b + Wrap + W + false + 0 + + + + + + 2029 + 591 + 17 + 20 + + + 2039 + 601 + + + + + + 1 + + + + + 1 + {0} + + + + + true + + + + + + + + + + + Item at {i'} + 4ca3f55b-10fb-41c3-9f24-2b4809b96eeb + false + Item + i + false + 0 + + + + + + 2076 + 551 + 13 + 60 + + + 2082.5 + 581 + + + + + + + + + + + + + + 8ec86459-bf01-4409-baee-174d0d2b13d0 + Data + + + + + Contains a collection of generic data + bcf27a28-24e5-4d31-8438-444d7fe511cb + Data + Trajectory + false + 4e17b2ad-e9af-41eb-b6a5-7585e1f6e333 + 1 + + + + + + 1246 + 954 + 50 + 24 + + + 1271.31 + 966.862 + + + + + + + + + + 410755b1-224a-4c1e-a407-bf32fb45ea7e + 00000000-0000-0000-0000-000000000000 + GhPython Script + + + + + configs = trajectory.points + GhPython provides a Python script component + + 182 + 182 + + + 558 + 571 + + true + true + 2 + false + f53212f5-507f-4bda-b372-34bf2b7020a3 + false + true + GhPython Script + get configs + + + + + + 1554 + 673 + 132 + 28 + + + 1624 + 687 + + + + + + 1 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 1 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + + + + + true + Script variable Python + 50f68354-3c25-4a84-a5f7-ddaf267be516 + trajectory + trajectory + true + 0 + true + e9d20ac9-0dbc-44cb-9f48-878ae446678f + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 1556 + 675 + 53 + 24 + + + 1584 + 687 + + + + + + + + Script output configs. + a4b043bc-8e30-4b4c-bb40-e7f42497696d + configs + configs + false + 0 + + + + + + 1639 + 675 + 45 + 24 + + + 1661.5 + 687 + + + + + + + + + + + + + + 8ec86459-bf01-4409-baee-174d0d2b13d0 + Data + + + + + Contains a collection of generic data + a38644b3-ef3b-4bc2-bf1d-8843907a4a1f + Data + Pickup config + false + 02bc89eb-6961-419b-a5c7-ecf1d7beb296 + 1 + 2 + + + + + + 1473 + 652 + 50 + 24 + + + 1498.681 + 664.9339 + + + + + + + + + + 8ec86459-bf01-4409-baee-174d0d2b13d0 + Data + + + + + Contains a collection of generic data + e9d20ac9-0dbc-44cb-9f48-878ae446678f + Data + Trajectory + false + bcf27a28-24e5-4d31-8438-444d7fe511cb + 1 + 2 + + + + + + 1474 + 676 + 50 + 24 + + + 1499.197 + 688.2636 + + + + + + + + + + 8ec86459-bf01-4409-baee-174d0d2b13d0 + Data + + + + + Contains a collection of generic data + 619d4216-bdfd-4395-b679-83b02e397c53 + Data + Robot + false + 4e66fe1b-29b3-4955-9524-ca986decd9ac + 1 + 2 + + + + + + 1474 + 628 + 50 + 24 + + + 1499.035 + 640.0879 + + + + + + + + + + c552a431-af5b-46a9-a8a4-0fcbc27ef596 + Group + + + + + 1 + + 150;240;218;146 + + A group of Grasshopper objects + ba94b074-3f68-4274-8b84-f87aa5c4cb3e + 01b0a494-be40-47b6-bdc4-7c92967b9f38 + 55db7485-e593-4762-a166-64303d976c7a + 97392278-c93e-4240-86e9-5e59dc2eb992 + 4a09e38e-e49b-43a1-809e-f310b5a4c3e2 + 1f8b3c58-8382-468d-8885-a179a0ad05e0 + 538c02c6-6b3b-4712-a784-dda0bc63f847 + c666c109-2ccb-4c50-90cd-00130af76eaa + 13b3eb29-3c6d-41ba-80fe-d6214ebc9674 + 9d4e5cda-5bb7-42fe-acfa-968fa6c6c067 + cd76efff-9d02-4eb1-b6dd-080d6a0e6d4d + bcf27a28-24e5-4d31-8438-444d7fe511cb + d93333c1-6121-4133-94e5-b1cdbd79792d + 8a1cd44e-8393-4da1-ba94-6a53dd4e3f37 + 54d5165c-c7b9-4b61-a3f4-725adfe6cedb + 15 + 4c3c7466-b1c2-4942-9ac0-63cb70a5b6b7 + Group + + + + + + + + + + + 59e0b89a-e487-49f8-bab8-b5bab16be14c + Panel + + + + + A panel for custom notes and text values + ecc8c71a-07d9-4980-90b1-a3cd2f8081a6 + Panel + + false + 0 + 0 + Define multiple target planes in any way you like, for example, +reference a curve from Rhino, divide it and assign a plane to each point + +Make sure all planes are oriented in a way that makes sense +for the robot to reach it as well. + + + + + + -530 + 485 + 523 + 96 + + 0 + 0 + 0 + + + + + 3 + + 255;255;250;90 + + true + true + true + false + false + true + + + + + Courier New + 8 + + + + + + + + + + + 59e0b89a-e487-49f8-bab8-b5bab16be14c + Panel + + + + + A panel for custom notes and text values + fb166dfc-4abf-4aa5-9ecf-d86922966dfe + Panel + + false + 0 + 0 + Define one pick-up plane in any way you like, +for example, reference a point from Rhino and assign a plane to it. + +Make sure the plane is oriented in a way that makes sense +for the robot to reach it. You can check this by observing the +results of the IK solution for this pickup-plane. + + + + + + -536 + 293 + 529 + 96 + + 0 + 0 + 0 + + -535.2353 + 293.4706 + + + + + + 3 + + 255;255;250;90 + + true + true + true + false + false + true + + + + + Courier New + 8 + + + + + + + + + + + 59e0b89a-e487-49f8-bab8-b5bab16be14c + Panel + + + + + A panel for custom notes and text values + c7cc41e4-23fe-4958-87c2-e75feb10ebac + Panel + + false + 0 + 0 + Load the robot from ROS. + +Make sure ROS/MoveIt is running before you start (ie. "Compose up"). + + + + + + -536 + 124 + 529 + 96 + + 0 + 0 + 0 + + -535.2353 + 124.4706 + + + + + + 3 + + 255;255;250;90 + + true + true + true + false + false + true + + + + + Courier New + 8 + + + + + + + + + + + 59e0b89a-e487-49f8-bab8-b5bab16be14c + Panel + + + + + A panel for custom notes and text values + 3f032319-94be-407d-8e0f-7615f6976834 + Panel + + false + 0 + 0 + Use inverse kinematics of the robot to find +a feasible configuration to reach the pickup plane. + +You can use the COMPAS FAB component or +code it in a GHPython component. + + + + + + -530 + 680 + 523 + 96 + + 0 + 0 + 0 + + -529.5882 + 680.8822 + + + + + + 3 + + 255;255;250;90 + + true + true + true + false + false + true + + + + + Courier New + 8 + + + + + + + + + + + 59e0b89a-e487-49f8-bab8-b5bab16be14c + Panel + + + + + A panel for custom notes and text values + 1f02a236-cf56-4437-8d21-1243b22a7b8e + Panel + + false + 0 + 0 + With the pickup config and a list of target planes, you are ready to compute the solution trajectory for each plane. + +First create a constraint from the selected plane, then use the plan free-space motion to calculate a trajectory. + + + + + + -530 + 942 + 523 + 96 + + 0 + 0 + 0 + + -529.353 + 942.6469 + + + + + + 3 + + 255;255;250;90 + + true + true + true + false + false + true + + + + + Courier New + 8 + + + + + + + + + + + 410755b1-224a-4c1e-a407-bf32fb45ea7e + 00000000-0000-0000-0000-000000000000 + ROS Connect + + + + + """ +Connect or disconnect to ROS. + +COMPAS FAB v0.27.0 +""" +from ghpythonlib.componentbase import executingcomponent as component +from scriptcontext import sticky as st + +from compas_fab.backends import RosClient +from compas_fab.ghpython.components import create_id + + +class ROSConnect(component): + def RunScript(self, ip, port, connect): + ros_client = None + + ip = ip or '127.0.0.1' + port = port or 9090 + + key = create_id(self, 'ros_client') + ros_client = st.get(key, None) + + if ros_client: + st[key].close() + if connect: + st[key] = RosClient(ip, port) + st[key].run(5) + + ros_client = st.get(key, None) + is_connected = ros_client.is_connected if ros_client else False + return (ros_client, is_connected) + + Connect or disconnect to ROS. +COMPAS FAB v0.27.0 + true + true + 2 + + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDwAACw8BkvkDpQAAAdZJREFUSEu1lD2O4kAQRrkBcwP2BnADfARuABEhcAMcEEyCQKuVCCEkY27A3ADCyUAimQyHm/V+r9bNNp5iSLwtPWF/9dvdZRohhP+KK9aJK9aJK9aJKzpk4k08W4XYiB/CYquJPJbX6zVMp9PQbrcV0XhIt9sN6/VaIVZoQLyXMGVC8piYXwp5jMfj0Gq1zK/f7yvUVsdLGnkRBV0RlHT2/g2WHH+KonmJI4PD4ZA6HwVFPd9IR1hTzWZTj76Tcjay1Wr1QWIKnE6n0Ov17DnhXeSiWnTJbvHZ7/d3BkNrg3E2m/2OBbiH4XCITkLg+YhNnMVtakRuib0CWgMMYlMUxetutzPH8vwZ00f+HB8auznHe6CxagDdnMt3ztPOkunAWYsiPcF3YYxGo19ZloXtdvtT78d4b9yDVpEmf8Eg8qiJt7gLCi0WC9v2IxjV6Mu9aU3SAh2MYhI1wZaPBMcZfwadl8n5oqX8Sya7OZkhgSJoge1Xu04pE/Ot3E4hTUQBmyDB+d7ZBIU4f4INBmE+n3/meR4ul8tS2pe4+5e/91CURRjH7BuYIIYCX/vf8fgqaKYFHxEvz6CZh8nBFUGLQl7nN7y4Kq5YJ65YJ65YJ65YH6HxB7b14P1B22tpAAAAAElFTkSuQmCC + + false + 5d051c72-528a-498d-a91b-f91e344562b4 + true + true + ROS Connect + ROS + + + + + + 329 + 114 + 153 + 64 + + + 392 + 146 + + + + + + 3 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 2 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + + + + + true + The ip address ROS. Defaults to 127.0.0.1. + 9f8ec376-61c8-4a5a-9978-8260b3433971 + ip + ip + true + 0 + true + 0 + 37261734-eec7-4f50-b6a8-b8d1f3c4396b + + + + + + 331 + 116 + 46 + 20 + + + 355.5 + 126 + + + + + + + + true + The port of ROS. Defaults to 9090. + 606cb857-159f-4994-b643-f4573ca19d5f + port + port + true + 0 + true + 0 + 48d01794-d3d8-4aef-990e-127168822244 + + + + + + 331 + 136 + 46 + 20 + + + 355.5 + 146 + + + + + + + + true + If True, connects to ROS. If False, disconnects from ROS. Defaults to False. + f3e97277-64e0-4595-adcd-93143d53f341 + connect + connect + true + 0 + true + f9dd4743-5ef1-4938-a2ce-b61e2f89ff71 + 1 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 331 + 156 + 46 + 20 + + + 355.5 + 166 + + + + + + + + The ROS client. + 1c3a0665-a31f-4f6b-a343-89073c77e7a7 + ros_client + ros_client + false + 0 + + + + + + 407 + 116 + 73 + 30 + + + 443.5 + 131 + + + + + + + + True if connection established. + 17ce31a9-caeb-4613-ab0b-fb88664811c6 + is_connected + is_connected + false + 0 + + + + + + 407 + 146 + 73 + 30 + + + 443.5 + 161 + + + + + + + + + + + + + + 2e78987b-9dfb-42a2-8b76-3923ac8bd91a + Boolean Toggle + + + + + Boolean (true/false) toggle + f9dd4743-5ef1-4938-a2ce-b61e2f89ff71 + Boolean Toggle + Toggle + false + 0 + true + + + + + + 106 + 163 + 104 + 22 + + + + + + + + + + 410755b1-224a-4c1e-a407-bf32fb45ea7e + 00000000-0000-0000-0000-000000000000 + ROS Robot + + + + + """ +Load robot directly from ROS. + +COMPAS FAB v0.27.0 +""" +from compas_ghpython.artists import RobotModelArtist +from ghpythonlib.componentbase import executingcomponent as component +from scriptcontext import sticky as st + +from compas_fab.ghpython.components import create_id + + +class ROSRobot(component): + def RunScript(self, ros_client, load): + key = create_id(self, 'robot') + + if ros_client and ros_client.is_connected and load: + # Load URDF from ROS + st[key] = ros_client.load_robot(load_geometry=True, precision='12f') + st[key].artist = RobotModelArtist(st[key].model) + + robot = st.get(key, None) + if robot: # client sometimes need to be restarted, without needing to reload geometry + robot.client = ros_client + return robot + + Load robot directly from ROS. +COMPAS FAB v0.27.0 + true + true + 2 + + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDwAACw8BkvkDpQAAAVtJREFUSEu9lMFRwzAQRVMCJaSElJASUgIlUAGTEhguXHPinBJSAiWkBDow/9n6ZmWtQzwYduaNpdVqtf5redN13Z+SOtckdS5B9iCeeKbrmXMJsrNg8CkOzXo1Gao5iYtg4z6uR2SP4iqY+Ans3Y5xk00sTjfsBcmOgbjOmMK2wvs/mgNKQL8o3sRzmb8Iy5BRySLbifHNpwsM3gWHvJY5ByAb44xKRtkoTz+vJkNiBn7CQXAIr29oqNd7OWTIhHxMrmNOD0oQb2EdSYL2VUUlDjlJ5kKQMDa8lahsdEPdNFfUHFLiiYsNJ766D9WG3lHLYy7TOCOjEArLi2gcQ7ATR2bvxC1yZ/7VjI1bQu4cXjt+KeaYxd8idQLJQmLDoelPbY7UaWTxCzGnLHaO1Glkv2546xhubUz2E8i2m+YxreP7Ji9htvmt4x8O4Ffhn9q93C/R2qTO9eg2XxfZxOCoCLXEAAAAAElFTkSuQmCC + + false + baea3a7f-42ad-4480-b62c-39cd2f8c2e8a + true + true + ROS Robot + Robot + + + + + + 525 + 137 + 124 + 44 + + + 595 + 159 + + + + + + 2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 1 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + + + + + true + The ROS client. + f7ba96f4-94e2-4197-b4a3-31f6a0ca2f34 + ros_client + ros_client + true + 0 + true + 1c3a0665-a31f-4f6b-a343-89073c77e7a7 + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 527 + 139 + 53 + 20 + + + 555 + 149 + + + + + + + + true + If True, loads the robot from ROS. Defaults to False. + e89e10b5-2ece-44bd-87f9-1811ce89ed0b + load + load + true + 0 + true + f9dd4743-5ef1-4938-a2ce-b61e2f89ff71 + 1 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 527 + 159 + 53 + 20 + + + 555 + 169 + + + + + + + + The robot. + 846547a4-0964-4bea-b2e5-d3fd03e0ff69 + robot + robot + false + 0 + + + + + + 610 + 139 + 37 + 40 + + + 628.5 + 159 + + + + + + + + + + + + + + 410755b1-224a-4c1e-a407-bf32fb45ea7e + 00000000-0000-0000-0000-000000000000 + Inverse Kinematics + + + + + """ +Calculate the robot's inverse kinematic for a given plane. + +COMPAS FAB v0.27.0 +""" +from compas_rhino.conversions import RhinoPlane +from ghpythonlib.componentbase import executingcomponent as component + + +class InverseKinematics(component): + def RunScript(self, robot, plane, start_configuration, group): + configuration = None + if robot and robot.client and robot.client.is_connected and plane: + frame = RhinoPlane.from_geometry(plane).to_compas_frame() + configuration = robot.inverse_kinematics(frame, start_configuration, group) + return configuration + + Calculate the robot's inverse kinematic for a given plane. +COMPAS FAB v0.27.0 + true + true + 2 + + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDwAACw8BkvkDpQAAAYFJREFUSEu1lLFxwzAMRVWn8gApNIKKDOAubbqk1AgeQRP4NIJG0AgqMoCq1BpBGzD/ywANkbAt3dm4eyfwkwBEElIRQngprvhMXHEL7+ff0tNTXFFBkhqMIAgz6MG3+AcvzuKKDJRETDqBFjSgE005efEWV0QgEzJBl+gs/CdzZLTzHpmAoEqCe9VgNWjePj5/oHMn3B13xnV37yITJEEMhH0BOsrqWLBuuQfYEVR2btFTAQEDmHQMawCdyTyZzCYeAAeEfrz8VXKC5Mv2dQzrJFALWDyNtDFeHQXJ0yOybzcD3scJWJ3YnQyazytQSoHlkmG6Az5XfQ9jMTosbIveLkCQnG2qBRg8p2tk7iDzHFhiI2RBFpi+YWzZFFgFRlnHYs1q3g5SYL0E1t78FlyRwLh9OiTr76344iW5Xq57/lvJhaIogZ6psunX7JEL11azH1H8cPaSC9fE/EW04se+3ksu5MdDbrbpI3Lh0tf246H/ki7iv+Xoze/BFZ9HKP4BuwtzfPsUblIAAAAASUVORK5CYII= + + false + df49cbca-ec61-4dc7-8c55-18e7e63a3700 + true + true + Inverse Kinematics + IK + + + + + + 504 + 704 + 207 + 84 + + + 619 + 746 + + + + + + 4 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 1 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + + + + + true + The robot. + 249e3fc8-1590-4989-8d02-71555d17803d + robot + robot + true + 0 + true + 846547a4-0964-4bea-b2e5-d3fd03e0ff69 + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + 2 + + + + + + 506 + 706 + 98 + 20 + + + 556.5 + 716 + + + + + + + + true + The plane or frame to calculate the inverse kinematic for. + 7f79fc84-f4dc-442f-b7ec-2c6ef6d32d53 + plane + plane + true + 0 + true + b96209a7-93e4-4212-b096-c83e82b4da7b + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 506 + 726 + 98 + 20 + + + 556.5 + 736 + + + + + + + + true + If passed, calculates the inverse such that the joint positions differ the least from the start_configuration. Defaults to the zero configuration. + 8aab3d36-825a-4b59-a5df-f5a5a92c336a + start_configuration + start_configuration + true + 0 + true + 0 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 506 + 746 + 98 + 20 + + + 556.5 + 756 + + + + + + + + true + The planning group used for calculation. Defaults to the robot's main planning group. + fd831072-ab33-48dd-88f3-f5635811e6b2 + group + group + true + 0 + true + 0 + 37261734-eec7-4f50-b6a8-b8d1f3c4396b + + + + + + 506 + 766 + 98 + 20 + + + 556.5 + 776 + + + + + + + + The planning group's configuration. + 1d8af690-69c5-4c9f-b553-1a05f97e8281 + configuration + configuration + false + 0 + + + + + + 634 + 706 + 75 + 80 + + + 671.5 + 746 + + + + + + + + + + + + + + fbac3e32-f100-4292-8692-77240a42fd1a + Point + + + + + Contains a collection of three-dimensional points + 13d747bd-3e05-4a41-8ea0-75bad3d5248b + Point + Pt + false + 0 + + + + + + 351 + 300 + 50 + 24 + + + 376.125 + 312 + + + + + + 1 + + + + + 1 + {0} + + + + + + + 0.367606789217143 + 0.00801042536875041 + -0.0177049653487109 + + + + + + + + + + + + + + cfb6b17f-ca82-4f5d-b604-d4f69f569de3 + Plane Normal + + + + + Create a plane perpendicular to a vector. + dd675efd-9233-4ad4-bb47-4b8f4932cc90 + Plane Normal + Pl + + + + + + 444 + 300 + 65 + 44 + + + 476 + 322 + + + + + + Origin of plane + a4967eb6-ce45-4b5a-a8bb-b57de9bc5816 + Origin + O + false + 13d747bd-3e05-4a41-8ea0-75bad3d5248b + 1 + + + + + + 446 + 302 + 15 + 20 + + + 455 + 312 + + + + + + 1 + + + + + 1 + {0} + + + + + + + 0 + 0 + 0 + + + + + + + + + + + + Z-Axis direction of plane + 6f2ccb4f-ad90-40cb-aa81-912ca1f36990 + Z-Axis + Z + false + 1f4c1d7b-92ac-410e-b8cf-de51d8691d13 + 1 + + + + + + 446 + 322 + 15 + 20 + + + 455 + 332 + + + + + + 1 + + + + + 1 + {0} + + + + + + 0 + 0 + 1 + + + + + + + + + + + + Plane definition + 3a86f18b-7506-4d48-8a5c-6048a1108886 + Plane + P + false + 0 + + + + + + 491 + 302 + 16 + 40 + + + 499 + 322 + + + + + + + + + + + + 9103c240-a6a9-4223-9b42-dbd19bf38e2b + Unit Z + + + + + Unit vector parallel to the world {z} axis. + 68575641-3532-400d-95f0-a0242e51e625 + Unit Z + Z + + + + + + 230 + 332 + 63 + 28 + + + 259 + 346 + + + + + + Unit multiplication + 1ec380b2-779c-4e5e-b32f-e1e05e1eaa2d + Factor + F + false + 0 + + + + + + 232 + 334 + 12 + 24 + + + 239.5 + 346 + + + + + + 1 + + + + + 1 + {0} + + + + + 1 + + + + + + + + + + + World {z} vector + 351348f7-2844-4518-aa54-7e8529b995cf + Unit vector + V + false + 0 + + + + + + 274 + 334 + 17 + 24 + + + 282.5 + 346 + + + + + + + + + + + + a3371040-e552-4bc8-b0ff-10a840258e88 + Negative + + + + + Compute the negative of a value. + eb5acce9-f665-4261-a8bc-ffd4947a64da + Negative + Neg + + + + + + 346 + 332 + 61 + 28 + + + 375 + 346 + + + + + + Input value + 28852126-05f6-43ae-8988-6d8909c2ffdf + Value + x + false + 351348f7-2844-4518-aa54-7e8529b995cf + 1 + + + + + + 348 + 334 + 12 + 24 + + + 355.5 + 346 + + + + + + + + Output value + 1f4c1d7b-92ac-410e-b8cf-de51d8691d13 + Result + y + false + 0 + + + + + + 390 + 334 + 15 + 24 + + + 397.5 + 346 + + + + + + + + + + + + d5967b9f-e8ee-436b-a8ad-29fdcecf32d5 + Curve + + + + + Contains a collection of generic curves + b171143f-e5e1-4bc8-92f7-eb329037f691 + Curve + Crv + false + 0 + + + + + + 205 + 462 + 50 + 24 + + + 230.4504 + 474.1136 + + + + + + 1 + + + + + 1 + {0} + + + + + -1 + + Y2BkYGD4DwQgGgR4mIBEWFBGZl6+c35ubn6ejkJYalFxZn6erbmekYWekbGBqYWesYGBoY6Cc2lOSWlRqm1eamlJUWKOjkJAaVJOZrJ3amVIfnZqnq2pqZGRhWGqpXmyuampqbEBK8gSSbDZeu6p+bmpJUWVen6lRUnFzqVFZaksQFn2MohlXIlFyRmZZanGKbmc+QWpeXkgVSwpiSWJIEUcHBxMIHcKqDMwGAFp18d8PJzMQAY/iPAEWsP0q56JwRbqqd//mRhEoP6TFFwfF8h9RXD/PwaBZkalD15SleJ/gPKsULUCzFCFINewMqCDD/YYQhDx/egi7NgVgkGgwhnRojUcDhBaAoMG2VudHp9fM/OtPbP+GT3ez8v379ipWnH0eO/+c/YXhM/8emb/5Nw7jz0aF+DiehsmX/r18rH9lReaJ47832kPE1e7vOXRU9979ovWC2xj47gGF/93lMNl3tMj9uKct19ttb4MF682mRz/v56pAeZWbjz+GAWjgIEBAA== + + 00000000-0000-0000-0000-000000000000 + + + + + + + + + + + + + 2162e72e-72fc-4bf8-9459-d4d82fa8aa14 + Divide Curve + + + + + Divide a curve into equal length segments + true + 37fef6aa-0c60-4da4-9d31-1ae0bdd95cd2 + Divide Curve + Divide + + + + + + 293 + 443 + 65 + 64 + + + 325 + 475 + + + + + + Curve to divide + 17b7b741-c039-457b-bc69-9a5f2f8e5819 + Curve + C + false + b171143f-e5e1-4bc8-92f7-eb329037f691 + 1 + + + + + + 295 + 445 + 15 + 20 + + + 304 + 455 + + + + + + + + Number of segments + c4252d68-c3f0-4449-bc33-3963a1f5b379 + Count + N + false + 0 + + + + + + 295 + 465 + 15 + 20 + + + 304 + 475 + + + + + + 1 + + + + + 1 + {0} + + + + + 10 + + + + + + + + + + + Split segments at kinks + c67cd2ce-aeaf-48f1-b87d-ae648d16cb78 + Kinks + K + false + 0 + + + + + + 295 + 485 + 15 + 20 + + + 304 + 495 + + + + + + 1 + + + + + 1 + {0} + + + + + false + + + + + + + + + + + 1 + Division points + 02d756d0-695e-4b84-977a-5211a88fe540 + Points + P + false + 0 + + + + + + 340 + 445 + 16 + 20 + + + 348 + 455 + + + + + + + + 1 + Tangent vectors at division points + ff7cd25b-7346-40cf-93bd-b862456b2fad + Tangents + T + false + 0 + + + + + + 340 + 465 + 16 + 20 + + + 348 + 475 + + + + + + + + 1 + Parameter values at division points + 9f8a284b-b097-43d8-8703-768571059955 + Parameters + t + false + 0 + + + + + + 340 + 485 + 16 + 20 + + + 348 + 495 + + + + + + + + + + + + 2a5cfb31-028a-4b34-b4e1-9b20ae15312e + Cross Product + + + + + Compute vector cross product. + d6cabb95-93fe-48fe-9b1b-2070fdd10e56 + Cross Product + XProd + + + + + + 423 + 478 + 66 + 64 + + + 455 + 510 + + + + + + First vector + 7677fda3-a48e-4b19-9a38-3848beb2729e + Vector A + A + false + ff7cd25b-7346-40cf-93bd-b862456b2fad + 1 + + + + + + 425 + 480 + 15 + 20 + + + 434 + 490 + + + + + + + + Second vector + ab1ebaa3-5740-431c-8fc9-a779c8b99336 + Vector B + B + false + 351348f7-2844-4518-aa54-7e8529b995cf + 1 + + + + + + 425 + 500 + 15 + 20 + + + 434 + 510 + + + + + + + + Unitize output + 45f1c846-268d-49fd-a50d-dcd25e91cccc + Unitize + U + false + 0 + + + + + + 425 + 520 + 15 + 20 + + + 434 + 530 + + + + + + 1 + + + + + 1 + {0} + + + + + false + + + + + + + + + + + Cross product vector + 633bc054-2115-4c2b-8be8-c286377bce3d + Vector + V + false + 0 + + + + + + 470 + 480 + 17 + 30 + + + 478.5 + 495 + + + + + + + + Vector length + 8243a1a9-6216-4bc2-93b0-d7d17da9a8c7 + Length + L + false + 0 + + + + + + 470 + 510 + 17 + 30 + + + 478.5 + 525 + + + + + + + + + + + + bc3e379e-7206-4e7b-b63a-ff61f4b38a3e + Construct Plane + + + + + Construct a plane from an origin point and {x}, {y} axes. + true + 3974a64b-9fea-4aa6-a9ad-21315ef8260a + Construct Plane + Pl + + + + + + 527 + 443 + 68 + 64 + + + 559 + 475 + + + + + + Origin of plane + ada5ea08-627b-4ef2-9244-2c11db2d896f + Origin + O + false + 02d756d0-695e-4b84-977a-5211a88fe540 + 1 + + + + + + 529 + 445 + 15 + 20 + + + 538 + 455 + + + + + + 1 + + + + + 1 + {0} + + + + + + + 0 + 0 + 0 + + + + + + + + + + + + X-Axis direction of plane + 07101ef1-80e2-4825-a3da-9039e03fb50f + X-Axis + X + false + ff7cd25b-7346-40cf-93bd-b862456b2fad + 1 + + + + + + 529 + 465 + 15 + 20 + + + 538 + 475 + + + + + + 1 + + + + + 1 + {0} + + + + + + 1 + 0 + 0 + + + + + + + + + + + + Y-Axis direction of plane + c37c73c0-ad8c-442c-941a-484cdb43364c + Y-Axis + Y + false + 633bc054-2115-4c2b-8be8-c286377bce3d + 1 + + + + + + 529 + 485 + 15 + 20 + + + 538 + 495 + + + + + + 1 + + + + + 1 + {0} + + + + + + 0 + 1 + 0 + + + + + + + + + + + + Constructed plane + 44d4a187-3a93-413f-992e-d4cc7e2e19ad + Plane + Pl + false + 0 + + + + + + 574 + 445 + 19 + 60 + + + 583.5 + 475 + + + + + + + + + + + + 410755b1-224a-4c1e-a407-bf32fb45ea7e + 00000000-0000-0000-0000-000000000000 + Inverse Kinematics + + + + + """ +Calculate the robot's inverse kinematic for a given plane. + +COMPAS FAB v0.27.0 +""" +from compas_rhino.conversions import RhinoPlane +from ghpythonlib.componentbase import executingcomponent as component + + +class InverseKinematics(component): + def RunScript(self, robot, plane, start_configuration, group): + configuration = None + if robot and robot.client and robot.client.is_connected and plane: + frame = RhinoPlane.from_geometry(plane).to_compas_frame() + configuration = robot.inverse_kinematics(frame, start_configuration, group) + return configuration + + Calculate the robot's inverse kinematic for a given plane. +COMPAS FAB v0.27.0 + true + true + 2 + + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDgAACw4BQL7hQQAAAYFJREFUSEu1lLFxwzAMRVWn8gApNIKKDOAubbqk1AgeQRP4NIJG0AgqMoCq1BpBGzD/ywANkbAt3dm4eyfwkwBEElIRQngprvhMXHEL7+ff0tNTXFFBkhqMIAgz6MG3+AcvzuKKDJRETDqBFjSgE005efEWV0QgEzJBl+gs/CdzZLTzHpmAoEqCe9VgNWjePj5/oHMn3B13xnV37yITJEEMhH0BOsrqWLBuuQfYEVR2btFTAQEDmHQMawCdyTyZzCYeAAeEfrz8VXKC5Mv2dQzrJFALWDyNtDFeHQXJ0yOybzcD3scJWJ3YnQyazytQSoHlkmG6Az5XfQ9jMTosbIveLkCQnG2qBRg8p2tk7iDzHFhiI2RBFpi+YWzZFFgFRlnHYs1q3g5SYL0E1t78FlyRwLh9OiTr76344iW5Xq57/lvJhaIogZ6psunX7JEL11azH1H8cPaSC9fE/EW04se+3ksu5MdDbrbpI3Lh0tf246H/ki7iv+Xoze/BFZ9HKP4BuwtzfPsUblIAAAAASUVORK5CYII= + + false + 0bd900d0-2016-4c53-af3b-1c52cf194064 + true + true + Inverse Kinematics + IK + + + + + + 652 + 287 + 207 + 84 + + + 767 + 329 + + + + + + 4 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 1 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + + + + + true + The robot. + a98f5131-0055-48d7-a0c2-fe32212117c6 + robot + robot + true + 0 + true + 846547a4-0964-4bea-b2e5-d3fd03e0ff69 + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + 2 + + + + + + 654 + 289 + 98 + 20 + + + 704.5 + 299 + + + + + + + + true + The plane or frame to calculate the inverse kinematic for. + 84d72e79-136b-457e-8f5b-27843e5bf7b3 + plane + plane + true + 0 + true + 3a86f18b-7506-4d48-8a5c-6048a1108886 + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 654 + 309 + 98 + 20 + + + 704.5 + 319 + + + + + + + + true + If passed, calculates the inverse such that the joint positions differ the least from the start_configuration. Defaults to the zero configuration. + 1682b475-974e-4465-847b-6f521d231a4b + start_configuration + start_configuration + true + 0 + true + 0 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 654 + 329 + 98 + 20 + + + 704.5 + 339 + + + + + + + + true + The planning group used for calculation. Defaults to the robot's main planning group. + 9da8c8d9-ac45-43a1-8553-97c0c52b171a + group + group + true + 0 + true + 0 + 37261734-eec7-4f50-b6a8-b8d1f3c4396b + + + + + + 654 + 349 + 98 + 20 + + + 704.5 + 359 + + + + + + + + The planning group's configuration. + ac00155a-4a35-4e0d-98f3-e0b82a464386 + configuration + configuration + false + 0 + + + + + + 782 + 289 + 75 + 80 + + + 819.5 + 329 + + + + + + + + + + + + + + 410755b1-224a-4c1e-a407-bf32fb45ea7e + 00000000-0000-0000-0000-000000000000 + Constraints From Plane + + + + + """ +Create a position and an orientation constraint from a plane calculated for the group's end-effector link. + +COMPAS FAB v0.27.0 +""" +import math + +from compas_rhino.conversions import RhinoPlane +from ghpythonlib.componentbase import executingcomponent as component + + +class ConstraintsFromPlane(component): + def RunScript(self, robot, plane, group, tolerance_position, tolerance_xaxis, tolerance_yaxis, tolerance_zaxis): + goal_constraints = None + if robot and plane: + tolerance_position = tolerance_position or 0.001 + tolerance_xaxis = tolerance_xaxis or 1. + tolerance_yaxis = tolerance_yaxis or 1. + tolerance_zaxis = tolerance_zaxis or 1. + + frame = RhinoPlane.from_geometry(plane).to_compas_frame() + tolerances_axes = [math.radians(tolerance_xaxis), math.radians(tolerance_yaxis), math.radians(tolerance_zaxis)] + goal_constraints = robot.constraints_from_frame(frame, tolerance_position, tolerances_axes, group) + + return goal_constraints + + Create a position and an orientation constraint from a plane calculated for the group's end-effector link. +COMPAS FAB v0.27.0 + true + true + 2 + + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDgAACw4BQL7hQQAAAd9JREFUSEu1lTFLw0AYho92ENShVFHE1p4ILipkcBXqDxA6OQfHThn8ARk7OBQdXfIPzOyUwUFwKfgHSifBJU7idL7f9S7ctV+bVHB4yN17+Z4vuZxVKKX+FTacRYjnBpdXgQ1dIJdgyK1VgQ1dIA/BiFurAhu6QJ4CDP62TWzoAnFuGvS49TLY0AJpYOREwt1TBhtaII2cBmPunjLY0AJp5jQgJHffMtjQBdIYZNxaFdjQZVmDo44MwdLmbEi8CNGl66Z4GqzV0zcai0fRBcVxhTwGGM7XW9gQ8hAoMLhpXXyLIFYQJ2ACRvKk3Yd4RHJDDhIw9428CeHILUnzTvQhzoHaudqeSqWc4Jrp8VRuGwWur0xORBA3wNfG7bqWU5P6fe398PhgQHOqxbVrGng/K4vkOUhNpl8bDXqds9Zn57T9U3uo0Zaprevmh21AYBzRHBR/9VbeAxmIgPeKBAro6fQHBa9oNNy73E3b5/u6gVkj9BsB2rqYaj3RIkyx3p5VoFpWuAgU0R4X5x5j75hiTG9K8shmRXEVUDg0gtDMZxvYo6u/G+EJykBhA4yNhOS2IT25lRdPT3iCKkAggT3/LrR9npzwJqsAWQBsI/pNYv/jzQWrAKk+vtzaFCV+ASnZhhTkLZwXAAAAAElFTkSuQmCC + + false + d93333c1-6121-4133-94e5-b1cdbd79792d + true + true + Constraints From Plane + Constraints From Plane + + + + + + 501 + 973 + 193 + 144 + + + 614 + 1045 + + + + + + 7 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 1 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + + + + + true + The robot. + cbf6a458-85d1-42a7-94f7-416fdfa1b2f0 + robot + robot + true + 0 + true + 538c02c6-6b3b-4712-a784-dda0bc63f847 + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + 2 + + + + + + 503 + 975 + 96 + 20 + + + 552.5 + 985 + + + + + + + + true + The plane or frame from which we create position and orientation constraints. + 87942239-75a1-43f9-98a8-39af07ed3dbf + plane + plane + true + 0 + true + 1b843cc6-0c2b-4427-85b3-c5303911f7e9 + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 503 + 995 + 96 + 20 + + + 552.5 + 1005 + + + + + + + + true + The planning group for which we specify the constraint. Defaults to the robot's main planning group. + 5f458976-1a25-4cf2-bb59-977ecaa69acf + group + group + true + 0 + true + 0 + 37261734-eec7-4f50-b6a8-b8d1f3c4396b + + + + + + 503 + 1015 + 96 + 20 + + + 552.5 + 1025 + + + + + + + + true + The allowed tolerance to the frame's position (defined in the robot's units). Defaults to 0.001 + f4df44e0-61e9-4a9c-adc5-322c77ee723c + tolerance_position + tolerance_position + true + 0 + true + 0 + 39fbc626-7a01-46ab-a18e-ec1c0c41685b + + + + + + 503 + 1035 + 96 + 20 + + + 552.5 + 1045 + + + + + + + + true + The allowed tolerance of the frame's X-axis in degrees. + 38431b6b-d582-43ce-b820-9189820976ff + tolerance_xaxis + tolerance_xaxis + true + 0 + true + 0 + 39fbc626-7a01-46ab-a18e-ec1c0c41685b + + + + + + 503 + 1055 + 96 + 20 + + + 552.5 + 1065 + + + + + + + + true + The allowed tolerance of the frame's Y-axis in degrees. + 27304578-70c5-46fe-966d-55f6d2a284f3 + tolerance_yaxis + tolerance_yaxis + true + 0 + true + 0 + 39fbc626-7a01-46ab-a18e-ec1c0c41685b + + + + + + 503 + 1075 + 96 + 20 + + + 552.5 + 1085 + + + + + + + + true + The allowed tolerance of the frame's Z-axis in degrees. + 745b4728-c179-4f50-ad5c-43f1ca9fb8f8 + tolerance_zaxis + tolerance_zaxis + true + 0 + true + 0 + 39fbc626-7a01-46ab-a18e-ec1c0c41685b + + + + + + 503 + 1095 + 96 + 20 + + + 552.5 + 1105 + + + + + + + + A list containing a position and an orientation constraint. + 1a96f4f6-fa5c-4bec-8121-df8feb673fae + constraints + constraints + false + 0 + + + + + + 629 + 975 + 63 + 140 + + + 660.5 + 1045 + + + + + + + + + + + + + + 59daf374-bc21-4a5e-8282-5504fb7ae9ae + List Item + + + + + 0 + Retrieve a specific item from a list. + 8a1cd44e-8393-4da1-ba94-6a53dd4e3f37 + List Item + Item + + + + + + 240 + 988 + 64 + 64 + + + 274 + 1020 + + + + + + 3 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + 2e3ab970-8545-46bb-836c-1c11e5610bce + cb95db89-6165-43b6-9c41-5702bc5bf137 + 1 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + + + + + 1 + Base list + 5adfeb6c-e7f6-49be-a873-3d13194ccef5 + List + L + false + 55db7485-e593-4762-a166-64303d976c7a + 1 + + + + + + 242 + 990 + 17 + 20 + + + 252 + 1000 + + + + + + + + Item index + 3c505437-9eea-46c1-ab35-c8afc8032305 + Index + i + false + 0 + + + + + + 242 + 1010 + 17 + 20 + + + 252 + 1020 + + + + + + 1 + + + + + 1 + {0} + + + + + 0 + + + + + + + + + + + Wrap index to list bounds + 578930d2-94b0-4edd-8d4a-cd8a25689009 + Wrap + W + false + 0 + + + + + + 242 + 1030 + 17 + 20 + + + 252 + 1040 + + + + + + 1 + + + + + 1 + {0} + + + + + true + + + + + + + + + + + Item at {i'} + 1b843cc6-0c2b-4427-85b3-c5303911f7e9 + false + Item + i + false + 0 + + + + + + 289 + 990 + 13 + 60 + + + 295.5 + 1020 + + + + + + + + + + + + + + 410755b1-224a-4c1e-a407-bf32fb45ea7e + 00000000-0000-0000-0000-000000000000 + Plan Motion + + + + + """ +Calculate a motion path. + +COMPAS FAB v0.27.0 +""" +from ghpythonlib.componentbase import executingcomponent as component +from scriptcontext import sticky as st + +from compas_fab.ghpython.components import create_id + + +class PlanMotion(component): + def RunScript(self, robot, goal_constraints, start_configuration, group, attached_collision_meshes, path_constraints, planner_id, compute): + + key = create_id(self, 'trajectory') + + path_constraints = list(path_constraints) if path_constraints else None + attached_collision_meshes = list(attached_collision_meshes) if attached_collision_meshes else None + planner_id = str(planner_id) if planner_id else 'RRTConnect' + + if robot and robot.client and robot.client.is_connected and start_configuration and goal_constraints and compute: + st[key] = robot.plan_motion(goal_constraints, + start_configuration=start_configuration, + group=group, + options=dict( + attached_collision_meshes=attached_collision_meshes, + path_constraints=path_constraints, + planner_id=planner_id, + )) + + trajectory = st.get(key, None) + return trajectory + + Calculate a motion path. +COMPAS FAB v0.27.0 + true + true + 2 + + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDwAACw8BkvkDpQAAAY1JREFUSEu1lM1tAjEQhSmBDkgJFMCBEnKJuKYESuAQiRoicaADKIEOkgK455icckHK5n3e8WbsHRJAG0sfjOc9478xo6Zp/pUwOSRhckjC5LWojcVWHMRezDvNGz1qM7ETm0j3qL0KAk+a5NyAtTO+iQ3fZ7z3Ins9+6QHAybGpyDBj58sPgb+lWk1h6QHA14EP/gkZpZjEgJ2M6n8U9NqVkn3ZhuQV1ucvdqD4OjWPm9avQvuZJy0wPxuprR6l6dCCN593ul3Yg5Fvui0Z78UC583jTyBuqUGahwjiyt3XnTasiTorVKNydGXtWZ63nm63C5fdP4+hiOaiHZIcRD8OgHHwCTh41ILV2kaY4t7S/kuaC+JaoBHb3IedvAl6grj1RNAsbtsoJY/zJDZeqP58iPkLrr3YH2Ck/cnzQz8QRHUTHsD2h0QpFetxtt4Fhztruc3U77cmqKmzbsQTMJ9+HG9B5j86eOKHZifms8FQSKsrORNHxfewS38BBdU0S2EySEJk0MSJoejGX0DqCUOkgYB1loAAAAASUVORK5CYII= + + false + 54d5165c-c7b9-4b61-a3f4-725adfe6cedb + true + true + Plan Motion + Plan Motion + + + + + + 895 + 884 + 224 + 164 + + + 1046 + 966 + + + + + + 8 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 1 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + + + + + true + The robot. + 3ab0c3a7-74d4-4e20-8d40-f9d959596a64 + robot + robot + true + 0 + true + 538c02c6-6b3b-4712-a784-dda0bc63f847 + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + 2 + + + + + + 897 + 886 + 134 + 20 + + + 965.5 + 896 + + + + + + + + 1 + true + The goal to be achieved, defined in a set of constraints. Constraints can be very specific, for example defining value domains for each joint, such that the goal configuration is included, or defining a volume in space, to which a specific robot link (e.g. the end-effector) is required to move to. + e4550953-1c4d-4196-accf-09e0629aecf8 + goal_constraints + goal_constraints + true + 1 + true + 1a96f4f6-fa5c-4bec-8121-df8feb673fae + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 897 + 906 + 134 + 20 + + + 965.5 + 916 + + + + + + + + true + The robot's full configuration, i.e. values for all configurable joints of the entire robot, at the starting position. Defaults to the all-zero configuration. + 045b29a2-7cdc-4ea7-b8be-65710ec81364 + start_configuration + start_configuration + true + 0 + true + c666c109-2ccb-4c50-90cd-00130af76eaa + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 897 + 926 + 134 + 20 + + + 965.5 + 936 + + + + + + + + true + The planning group used for calculation. Defaults to the robot's main planning group. + bc8ad3dc-fbe4-440a-98c4-151f7e612cbb + group + group + true + 0 + true + 0 + 37261734-eec7-4f50-b6a8-b8d1f3c4396b + + + + + + 897 + 946 + 134 + 20 + + + 965.5 + 956 + + + + + + + + 1 + true + A list of attached collision meshes to be included for planning. + 8ef44a5c-ec14-4d30-9c85-7fed0cea4feb + attached_collision_meshes + attached_collision_meshes + true + 1 + true + 0 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 897 + 966 + 134 + 20 + + + 965.5 + 976 + + + + + + + + 1 + true + Optional constraints that can be imposed along the solution path. Note that path calculation won't work if the start_configuration violates these constraints. Defaults to None. + 79c1632c-fba5-40b8-a628-530ad610655d + path_constraints + path_constraints + true + 1 + true + 0 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 897 + 986 + 134 + 20 + + + 965.5 + 996 + + + + + + + + true + The name of the algorithm used for path planning. Defaults to 'RRTConnect' + 59c97f48-1889-4f3b-b990-cedd3ddf9849 + planner_id + planner_id + true + 0 + true + 0 + 37261734-eec7-4f50-b6a8-b8d1f3c4396b + + + + + + 897 + 1006 + 134 + 20 + + + 965.5 + 1016 + + + + + + + + true + If True, calculates a trajectory. + 2dd1af7b-a420-4d72-8c10-01811c07df29 + compute + compute + true + 0 + true + e8dd8875-225b-4b6d-a8de-4f454ff7d868 + 1 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 897 + 1026 + 134 + 20 + + + 965.5 + 1036 + + + + + + + + The calculated trajectory. + 4e17b2ad-e9af-41eb-b6a5-7585e1f6e333 + trajectory + trajectory + false + 0 + + + + + + 1061 + 886 + 56 + 160 + + + 1089 + 966 + + + + + + + + + + + + + + 2e78987b-9dfb-42a2-8b76-3923ac8bd91a + Boolean Toggle + + + + + Boolean (true/false) toggle + e8dd8875-225b-4b6d-a8de-4f454ff7d868 + Boolean Toggle + Toggle + false + 0 + true + + + + + + 735 + 1033 + 104 + 22 + + + + + + + + + + b83c36e8-c587-4607-a4b3-d9fdad45d185 + 1c9de8a1-315f-4c56-af06-8f69fee80a7a + Flip Plane + + + + + Flip a plane by specified axes with the option of using a guide plane. + 711d6fa3-3862-4211-a255-f8c00962a10d + Flip Plane + FlipPln + + + + + + 701 + 443 + 67 + 104 + + + 734 + 495 + + + + + + Plane to flip + abc3aafd-8660-4da2-b7a9-b9b7e034def6 + Plane + Pl + false + 44d4a187-3a93-413f-992e-d4cc7e2e19ad + 1 + + + + + + 703 + 445 + 16 + 20 + + + 712.5 + 455 + + + + + + + + Optional guide plane to determine if the plane should flip, based on the guide plane axis angle to the axis of plane to flip + 70ee89b8-6d85-4c25-a81f-6e6012e6adde + Guide + G + true + 0 + + + + + + 703 + 465 + 16 + 20 + + + 712.5 + 475 + + + + + + + + Flip the planes X axis + 46e3bfc4-b95f-44bc-908c-be468fd2a325 + Flip X + X + false + 0 + + + + + + 703 + 485 + 16 + 20 + + + 712.5 + 495 + + + + + + 1 + + + + + 1 + {0} + + + + + false + + + + + + + + + + + Flip the planes Y axis + 21e47292-bdcc-4ecc-9890-bf40fedfefdc + Flip Y + Y + false + 0 + + + + + + 703 + 505 + 16 + 20 + + + 712.5 + 515 + + + + + + 1 + + + + + 1 + {0} + + + + + false + + + + + + + + + + + Flip the planes Z axis + 1352c30f-e3c9-4c38-800e-8703728f4f9d + Flip Z + Z + false + 0 + + + + + + 703 + 525 + 16 + 20 + + + 712.5 + 535 + + + + + + 1 + + + + + 1 + {0} + + + + + true + + + + + + + + + + + Resulting flipped plane + a4e35366-aed9-4624-91f1-08abb1a092fd + Flipped + F + false + 0 + + + + + + 749 + 445 + 17 + 50 + + + 757.5 + 470 + + + + + + + + True if plane was flipped, False if plane was not flipped + 4aa67233-ed42-4970-aca1-04b6a9204c9f + Result Boolean + R + false + 0 + + + + + + 749 + 495 + 17 + 50 + + + 757.5 + 520 + + + + + + + + + + + + + + + + + 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 + + + + + \ No newline at end of file diff --git a/lecture_04/assignment_03/assignment_03_Lihin_weera.3dm b/lecture_04/assignment_03/assignment_03_Lihin_weera.3dm new file mode 100644 index 0000000000000000000000000000000000000000..87cbd3112ed6f5fb0aa403490b811999674d7991 GIT binary patch literal 66017 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%0A=<>)~n!G5pdtt&n3V2g7#85lbF)=BF{c> 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