From 23665f213136e1f122fdb7f698236569361b53ff Mon Sep 17 00:00:00 2001 From: Tismo Date: Wed, 26 Mar 2025 21:22:59 +0100 Subject: [PATCH 1/2] Enable handling of component occurrences for URDF file generation --- .gitignore | 2 ++ Add-IN/ACDC4Robot/.env | 1 - .../commands/ACDC4Robot/acdc4robot.py | 31 +++++++++++++------ Add-IN/ACDC4Robot/core/joint.py | 18 ++++------- Add-IN/ACDC4Robot/core/urdf.py | 16 +++++----- Add-IN/ACDC4Robot/core/utils.py | 18 +++++++++-- 6 files changed, 52 insertions(+), 34 deletions(-) delete mode 100644 Add-IN/ACDC4Robot/.env diff --git a/.gitignore b/.gitignore index e43b0f9..57137c7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .DS_Store +.vscode +Add-IN/ACDC4Robot/.env \ No newline at end of file diff --git a/Add-IN/ACDC4Robot/.env b/Add-IN/ACDC4Robot/.env deleted file mode 100644 index f101a74..0000000 --- a/Add-IN/ACDC4Robot/.env +++ /dev/null @@ -1 +0,0 @@ -PYTHONPATH=/Users/aspartame/Library/Application Support/Autodesk/webdeploy/production/0b28106eb374bf811f579480c256234fe9cdc357/Api/Python/packages diff --git a/Add-IN/ACDC4Robot/commands/ACDC4Robot/acdc4robot.py b/Add-IN/ACDC4Robot/commands/ACDC4Robot/acdc4robot.py index 9f696c2..bb2fba2 100644 --- a/Add-IN/ACDC4Robot/commands/ACDC4Robot/acdc4robot.py +++ b/Add-IN/ACDC4Robot/commands/ACDC4Robot/acdc4robot.py @@ -54,7 +54,7 @@ def get_link_joint_list(design: adsk.fusion.Design): return link_list, joint_list -def export_stl(design: adsk.fusion.Design, save_dir: str, links: list[Link]): +def export_stl(design: adsk.fusion.Design, save_dir: str, links: list[Link], rdf: str): """ export each component's stl file into "save_dir/mesh" @@ -64,6 +64,8 @@ def export_stl(design: adsk.fusion.Design, save_dir: str, links: list[Link]): current active design save_dir: str the directory to store the export stl file + rdf: str + robot description format """ # create a single exportManager instance export_manager = design.exportManager @@ -75,9 +77,14 @@ def export_stl(design: adsk.fusion.Design, save_dir: str, links: list[Link]): for link in links: visual_body: adsk.fusion.BRepBody = link.get_visual_body() col_body: adsk.fusion.BRepBody = link.get_collision_body() + if rdf == "URDF": + mesh_name = mesh_dir + "/" + link.link.component.name + else : + mesh_name = mesh_dir + "/" + link.get_name() if (visual_body is None) and (col_body is None): # export the whole occurrence - mesh_name = mesh_dir + "/" + link.get_name() + if os.path.isfile(mesh_name) : + continue occ = link.get_link_occ() # obj_export_options = export_manager.createOBJExportOptions(occ, mesh_name) # obj_export_options.unitType = adsk.fusion.DistanceUnits.MillimeterDistanceUnits # set unit to mm @@ -90,14 +97,18 @@ def export_stl(design: adsk.fusion.Design, save_dir: str, links: list[Link]): export_manager.execute(stl_export_options) elif (visual_body is not None) and (col_body is not None): # export visual and collision geometry seperately - visual_mesh_name = mesh_dir + "/" + link.get_name() + "_visual" + visual_mesh_name = mesh_name + "_visual" + if os.path.isfile(visual_mesh_name) : + continue visual_exp_options = export_manager.createSTLExportOptions(visual_body, visual_mesh_name) visual_exp_options.sendToPrintUtility = False visual_exp_options.isBinaryFormat = True visual_exp_options.meshRefinement = adsk.fusion.MeshRefinementSettings.MeshRefinementLow export_manager.execute(visual_exp_options) - col_mesh_name = mesh_dir + "/" + link.get_name() + "_collision" + col_mesh_name = mesh_name + "_collision" + if os.path.isfile(col_mesh_name) : + continue col_exp_options = export_manager.createSTLExportOptions(col_body, col_mesh_name) col_exp_options.sendToPrintUtility = False col_exp_options.isBinaryFormat = True @@ -179,14 +190,14 @@ def run(): # write to .urdf file write.write_urdf(link_list, joint_list, save_folder, robot_name) # export mesh files - export_stl(design, save_folder, link_list) + export_stl(design, save_folder, link_list, rdf) ui.messageBox("Finished exporting URDF for Gazebo.", msg_box_title) elif simulator == "PyBullet": # write to .urdf file write.write_urdf(link_list, joint_list, save_folder, robot_name) # export mesh files - export_stl(design, save_folder, link_list) + export_stl(design, save_folder, link_list, rdf) # generate pybullet script write.write_hello_pybullet(rdf, robot_name, save_folder) ui.messageBox("Finished exporting URDF for PyBullet.", msg_box_title) @@ -195,7 +206,7 @@ def run(): # write to .urdf file write.write_urdf(link_list, joint_list, save_folder, robot_name) # export mesh files - export_stl(design, save_folder, link_list) + export_stl(design, save_folder, link_list, rdf) ui.messageBox("Finished exporting URDF for MuJoCo.", msg_box_title) @@ -211,13 +222,13 @@ def run(): des = constants.get_model_description() write.write_sdf_config(save_folder, robot_name, author, des) # export stl files - export_stl(design, save_folder, link_list) + export_stl(design, save_folder, link_list, rdf) ui.messageBox("Finished exporting SDFormat for Gazebo.", msg_box_title) elif simulator == "PyBullet": # write to .sdf file write.write_sdf(link_list, joint_list, save_folder, robot_name) # export stl files - export_stl(design, save_folder, link_list) + export_stl(design, save_folder, link_list, rdf) # generate pybullet script write.write_hello_pybullet(rdf,robot_name, save_folder) ui.messageBox("Finished exporting SDFormat for PyBullet.", msg_box_title) @@ -240,7 +251,7 @@ def run(): # write to .xml file write.write_mjcf(root, robot_name, save_folder) # export stl files - export_stl(design, save_folder, link_list) + export_stl(design, save_folder, link_list, rdf) time.sleep(0.1) ui.messageBox("Finished exporting MJCF for MuJoCo.", msg_box_title) diff --git a/Add-IN/ACDC4Robot/core/joint.py b/Add-IN/ACDC4Robot/core/joint.py index 98d7577..0145bdc 100644 --- a/Add-IN/ACDC4Robot/core/joint.py +++ b/Add-IN/ACDC4Robot/core/joint.py @@ -181,20 +181,14 @@ def get_joint_frame(self) -> adsk.core.Matrix3D: a homogeneous matrix represents joint frame J in world frame W translation unit: cm """ - # get parent joint origin's coordinate w.r.t world frame - if self.joint.geometryOrOriginTwo == adsk.fusion.JointOrigin: - w_P_J = self.joint.geometryOrOriginTwo.geometry.origin.asArray() - else: - w_P_J = self.joint.geometryOrOriginTwo.origin.asArray() + geometry_two_transform = self.joint.geometryTwoTransform + matrix_array = geometry_two_transform.asArray() - w_P_J = [round(i, 6) for i in w_P_J] - - # no matter jointGeometry or jointOrigin object, both have these properties - zAxis: adsk.core.Vector3D = self.joint.geometryOrOriginTwo.primaryAxisVector - xAxis: adsk.core.Vector3D = self.joint.geometryOrOriginTwo.secondaryAxisVector - yAxis: adsk.core.Vector3D = self.joint.geometryOrOriginTwo.thirdAxisVector + origin = adsk.core.Point3D.create(matrix_array[3], matrix_array[7], matrix_array[11]) - origin = adsk.core.Point3D.create(w_P_J[0], w_P_J[1], w_P_J[2]) + xAxis = adsk.core.Vector3D.create(matrix_array[0], matrix_array[1], matrix_array[2]) + yAxis = adsk.core.Vector3D.create(matrix_array[4], matrix_array[5], matrix_array[6]) + zAxis = adsk.core.Vector3D.create(matrix_array[8], matrix_array[9], matrix_array[10]) joint_frame = adsk.core.Matrix3D.create() joint_frame.setWithCoordinateSystem(origin, xAxis, yAxis, zAxis) diff --git a/Add-IN/ACDC4Robot/core/urdf.py b/Add-IN/ACDC4Robot/core/urdf.py index 9b98735..a4a69c8 100644 --- a/Add-IN/ACDC4Robot/core/urdf.py +++ b/Add-IN/ACDC4Robot/core/urdf.py @@ -200,19 +200,19 @@ def get_link_visual_geo(link: Link) -> str: col_body = link.get_collision_body() if (visual_body is None) and (col_body is None): # visual and collision geometry is same - mesh_loc = "meshes/" + link.get_name() + ".stl" + mesh_loc = "meshes/" + link.link.component.name + ".stl" return mesh_loc elif (visual_body is not None) and (col_body is not None): - mesh_loc = "meshes/" + link.get_name() + "_visual.stl" + mesh_loc = "meshes/" + link.link.component.name + "_visual.stl" return mesh_loc elif (visual_body is None) and (col_body is not None): error_message = "Please set two bodies, one for visual and one for collision. \n" - error_message = error_message + link.get_name() + " body for visual missing." + error_message = error_message + link.link.component.name + " body for visual missing." utils.error_box(error_message) utils.terminate_box() elif (visual_body is not None) and (col_body is None): error_message = "Please set two bodies, one for visual and one for collision. \n" - error_message = error_message + link.get_name() + " body for collision missing." + error_message = error_message + link.link.component.name + " body for collision missing." utils.error_box(error_message) utils.terminate_box() @@ -227,19 +227,19 @@ def get_link_collision_geo(link: Link) -> str: visual_body = link.get_visual_body() col_body = link.get_collision_body() if (visual_body is None) and (col_body is None): - mesh_loc = "meshes/" + link.get_name() + ".stl" + mesh_loc = "meshes/" + link.link.component.name + ".stl" return mesh_loc elif (visual_body is not None) and (col_body is not None): - mesh_loc = "meshes/" + link.get_name() + "_collision.stl" + mesh_loc = "meshes/" + link.link.component.name + "_collision.stl" return mesh_loc elif (visual_body is None) and (col_body is not None): error_message = "Please set two bodies, one for visual and one for collision. \n" - error_message = error_message + link.get_name() + " body for visual missing." + error_message = error_message + link.link.component.name + " body for visual missing." utils.error_box(error_message) utils.terminate_box() elif (visual_body is not None) and (col_body is None): error_message = "Please set two bodies, one for visual and one for collision. \n" - error_message = error_message + link.get_name() + " body for collision missing." + error_message = error_message + link.link.component.name + " body for collision missing." utils.error_box(error_message) utils.terminate_box() diff --git a/Add-IN/ACDC4Robot/core/utils.py b/Add-IN/ACDC4Robot/core/utils.py index 85d438d..598cadc 100644 --- a/Add-IN/ACDC4Robot/core/utils.py +++ b/Add-IN/ACDC4Robot/core/utils.py @@ -15,10 +15,22 @@ def get_valid_filename(s): >>> get_valid_filename("john's portrait in 2004.jpg") 'johns_portrait_in_2004.jpg' """ - # Replace the number `:#+` by `-` + + if re.search(r':1\+', s): + # Remove the number id + # Replace the number `:#+` by `_` + s = re.sub(r':.*?\+', '_', s) + # Remove the number at the end of the full path name + s = re.sub(r':.*$', '', s) + else : + # Several body for the composant so keep the number id + # Replace `:` by `-` + s = re.sub(r':', '-', s) + # Replace `+` by `_` + s = re.sub(r'\+', '_', s) + + # Replace the number `:#+` by `-#_` s = re.sub(r':.*?\+', '_', s) - # Remove the number at the end of the full path name - s = re.sub(r':.*$', '', s) s = str(s).strip().replace(' ', '-') return re.sub(r'(?u)[^-\w.]', '', s) From 52104d1075298b785713e7dccfac18f46c2e30e1 Mon Sep 17 00:00:00 2001 From: Tismo Date: Thu, 27 Mar 2025 15:37:16 +0100 Subject: [PATCH 2/2] Correction of a potential source of error created by my last commit. --- Add-IN/ACDC4Robot/core/utils.py | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/Add-IN/ACDC4Robot/core/utils.py b/Add-IN/ACDC4Robot/core/utils.py index 598cadc..f0df42e 100644 --- a/Add-IN/ACDC4Robot/core/utils.py +++ b/Add-IN/ACDC4Robot/core/utils.py @@ -16,21 +16,11 @@ def get_valid_filename(s): 'johns_portrait_in_2004.jpg' """ - if re.search(r':1\+', s): - # Remove the number id - # Replace the number `:#+` by `_` - s = re.sub(r':.*?\+', '_', s) - # Remove the number at the end of the full path name - s = re.sub(r':.*$', '', s) - else : - # Several body for the composant so keep the number id - # Replace `:` by `-` - s = re.sub(r':', '-', s) - # Replace `+` by `_` - s = re.sub(r'\+', '_', s) - - # Replace the number `:#+` by `-#_` - s = re.sub(r':.*?\+', '_', s) + # Several body for the composant so keep the number id + # Replace `:` by `-` + s = re.sub(r':', '-', s) + # Replace `+` by `_` + s = re.sub(r'\+', '_', s) s = str(s).strip().replace(' ', '-') return re.sub(r'(?u)[^-\w.]', '', s)