Skip to content

Commit 22e5c4e

Browse files
fix: part names with - throw errors in USD export
1 parent fc14b06 commit 22e5c4e

File tree

2 files changed

+84
-30
lines changed

2 files changed

+84
-30
lines changed

examples/simulation/main.py

Lines changed: 83 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,34 @@
1919
from onshape_robotics_toolkit.models.document import Document
2020
from onshape_robotics_toolkit.robot import Robot, RobotType
2121

22-
N_DESIGN_TRAILS = 50
23-
N_PID_TRAILS = 150
22+
N_DESIGN_TRAILS = 100
23+
N_PID_TRAILS = 50
2424

2525
USE_MUJOCO_VIEWER = False
2626

2727
HEIGHT = 480
2828
WIDTH = 640
2929

3030
FREQUENCY = 200
31-
USD_FRAME_RATE = 30
31+
USD_FRAME_RATE = 25
3232
dt = 1 / FREQUENCY
3333

3434
# Variable bounds (in mm and degrees)
35-
WHEEL_DIAMETER_BOUNDS = (100, 200)
36-
SPACER_HEIGHT_BOUNDS = (75, 200)
37-
ALPHA_BOUNDS = (30, 55)
35+
WHEEL_DIAMETER_BOUNDS = (100, 150)
36+
SPACER_HEIGHT_BOUNDS = (75, 150)
37+
ALPHA_BOUNDS = (35, 50)
3838
PLATE_BOUNDS = (1, 30)
3939

40-
SIMULATION_DURATION = 200 # seconds to run each trial
40+
LAMBDA_WEIGHT = 100.0
41+
BETA_WEIGHT = 25.0
42+
43+
SIMULATION_DURATION = 120 # seconds to run each trial
4144
VIBRATION_PENALTY = 1e-3
4245

43-
TARGET_VALUE = 100.0 # Exit control optimation if balanced for this long
46+
TARGET_VALUE = 50.0 # Exit control optimation if balanced for this long
4447
PERTURBATION_INCREASE = 0.125 # Amount of Newtons to increase perturbation by each time
4548
PERTURBATION_START = 5 # Time delay before perturbations begin
46-
PERTURBATION_REST = 7.5 # Time delay between perturbations
49+
PERTURBATION_REST = 7 # Time delay between perturbations
4750

4851
MAX_ANGLE = np.deg2rad(60)
4952
MAX_DISTANCE_FROM_BALL = 0.3 # meters
@@ -54,7 +57,7 @@
5457
KD = 2.4
5558
FF = 0.2
5659

57-
DERIVATIVE_FILTER_ALPHA = 0.2
60+
DERIVATIVE_FILTER_ALPHA = 0.1
5861

5962
TORQUE_LIMIT_HIGH = 10.0
6063
TORQUE_LIMIT_LOW = -10.0
@@ -169,9 +172,9 @@ def apply_perturbation(data, count):
169172

170173
def find_best_pid_params(trial, model, data, viewer, variables, usd_output_dir):
171174
# Suggest values for the PID gains
172-
kp = trial.suggest_float('kp', low=2, high=25.0, step=0.1)
175+
kp = trial.suggest_float('kp', low=5, high=25.0, step=0.1)
173176
ki = trial.suggest_float('ki', low=0.0, high=15.0, step=0.1)
174-
kd = trial.suggest_float('kd', low=0.0, high=1.0, step=0.001)
177+
kd = trial.suggest_float('kd', low=0.0, high=1.0, step=0.01)
175178
ff = trial.suggest_float('ff', low=0.01, high=1.01, step=0.05)
176179

177180
LOGGER.info(f"KP: {kp}, KI: {ki}, KD: {kd}, FF: {ff}")
@@ -208,10 +211,14 @@ def find_best_pid_params(trial, model, data, viewer, variables, usd_output_dir):
208211
roll_pid.reset()
209212
pitch_pid.reset()
210213

214+
# Initialize variables to track distance
215+
cumulative_distance = 0.0
216+
cumulative_vibration = 0.0
217+
steps = 0
218+
211219
# Run the simulation
212220
j = 0
213221

