From 1279610f2459b2deb42f783a9640a4fc1056e329 Mon Sep 17 00:00:00 2001 From: Stephen30 <91248027+stephen300105@users.noreply.github.com> Date: Wed, 23 Mar 2022 05:04:07 +0100 Subject: [PATCH 1/2] Ming_Yang, Wang assignment --- lecture_04/assignment_03/assignment-03.json | 1 + lecture_04/assignment_03/assignment_03.py | 76 +++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 lecture_04/assignment_03/assignment-03.json create mode 100644 lecture_04/assignment_03/assignment_03.py diff --git a/lecture_04/assignment_03/assignment-03.json b/lecture_04/assignment_03/assignment-03.json new file mode 100644 index 0000000..869c177 --- /dev/null +++ b/lecture_04/assignment_03/assignment-03.json @@ -0,0 +1 @@ +[{"dtype": "compas.robots/Configuration", "value": {"joint_values": [2.561262720869387, -5.845043360828665, -1.067981152698738, -4.0825497691261345, 1.5707964585802723, 4.132059047869463], "joint_types": [0, 0, 0, 0, 0, 0], "joint_names": ["shoulder_pan_joint", "shoulder_lift_joint", "elbow_joint", "wrist_1_joint", "wrist_2_joint", "wrist_3_joint"]}}, {"dtype": "compas.robots/Configuration", "value": {"joint_values": [2.212580402338498, -5.6890812488180975, -1.4328564192444617, -3.87363666067149, 1.5707964587832621, 3.7833767293385714], "joint_types": [0, 0, 0, 0, 0, 0], "joint_names": ["shoulder_pan_joint", "shoulder_lift_joint", "elbow_joint", "wrist_1_joint", "wrist_2_joint", "wrist_3_joint"]}}, {"dtype": "compas.robots/Configuration", "value": {"joint_values": [1.8257972591896752, -5.625716027297366, -1.5888987135132564, -3.780959638934701, 1.5707964423990544, 3.3965935861897454], "joint_types": [0, 0, 0, 0, 0, 0], "joint_names": ["shoulder_pan_joint", "shoulder_lift_joint", "elbow_joint", "wrist_1_joint", "wrist_2_joint", "wrist_3_joint"]}}, {"dtype": "compas.robots/Configuration", "value": {"joint_values": [1.4690334553023976, -5.638830284028951, -1.5560718566051077, -3.8006722817307574, 1.5707964110613697, 3.039829782302467], "joint_types": [0, 0, 0, 0, 0, 0], "joint_names": ["shoulder_pan_joint", "shoulder_lift_joint", "elbow_joint", "wrist_1_joint", "wrist_2_joint", "wrist_3_joint"]}}, {"dtype": "compas.robots/Configuration", "value": {"joint_values": [1.1849644879977033, -5.719080940749628, -1.3609189851999328, -3.9155745228308336, 1.5707963742135331, 2.7557608149977737], "joint_types": [0, 0, 0, 0, 0, 0], "joint_names": ["shoulder_pan_joint", "shoulder_lift_joint", "elbow_joint", "wrist_1_joint", "wrist_2_joint", "wrist_3_joint"]}}, {"dtype": "compas.robots/Configuration", "value": {"joint_values": [0.9504148713420365, -5.857413858219323, -1.0398192304557676, -4.098341373414232, 1.5707963369781726, 2.5212111983421095], "joint_types": [0, 0, 0, 0, 0, 0], "joint_names": ["shoulder_pan_joint", "shoulder_lift_joint", "elbow_joint", "wrist_1_joint", "wrist_2_joint", "wrist_3_joint"]}}, {"dtype": "compas.robots/Configuration", "value": {"joint_values": [0.7304478559449634, -6.040034968906261, -0.632294992266762, -4.323244504758792, 1.5707962986336736, 2.3012441829450396], "joint_types": [0, 0, 0, 0, 0, 0], "joint_names": ["shoulder_pan_joint", "shoulder_lift_joint", "elbow_joint", "wrist_1_joint", "wrist_2_joint", "wrist_3_joint"]}}, {"dtype": "compas.robots/Configuration", "value": {"joint_values": [-1.9609183626460736, -2.2560051576574396, -1.7804900223131386, -0.67589380051819, 1.5707963283936743, -0.39012203603423334], "joint_types": [0, 0, 0, 0, 0, 0], "joint_names": ["shoulder_pan_joint", "shoulder_lift_joint", "elbow_joint", "wrist_1_joint", "wrist_2_joint", "wrist_3_joint"]}}, {"dtype": "compas.robots/Configuration", "value": {"joint_values": [-2.2151951573367987, -2.3018552476676435, -1.6818990100531652, -0.7286347232264484, 1.5707963283139124, -0.6443988307249585], "joint_types": [0, 0, 0, 0, 0, 0], "joint_names": ["shoulder_pan_joint", "shoulder_lift_joint", "elbow_joint", "wrist_1_joint", "wrist_2_joint", "wrist_3_joint"]}}, {"dtype": "compas.robots/Configuration", "value": {"joint_values": [-2.4614541701041044, -2.354350707857781, -1.5695136332221329, -0.788524640291731, 1.5707963281244355, -0.8906578434922641], "joint_types": [0, 0, 0, 0, 0, 0], "joint_names": ["shoulder_pan_joint", "shoulder_lift_joint", "elbow_joint", "wrist_1_joint", "wrist_2_joint", "wrist_3_joint"]}}, {"dtype": "compas.robots/Configuration", "value": {"joint_values": [-2.6933975993893724, -2.432441231285667, -1.4030353091719046, -0.8769124412710774, 1.5707963278493013, -1.122601272777532], "joint_types": [0, 0, 0, 0, 0, 0], "joint_names": ["shoulder_pan_joint", "shoulder_lift_joint", "elbow_joint", "wrist_1_joint", "wrist_2_joint", "wrist_3_joint"]}}] \ No newline at end of file diff --git a/lecture_04/assignment_03/assignment_03.py b/lecture_04/assignment_03/assignment_03.py new file mode 100644 index 0000000..61f0be7 --- /dev/null +++ b/lecture_04/assignment_03/assignment_03.py @@ -0,0 +1,76 @@ +"""Assignment 03: Using inverse kinematics +""" +import os +import compas +from compas_fab.backends import RosClient +from compas_fab.robots import Configuration + +from compas.geometry import Frame +from compas.geometry import Translation +from compas.geometry import Point +from compas.geometry import Vector + +import math + + +# Step 1: Inside this function, complete the main part of the solution for the assignment: +# - Taking a robot and a list of frames as parameter, calculate a feasible configuration for each of the frames +# - Try to find an optimal start_configuration for each so that the motion from one config to the next is minimized +def calculate_ik_for_frames(robot, frames): + configs = [] + + T = Translation.from_vector([0.1,0,0.1]) + frame_0 = frames[0].transformed(T) + + start_configuration = robot.zero_configuration() + + # Configuration.joint_values = (0,-math.pi/2,0,-math.pi/2,0,0) + # configs.append(start_configuration) + + configuration_1st = robot.inverse_kinematics(frame_0, start_configuration) + configs.append(configuration_1st) + + + for i,f in enumerate(frames): + c = robot.inverse_kinematics(f,configs[i]) + configs.append(c) + + configs.pop(0) + + return configs + + +# Step 2: store all found configurations in a JSON file using compas.json_dump or compas.json_dumps +def store_configurations(configurations, filename): + compas.json_dump(configurations, filename) + + +# Use the following to test from the command line +# Or copy solution_viewer.ghx next to the folder where you created assignment_03.py to visualize the same in Grasshopper +if __name__ == '__main__': + + frames = [ + Frame(Point(-0.329, 0.059, 0.082), Vector(1.000, 0.000, 0.000), Vector(0.000, -1.000, 0.000)), + Frame(Point(-0.260, 0.129, 0.082), Vector(1.000, 0.000, 0.000), Vector(0.000, -1.000, 0.000)), + Frame(Point(-0.186, 0.194, 0.082), Vector(1.000, 0.000, 0.000), Vector(0.000, -1.000, 0.000)), + Frame(Point(-0.106, 0.252, 0.082), Vector(1.000, 0.000, 0.000), Vector(0.000, -1.000, 0.000)), + Frame(Point(-0.020, 0.299, 0.082), Vector(1.000, 0.000, 0.000), Vector(0.000, -1.000, 0.000)), + Frame(Point(0.074, 0.329, 0.082), Vector(1.000, 0.000, 0.000), Vector(0.000, -1.000, 0.000)), + Frame(Point(0.172, 0.330, 0.082), Vector(1.000, 0.000, 0.000), Vector(0.000, -1.000, 0.000)), + Frame(Point(0.263, 0.295, 0.082), Vector(1.000, 0.000, 0.000), Vector(0.000, -1.000, 0.000)), + Frame(Point(0.339, 0.233, 0.082), Vector(1.000, 0.000, 0.000), Vector(0.000, -1.000, 0.000)), + Frame(Point(0.400, 0.155, 0.082), Vector(1.000, 0.000, 0.000), Vector(0.000, -1.000, 0.000)), + Frame(Point(0.448, 0.070, 0.082), Vector(1.000, 0.000, 0.000), Vector(0.000, -1.000, 0.000))] + + # Loads the robot from ROS + with RosClient('localhost') as client: + robot = client.load_robot() + + # Step 1: calculate IK solutions for each frame + configurations = calculate_ik_for_frames(robot, frames) + print("Found {} configurations".format(len(configurations))) + + # Step 2: store all configurations in a JSON file + filename = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'assignment-03.json') + store_configurations(configurations, filename) + print("Stored results in {}".format(filename)) From 8490f3cc8e385893d1c8f77fda9a67a3e65f8751 Mon Sep 17 00:00:00 2001 From: Stephen30 <91248027+stephen300105@users.noreply.github.com> Date: Wed, 23 Mar 2022 05:05:00 +0100 Subject: [PATCH 2/2] Update solution_viewer.ghx --- lecture_04/assignment_03/solution_viewer.ghx | 1246 ++++++++++++++++-- 1 file changed, 1115 insertions(+), 131 deletions(-) diff --git a/lecture_04/assignment_03/solution_viewer.ghx b/lecture_04/assignment_03/solution_viewer.ghx index 984ddf4..b5e7fef 100644 --- a/lecture_04/assignment_03/solution_viewer.ghx +++ b/lecture_04/assignment_03/solution_viewer.ghx @@ -48,10 +48,10 @@ - 76 - 184 + 107 + -57 - 0.7676566 + 1.27500021 @@ -73,8 +73,8 @@ - GhPython, Version=7.15.22039.13001, Culture=neutral, PublicKeyToken=null - 7.15.22039.13001 + GhPython, Version=7.14.22010.17001, Culture=neutral, PublicKeyToken=null + 7.14.22010.17001 00000000-0000-0000-0000-000000000000 @@ -85,9 +85,9 @@ - 11 + 19 - + 2e78987b-9dfb-42a2-8b76-3923ac8bd91a @@ -110,7 +110,7 @@ 31 228 - 110 + 113 22 @@ -141,7 +141,7 @@ 29 252 - 94 + 96 22 @@ -208,8 +208,8 @@ configuration = calculate_ik_for_frames(robot, frames) GhPython provides a Python script component - 905 - -745 + 304 + 304 685 @@ -228,10 +228,10 @@ configuration = calculate_ik_for_frames(robot, frames) - 787 - 233 - 149 - 60 + 785 + 241 + 156 + 44 844 @@ -266,14 +266,14 @@ configuration = calculate_ik_for_frames(robot, frames) - 789 - 235 - 40 - 28 + 787 + 243 + 42 + 20 - 810.5 - 249 + 809.5 + 253 @@ -298,14 +298,14 @@ configuration = calculate_ik_for_frames(robot, frames) - 789 + 787 263 - 40 - 28 + 42 + 20 - 810.5 - 277 + 809.5 + 273 @@ -325,12 +325,12 @@ configuration = calculate_ik_for_frames(robot, frames) 859 - 235 - 75 - 56 + 243 + 80 + 40 - 896.5 + 899 263 @@ -361,9 +361,9 @@ configuration = calculate_ik_for_frames(robot, frames) - 990 + 989 251 - 64 + 65 64 @@ -397,13 +397,13 @@ configuration = calculate_ik_for_frames(robot, frames) - 992 + 991 253 - 17 + 18 20 - 1002 + 1001.5 263 @@ -424,13 +424,13 @@ configuration = calculate_ik_for_frames(robot, frames) - 992 + 991 273 - 17 + 18 20 - 1002 + 1001.5 283 @@ -470,13 +470,13 @@ configuration = calculate_ik_for_frames(robot, frames) - 992 + 991 293 - 17 + 18 20 - 1002 + 1001.5 303 @@ -555,14 +555,14 @@ configuration = calculate_ik_for_frames(robot, frames) - 697 + 716 338 - 160 + 162 20 - 697.8439 - 338.424 + 716.2881 + 338.076 @@ -574,7 +574,7 @@ configuration = calculate_ik_for_frames(robot, frames) 10 0 0 - 0 + 3 @@ -601,9 +601,9 @@ configuration = calculate_ik_for_frames(robot, frames) 688 - 267 + 265 50 - 20 + 24 713.3483 @@ -869,7 +869,7 @@ COMPAS FAB v0.22.0 true true - iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDwAACw8BkvkDpQAAAdZJREFUSEu1lD2O4kAQRrkBcwP2BnADfARuABEhcAMcEEyCQKuVCCEkY27A3ADCyUAimQyHm/V+r9bNNp5iSLwtPWF/9dvdZRohhP+KK9aJK9aJK9aJKzpk4k08W4XYiB/CYquJPJbX6zVMp9PQbrcV0XhIt9sN6/VaIVZoQLyXMGVC8piYXwp5jMfj0Gq1zK/f7yvUVsdLGnkRBV0RlHT2/g2WHH+KonmJI4PD4ZA6HwVFPd9IR1hTzWZTj76Tcjay1Wr1QWIKnE6n0Ov17DnhXeSiWnTJbvHZ7/d3BkNrg3E2m/2OBbiH4XCITkLg+YhNnMVtakRuib0CWgMMYlMUxetutzPH8vwZ00f+HB8auznHe6CxagDdnMt3ztPOkunAWYsiPcF3YYxGo19ZloXtdvtT78d4b9yDVpEmf8Eg8qiJt7gLCi0WC9v2IxjV6Mu9aU3SAh2MYhI1wZaPBMcZfwadl8n5oqX8Sya7OZkhgSJoge1Xu04pE/Ot3E4hTUQBmyDB+d7ZBIU4f4INBmE+n3/meR4ul8tS2pe4+5e/91CURRjH7BuYIIYCX/vf8fgqaKYFHxEvz6CZh8nBFUGLQl7nN7y4Kq5YJ65YJ65YJ65YH6HxB7b14P1B22tpAAAAAElFTkSuQmCC + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDQAACw0B7QfALAAAAdZJREFUSEu1lD2O4kAQRrkBcwP2BnADfARuABEhcAMcEEyCQKuVCCEkY27A3ADCyUAimQyHm/V+r9bNNp5iSLwtPWF/9dvdZRohhP+KK9aJK9aJK9aJKzpk4k08W4XYiB/CYquJPJbX6zVMp9PQbrcV0XhIt9sN6/VaIVZoQLyXMGVC8piYXwp5jMfj0Gq1zK/f7yvUVsdLGnkRBV0RlHT2/g2WHH+KonmJI4PD4ZA6HwVFPd9IR1hTzWZTj76Tcjay1Wr1QWIKnE6n0Ov17DnhXeSiWnTJbvHZ7/d3BkNrg3E2m/2OBbiH4XCITkLg+YhNnMVtakRuib0CWgMMYlMUxetutzPH8vwZ00f+HB8auznHe6CxagDdnMt3ztPOkunAWYsiPcF3YYxGo19ZloXtdvtT78d4b9yDVpEmf8Eg8qiJt7gLCi0WC9v2IxjV6Mu9aU3SAh2MYhI1wZaPBMcZfwadl8n5oqX8Sya7OZkhgSJoge1Xu04pE/Ot3E4hTUQBmyDB+d7ZBIU4f4INBmE+n3/meR4ul8tS2pe4+5e/91CURRjH7BuYIIYCX/vf8fgqaKYFHxEvz6CZh8nBFUGLQl7nN7y4Kq5YJ65YJ65YJ65YH6HxB7b14P1B22tpAAAAAElFTkSuQmCC false eccb9686-8536-4332-975d-684efb918cee @@ -882,9 +882,9 @@ COMPAS FAB v0.22.0 - 178 + 176 187 - 153 + 159 64 @@ -921,13 +921,13 @@ COMPAS FAB v0.22.0 - 180 + 178 189 - 46 + 48 20 - 204.5 + 203.5 199 @@ -951,13 +951,13 @@ COMPAS FAB v0.22.0 - 180 + 178 209 - 46 + 48 20 - 204.5 + 203.5 219 @@ -982,13 +982,13 @@ COMPAS FAB v0.22.0 - 180 + 178 229 - 46 + 48 20 - 204.5 + 203.5 239 @@ -1010,11 +1010,11 @@ COMPAS FAB v0.22.0 256 189 - 73 + 77 30 - 292.5 + 294.5 204 @@ -1036,11 +1036,11 @@ COMPAS FAB v0.22.0 256 219 - 73 + 77 30 - 292.5 + 294.5 234 @@ -1093,7 +1093,7 @@ COMPAS FAB v0.22.0 true true - iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDwAACw8BkvkDpQAAAVtJREFUSEu9lMFRwzAQRVMCJaSElJASUgIlUAGTEhguXHPinBJSAiWkBDow/9n6ZmWtQzwYduaNpdVqtf5redN13Z+SOtckdS5B9iCeeKbrmXMJsrNg8CkOzXo1Gao5iYtg4z6uR2SP4iqY+Ans3Y5xk00sTjfsBcmOgbjOmMK2wvs/mgNKQL8o3sRzmb8Iy5BRySLbifHNpwsM3gWHvJY5ByAb44xKRtkoTz+vJkNiBn7CQXAIr29oqNd7OWTIhHxMrmNOD0oQb2EdSYL2VUUlDjlJ5kKQMDa8lahsdEPdNFfUHFLiiYsNJ766D9WG3lHLYy7TOCOjEArLi2gcQ7ATR2bvxC1yZ/7VjI1bQu4cXjt+KeaYxd8idQLJQmLDoelPbY7UaWTxCzGnLHaO1Glkv2546xhubUz2E8i2m+YxreP7Ji9htvmt4x8O4Ffhn9q93C/R2qTO9eg2XxfZxOCoCLXEAAAAAElFTkSuQmCC + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDQAACw0B7QfALAAAAVtJREFUSEu9lMFRwzAQRVMCJaSElJASUgIlUAGTEhguXHPinBJSAiWkBDow/9n6ZmWtQzwYduaNpdVqtf5redN13Z+SOtckdS5B9iCeeKbrmXMJsrNg8CkOzXo1Gao5iYtg4z6uR2SP4iqY+Ans3Y5xk00sTjfsBcmOgbjOmMK2wvs/mgNKQL8o3sRzmb8Iy5BRySLbifHNpwsM3gWHvJY5ByAb44xKRtkoTz+vJkNiBn7CQXAIr29oqNd7OWTIhHxMrmNOD0oQb2EdSYL2VUUlDjlJ5kKQMDa8lahsdEPdNFfUHFLiiYsNJ766D9WG3lHLYy7TOCOjEArLi2gcQ7ATR2bvxC1yZ/7VjI1bQu4cXjt+KeaYxd8idQLJQmLDoelPbY7UaWTxCzGnLHaO1Glkv2546xhubUz2E8i2m+YxreP7Ji9htvmt4x8O4Ffhn9q93C/R2qTO9eg2XxfZxOCoCLXEAAAAAElFTkSuQmCC false ed6dd17e-9615-4209-9f27-8c842a439b86 @@ -1106,10 +1106,10 @@ COMPAS FAB v0.22.0 - 384 - 224 - 124 - 54 + 381 + 229 + 129 + 44 454 @@ -1144,14 +1144,14 @@ COMPAS FAB v0.22.0 - 386 - 226 - 53 - 25 + 383 + 231 + 56 + 20 - 414 - 238.5 + 412.5 + 241 @@ -1175,14 +1175,14 @@ COMPAS FAB v0.22.0 - 386 + 383 251 - 53 - 25 + 56 + 20 - 414 - 263.5 + 412.5 + 261 @@ -1202,12 +1202,12 @@ COMPAS FAB v0.22.0 469 - 226 - 37 - 50 + 231 + 39 + 40 - 487.5 + 488.5 251 @@ -1228,7 +1228,7 @@ COMPAS FAB v0.22.0 - + """ Visualizes the robot. @@ -1294,10 +1294,11 @@ class RobotVisualize(component): Visualizes the robot. COMPAS FAB v0.22.0 + true true true - iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDwAACw8BkvkDpQAAAdhJREFUSEu1lLFKA0EQhlUIQVBMOhGLgGAtxAcIYmmRJpWNrZ2dhSCWqURtxC6VRSofIYWlhS8QyBMEOzvP/zt2jtm9VSLEg+9ud2bnn9nZu1spiuJfyRqXSdb4F3ZvX1vigmfOXzP8FQm/iEJ8iH7qjyZUIUZiIgjseb9HvjMxE4jbE4jt2Lo0CGca0BOI3Ti8nzGFdYTFv9cShAWlUzyK6zC/E9aGHFFbND8Q1c5TBwHPgiQPYU4C2uZFPVEbNa/aA9wqg5wIE2RP6AuSsH2DAzV/2Q49aRPtwzYzTW5VBXKwC+sjIvQ+qiiso52IWSG00B941CKfwA7UDs0qqiUJ61nnD5z10ffALe2hb48x8Ws88lEIhWWLqBnC4jQBRIUsStYosdxbUx6croFgAJcWo6st5sE+ruw28EiMbfs3xbjBnxWKEw8quw1SEEvEgaQtCQydWJv1zjb3OpFoisT8G2KMJNINYlBWq8t2NfQakWCKxH48cAlNg+CT8AmPvUYkCArmq82JRmydnJeCa+sbX42dvfsgPk31ogko2L7kX9m+GpcJYLXR/AzjqD0QTUDBCyWA5v5hlSTQTfWiCSiQX4X91H5l8+jUzgHeUi2oGZZN1rg8ipVvhzuVIxcFIsQAAAAASUVORK5CYII= + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDQAACw0B7QfALAAAAdhJREFUSEu1lLFKA0EQhlUIQVBMOhGLgGAtxAcIYmmRJpWNrZ2dhSCWqURtxC6VRSofIYWlhS8QyBMEOzvP/zt2jtm9VSLEg+9ud2bnn9nZu1spiuJfyRqXSdb4F3ZvX1vigmfOXzP8FQm/iEJ8iH7qjyZUIUZiIgjseb9HvjMxE4jbE4jt2Lo0CGca0BOI3Ti8nzGFdYTFv9cShAWlUzyK6zC/E9aGHFFbND8Q1c5TBwHPgiQPYU4C2uZFPVEbNa/aA9wqg5wIE2RP6AuSsH2DAzV/2Q49aRPtwzYzTW5VBXKwC+sjIvQ+qiiso52IWSG00B941CKfwA7UDs0qqiUJ61nnD5z10ffALe2hb48x8Ws88lEIhWWLqBnC4jQBRIUsStYosdxbUx6croFgAJcWo6st5sE+ruw28EiMbfs3xbjBnxWKEw8quw1SEEvEgaQtCQydWJv1zjb3OpFoisT8G2KMJNINYlBWq8t2NfQakWCKxH48cAlNg+CT8AmPvUYkCArmq82JRmydnJeCa+sbX42dvfsgPk31ogko2L7kX9m+GpcJYLXR/AzjqD0QTUDBCyWA5v5hlSTQTfWiCSiQX4X91H5l8+jUzgHeUi2oGZZN1rg8ipVvhzuVIxcFIsQAAAAASUVORK5CYII= false 10a49928-eb17-4269-a1f5-98ee19233fed @@ -1310,9 +1311,9 @@ COMPAS FAB v0.22.0 - 1235 + 1225 231 - 261 + 278 204 @@ -1362,13 +1363,13 @@ COMPAS FAB v0.22.0 - 1237 + 1227 233 - 134 + 144 20 - 1305.5 + 1300.5 243 @@ -1392,13 +1393,13 @@ COMPAS FAB v0.22.0 - 1237 + 1227 253 - 134 + 144 20 - 1305.5 + 1300.5 263 @@ -1423,13 +1424,13 @@ COMPAS FAB v0.22.0 - 1237 + 1227 273 - 134 + 144 20 - 1305.5 + 1300.5 283 @@ -1454,13 +1455,13 @@ COMPAS FAB v0.22.0 - 1237 + 1227 293 - 134 + 144 20 - 1305.5 + 1300.5 303 @@ -1484,13 +1485,13 @@ COMPAS FAB v0.22.0 - 1237 + 1227 313 - 134 + 144 20 - 1305.5 + 1300.5 323 @@ -1514,13 +1515,13 @@ COMPAS FAB v0.22.0 - 1237 + 1227 333 - 134 + 144 20 - 1305.5 + 1300.5 343 @@ -1544,13 +1545,13 @@ COMPAS FAB v0.22.0 - 1237 + 1227 353 - 134 + 144 20 - 1305.5 + 1300.5 363 @@ -1574,13 +1575,13 @@ COMPAS FAB v0.22.0 - 1237 + 1227 373 - 134 + 144 20 - 1305.5 + 1300.5 383 @@ -1604,13 +1605,13 @@ COMPAS FAB v0.22.0 - 1237 + 1227 393 - 134 + 144 20 - 1305.5 + 1300.5 403 @@ -1634,13 +1635,13 @@ COMPAS FAB v0.22.0 - 1237 + 1227 413 - 134 + 144 20 - 1305.5 + 1300.5 423 @@ -1662,11 +1663,11 @@ COMPAS FAB v0.22.0 1401 233 - 93 + 100 33 - 1447.5 + 1451 249.6667 @@ -1688,11 +1689,11 @@ COMPAS FAB v0.22.0 1401 266 - 93 + 100 33 - 1447.5 + 1451 283 @@ -1714,11 +1715,11 @@ COMPAS FAB v0.22.0 1401 299 - 93 + 100 34 - 1447.5 + 1451 316.3333 @@ -1740,11 +1741,11 @@ COMPAS FAB v0.22.0 1401 333 - 93 + 100 33 - 1447.5 + 1451 349.6667 @@ -1766,11 +1767,11 @@ COMPAS FAB v0.22.0 1401 366 - 93 + 100 33 - 1447.5 + 1451 383 @@ -1792,11 +1793,11 @@ COMPAS FAB v0.22.0 1401 399 - 93 + 100 34 - 1447.5 + 1451 416.3333 @@ -1809,6 +1810,989 @@ COMPAS FAB v0.22.0 + + + 410755b1-224a-4c1e-a407-bf32fb45ea7e + 00000000-0000-0000-0000-000000000000 + Robot Visualize + + + + + """ +Visualizes the robot. + +COMPAS FAB v0.22.0 +""" +from compas.geometry import Frame +from compas.geometry import Transformation +from compas_ghpython.artists import FrameArtist +from compas_ghpython.artists import MeshArtist +from ghpythonlib.componentbase import executingcomponent as component + + +class RobotVisualize(component): + def RunScript(self, robot, group, configuration, attached_collision_meshes, show_visual, show_collision, + show_frames, show_base_frame, show_end_effector_frame, show_acm): + + visual = None + collision = 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 + 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 = FrameArtist(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 = FrameArtist(ee_compas_frame) + ee_frame = artist.draw() + + if show_frames: + frames = [] + for compas_frame in compas_frames[1:]: + artist = FrameArtist(compas_frame) + frame = artist.draw() + frames.append(frame) + + if show_acm: + attached_meshes = [] + for acm in attached_collision_meshes: + frame = robot.forward_kinematics(configuration, options=dict(solver='model', link_name=acm.link_name)) + T = Transformation.from_frame_to_frame(Frame.worldXY(), frame) + mesh = acm.collision_mesh.mesh.transformed(T) + attached_meshes.append(MeshArtist(mesh).draw()) + + return (visual, collision, attached_meshes, frames, base_frame, ee_frame) + + Visualizes the robot. +COMPAS FAB v0.22.0 + true + true + + iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALDAAACwwBP0AiyAAAAdhJREFUSEu1lLFKA0EQhlUIQVBMOhGLgGAtxAcIYmmRJpWNrZ2dhSCWqURtxC6VRSofIYWlhS8QyBMEOzvP/zt2jtm9VSLEg+9ud2bnn9nZu1spiuJfyRqXSdb4F3ZvX1vigmfOXzP8FQm/iEJ8iH7qjyZUIUZiIgjseb9HvjMxE4jbE4jt2Lo0CGca0BOI3Ti8nzGFdYTFv9cShAWlUzyK6zC/E9aGHFFbND8Q1c5TBwHPgiQPYU4C2uZFPVEbNa/aA9wqg5wIE2RP6AuSsH2DAzV/2Q49aRPtwzYzTW5VBXKwC+sjIvQ+qiiso52IWSG00B941CKfwA7UDs0qqiUJ61nnD5z10ffALe2hb48x8Ws88lEIhWWLqBnC4jQBRIUsStYosdxbUx6croFgAJcWo6st5sE+ruw28EiMbfs3xbjBnxWKEw8quw1SEEvEgaQtCQydWJv1zjb3OpFoisT8G2KMJNINYlBWq8t2NfQakWCKxH48cAlNg+CT8AmPvUYkCArmq82JRmydnJeCa+sbX42dvfsgPk31ogko2L7kX9m+GpcJYLXR/AzjqD0QTUDBCyWA5v5hlSTQTfWiCSiQX4X91H5l8+jUzgHeUi2oGZZN1rg8ipVvhzuVIxcFIsQAAAAASUVORK5CYII= + + false + 0b2f4ee5-66ca-4077-b741-2e4858ccaeac + true + true + Robot Visualize + Robot Visualize + + + + + + 1228 + 474 + 278 + 204 + + + 1389 + 576 + + + + + + 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 + 6 + 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. + 38939a2f-4118-4dc9-9681-b4d359786df5 + robot + robot + true + 0 + true + d4bae7b0-750f-4b86-a929-7bf58d55c307 + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + 2 + + + + + + 1230 + 476 + 144 + 20 + + + 1303.5 + 486 + + + + + + + + true + The planning group used for end-effector and base visualization. + 791df07c-1921-4ad1-939f-6d2fb4099503 + group + group + true + 0 + true + 0 + 37261734-eec7-4f50-b6a8-b8d1f3c4396b + + + + + + 1230 + 496 + 144 + 20 + + + 1303.5 + 506 + + + + + + + + true + The robot's full configuration. + 3829e793-c4d4-492b-97c1-fdae0862756a + configuration + configuration + true + 0 + true + 6cf97b0d-08d6-431a-9ade-d1211356b98f + 1 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 1230 + 516 + 144 + 20 + + + 1303.5 + 526 + + + + + + + + 1 + true + A list of attached collision meshes. + 9175821d-cf5f-4b41-a175-9dcd0ab43931 + attached_collision_meshes + attached_collision_meshes + true + 1 + true + 0 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 1230 + 536 + 144 + 20 + + + 1303.5 + 546 + + + + + + + + true + Whether or not to show the robot's visual meshes. + 1e07bedb-3543-488d-911e-35d5d7fa8962 + show_visual + show_visual + true + 0 + true + 0 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 1230 + 556 + 144 + 20 + + + 1303.5 + 566 + + + + + + + + true + Whether or not to show the robot's collision meshes. + e5ea71d7-35b2-4bc6-bf1d-a015c26498ef + show_collision + show_collision + true + 0 + true + 0 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 1230 + 576 + 144 + 20 + + + 1303.5 + 586 + + + + + + + + true + Whether or not to show the robot's joint frames. + 13069860-ce07-482a-9db9-6cb684dbce39 + show_frames + show_frames + true + 0 + true + 0 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 1230 + 596 + 144 + 20 + + + 1303.5 + 606 + + + + + + + + true + Whether or not to show the robot's base frame. + 4db73b53-e314-4e75-8a7b-6f526d076de2 + show_base_frame + show_base_frame + true + 0 + true + 0 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 1230 + 616 + 144 + 20 + + + 1303.5 + 626 + + + + + + + + true + Whether or not to show the robot's end-effector frame. + 0b78ab53-c190-41e2-a96d-077f0ac9bf05 + show_end_effector_frame + show_end_effector_frame + true + 0 + true + 0 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 1230 + 636 + 144 + 20 + + + 1303.5 + 646 + + + + + + + + true + Whether or not to show the attached collision meshes (if any). + a10f3fa4-1b79-4714-91b4-77f1a27336c2 + show_acm + show_acm + true + 0 + true + 0 + d60527f5-b5af-4ef6-8970-5f96fe412559 + + + + + + 1230 + 656 + 144 + 20 + + + 1303.5 + 666 + + + + + + + + The robot's visual Rhino meshes (if any). + 0b833af4-7e09-425a-a702-19aed07a2cfc + visual + visual + false + 0 + + + + + + 1404 + 476 + 100 + 33 + + + 1454 + 492.6667 + + + + + + + + The robot's collision Rhino meshes (if any). + d23c923d-4173-4e36-980a-f61ef0e808aa + collision + collision + false + 0 + + + + + + 1404 + 509 + 100 + 33 + + + 1454 + 526 + + + + + + + + The attached collision Rhino meshes (if any). + f7ab0f71-7a87-410b-98c5-c918be908e27 + attached_meshes + attached_meshes + false + 0 + + + + + + 1404 + 542 + 100 + 34 + + + 1454 + 559.3334 + + + + + + + + The robot's joint frames as Rhino planes (if any). + 41114392-d3cf-4130-9f8a-b0e643c3f4cd + frames + frames + false + 0 + + + + + + 1404 + 576 + 100 + 33 + + + 1454 + 592.6667 + + + + + + + + The robot's base frame as a Rhino plane (if any). + 95f47926-93b6-495f-9018-36a05b19f629 + base_frame + base_frame + false + 0 + + + + + + 1404 + 609 + 100 + 33 + + + 1454 + 626 + + + + + + + + The robot's end-effector frame as a Rhino plane (if any). + e2c6c21e-90b8-4e33-a3d5-78b1b5242ddc + ee_frame + ee_frame + false + 0 + + + + + + 1404 + 642 + 100 + 33 + + + 1454 + 659.3333 + + + + + + + + + + + + + + 57da07bd-ecab-415d-9d86-af36d7073abc + Number Slider + + + + + Numeric slider for single values + c4b5b947-524c-4625-a940-28616064ccea + Number Slider + a6 + false + 0 + + + + + + 677 + 599 + 227 + 20 + + + 677.2665 + 599.05 + + + + + + 3 + 1 + 1 + 360 + -360 + 0 + 0 + + + + + + + + + 410755b1-224a-4c1e-a407-bf32fb45ea7e + 00000000-0000-0000-0000-000000000000 + Python Script + + + + + import math +from compas.robots import Configuration + +config = Configuration.from_revolute_values([math.radians(a) for a in vals]) + + GhPython provides a Python script component + + 191 + 194 + + + 1300 + 740 + + true + true + false + d85207c1-dfae-4aa0-a6bd-8a735410940d + false + true + Python Script + config + + + + + + 968 + 525 + 104 + 28 + + + 1012 + 539 + + + + + + 1 + 84fa917c-1ed8-4db3-8be1-7bdc4a6495a2 + 1 + 8ec86459-bf01-4409-baee-174d0d2b13d0 + + + + + 1 + true + Script input a1. + a4371db6-7801-4527-8966-3bff55e66b99 + vals + vals + true + 1 + true + 4b83dabb-3ae5-4018-bddb-47cbc06a8179 + aca92276-402f-4cbe-86cc-976491a7a93b + 9f1b8099-978b-4566-b244-5f08f468ec49 + ea36e11d-cccd-43cd-954f-479a1070b8be + 4badb2ae-7e0b-4097-b7c5-ac6ecd206e7d + c4b5b947-524c-4625-a940-28616064ccea + 6 + 87f87f55-5b71-41f4-8aea-21d494016f81 + + + + + + 970 + 527 + 27 + 24 + + + 985 + 539 + + + + + + + + Script output config. + 6cf97b0d-08d6-431a-9ade-d1211356b98f + config + config + false + 0 + + + + + + 1027 + 527 + 43 + 24 + + + 1048.5 + 539 + + + + + + + + + + + + + + 57da07bd-ecab-415d-9d86-af36d7073abc + Number Slider + + + + + Numeric slider for single values + 4badb2ae-7e0b-4097-b7c5-ac6ecd206e7d + Number Slider + a5 + false + 0 + + + + + + 676 + 576 + 227 + 20 + + + 676.6666 + 576.0501 + + + + + + 3 + 1 + 1 + 360 + -360 + 0 + 0 + + + + + + + + + 57da07bd-ecab-415d-9d86-af36d7073abc + Number Slider + + + + + Numeric slider for single values + 4b83dabb-3ae5-4018-bddb-47cbc06a8179 + Number Slider + a1 + false + 0 + + + + + + 676 + 484 + 227 + 20 + + + 676.8266 + 484.1299 + + + + + + 3 + 1 + 1 + 360 + -360 + 0 + -36 + + + + + + + + + 57da07bd-ecab-415d-9d86-af36d7073abc + Number Slider + + + + + Numeric slider for single values + ea36e11d-cccd-43cd-954f-479a1070b8be + Number Slider + a4 + false + 0 + + + + + + 676 + 553 + 227 + 20 + + + 676.6666 + 553.0498 + + + + + + 3 + 1 + 1 + 360 + -360 + 0 + -90 + + + + + + + + + 57da07bd-ecab-415d-9d86-af36d7073abc + Number Slider + + + + + Numeric slider for single values + aca92276-402f-4cbe-86cc-976491a7a93b + Number Slider + a2 + false + 0 + + + + + + 676 + 506 + 227 + 20 + + + 676.5396 + 506.5606 + + + + + + 3 + 1 + 1 + 360 + -360 + 0 + -90 + + + + + + + + + 57da07bd-ecab-415d-9d86-af36d7073abc + Number Slider + + + + + Numeric slider for single values + 9f1b8099-978b-4566-b244-5f08f468ec49 + Number Slider + a3 + false + 0 + + + + + + 677 + 530 + 227 + 20 + + + 677.2665 + 530.33 + + + + + + 3 + 1 + 1 + 360 + -360 + 0 + 0 + + + + + + @@ -1816,7 +2800,7 @@ COMPAS FAB v0.22.0 - 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