Skip to content

Commit

Permalink
Added convenience function to export a robot class straight from an O…
Browse files Browse the repository at this point in the history
…nshape URL. Added RoboType enum to split execution flow: MJCF and URDF exports.
  • Loading branch information
senthurayyappan committed Dec 10, 2024
1 parent 6841599 commit df05b59
Show file tree
Hide file tree
Showing 10 changed files with 253 additions and 212 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ examples/**/*.stl
examples/**/*.png
examples/**/*.prof
examples/**/*.json
examples/**/*.xml

onshape_api/data/**/*.json
onshape_api/data/**/*.parquet
Expand All @@ -180,11 +181,13 @@ benchmark/**/*.stl
benchmark/**/*.png
benchmark/**/*.prof
benchmark/**/*.json
examples/**/*.xml

tests/**/*.urdf
tests/**/*.stl
tests/**/*.png
tests/**/*.prof
tests/**/*.json
examples/**/*.xml

playground
2 changes: 1 addition & 1 deletion docs/tutorials/edit.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ from onshape_api.parse import (
)

# Retrieve the assembly
assembly, _ = client.get_assembly(doc.did, doc.wtype, doc.wid, elements["assembly"].id)
assembly = client.get_assembly(doc.did, doc.wtype, doc.wid, elements["assembly"].id)

# Extract components
instances, id_to_name_map = get_instances(assembly)
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/export.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ document = Document.from_url(
"https://cad.onshape.com/documents/00fdecd70b9459267a70825e/w/5b8859e00b5d129724548da1/e/8bb8553f756c40770e11d5b4"
)

