add: modify project param
This commit is contained in:
@@ -5,7 +5,7 @@ mode = "geometric"
|
||||
max_tilt = 0.35 # rad,仅 linear 外环限幅
|
||||
|
||||
[position.linear]
|
||||
kp = 0.8
|
||||
kp = 8.8
|
||||
ki = 0.2
|
||||
kd = 0.9
|
||||
|
||||
|
||||
@@ -42,6 +42,8 @@ from uavcatch.eval import (
|
||||
|
||||
evaluate_maneuver,
|
||||
|
||||
plot_control_performance,
|
||||
|
||||
plot_maneuver_report,
|
||||
|
||||
plot_summary_comparison,
|
||||
@@ -290,13 +292,23 @@ def main() -> int:
|
||||
|
||||
out_file = args.output / f"{spec.name}.png"
|
||||
|
||||
plot_maneuver_report(data, metrics, save_path=out_file, show=args.show)
|
||||
plot_maneuver_report(data, metrics, save_path=out_file, show=args.show, show_actuator=False)
|
||||
|
||||
ctrl_file = args.output / f"{spec.name}_control.png"
|
||||
plot_control_performance(
|
||||
data,
|
||||
metrics,
|
||||
omega_max=uav_cfg.rotor.omega_max,
|
||||
save_path=ctrl_file,
|
||||
show=args.show,
|
||||
)
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
plt.close("all")
|
||||
|
||||
print(f" -> saved {out_file}")
|
||||
print(f" -> saved {ctrl_file}")
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 211 KiB After Width: | Height: | Size: 167 KiB |
BIN
output/eval_control/circle_control.png
Normal file
BIN
output/eval_control/circle_control.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 182 KiB |
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from uavcatch.eval.maneuvers import ManeuverSpec, default_maneuver_suite
|
||||
from uavcatch.eval.metrics import ManeuverMetrics, evaluate_maneuver
|
||||
from uavcatch.eval.plots import plot_maneuver_report, plot_summary_comparison
|
||||
from uavcatch.eval.plots import plot_control_performance, plot_maneuver_report, plot_summary_comparison
|
||||
from uavcatch.eval.recorder import SimRecorder
|
||||
|
||||
__all__ = [
|
||||
@@ -13,6 +13,7 @@ __all__ = [
|
||||
"SimRecorder",
|
||||
"default_maneuver_suite",
|
||||
"evaluate_maneuver",
|
||||
"plot_control_performance",
|
||||
"plot_maneuver_report",
|
||||
"plot_summary_comparison",
|
||||
]
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -15,17 +15,17 @@ def plot_maneuver_report(
|
||||
metrics: ManeuverMetrics,
|
||||
save_path: Path | None = None,
|
||||
show: bool = False,
|
||||
show_actuator: bool = True,
|
||||
) -> plt.Figure:
|
||||
time = data["time"]
|
||||
pos = data["position"]
|
||||
target = data["target_position"]
|
||||
err = data["tracking_error"]
|
||||
euler = np.degrees(data["euler"])
|
||||
omega = data["omega"]
|
||||
|
||||
fig = plt.figure(figsize=(12, 10))
|
||||
nrows = 4 if show_actuator else 3
|
||||
fig = plt.figure(figsize=(12, 10 if show_actuator else 8))
|
||||
fig.suptitle(f"{metrics.name} [{metrics.mode}] - {metrics.description}", fontsize=11)
|
||||
gs = fig.add_gridspec(4, 3, hspace=0.35, wspace=0.28)
|
||||
gs = fig.add_gridspec(nrows, 3, hspace=0.35, wspace=0.28)
|
||||
|
||||
labels = ("x", "y", "z")
|
||||
colors = ("#2563eb", "#16a34a", "#dc2626")
|
||||
@@ -48,24 +48,29 @@ def plot_maneuver_report(
|
||||
ax.set_xlabel("Time (s)")
|
||||
ax.grid(alpha=0.3)
|
||||
|
||||
ax_att = fig.add_subplot(gs[2, 0])
|
||||
att_labels = ("roll", "pitch", "yaw")
|
||||
for i, (lab, c) in enumerate(zip(att_labels, colors)):
|
||||
ax_att.plot(time, euler[:, i], color=c, linewidth=1.2, label=lab)
|
||||
ax_att.set_ylabel("Attitude (deg)")
|
||||
ax_att.set_xlabel("Time (s)")
|
||||
ax_att.legend(fontsize=8)
|
||||
ax_att.grid(alpha=0.3)
|
||||
if show_actuator:
|
||||
euler = np.degrees(data["euler"])
|
||||
omega = data["omega"]
|
||||
|
||||
ax_om = fig.add_subplot(gs[2, 1:])
|
||||
for i in range(omega.shape[1]):
|
||||
ax_om.plot(time, omega[:, i], linewidth=1.0, alpha=0.85, label=f"m{i + 1}")
|
||||
ax_om.set_ylabel("Motor ω (rad/s)")
|
||||
ax_om.set_xlabel("Time (s)")
|
||||
ax_om.legend(fontsize=7, ncol=2)
|
||||
ax_om.grid(alpha=0.3)
|
||||
ax_att = fig.add_subplot(gs[2, 0])
|
||||
att_labels = ("roll", "pitch", "yaw")
|
||||
for i, (lab, c) in enumerate(zip(att_labels, colors)):
|
||||
ax_att.plot(time, euler[:, i], color=c, linewidth=1.2, label=lab)
|
||||
ax_att.set_ylabel("Attitude (deg)")
|
||||
ax_att.set_xlabel("Time (s)")
|
||||
ax_att.legend(fontsize=8)
|
||||
ax_att.grid(alpha=0.3)
|
||||
|
||||
ax_txt = fig.add_subplot(gs[3, :])
|
||||
ax_om = fig.add_subplot(gs[2, 1:])
|
||||
for i in range(omega.shape[1]):
|
||||
ax_om.plot(time, omega[:, i], linewidth=1.0, alpha=0.85, label=f"m{i + 1}")
|
||||
ax_om.set_ylabel("Motor ω (rad/s)")
|
||||
ax_om.set_xlabel("Time (s)")
|
||||
ax_om.legend(fontsize=7, ncol=2)
|
||||
ax_om.grid(alpha=0.3)
|
||||
|
||||
txt_row = 3 if show_actuator else 2
|
||||
ax_txt = fig.add_subplot(gs[txt_row, :])
|
||||
ax_txt.axis("off")
|
||||
lines = [
|
||||
f"3D RMSE = {metrics.tracking.rmse_3d:.4f} m | Max error = {metrics.tracking.max_error_3d:.4f} m",
|
||||
@@ -91,6 +96,68 @@ def plot_maneuver_report(
|
||||
return fig
|
||||
|
||||
|
||||
def plot_control_performance(
|
||||
data: dict[str, np.ndarray],
|
||||
metrics: ManeuverMetrics,
|
||||
omega_max: float | None = None,
|
||||
save_path: Path | None = None,
|
||||
show: bool = False,
|
||||
) -> plt.Figure:
|
||||
"""Supplementary figure focused on velocity tracking and motor control."""
|
||||
time = data["time"]
|
||||
vel = data["velocity"]
|
||||
tgt_vel = data["target_velocity"]
|
||||
omega = data["omega"]
|
||||
vel_err = tgt_vel - vel
|
||||
|
||||
fig = plt.figure(figsize=(12, 9))
|
||||
fig.suptitle(f"{metrics.name} — Control Performance", fontsize=11, fontweight="bold")
|
||||
gs = fig.add_gridspec(3, 3, hspace=0.35, wspace=0.28)
|
||||
|
||||
labels = ("x", "y", "z")
|
||||
colors = ("#2563eb", "#16a34a", "#dc2626")
|
||||
|
||||
# --- Velocity tracking ---
|
||||
ax_vel = fig.add_subplot(gs[0, :])
|
||||
for i, (lab, c) in enumerate(zip(labels, colors)):
|
||||
ax_vel.plot(time, tgt_vel[:, i], "--", color=c, alpha=0.5, linewidth=1.0, label=f"{lab} ref")
|
||||
ax_vel.plot(time, vel[:, i], "-", color=c, linewidth=1.5, label=f"{lab} act")
|
||||
ax_vel.set_ylabel("Velocity (m/s)")
|
||||
ax_vel.set_xlabel("Time (s)")
|
||||
ax_vel.legend(loc="upper right", ncol=3, fontsize=8)
|
||||
ax_vel.grid(alpha=0.3)
|
||||
|
||||
# --- Velocity error per axis ---
|
||||
for i, (lab, c) in enumerate(zip(labels, colors)):
|
||||
ax = fig.add_subplot(gs[1, i])
|
||||
ax.plot(time, vel_err[:, i], color=c, linewidth=1.3)
|
||||
ax.axhline(0.0, color="k", linewidth=0.6, alpha=0.4)
|
||||
rmse = float(np.sqrt(np.mean(vel_err[:, i] ** 2)))
|
||||
ax.set_title(f"Vel Error {lab} RMSE={rmse:.3f} m/s")
|
||||
ax.set_ylabel("Error (m/s)")
|
||||
ax.set_xlabel("Time (s)")
|
||||
ax.grid(alpha=0.3)
|
||||
|
||||
# --- Motor speeds ---
|
||||
ax_om = fig.add_subplot(gs[2, :])
|
||||
for i in range(omega.shape[1]):
|
||||
ax_om.plot(time, omega[:, i], linewidth=1.0, alpha=0.85, label=f"m{i + 1}")
|
||||
if omega_max is not None:
|
||||
ax_om.axhline(omega_max, color="red", linewidth=0.8, linestyle="--", alpha=0.6, label=f"ω_max={omega_max:.0f}")
|
||||
ax_om.set_ylabel("Motor ω (rad/s)")
|
||||
ax_om.set_xlabel("Time (s)")
|
||||
ax_om.legend(fontsize=7, ncol=4)
|
||||
ax_om.grid(alpha=0.3)
|
||||
|
||||
if save_path is not None:
|
||||
save_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
fig.savefig(save_path, dpi=140, bbox_inches="tight")
|
||||
|
||||
if show:
|
||||
plt.show()
|
||||
return fig
|
||||
|
||||
|
||||
def plot_summary_comparison(
|
||||
all_metrics: list[ManeuverMetrics],
|
||||
save_path: Path | None = None,
|
||||
|
||||
Reference in New Issue
Block a user