Skip to content

Commit 7801820

Browse files
Merge pull request #66 from neurobionics/65-bug-set_variables-payload-missing-required-type-field-api-contract-mismatch
Fixes #65: set variables bug
2 parents 19329ad + c5d35f4 commit 7801820

File tree

7 files changed

+80
-34
lines changed

7 files changed

+80
-34
lines changed

examples/edit/main.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from onshape_robotics_toolkit.connect import Client
2+
from onshape_robotics_toolkit.formats.urdf import URDFSerializer
23
from onshape_robotics_toolkit.graph import KinematicGraph
34
from onshape_robotics_toolkit.models.document import Document
45
from onshape_robotics_toolkit.parse import CAD
@@ -23,17 +24,14 @@
2324
variables["wheelThickness"].expression = "71 mm"
2425
variables["forkAngle"].expression = "20 deg"
2526

26-
# Create dictionary with variable names and their new expressions
27-
variables_to_set = {
28-
"wheelDiameter": variables["wheelDiameter"].expression,
29-
"wheelThickness": variables["wheelThickness"].expression,
30-
"forkAngle": variables["forkAngle"].expression,
31-
}
32-
33-
client.set_variables(document.did, document.wid, elements["variables"].id, variables_to_set)
27+
client.set_variables(document.did, document.wid, elements["variables"].id, variables=variables)
3428
assembly = client.get_assembly(document.did, document.wtype, document.wid, elements["assembly"].id)
3529

3630
cad = CAD.from_assembly(assembly, max_depth=MAX_DEPTH, client=client)
3731
graph = KinematicGraph.from_cad(cad, use_user_defined_root=True)
3832
robot = Robot.from_graph(kinematic_graph=graph, client=client, name=f"edit_{MAX_DEPTH}")
39-
robot.save()
33+
34+
urdf_serializer = URDFSerializer()
35+
urdf_serializer.save(
36+
robot=robot, file_path="output/edited_robot.urdf", download_assets=True, mesh_dir="output/meshes"
37+
)

examples/simulation/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Simulation Example
2+
3+
This example demonstrates how to use the onshape-robotics-toolkit with MuJoCo for physics simulation and Optuna for design optimization of a ballbot robot.
4+
5+
## Additional Dependencies
6+
7+
This example requires additional dependencies that are not part of the core toolkit. Install them using:
8+
9+
```bash
10+
pip install onshape-robotics-toolkit[simulation]
11+
```
12+
13+
Or if you're using uv:
14+
15+
```bash
16+
uv pip install onshape-robotics-toolkit[simulation]
17+
```
18+
19+
This will install:
20+
21+
- `mujoco` - Physics simulation engine
22+
- `optuna` - Hyperparameter optimization framework
23+
- `plotly` - Interactive visualization library
24+
- `usd-core` - Universal Scene Description for 3D scene export
25+
26+
## Running the Example
27+
28+
After installing the simulation dependencies, you can run the example:
29+
30+
```bash
31+
python examples/simulation/main.py
32+
```
33+
34+
The script will prompt you for a run name and then perform:
35+
36+
1. Design optimization (finding optimal physical parameters)
37+
2. Control optimization (tuning PID controllers)
38+
3. Export simulation results as USD files and visualization plots

examples/simulation/main.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
"""
2+
Ballbot Design and Control Optimization Example
3+
4+
This example requires additional simulation dependencies.
5+
Install them with: pip install onshape-robotics-toolkit[simulation]
6+
"""
7+
18
import json
29
import os
310
from functools import partial
@@ -302,14 +309,7 @@ def find_best_design_variables(trial):
302309
variables["spacer_height"].expression = f"{spacer_height:.1f} mm"
303310
variables["plate_thickness"].expression = f"{plate_thickness:.1f} mm"
304311

305-
variables_to_set = {
306-
"wheel_diameter": variables["wheel_diameter"].expression,
307-
"alpha": variables["alpha"].expression,
308-
"spacer_height": variables["spacer_height"].expression,
309-
"plate_thickness": variables["plate_thickness"].expression,
310-
}
311-
312-
client.set_variables(doc.did, doc.wid, elements["variables"].id, variables_to_set)
312+
client.set_variables(doc.did, doc.wid, elements["variables"].id, variables=variables)
313313
assembly = client.get_assembly(doc.did, doc.wtype, doc.wid, doc.eid)
314314