214-
#while data.time < SIMULATION_DURATION and viewer.is_running():
215222
while data.time < SIMULATION_DURATION:
216223
mujoco.mj_step(model, data)
217224

@@ -228,14 +235,35 @@ def find_best_pid_params(trial, model, data, viewer, variables, usd_output_dir):
228235
if exit_condition(data):
229236
break
230237

231-
viewer.sync()
238+
ball_pos = get_ball_pos(data)
239+
distance = np.linalg.norm(np.array(ball_pos))
240+
cumulative_distance += distance
232241

233-
# Combine performance metric with vibration penalty
234-
time_on_ball = data.time # TODO: Make this more accurate with contact detection
242+
dtheta = get_dtheta(data)
243+
cumulative_vibration += np.linalg.norm(dtheta)
244+
steps += 1
245+
246+
if USE_MUJOCO_VIEWER:
247+
viewer.sync()
248+
elif viewer.is_running():
249+
viewer.close()
250+
251+
# Combine performance metric with vibration penalty and distance
252+
time_on_ball = data.time # Time the ball stayed on top
253+
average_distance = cumulative_distance / steps if steps > 0 else 0.0
254+
average_vibration = cumulative_vibration / steps if steps > 0 else 0.0
255+
objective_value = time_on_ball - LAMBDA_WEIGHT * average_distance - BETA_WEIGHT * average_vibration
256+
257+
LOGGER.info(
258+
f"Time on Ball: {time_on_ball}, "
259+
f"Average Distance: {average_distance}, "
260+
f"Average Vibration: {average_vibration}, "
261+
f"Objective: {objective_value}"
262+
)
235263

236264
usd_exporter.save_scene(filetype="usd")
237265

238-
return time_on_ball
266+
return objective_value
239267

240268
def stop_when_target_reached(study, trial):
241269
if trial.value is not None and trial.value >= TARGET_VALUE:
@@ -346,6 +374,11 @@ def find_best_design_variables(trial):
346374
if not USE_MUJOCO_VIEWER:
347375
viewer.close()
348376

377+
# Initialize variables to track distance
378+
cumulative_distance = 0.0
379+
cumulative_vibration = 0.0
380+
steps = 0
381+
349382
#while data.time < SIMULATION_DURATION and viewer.is_running():
350383
while data.time < SIMULATION_DURATION:
351384
mujoco.mj_step(model, data)
@@ -373,15 +406,36 @@ def find_best_design_variables(trial):
373406
if exit_condition(data):
374407
break
375408

409+
ball_pos = get_ball_pos(data)
410+
distance = np.linalg.norm(np.array(ball_pos))
411+
cumulative_distance += distance
412+
413+
dtheta = get_dtheta(data)
414+
cumulative_vibration += np.linalg.norm(dtheta)
415+
steps += 1
376416

377417
if USE_MUJOCO_VIEWER:
378418
viewer.sync()
379419
elif viewer.is_running():
380420
viewer.close()
381421

382-
objective_value = data.time
422+
time_on_ball = data.time # Time the ball stayed on top
423+
average_distance = cumulative_distance / steps if steps > 0 else 0.0
424+
average_vibration = cumulative_vibration / steps if steps > 0 else 0.0
425+
426+
objective_value = time_on_ball - LAMBDA_WEIGHT * average_distance - BETA_WEIGHT * average_vibration
427+
428+
LOGGER.info(
429+
f"Time on Ball: {time_on_ball}, "
430+
f"Average Distance: {average_distance}, "
431+
f"Average Vibration: {average_vibration}, "
432+
f"Objective: {objective_value}"
433+
)
434+
435+
436+
if viewer.is_running():
437+
viewer.close()
383438

384-
viewer.close()
385439
usd_exporter.save_scene(filetype="usd")
386440

