InĀ [1]:
import numpy as np
from robosandbox.optimization.sweeper import ParameterSweeper
np.random.seed(42)
Function¶
InĀ [2]:
import robosandbox.models.DH.Generic as generic
from robosandbox.performance.workspace import WorkSpace
def Global_Index(alpha0, alpha1, method="invcondition", axes="all", **kwargs):
"""function to evaluate robot performance for given alpha values"""
robot = generic.GenericFour(alpha=[alpha0, alpha1, 0, 0])
ws = WorkSpace(robot=robot)
G = ws.global_indice(
initial_samples=3000,
batch_ratio=0.1,
error_tolerance_percentage=1e-3,
method=method,
axes=axes,
max_samples=30000,
is_normalized=kwargs.get("is_normalized", False),
)
return G
InĀ [4]:
import plotly.graph_objects as go
def plot_global_index_results(
alpha_list_deg0,
alpha_list_deg1,
res_mat,
plot_type="heatmap",
method="invcondition",
axes="all",
isSave=False,
step=15,
isNormalized=False,
colorscale="Viridis",
title="",
):
"""
Plot the effect of alpha on the global indices using Plotly.
"""
G_mat = res_mat
fontsize = 40
# Create the appropriate figure based on plot_type
if plot_type == "heatmap":
fig = go.Figure(
data=go.Heatmap(
z=G_mat,
x=alpha_list_deg0,
y=alpha_list_deg1,
colorscale=colorscale,
colorbar=dict(
title=dict(text=title, font=dict(size=fontsize)),
tickfont=dict(size=fontsize),
),
)
)
# Apply layout settings for heatmap
fig.update_layout(
xaxis_title="αā [deg]",
yaxis_title="αā [deg]",
autosize=True,
height=800,
width=900,
xaxis_title_font=dict(size=fontsize),
yaxis_title_font=dict(size=fontsize),
xaxis=dict(tickfont=dict(size=fontsize), dtick=step * 2),
yaxis=dict(tickfont=dict(size=fontsize), dtick=step * 2),
)
elif plot_type == "surface":
fontsize = 40
fig = go.Figure(
data=go.Surface(
z=G_mat,
x=alpha_list_deg0,
y=alpha_list_deg1,
colorbar=dict(
title=dict(text=title, font=dict(size=fontsize)),
tickfont=dict(size=fontsize),
),
colorscale=colorscale,
)
)
# Apply proper 3D scene layout settings for surface plot
fontsize = 18
fig.update_layout(
scene=dict(
xaxis_title="αā [deg]",
yaxis_title="αā [deg]",
xaxis_title_font=dict(size=32),
yaxis_title_font=dict(size=32),
# zaxis_title=method,
xaxis=dict(tickfont=dict(size=fontsize), dtick=step * 4),
yaxis=dict(
# titlefont=dict(size=fontsize),
tickfont=dict(size=fontsize),
dtick=step * 4,
),
# zaxis=dict(
# # titlefont=dict(size=fontsize),
# tickfont=dict(size=fontsize)
# ),
# Do not display z axis's tick and title
zaxis=dict(showticklabels=False, title=""),
camera=dict(eye=dict(x=-1.2, y=-1.2, z=1.65), up=dict(x=0, y=0, z=1)),
# aspectratio=dict(x=1, y=1, z=0.8),
),
autosize=False,
height=800,
width=900,
)
else:
fig = go.Figure() # Default empty figure if plot_type is not recognized
# Save the figure if requested
if isSave:
import os
os.makedirs("fig/two_alpha", exist_ok=True)
fig.write_image(
f"fig/two_alpha/{method}_{axes}_{plot_type}_normalised_{isNormalized}.pdf",
scale=4,
width=900,
height=800,
)
# fig.write_html(
# f"fig/two_alpha/{method}_{axes}_{plot_type}_normalised_{isNormalized}.html"
# )
# Display the figure
fig.show()
Sweeping for Global Inverse Condition Number¶
InĀ [5]:
sweeper = ParameterSweeper(objective_function=Global_Index)
# Define parameter ranges
step = 15
alpha0_list = np.deg2rad(np.arange(0, 181, step))
alpha1_list = np.deg2rad(np.arange(0, 181, step))
InĀ [11]:
method = "invcondition"
normalize_options = [False] # [True, False]
axes_options = ["trans"] # ["trans", "all"]
isRun = (
False # Set to False if you want to load saved data rather than running the sweep
)
for isNormalized in normalize_options:
for axes in axes_options:
filename = f"data/{method}_{axes}_normalized_{isNormalized}.npz"
# Run the sweep or load data
if not isRun:
data = np.load(filename)
results = data["results"]
result_matrix = data["result_matrix"].T
else:
results, result_matrix = sweeper.sweep(
param_dict={"alpha0": alpha0_list, "alpha1": alpha1_list},
fixed_params={
"method": method,
"axes": axes,
"is_normalized": isNormalized,
},
save_intermediate=False,
save_path=filename,
)
# Round the results based on accepted precision
results = np.round(results, 3)
result_matrix = np.round(result_matrix, 3)
# Plot the results
plot_global_index_results(
alpha_list_deg0=alpha0_list * 180 / np.pi,
alpha_list_deg1=alpha1_list * 180 / np.pi,
res_mat=result_matrix,
plot_type="heatmap",
method=method,
axes=axes,
isSave=True,
isNormalized=isNormalized,
step=step,
title="G<sub>k<sub>t</sub><sup>-1</sup></sub>",
)
plot_global_index_results(
alpha_list_deg0=alpha0_list * 180 / np.pi,
alpha_list_deg1=alpha1_list * 180 / np.pi,
res_mat=result_matrix,
plot_type="surface",
method=method,
axes=axes,
isSave=True,
isNormalized=isNormalized,
step=step,
title="G<sub>k<sub>t</sub><sup>-1</sup></sub>",
)
print(f"Completed: method={method}, axes={axes}, isNormalized={isNormalized}")
Completed: method=invcondition, axes=trans, isNormalized=False
Sweeping for Global Yoshikawa Manipulability¶
InĀ [Ā ]:
sweeper = ParameterSweeper(objective_function=Global_Index)
# Define parameter ranges
step = 15
alpha0_list = np.deg2rad(np.arange(0, 181, step))
alpha1_list = np.deg2rad(np.arange(0, 181, step))
method = "yoshikawa"
normalize_options = [False] # [True, False]
axes_options = ["trans"] # ["trans", "all"]
isRun = (
False # Set to False if you want to load saved data rather than running the sweep
)
for isNormalized in normalize_options:
for axes in axes_options:
filename = f"data/{method}_{axes}_normalized_{isNormalized}.npz"
# Run the sweep or load data
if not isRun:
data = np.load(filename)
results = data["results"]
result_matrix = data["result_matrix"].T
else:
results, result_matrix = sweeper.sweep(
param_dict={"alpha0": alpha0_list, "alpha1": alpha1_list},
fixed_params={
"method": method,
"axes": axes,
"is_normalized": isNormalized,
},
save_intermediate=False,
save_path=filename,
)
# Round the results based on accepted precision
results = np.round(results, 3)
result_matrix = np.round(result_matrix, 3)
# Plot the results
plot_global_index_results(
alpha_list_deg0=alpha0_list * 180 / np.pi,
alpha_list_deg1=alpha1_list * 180 / np.pi,
res_mat=result_matrix,
plot_type="heatmap",
method=method,
axes=axes,
isSave=True,
isNormalized=isNormalized,
step=step,
title="G<sub>μ<sub>t</sub></sub>",
)
plot_global_index_results(
alpha_list_deg0=alpha0_list * 180 / np.pi,
alpha_list_deg1=alpha1_list * 180 / np.pi,
res_mat=result_matrix,
plot_type="surface",
method=method,
axes=axes,
isSave=True,
isNormalized=isNormalized,
step=step,
title="G<sub>μ<sub>t</sub></sub>",
)
print(f"Completed: method={method}, axes={axes}, isNormalized={isNormalized}")
alpha0 progress: 100%|āāāāāāāāāā| 13/13 [02:53<00:00, 13.38s/iter]
WARNING Thread(Thread-14 (run)) choreographer.browser_async:browser_async.py:_close()- Resorting to unclean kill browser.
Completed: method=yoshikawa, axes=trans, isNormalized=False
Evaluate $\mu$ and $\mu_t$ on c1¶
InĀ [6]:
c1 = generic.Generic(
dofs=4,
a=[0, -0.4, -0.4, -0.4],
d=[0.4, 0, 0, 0],
alpha=[np.pi / 2, 0, 0, 0],
qlim=[[-np.pi, np.pi]] * 4,
offset=[0, -np.pi / 2, 0, 0],
)
fig = c1.plotly(q=c1.qz, zoom_factor=0.5)
$\mu_t$¶
InĀ [89]:
method = "yoshikawa"
axes = "trans"
c1_ws = WorkSpace(robot=c1)
G_mu_t = c1_ws.global_indice(
initial_samples=3000,
batch_ratio=0.1,
error_tolerance_percentage=1e-2,
method=method,
axes=axes,
max_samples=50000,
is_normalized=False, # Use the slider value here
)
fig = go.Figure()
fig = c1_ws.plot(color=method, fig=fig, isShow=False)
# set color bar range
fig.update_traces(
marker_colorbar=dict(tickfont=dict(size=22), title="μā"),
)
fig.update_layout(
scene=dict(
xaxis_title_font=dict(size=22),
yaxis_title_font=dict(size=22),
zaxis_title_font=dict(size=22),
xaxis=dict(tickfont=dict(size=18)),
yaxis=dict(tickfont=dict(size=18)),
zaxis=dict(tickfont=dict(size=18)),
camera=dict(
eye=dict(
x=1.6,
y=-1.6,
z=1,
), # Position of the camera
center=dict(x=0, y=0, z=0), # Point the camera is looking at
up=dict(x=0, y=0, z=1), # Up vector direction
),
),
width=800,
height=600,
margin=dict(l=0, r=0, b=0, t=0),
)
fig.show("png")
fig.write_image(f"./fig/workspace_{method}_{axes}.pdf", scale=4)
WARNING Thread(Thread-289 (run)) choreographer.browser_async:browser_async.py:_close()- Resorting to unclean kill browser.
InĀ [87]:
print(f"Global translational manipulability of c1: {G_mu_t}")
Global translational manipulability of c1: 0.10550654203634664
$\mu$¶
InĀ [Ā ]:
method = "yoshikawa"
axes = "all"
c1_ws = WorkSpace(robot=c1)
G_mu = c1_ws.global_indice(
initial_samples=3000,
batch_ratio=0.1,
error_tolerance_percentage=1e-2,
method=method,
axes=axes,
max_samples=50000,
is_normalized=False, # Use the slider value here
)
fig = go.Figure()
fig = c1_ws.plot(color=method, fig=fig, isShow=False)
fig.update_traces(
marker_colorbar=dict(tickfont=dict(size=22), title="μ"),
marker=dict(cmin=0, cmax=0.001),
)
fig.update_layout(
scene=dict(
xaxis_title_font=dict(size=22),
yaxis_title_font=dict(size=22),
zaxis_title_font=dict(size=22),
xaxis=dict(tickfont=dict(size=18)),
yaxis=dict(tickfont=dict(size=18)),
zaxis=dict(tickfont=dict(size=18)),
camera=dict(
eye=dict(
x=1.6,
y=-1.6,
z=1,
), # Position of the camera
center=dict(x=0, y=0, z=0), # Point the camera is looking at
up=dict(x=0, y=0, z=1), # Up vector direction
),
),
width=800,
height=600,
margin=dict(l=0, r=0, b=0, t=0),
)
fig.show("png")
fig.write_image(f"./fig/workspace_{method}_{axes}.pdf", scale=4)
InĀ [85]:
print(f"Global manipulability of c1: {G_mu}")
Global manipulability of c1: 2.7393050132558384e-18