RSI-PI/src/RSIPI/kuka_visualiser.py
2025-04-13 22:48:42 +01:00

160 lines
5.1 KiB
Python

import pandas as pd
import matplotlib.pyplot as plt
import argparse
import os
class KukaRSIVisualiser:
"""
Visualises robot motion and diagnostics from RSI-generated CSV logs.
Supports:
- 3D trajectory plotting (actual vs planned)
- Joint position plotting with safety band overlays
- Force correction trend visualisation
- Optional graph export to PNG
"""
def __init__(self, csv_file, safety_limits=None):
"""
Initialise the visualiser.
Args:
csv_file (str): Path to the RSI CSV log.
safety_limits (dict): Optional dict of axis limits (e.g., {"AIPos.A1": [-170, 170]}).
"""
self.csv_file = csv_file
self.safety_limits = safety_limits or {}
if not os.path.exists(csv_file):
raise FileNotFoundError(f"CSV file {csv_file} not found.")
self.df = pd.read_csv(csv_file)
def plot_trajectory(self, save_path=None):
"""
Plots the 3D robot trajectory from actual and planned data.
Args:
save_path (str): Optional path to save the figure.
"""
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(self.df["RIst.X"], self.df["RIst.Y"], self.df["RIst.Z"],
label="Actual Trajectory", linestyle='-')
if "RSol.X" in self.df.columns:
ax.plot(self.df["RSol.X"], self.df["RSol.Y"], self.df["RSol.Z"],
label="Planned Trajectory", linestyle='--')
ax.set_xlabel("X Position")
ax.set_ylabel("Y Position")
ax.set_zlabel("Z Position")
ax.set_title("Robot Trajectory")
ax.legend()
if save_path:
plt.savefig(save_path)
plt.show()
def has_column(self, col):
"""
Checks if the given column exists in the dataset.
Args:
col (str): Column name to check.
"""
return col in self.df.columns
def plot_joint_positions(self, save_path=None):
"""
Plots joint angle positions over time, with optional safety zone overlays.
Args:
save_path (str): Optional path to save the figure.
"""
plt.figure()
time_series = range(len(self.df))
for col in ["AIPos.A1", "AIPos.A2", "AIPos.A3", "AIPos.A4", "AIPos.A5", "AIPos.A6"]:
if col in self.df.columns:
plt.plot(time_series, self.df[col], label=col)
if col in self.safety_limits:
low, high = self.safety_limits[col]
plt.axhspan(low, high, color='red', alpha=0.1, label=f"{col} Safe Zone")
plt.xlabel("Time Steps")
plt.ylabel("Joint Position (Degrees)")
plt.title("Joint Positions Over Time")
plt.legend()
if save_path:
plt.savefig(save_path)
plt.show()
def plot_force_trends(self, save_path=None):
"""
Plots force correction trends (PosCorr.*) over time, if present.
Args:
save_path (str): Optional path to save the figure.
"""
force_columns = ["PosCorr.X", "PosCorr.Y", "PosCorr.Z"]
plt.figure()
time_series = range(len(self.df))
for col in force_columns:
if col in self.df.columns:
plt.plot(time_series, self.df[col], label=col)
if col in self.safety_limits:
low, high = self.safety_limits[col]
plt.axhspan(low, high, color='red', alpha=0.1, label=f"{col} Safe Zone")
plt.xlabel("Time Steps")
plt.ylabel("Force Correction (N)")
plt.title("Force Trends Over Time")
plt.legend()
if save_path:
plt.savefig(save_path)
plt.show()
def export_graphs(self, export_dir="exports"):
"""
Saves all graphs (trajectory, joints, force) as PNG images.
Args:
export_dir (str): Output directory.
"""
os.makedirs(export_dir, exist_ok=True)
self.plot_trajectory(save_path=os.path.join(export_dir, "trajectory.png"))
self.plot_joint_positions(save_path=os.path.join(export_dir, "joint_positions.png"))
self.plot_force_trends(save_path=os.path.join(export_dir, "force_trends.png"))
print(f"Graphs exported to {export_dir}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Visualise RSI data logs.")
parser.add_argument("csv_file", type=str, help="Path to the RSI CSV log file.")
parser.add_argument("--export", action="store_true", help="Export graphs as PNG/PDF.")
parser.add_argument("--limits", type=str, help="Optional .rsi.xml file to overlay safety bands")
args = parser.parse_args()
if args.limits:
from src.RSIPI.rsi_limit_parser import parse_rsi_limits
limits = parse_rsi_limits(args.limits)
visualiser = Kukarsivisualiser(args.csv_file, safety_limits=limits)
else:
visualiser = Kukarsivisualiser(args.csv_file)
visualiser.plot_trajectory()
visualiser.plot_joint_positions()
visualiser.plot_force_trends()
if args.export:
visualiser.export_graphs()