387441
return objective_value
@@ -390,14 +444,14 @@ def find_best_design_variables(trial):
390444
if __name__ == "__main__":
391445
run_name = input("Enter run name: ")
392446
# Create output directory for this run
393-
output_dir = f"{run_name}"
447+
output_dir = run_name
394448
os.makedirs(output_dir, exist_ok=True)
395449
os.makedirs(os.path.join(output_dir, "scenes"), exist_ok=True) # Create scenes subdirectory
396450
# Update log file path
397-
LOGGER.set_file_name(f"{output_dir}/{run_name}.log")
451+
LOGGER.set_file_name(os.path.join(output_dir, f"{run_name}.log"))
398452
LOGGER.set_stream_level(LogLevel.INFO)
399453

400-
client = Client()
454+
client = Client(env=".env")
401455
doc = Document.from_url(
402456
url="https://cad.onshape.com/documents/01d73bbd0f243938a11fbb7c/w/20c6ecfe7711055ba2420fdc/e/833959fcd6ba649195a1e94c"
403457
)
@@ -421,7 +475,7 @@ def find_best_design_variables(trial):
421475
LOGGER.info(f" ff: {study.best_trial.user_attrs['ff']}")
422476

423477
# Save outputs in the run directory
424-
with open(f"{output_dir}/best_params.json", "w") as f:
478+
with open(os.path.join(output_dir, "best_params.json"), "w") as f:
425479
# Combine design parameters and PID values
426480
all_params = {
427481
**study.best_trial.params,
@@ -434,21 +488,21 @@ def find_best_design_variables(trial):
434488
}
435489
json.dump(all_params, f)
436490

437-
study.trials_dataframe().to_csv(f"{output_dir}/data.csv")
491+
study.trials_dataframe().to_csv(os.path.join(output_dir, "data.csv"))
438492

439493
# Save visualization plots
440494
contour_plot = optuna.visualization.plot_contour(study)
441-
plotly.io.write_html(contour_plot, f"{output_dir}/contour.html")
495+
plotly.io.write_html(contour_plot, os.path.join(output_dir, "contour.html"))
442496

443497
optimization_history_plot = optuna.visualization.plot_optimization_history(study)
444-
plotly.io.write_html(optimization_history_plot, f"{output_dir}/optimization_history.html")
498+
plotly.io.write_html(optimization_history_plot, os.path.join(output_dir, "optimization_history.html"))
445499

446500
hyperparameter_importance_plot = optuna.visualization.plot_param_importances(study)
447-
plotly.io.write_html(hyperparameter_importance_plot, f"{output_dir}/hyperparameter_importance.html")
501+
plotly.io.write_html(hyperparameter_importance_plot, os.path.join(output_dir, "hyperparameter_importance.html"))
448502

449503
timeline_plot = optuna.visualization.plot_timeline(study)
450-
plotly.io.write_html(timeline_plot, f"{output_dir}/timeline.html")
504+
plotly.io.write_html(timeline_plot, os.path.join(output_dir, "timeline.html"))
451505

452506
parallel_coordinate_plot = optuna.visualization.plot_parallel_coordinate(study)
453-
plotly.io.write_html(parallel_coordinate_plot, f"{output_dir}/parallel_coordinate.html")
507+
plotly.io.write_html(parallel_coordinate_plot, os.path.join(output_dir, "parallel_coordinate.html"))
454508

examples/simulation/mods.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def modify_ballbot(ballbot: Robot) -> Robot:
9292

9393
ballbot.add_custom_element_by_tag(name="contact", parent_tag="mujoco", element=contact)
9494

95-
ballbot_mesh = ET.Element("mesh", attrib={"name": "Part_1_1", "file": "meshes/ball.stl"})
95+
ballbot_mesh = ET.Element("mesh", attrib={"name": "Part_1_1", "file": "meshes\\ball.stl"})
9696
ballbot.add_custom_element_by_tag(name="ballbot", parent_tag="asset", element=ballbot_mesh)
9797
ball = load_element("ball.xml")
9898
ballbot.add_custom_element_by_tag(name="ball", parent_tag="worldbody", element=ball)

0 commit comments

Comments
 (0)