assembly, _ = client.get_assembly(
assembly = client.get_assembly(
did=document.did,
wtype=document.wtype,
wid=document.wid,
Expand Down
67 changes: 33 additions & 34 deletions examples/edit/main.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,45 @@
import onshape_api as osa
from onshape_api.connect import Client
from onshape_api.graph import create_graph, plot_graph
from onshape_api.models.robot import Robot
from onshape_api.log import LOGGER, LogLevel
from onshape_api.models.document import Document
from onshape_api.parse import (
get_instances,
get_mates_and_relations,
get_occurrences,
get_parts,
get_subassemblies,
)
from onshape_api.robot import Robot
from onshape_api.urdf import get_urdf_components

# Initialize the client with the constructed path
client = osa.Client()
doc = osa.Document.from_url(
url="https://cad.onshape.com/documents/a1c1addf75444f54b504f25c/w/0d17b8ebb2a4c76be9fff3c7/e/a86aaf34d2f4353288df8812"
)
if __name__ == "__main__":
LOGGER.set_file_name("edit.log")
LOGGER.set_stream_level(LogLevel.INFO)

elements = client.get_elements(doc.did, doc.wtype, doc.wid)
variables = client.get_variables(doc.did, doc.wid, elements["variables"].id)

variables["wheelDiameter"].expression = "180 mm"
variables["wheelThickness"].expression = "71 mm"
variables["forkAngle"].expression = "20 deg"

client.set_variables(doc.did, doc.wid, elements["variables"].id, variables)
assembly, _ = client.get_assembly(doc.did, doc.wtype, doc.wid, elements["assembly"].id)

instances, id_to_name_map = get_instances(assembly)
occurrences = get_occurrences(assembly, id_to_name_map)
parts = get_parts(assembly, client, instances)
subassemblies, rigid_subassemblies = get_subassemblies(assembly, client, instances)
mates, relations = get_mates_and_relations(
assembly=assembly,
subassembly_map=subassemblies,
rigid_subassembly_map=rigid_subassemblies,
id_to_name_map=id_to_name_map,
parts=parts,
)
client = Client()
doc = Document.from_url(
url="https://cad.onshape.com/documents/a1c1addf75444f54b504f25c/w/0d17b8ebb2a4c76be9fff3c7/e/a86aaf34d2f4353288df8812"
)

elements = client.get_elements(doc.did, doc.wtype, doc.wid)
variables = client.get_variables(doc.did, doc.wid, elements["variables"].id)

variables["wheelDiameter"].expression = "180 mm"
variables["wheelThickness"].expression = "71 mm"
variables["forkAngle"].expression = "20 deg"

client.set_variables(doc.did, doc.wid, elements["variables"].id, variables)
assembly = client.get_assembly(doc.did, doc.wtype, doc.wid, elements["assembly"].id)

instances, occurrences, id_to_name_map = get_instances(assembly)

subassemblies, rigid_subassemblies = get_subassemblies(assembly, client, instances)
parts = get_parts(assembly, rigid_subassemblies, client, instances)

mates, relations = get_mates_and_relations(assembly, subassemblies, rigid_subassemblies, id_to_name_map, parts)

graph, root_node = create_graph(occurrences=occurrences, instances=instances, parts=parts, mates=mates)
plot_graph(graph, "bike.png")
graph, root_node = create_graph(occurrences=occurrences, instances=instances, parts=parts, mates=mates)
plot_graph(graph, "bike.png")

links, joints = get_urdf_components(assembly, graph, root_node, parts, mates, relations, client)
robot = Robot(name="bike", links=links, joints=joints)
robot.save("bike.urdf")
links, joints, assets = get_urdf_components(assembly, graph, root_node, parts, mates, relations, client)
robot = Robot(name="bike", links=links, joints=joints, assets=assets)
robot.save()
18 changes: 6 additions & 12 deletions examples/export/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,24 @@

from onshape_api.connect import Client
from onshape_api.graph import create_graph, plot_graph
from onshape_api.log import LOGGER
from onshape_api.log import LOGGER, LogLevel
from onshape_api.models.document import Document
from onshape_api.models.robot import Robot
from onshape_api.parse import get_instances, get_mates_and_relations, get_parts, get_subassemblies
from onshape_api.robot import Robot
from onshape_api.urdf import get_urdf_components
from onshape_api.utilities.helpers import save_model_as_json

SCRIPT_DIRECTORY = os.path.dirname(os.path.realpath(__file__))

if __name__ == "__main__":
LOGGER.set_file_name("export.log")
LOGGER.set_stream_level(LogLevel.INFO)
client = Client()
# robot = https://cad.onshape.com/documents/a8f62e825e766a6512320ceb/w/b9099bcbdc92e6d6c810f0b7/e/f5b0475edd5ad0193d280fc4
# robot dog = https://cad.onshape.com/documents/d0223bce364d259e80667122/w/b52c33333c8553dce379aac6/e/57728d0a8bc87b7b065e43be
# simple robot dog = https://cad.onshape.com/documents/64d7b47821f3f5c91e3cd128/w/051d83c286bca38e8952dd84/e/ba886678bddf9de9c01723c8

# test-nested-subassemblies = https://cad.onshape.com/documents/8c7a1c45e27a40a5b6e44d92/w/9c50078d1ac7106985359fe8/e/8c0e0762c95eb6e8b2f4b1f1
# test-transformations = https://cad.onshape.com/documents/9c982cc66e2d3357ecf31371/w/21b699e5966180f4906fb6d1/e/1a44468a497fb472bc80d884
# test-nested-mategroups = https://cad.onshape.com/documents/12124a46ebda8f31ccfe8c8f/w/820e30e034d40fc174232361/e/54c32b7d2abd32b9bf6d9641
# ballbot = https://cad.onshape.com/documents/1f42f849180e6e5c9abfce52/w/0c00b6520fac5fada24b2104/e/c96b40ef586e60c182f41d29

document = Document.from_url(
"https://cad.onshape.com/documents/1f42f849180e6e5c9abfce52/w/0c00b6520fac5fada24b2104/e/c96b40ef586e60c182f41d29"
)
assembly, _ = client.get_assembly(
assembly = client.get_assembly(
did=document.did,
wtype=document.wtype,
wid=document.wid,
Expand Down Expand Up @@ -62,4 +56,4 @@
)

robot = Robot(name=assembly_robot_name, links=links, joints=joints, assets=assets)
robot.save(f"{assembly_robot_name}.urdf")
robot.save()
95 changes: 22 additions & 73 deletions examples/simulation/main.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
import os
from typing import Optional

import mujoco
import mujoco.viewer
import numpy as np
from scipy.spatial.transform import Rotation
from transformations import compute_motor_torques
from utilities import save_gif

from onshape_api.connect import Client
from onshape_api.graph import create_graph
from onshape_api.log import LOGGER
from onshape_api.models.document import Document
from onshape_api.models.robot import Robot
from onshape_api.parse import get_instances, get_mates_and_relations, get_parts, get_subassemblies
from onshape_api.urdf import get_urdf_components
from onshape_api.log import LOGGER, LogLevel
from onshape_api.robot import get_robot
from onshape_api.utilities import save_gif

HEIGHT = 480
WIDTH = 640
Expand Down Expand Up @@ -92,75 +84,32 @@ def control(data, roll_sp=0, pitch_sp=0):
# print(f"Roll {roll}, Pitch: {pitch}")


def export_urdf(url, filename: Optional[str] = None) -> str:
# if file already exists, return
if filename is not None and os.path.exists(f"{filename}.urdf"):
return f"{filename}.urdf"

client = Client()
document = Document.from_url(url)
assembly, _ = client.get_assembly(
did=document.did,
wtype=document.wtype,
wid=document.wid,
eid=document.eid,
)

LOGGER.info(assembly.document.url)
assembly_robot_name = f"{assembly.document.name + '-' + assembly.name}"

instances, occurrences, id_to_name_map = get_instances(assembly)
subassemblies, rigid_subassemblies = get_subassemblies(assembly, client, instances)

parts = get_parts(assembly, rigid_subassemblies, client, instances)
mates, relations = get_mates_and_relations(assembly, subassemblies, rigid_subassemblies, id_to_name_map, parts)

graph, root_node = create_graph(
occurrences=occurrences,
instances=instances,
parts=parts,
mates=mates,
use_user_defined_root=False,
)

links, joints, assets = get_urdf_components(
assembly=assembly,
graph=graph,
root_node=root_node,
parts=parts,
mates=mates,
relations=relations,
client=client,
)

robot = Robot(name=assembly_robot_name, links=links, joints=joints, assets=assets)

if filename is None:
filename = assembly_robot_name

robot.save(f"{filename}.urdf")


if __name__ == "__main__":
urdf_path = export_urdf(
LOGGER.set_file_name("sim.log")
LOGGER.set_stream_level(LogLevel.INFO)

ballbot = get_robot(
url="https://cad.onshape.com/documents/1f42f849180e6e5c9abfce52/w/0c00b6520fac5fada24b2104/e/c96b40ef586e60c182f41d29",
filename="ballbot",
robot_name="ballbot",
)

model = mujoco.MjModel.from_xml_path(filename=urdf_path)
data = mujoco.MjData(model)
ballbot.save()

# run_simulation(model, data, 20, 60)
# model = mujoco.MjModel.from_xml_path(filename=urdf_path)
# mujoco.mj_saveLastXML("ballbot.xml", model)
# data = mujoco.MjData(model)

mujoco.mj_resetData(model, data)
# # run_simulation(model, data, 20, 60)

with mujoco.viewer.launch_passive(model, data, key_callback=key_callback) as viewer:
initial_roll, initial_pitch, initial_yaw = get_theta(data)
# mujoco.mj_resetData(model, data)

while viewer.is_running():
mujoco.mj_step(model, data)
mujoco.mj_forward(model, data)
# with mujoco.viewer.launch_passive(model, data, key_callback=key_callback) as viewer:
# initial_roll, initial_pitch, initial_yaw = get_theta(data)

control(data)
# while viewer.is_running():
# mujoco.mj_step(model, data)
# mujoco.mj_forward(model, data)

# control(data)

viewer.sync()
# viewer.sync()
Loading

0 comments on commit df05b59

Please sign in to comment.