315315
cad = CAD.from_assembly(assembly, max_depth=1, client=client)

onshape_robotics_toolkit/connect.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -350,15 +350,15 @@ def get_variables(self, did: str, wid: str, eid: str) -> dict[str, Variable]:
350350

351351
return {variable["name"]: Variable.model_validate(variable) for variable in _variables_json[0]["variables"]}
352352

353-
def set_variables(self, did: str, wid: str, eid: str, variables: dict[str, str]) -> requests.Response:
353+
def set_variables(self, did: str, wid: str, eid: str, variables: dict[str, Variable]) -> requests.Response:
354354
"""
355355
Set values for variables of a variable studio in a document.
356356
357357
Args:
358358
did: The unique identifier of the document.
359359
wid: The unique identifier of the workspace.
360360
eid: The unique identifier of the variable studio.
361-
variables: A dictionary of variable name and expression pairs.
361+
variables: A dictionary of variable name and Variable pairs
362362
363363
Returns:
364364
requests.Response: Response from Onshape API after setting the variables.
@@ -376,8 +376,11 @@ def set_variables(self, did: str, wid: str, eid: str, variables: dict[str, str])
376376
... )
377377
<Response [200]>
378378
"""
379+
for var_name, variable in variables.items():
380+
if not isinstance(variable, Variable):
381+
raise TypeError(f"Variable '{var_name}' is not a valid Variable object.")
379382

380-
payload = [{"name": name, "expression": expression} for name, expression in variables.items()]
383+
payload = [variable.model_dump() for variable in variables.values()]
381384

382385
# api/v9/variables/d/a1c1addf75444f54b504f25c/w/0d17b8ebb2a4c76be9fff3c7/e/cba5e3ca026547f34f8d9f0f/variables
383386
request_path = "/api/variables/d/" + did + "/w/" + wid + "/e/" + eid + "/variables"
@@ -388,7 +391,9 @@ def set_variables(self, did: str, wid: str, eid: str, variables: dict[str, str])
388391
body=payload,
389392
)
390393

391-
record_variable_update(element_id=eid, expressions=variables)
394+
# Extract expressions from Variable objects for session recording
395+
expressions = {name: var.expression for name, var in variables.items() if var.expression is not None}
396+
record_variable_update(element_id=eid, expressions=expressions)
392397

393398
return response
394399

onshape_robotics_toolkit/formats/mjcf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def load_element(file_name: str) -> ET._Element:
3838
root: ET._Element = tree.getroot()
3939
return root
4040

41+
4142
if TYPE_CHECKING:
4243
from onshape_robotics_toolkit.parse import PathKey
4344
from onshape_robotics_toolkit.robot import Robot

pyproject.toml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ filterwarnings = [
8484
target-version = "py39"
8585
line-length = 120
8686
fix = true
87+
88+
[tool.ruff.lint]
8789
select = [
8890
# flake8-2020
8991
"YTT",
@@ -125,6 +127,9 @@ ignore = [
125127
"TRY300",
126128
]
127129

130+
[tool.ruff.lint.per-file-ignores]
131+
"tests/*" = ["S101"]
132+
128133
[tool.ruff.format]
129134
preview = true
130135

@@ -135,11 +140,8 @@ skip_empty = true
135140
branch = true
136141
source = ["onshape_robotics_toolkit"]
137142

138-
[tool.ruff.per-file-ignores]
139-
"tests/*" = ["S101"]
140-
141143
[tool.deptry]
142144
# Skip example directories as they are not part of the main package
143145
extend_exclude = ["examples"]
144146
# Set dev dependency groups to ignore test/dev dependencies in obsolete check
145-
pep621_dev_dependency_groups = ["docs"]
147+
pep621_dev_dependency_groups = ["docs", "simulation"]

uv.lock

Lines changed: 11 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)