diff --git a/catkin_ws/src/panda_autodynamics/scripts/panda_auto_dynamics_v1.py b/catkin_ws/src/panda_autodynamics/scripts/panda_auto_dynamics_v1.py index 7d539381fee2903df89102b5d35f7ad9f15b70b3..c38b68ef1f0b61f539cfafd12cf823f0599508f2 100755 --- a/catkin_ws/src/panda_autodynamics/scripts/panda_auto_dynamics_v1.py +++ b/catkin_ws/src/panda_autodynamics/scripts/panda_auto_dynamics_v1.py @@ -208,6 +208,24 @@ def main(): f"""Path No.: {iter_traj}\tVelocity factor: {global_qd_factor}\tAcceleration factor: {global_qdd_factor}""" ) + ##########Start Position for ISO###### + # move robot to start position, so that this is not part of the collected data. + if MOVEMENT == "true": + if DATASET_TYPE == "TEST": + if ( + ROBOT_UUID == "c9ff52e1-1733-4829-a209-ebd1586a8697" + ): # For ITA move start position to the other side + move_group.set_pose_target([-0.18, -0.6, 0.2, -np.pi, 0, 0]) + if TEST == "true": # LLT + move_group.set_pose_target( + [0.25, 0, 0.2, -np.pi, 0, 0] + ) # TODO test 0.6,0,0.2 + else: + move_group.set_pose_target( + [-0.18, 0.6, 0.2, -np.pi, 0, 0] + ) # Left of base + move_group.go(wait=True) + #########Setup data subscribers####### trajectory_listener = rospy.Subscriber( "/move_group/display_planned_path", @@ -223,13 +241,6 @@ def main(): ######Execute motion################## if MOVEMENT == "true": if DATASET_TYPE == "TEST": - if ROBOT_UUID == "c9ff52e1-1733-4829-a209-ebd1586a8697":# For ITA move start position to the other side - move_group.set_pose_target([-0.18, -0.6, 0.2, -np.pi, 0, 0]) - if TEST == "true": # LLT - move_group.set_pose_target([0.25, 0, 0.2, -np.pi, 0, 0]) # TODO test 0.6,0,0.2 - else: - move_group.set_pose_target([-0.18, 0.6, 0.2, -np.pi, 0, 0]) # Left of base - move_group.go(wait=True) plan, _ = plan_cartesian_path(move_group) success = move_group.execute(plan, wait=True) else: diff --git a/docker-compose.yaml b/docker-compose.yaml index f3d825723e39edbf815fcd6d29132a199ef2aebb..13ac5bff125ebaf0f26ee03cca651630a9cfd8d7 100755 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -92,6 +92,43 @@ services: # network_mode: pandavlan # Uses the host's network stack, not creating a separate network namespace #########################foundation_model############################## + foundation_model_cron_job: + build: + context: . + dockerfile: ./dynamics_learning/Dockerfile.foundation_model_cron_job + deploy: + resources: + reservations: + devices: + - capabilities: [gpu] + cpus: '10' + memory: 30G + ipc: host + ulimits: + memlock: + soft: -1 + hard: -1 + stack: + soft: 67108864 + hard: 67108864 + container_name: foundation_model_cron_job # Sets a custom name for the container + stdin_open: true # Keeps the container's standard input open (similar to 'docker run -i') + tty: true # Allocates a pseudo-TTY (like 'docker run -t'), useful for interactive shells + network_mode: host + environment: + COSCINE_API_TOKEN: ${COSCINE_API_TOKEN} + DATASET_TYPE: ${DATASET_TYPE} + WANDB_API_TOKEN: ${WANDB_API_TOKEN} + WANDB_NOTES: ${WANDB_NOTES} + WANDB_ENTITY: ${WANDB_ENTITY} + WANDB_PROJECT: ${WANDB_PROJECT} + ROBOT_UUID: ${ROBOT_UUID} + SWEEP_ID: ${SWEEP_ID} + CUDA_DEVICE: ${CUDA_DEVICE} + NUM_MODELS: ${NUM_MODELS} + volumes: + - /home/lgorissen/git/iop/franka_wwl_demonstrator:/app + foundation_model: build: context: . @@ -101,8 +138,8 @@ services: reservations: devices: - capabilities: [gpu] - cpus: '20' - memory: 60G + cpus: '10' + memory: 30G ipc: host ulimits: memlock: @@ -115,8 +152,8 @@ services: stdin_open: true # Keeps the container's standard input open (similar to 'docker run -i') tty: true # Allocates a pseudo-TTY (like 'docker run -t'), useful for interactive shells network_mode: host - # volumes: - # - /home/lgorissen/git/iop/franka_wwl_demonstrator:/app + volumes: + - /home/lgorissen/git/iop/franka_wwl_demonstrator:/app environment: COSCINE_API_TOKEN: ${COSCINE_API_TOKEN} DATASET_TYPE: ${DATASET_TYPE} @@ -126,3 +163,5 @@ services: WANDB_PROJECT: ${WANDB_PROJECT} ROBOT_UUID: ${ROBOT_UUID} SWEEP_ID: ${SWEEP_ID} + CUDA_DEVICE: ${CUDA_DEVICE} + NUM_MODELS: ${NUM_MODELS} diff --git a/dynamics_learning/Dockerfile.foundation_model b/dynamics_learning/Dockerfile.foundation_model index dc9b947896d4be1e474b9c29de21d3d0e10bbf3f..fa2479404af6bb8221c4047a0c63233439f2d4d0 100644 --- a/dynamics_learning/Dockerfile.foundation_model +++ b/dynamics_learning/Dockerfile.foundation_model @@ -6,14 +6,8 @@ COPY . . WORKDIR /app/dynamics_learning -RUN apt update && apt install -y cron nano - -RUN service cron start - RUN pip install -e /app/dynamics_learning/ RUN git config --global --add safe.directory /app -RUN chmod +x /app/dynamics_learning/entrypoint.sh - -ENTRYPOINT ["/app/dynamics_learning/entrypoint.sh"] \ No newline at end of file +#CMD [ "/usr/bin/python3", "/app/dynamics_learning/foundation_model.py" ] \ No newline at end of file diff --git a/dynamics_learning/Dockerfile.foundation_model_cron_job b/dynamics_learning/Dockerfile.foundation_model_cron_job new file mode 100644 index 0000000000000000000000000000000000000000..23236cf1960bd3ad3bcc61892777629b60fc1cef --- /dev/null +++ b/dynamics_learning/Dockerfile.foundation_model_cron_job @@ -0,0 +1,19 @@ +FROM nvcr.io/nvidia/tensorflow:23.05-tf2-py3 + +WORKDIR /app + +COPY . . + +WORKDIR /app/dynamics_learning + +RUN apt update && apt install -y cron nano + +RUN service cron start + +RUN pip install -e /app/dynamics_learning/ + +RUN git config --global --add safe.directory /app + +RUN chmod +x /app/dynamics_learning/entrypoint.sh /app/dynamics_learning/cron_test/crons /app/dynamics_learning/cron_test/testscript.sh + +ENTRYPOINT ["/app/dynamics_learning/entrypoint.sh"] diff --git a/dynamics_learning/README.rst b/dynamics_learning/README.rst index 41ad65ac492631607f6db6550c061ddacf1963b2..1f9e413c44d41bff89c32f9e6a8950739a30f80b 100644 --- a/dynamics_learning/README.rst +++ b/dynamics_learning/README.rst @@ -38,6 +38,13 @@ Next, export some notes, if you want: export WANDB_NOTES="your notes. here spaces are allowed" +Optional Setup: + +.. code-block:: bash + + export CUDA_DEVICE="0" + export NUM_MODELS="10" + Adding an Agent to an existing sweep ------------------------------------ diff --git a/dynamics_learning/benchmark_model_accuracy.py b/dynamics_learning/benchmark_model_accuracy.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/dynamics_learning/benchmark_number_of_runs.py b/dynamics_learning/benchmark_number_of_runs.py new file mode 100644 index 0000000000000000000000000000000000000000..3771ef16e20b9fa94d1f7fda5204928029fa56a8 --- /dev/null +++ b/dynamics_learning/benchmark_number_of_runs.py @@ -0,0 +1,31 @@ +THRESHOLD = 50 +NUMBER_OF_TRAJECTORIES = 100 + +if __name__ == "__main__": + # Download Training Data from the server + + # Download Test Data from the server + + runs_instance_model_from_scratch = 0 + val_loss = 100 + while val_loss > 50: + # Train model instance_model_from_scratch(count = 1) + runs_instance_model_from_scratch += 1 + + runs_instance_model_from_pretrained_instance_unknown = 0 + val_loss = 100 + while val_loss > 50: + # Train model instance_model_from_pretrained_instance_unknown(count = 1) + runs_instance_model_from_pretrained_instance_unknown += 1 + + runs_instance_model_from_pretrained_instance_known = 0 + val_loss = 100 + while val_loss > 50: + # Train model instance_model_from_pretrained_instance_known(count = 1) + runs_instance_model_from_pretrained_instance_known += 1 + + runs_instance_model_from_pretrained_foundation = 0 + val_loss = 100 + while val_loss > 50: + # Train model instance_model_from_pretrained_foundation(count = 1) + runs_instance_model_from_pretrained_foundation += 1 diff --git a/dynamics_learning/cron_test/crons b/dynamics_learning/cron_test/crons new file mode 100644 index 0000000000000000000000000000000000000000..b571ce3d5757ebb8b16eac87fa97a76110a14d8e --- /dev/null +++ b/dynamics_learning/cron_test/crons @@ -0,0 +1,5 @@ +SHELL=/bin/bash + +0 2 * * * /bin/bash -c 'source /etc/environment && /usr/bin/python3 $PYTHON_SCRIPT_PATH >> /var/log/cron.log 2>&1' +* * * * * /bin/bash -c 'source /etc/environment && echo $COSCINE_API_TOKEN >> /var/log/cron_test.log 2>&1' +# Required empty newline diff --git a/dynamics_learning/cron_test/testscript.sh b/dynamics_learning/cron_test/testscript.sh new file mode 100644 index 0000000000000000000000000000000000000000..f25a27fcc7f626f890c7d73591113e86339e519c --- /dev/null +++ b/dynamics_learning/cron_test/testscript.sh @@ -0,0 +1,2 @@ +echo "Displaying env vars..." +echo $COSCINE_API_TOKEN diff --git a/dynamics_learning/dynamics_learning/environment.py b/dynamics_learning/dynamics_learning/environment.py index c59ac8115debe2c45c6c16b99e555f89968697a4..4e475e75c24a8d98e105b0b8aec2a19cf72ae9fc 100644 --- a/dynamics_learning/dynamics_learning/environment.py +++ b/dynamics_learning/dynamics_learning/environment.py @@ -14,6 +14,75 @@ def get_env_variable(var_name): return value +try: + COSCINE_API_TOKEN = get_env_variable("COSCINE_API_TOKEN") +except EnvironmentError as e: + logger.critical(e) + sys.exit(1) + +try: + WANDB_API_TOKEN = get_env_variable("WANDB_API_TOKEN") +except EnvironmentError as e: + logger.critical(e) + logger.log("Exiting...", "error") + sys.exit(1) + +try: + WANDB_PROJECT = get_env_variable("WANDB_PROJECT") +except EnvironmentError as e: + WANDB_PROJECT = "franka_wwl_demonstrator" + logger.log(e, "warning") + logger.log(f"Setting WANDB_PROJECT to {WANDB_PROJECT}") + +try: + WANDB_NOTES = get_env_variable("WANDB_NOTES") +except EnvironmentError as e: + WANDB_NOTES = "default" + logger.log(e, "warning") + logger.log(f"Setting WANDB_NOTES to {WANDB_NOTES}") + +try: + WANDB_ENTITY = get_env_variable("WANDB_ENTITY") +except EnvironmentError as e: + WANDB_ENTITY = "leon-gorissen" + logger.log(e, "warning") + logger.log(f"Setting WANDB_ENTITY to {WANDB_ENTITY}") + +try: + SWEEP_ID = get_env_variable("SWEEP_ID") +except EnvironmentError as e: + logger.log(e, "warning") + logger.log("Creating a new sweep...") + SWEEP_ID = None + +try: + DATASET_TYPE = get_env_variable("DATASET_TYPE") +except EnvironmentError as e: + logger.log(e, "warning") + DATASET_TYPE = "train" + logger.log(f"Setting DATASET_TYPE to {DATASET_TYPE}") + +try: + ROBOT_UUID = get_env_variable("ROBOT_UUID") +except EnvironmentError as e: + ROBOT_UUID = None + logger.log(e, "warning") + logger.log(f"Setting ROBOT_UUID to {ROBOT_UUID}") + +try: + CUDA_DEVICE = get_env_variable("CUDA_DEVICE") +except EnvironmentError as e: + CUDA_DEVICE = "0" + logger.log(e, "warning") + logger.log(f"Setting CUDA_DEVICE to {CUDA_DEVICE}") + +try: + NUM_MODELS = int(get_env_variable("NUM_MODELS")) +except (EnvironmentError, ValueError) as e: + NUM_MODELS = int(10) + logger.log(e, "warning") + logger.log(f"Setting NUM_MODELS to {NUM_MODELS}") + # Suppress CUDA and cuDNN logs try: if "TF_CPP_MIN_LOG_LEVEL" not in os.environ: @@ -39,10 +108,10 @@ except Exception as e: # Set CUDA visible devices to 1 as 0 will run continously in the beginning. try: if "CUDA_VISIBLE_DEVICES" not in os.environ: - os.environ["CUDA_VISIBLE_DEVICES"] = ( - "1" # Use only the first GPU, if you have multiple GPUs - ) - logger.info("Setting CUDA_VISIBLE_DEVICES to 1...") + os.environ["CUDA_VISIBLE_DEVICES"] = str( + CUDA_DEVICE + ) # Use only the first GPU, if you have multiple GPUs + logger.info(f"Setting CUDA_VISIBLE_DEVICES to {str(CUDA_DEVICE)}...") else: logger.debug("CUDA_VISIBLE_DEVICES is already set.") except Exception as e: diff --git a/dynamics_learning/dynamics_learning/testing/__init__.py b/dynamics_learning/dynamics_learning/testing/__init__.py index a4983705baf2afa1829a47ca2b820f79dfeab19f..53c9dcdccf5b8eb3274dd2869cdb360a0b549e28 100644 --- a/dynamics_learning/dynamics_learning/testing/__init__.py +++ b/dynamics_learning/dynamics_learning/testing/__init__.py @@ -1,6 +1,4 @@ # %% -# noqa: E402 -# Import import sys import coscine.exceptions @@ -12,28 +10,13 @@ from pritty_logger import RichLogger logger = RichLogger("dynamics_learning-testing") - -# # Suppress CUDA and cuDNN logs -# os.environ["TF_CPP_MIN_LOG_LEVEL"] = ( -# "3" # Suppress TensorFlow logs (0 = all logs, 1 = INFO, 2 = WARNING, 3 = ERROR) -# ) -# logger.info("Suppressing TensorFlow logs...") -# os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" -# logger.info("Setting CUDA_DEVICE_ORDER to PCI_BUS_ID...") -# os.environ["CUDA_VISIBLE_DEVICES"] = ( -# "0" # Use only the first GPU, if you have multiple GPUs -# ) -# logger.info("Setting CUDA_VISIBLE_DEVICES to 0...") -# os.environ["TF_FORCE_GPU_ALLOW_GROWTH"] = "true" # Allow GPU memory growth -# logger.info("Setting TF_FORCE_GPU_ALLOW_GROWTH to true...") -# os.environ["ROBOT_UUID"] = "f2e72889-c140-4397-809f-fba1b892f17a" - import warnings import keras import matplotlib.pyplot as plt import numpy as np import pandas as pd +from datetime import datetime # Suppress FutureWarning for the specific deprecation warning in pandas warnings.simplefilter(action="ignore", category=FutureWarning) @@ -52,7 +35,9 @@ from dynamics_learning.model_io import ( ) from dynamics_learning.environment import ROBOT_UUID -# noqa: E402 + +def drop_nan(array): + return array[~np.isnan(array).any(axis=1)] @attr.s(auto_attribs=True) @@ -177,7 +162,7 @@ class Dataset: # filter files based on the type and criteria if self.type == "test": # if robot uuid is given, keep only files from this robot - if ROBOT_UUID: # FIXME + if ROBOT_UUID: # files to look for most recent file logger.info(f"Robot UUID is {ROBOT_UUID}.") filtered_files = [ @@ -217,10 +202,6 @@ class Dataset: # return None -# dataset = Dataset("test") -# %% - - def model_analysis( dataset: Dataset, model: tf.keras.Sequential, @@ -272,20 +253,20 @@ def model_analysis( if filename.endswith("interp_com.csv"): # - # somewhere FIXME: FFT zeigt nur nn und rtb data nicht gemessen - # somewhere FIXME: nn hat keine daten + # somewhere FIXME: Daten scheinen zu kurz zu sein? # logger.log(f"Loading interpolated command data from: {filename}") # Command Traj data_com = np.genfromtxt( os.path.join(dataset.local_path, filename), dtype=float, delimiter="," ) - # select every row other than the header + data_com = drop_nan(data_com) + data_com = data_com[1:, :] # select every row other than the header # select every column for each feature. There are 4 features:q, qd, qdd, tau and each have 7 joints (i.e. columns) - _t_command = data_com[1:, 0] - q_command = data_com[1:, 1:8] - qd_command = data_com[1:, 8:15] - qdd_command = data_com[1:, 15:22] + _t_command = data_com[:, 0] + q_command = data_com[:, 1:8] + qd_command = data_com[:, 8:15] + qdd_command = data_com[:, 15:22] logger.info("""====================================== Input Data Information: Start ======================================""") @@ -310,12 +291,13 @@ Input Data Information: Concluded data_meas = np.genfromtxt( os.path.join(dataset.local_path, filename2), dtype=float, delimiter="," ) - # select every row other than the header + data_meas = drop_nan(data_meas) + data_meas = data_meas[1:, :] # select every row other than the header # select every column for each feature. There are 4 features:q, qd, qdd, tau and each have 7 joints (i.e. columns) - t_meas = data_meas[1:, 0] - _q_meas = data_meas[1:, 1:8] - _qd_meas = data_meas[1:, 8:15] - tau_meas = data_meas[1:, 15:22] + t_meas = data_meas[:, 0] + _q_meas = data_meas[:, 1:8] + _qd_meas = data_meas[:, 8:15] + tau_meas = data_meas[:, 15:22] logger.info("""====================================== Output Data Information: Start ======================================""") @@ -604,12 +586,404 @@ LSTM Implementation Output: Concluded return None +# %% if __name__ == "__main__": model = Model() tf_model = model.load_model() test_dataset = Dataset("test") + test_dataset.download() from dynamics_learning.preprocessing.trajectory_interpolation import interpolate interpolate("/app/dynamics_learning/Trajectory Data/test") - # dont do multiprocessing, as an issue with gpu arises - model_analysis(test_dataset, tf_model, "20240719_141308_iso_interp_com.csv") + # %% + test_dataset + # %% + dataset = test_dataset + model = tf_model + filename = dataset.analysis_file + filename += "_iso_interp_com.csv" + # Get windowsize from model + window_size = model.input_shape[1] + + # create model architecture plot + # file name can not be model_plot.png or model_architecture_plot.png. While it does not show in coscine web ui and does not get downloaded, it raises a file already exists error. This is a coscine issue. + keras.utils.vis_utils.plot_model( + model, + to_file="/app/dynamics_learning/Foundation_Model/analysis/test_model_architecture_plot.png", + show_shapes=True, + show_layer_names=True, + ) + # resource = PROJECT.resource("Foundation_Model") + # metadataform = resource.metadata_form() + # metadataform["Title"] = "Model Architecture" + # update_existing_file( + # file_path="/app/dynamics_learning/Foundation_Model/analysis/test_model_architecture_plot.png", + # metadataform=metadataform, + # resource=resource, + # ) + + rms_joint_nn = np.empty([0, 7]) + rms_joint_rtbp = np.empty([0, 7]) + + logger.log(filename) + + now = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + + if "meas" in filename: + filename = filename.replace("meas", "interp_com") + + if filename.endswith("iso_com.csv"): + filename = filename.replace("iso_com.csv", "iso_interp_com.csv") + + if filename.endswith("interp_com.csv"): + # + # somewhere FIXME: Daten scheinen zu kurz zu sein? + # + logger.log(f"Loading interpolated command data from: {filename}") + # Command Traj + data_com = np.genfromtxt( + os.path.join(dataset.local_path, filename), dtype=float, delimiter="," + ) + data_com = drop_nan(data_com) + # select every row other than the header + # select every column for each feature. There are 4 features:q, qd, qdd, tau and each have 7 joints (i.e. columns) + _t_command = data_com[1:, 0] + q_command = data_com[1:, 1:8] + qd_command = data_com[1:, 8:15] + qdd_command = data_com[1:, 15:22] + logger.info("""====================================== +Input Data Information: Start +======================================""") + logger.info( + f"The shape of the interpolated command joint positions is {q_command.shape}" + ) + logger.info(f"The interpolated command joint positions are {q_command}") + logger.info( + f"The shape of the interpolated command joint velocities is {qd_command.shape}" + ) + logger.info(f"The interpolated command joint velocities are {qd_command}") + logger.info( + f"The shape of the interpolated command joint accelerations is {qdd_command.shape}" + ) + logger.info(f"The interpolated command joint accelerations are {qdd_command}") + logger.info("""====================================== +Input Data Information: Concluded +======================================""") + # Measurement Traj + filename2 = filename.replace("interp_com", "meas") + logger.info(f"Loading measurement data from: {filename2}") + data_meas = np.genfromtxt( + os.path.join(dataset.local_path, filename2), dtype=float, delimiter="," + ) + data_meas = drop_nan(data_meas) + # select every row other than the header + # select every column for each feature. There are 4 features:q, qd, qdd, tau and each have 7 joints (i.e. columns) + t_meas = data_meas[1:, 0] + _q_meas = data_meas[1:, 1:8] + _qd_meas = data_meas[1:, 8:15] + tau_meas = data_meas[1:, 15:22] + logger.info("""====================================== +Output Data Information: Start +======================================""") + logger.info(f"The shape of the measured torques is {tau_meas.shape}") + logger.info(f"The measured torques are {tau_meas}") + logger.info("""====================================== +Output Data Information: Concluded +======================================""") + if len(t_meas) != len(_t_command): + logger.warn( + f"The arrays are of the same length: {len(t_meas) == len(_t_command)}" + ) + logger.warn( + f"The interpolated command array is of length: {len(_t_command)} and the measurement array is of length: {len(t_meas)}" + ) + + # Robotics Toolbox implementation + panda = rtb.models.DH.Panda() + tau_rtbp = panda.rne( + q=q_command, qd=qd_command, qdd=qdd_command, gravity=(0, 0, -9.81) + ) + logger.info("""====================================== +Conventional Implementation Output: Start +======================================""") + logger.info(f"The shape of the RTB-P estimation is {tau_rtbp.shape}") + logger.info(f"The RTB-P estimation is:\n{tau_rtbp}") + logger.info("""====================================== +Conventional Implementation Output: Concluded +======================================""") + + # Convert to tensors + X = tf.convert_to_tensor(data_com[1:, 1:22]) + + # Sliding Window + X_test = tf_text.sliding_window(data=X, width=window_size, axis=0) + logger.info("""====================================== +LSTM Implementation Output: Start +======================================""") + logger.info( + f"The shape of the input data for our model after applying the sliding window is {X_test.shape}" + ) + logger.info( + f"The input data for our model after applying the sliding window is:\n{X_test}" + ) + y_pred = model.predict(X_test, verbose=0) + logger.info(f"The shape of the predictions is {y_pred.shape}") + logger.info(f"The predictions are:\n{y_pred}") + logger.info("Dropna") + # y_pred.dropna() + y_pred = y_pred[~np.isnan(y_pred).any(axis=1)] + logger.info(f"The shape of the predictions is {y_pred.shape}") + logger.info(f"The predictions are:\n{y_pred}") + logger.info("""====================================== +LSTM Implementation Output: Concluded +======================================""") + + rms_nn = np.sqrt( + ((tau_meas[: -window_size + 1] - y_pred) ** 2).mean(axis=0) + ) # minus one due to width -1 from sliding_window method # y_pred: 1045,7 ; windowsize: 1, tau_meas: 1044,7: prediction needs to be shorted by windowsize? + rms_rtbp = np.sqrt( + ((tau_meas - tau_rtbp) ** 2).mean(axis=0) + ) # windowsize: 6, layers: 4, interpol: 1044, measured: 1044, rtbp: 1044, input ater sliding window: 1040, pred: 1040, + # windowsize: 3, layers: 10, interpol: 1044, measured: 1044, rtbp: 1044, input after sliding window: + if "ISO" not in filename: + rms_joint_nn = np.vstack([rms_joint_nn, rms_nn]) + rms_joint_rtbp = np.vstack([rms_joint_rtbp, rms_rtbp]) + + df = pd.DataFrame({"NN": rms_nn, "RTB-P": rms_rtbp}) + df = df.append( + {"NN": rms_nn.mean(), "RTB-P": rms_rtbp.mean()}, + ignore_index=True, + ) + df.index = [ + "RMS Axis 1 [Nm]", + "RMS Axis 2 [Nm]", + "RMS Axis 3 [Nm]", + "RMS Axis 4 [Nm]", + "RMS Axis 5 [Nm]", + "RMS Axis 6 [Nm]", + "RMS Axis 7 [Nm]", + "RMS All [Nm]", + ] + logger.info(f"The statistics over the joints are:\n{df}") + + current_filename = f"/app/dynamics_learning/Foundation_Model/analysis/{now}_test_result_{filename.replace('_interp_com.csv', '')}.csv" + df.T.to_csv( + current_filename, + float_format="%.3f", + ) + # # Upload + # metadataform["Title"] = "Analysis Data" + # update_existing_file( + # file_path=current_filename, metadataform=metadataform, resource=resource + # ) + + # Plot test trajectory + with plt.style.context("default"): + plt.rcParams["savefig.dpi"] = 300 + num_row = 3 + num_col = 3 + fig, axs = plt.subplots( + num_row, num_col, figsize=(num_col * 6, num_row * 3) + ) + for joint_number in range(7): + axs[joint_number // num_col, joint_number % num_col].axvspan( + t_meas[0], + t_meas[window_size], + facecolor=rwth_style.blue, + alpha=0.5, + label="Initialization Phase for NN", + ) + axs[joint_number // num_col, joint_number % num_col].plot( + t_meas[:], + tau_meas[:, joint_number], + label="Measurement", + color=rwth_style.green, + ) + + axs[joint_number // num_col, joint_number % num_col].scatter( + t_meas[window_size - 1 :], + y_pred[:, joint_number], + label="Prediction based on command trajectory (NN)", + marker="o", + s=2, + color=rwth_style.blue, + ) + + axs[joint_number // num_col, joint_number % num_col].scatter( + t_meas[:], + tau_rtbp[:, joint_number], + label="Estimation based on command trajectory (RTB-P)", + marker="o", + s=2, + color=rwth_style.blue_light, + ) + + axs[joint_number // num_col, joint_number % num_col].set_title( + "Axis {}".format(joint_number + 1) + ) + axs[joint_number // num_col, joint_number % num_col].set_ylabel( + "Torque [Nm]" + ) + axs[joint_number // num_col, joint_number % num_col].set_xlabel( + "Time [s]" + ) + if joint_number < 4: + axs[joint_number // num_col, joint_number % num_col].set_ylim( + [-90, 90] + ) + axs[joint_number // num_col, joint_number % num_col].set_yticks( + [-87, -40, 0, 40, 87] + ) + else: + axs[joint_number // num_col, joint_number % num_col].set_ylim( + [-12, 12] + ) + axs[joint_number // num_col, joint_number % num_col].set_yticks( + [-12, -6, 0, 6, 12] + ) + axs[joint_number // num_col, joint_number % num_col].grid(which="both") + axs[joint_number // num_col, joint_number % num_col].set_xlim( + [0, t_meas[1:].max()] + ) + # Detail Axis + axs[2, -2].axvspan( + t_meas[0], + t_meas[window_size], + facecolor=rwth_style.blue, + alpha=0.5, + label="Initialization Phase for NN", + ) + axs[2, -2].plot( + t_meas[:], tau_meas[:, 1], label="Measurement", color=rwth_style.green + ) + axs[2, -2].scatter( + t_meas[window_size - 1 :], + y_pred[:, 1], + label="Prediction based on command trajectory (NN)", + marker="o", + s=2, + color=rwth_style.blue, + ) + axs[2, -2].scatter( + t_meas[:], + tau_rtbp[:, 1], + label="Estimation based on command trajectory (RTB-P)", + marker="o", + s=2, + color=rwth_style.blue_light, + ) + + axs[2, -2].grid() + axs[2, -2].set_title("Detailed View of Axis 2") + axs[2, -2].set_ylabel("Torque [Nm]") + axs[2, -2].set_xlabel("Time [s]") + axs[2, -2].set_xlim([0, t_meas[1:].max()]) + # Allgemein + fig.delaxes(axs[-1, -1]) + handles, labels = axs[0, 0].get_legend_handles_labels() + pos1 = axs[-1, -1].get_position() + fig.legend( + handles, + labels, + loc="lower left", + bbox_to_anchor=(pos1.x0 + 0.02, pos1.y0 - 0.055), + ) + fig.tight_layout() + current_filename = f"/app/dynamics_learning/Foundation_Model/analysis/{now}_test_result_{filename.replace('_interp_com.csv', '')}.png" + fig.savefig(current_filename) + plt.close(fig) + + # # Upload + # metadataform["Title"] = "Analysis Data Plot" + # update_existing_file( + # file_path=current_filename, metadataform=metadataform, resource=resource + # ) + + # FFT analysis + with plt.style.context("default"): + plt.rcParams["savefig.dpi"] = 300 + num_row = 4 + num_col = 2 + fig, axs = plt.subplots( + num_row, num_col, figsize=(num_col * 6, num_row * 3) + ) + for joint_number in range(7): + n = t_meas.size + freq = np.fft.fftfreq(n=n, d=1.0 / 100) + logger.info( + f"The input for the FFT of the measured data is:\n{tau_meas[:, joint_number]}" + ) + axs[joint_number // num_col, joint_number % num_col].plot( + freq[: n // 2], + 2.0 / n * np.abs(np.fft.fft(tau_meas[:, joint_number])[: n // 2]), + label="Measurement", + color=rwth_style.green, + ) + logger.info( + f"The input for the FFT of the RTB-P estimation is:\n{tau_rtbp[:, joint_number]}" + ) + axs[joint_number // num_col, joint_number % num_col].plot( + freq[: n // 2], + 2.0 / n * np.abs(np.fft.fft(tau_rtbp[:, joint_number])[: n // 2]), + label="Estimation based on command trajectory (RTB-P)", + color=rwth_style.blue_light, + ) + logger.info( + f"The input for the FFT of the NN prediction is:\n{y_pred[:, joint_number]}" + ) + n = t_meas.size - window_size + 1 + freq = np.fft.fftfreq(n=n, d=1.0 / 100) + axs[joint_number // num_col, joint_number % num_col].plot( + freq[: n // 2], + 2.0 / n * np.abs(np.fft.fft(y_pred[:, joint_number])[: n // 2]), + label="Prediction based on command trajectory (NN)", + color=rwth_style.blue, + ) + axs[joint_number // num_col, joint_number % num_col].set_title( + "Axis {}".format(joint_number + 1) + ) + axs[joint_number // num_col, joint_number % num_col].set_ylabel( + "Magnitude" + ) + axs[joint_number // num_col, joint_number % num_col].set_xlabel( + "Frequency [Hz]" + ) + axs[joint_number // num_col, joint_number % num_col].set_xlim([0, 50]) + axs[joint_number // num_col, joint_number % num_col].set_yscale("log") + axs[joint_number // num_col, joint_number % num_col].grid() + fig.delaxes(axs[-1, -1]) + handles, labels = axs[0, 0].get_legend_handles_labels() + pos1 = axs[-1, 1].get_position() + fig.legend( + handles, labels, loc="lower left", bbox_to_anchor=(pos1.x0, pos1.y0) + ) + fig.tight_layout() + current_filename = f"/app/dynamics_learning/Foundation_Model/analysis/{now}_test_result_fft_{filename.replace('_interp_com.csv', '')}.png" + fig.savefig(current_filename) + plt.close(fig) + + # # Upload + # metadataform["Title"] = "Analysis Data FFT Plot" + # update_existing_file( + # file_path=current_filename, metadataform=metadataform, resource=resource + # ) + # %% + plt.plot(tau_rtbp[:, 2], label="RTB") + plt.plot(tau_meas[:, 2], label="Measured") + plt.plot() + plt.legend() + plt.show() + # %% + + # %% + x = tau_meas + x = x[~np.isnan(x).any(axis=1)] + # %% + x.shape + # %% + tau_meas.shape + # %% + y_pred.shape + # %% + window_size +# %% diff --git a/dynamics_learning/entrypoint.sh b/dynamics_learning/entrypoint.sh index 8ac34825b89b0af748e96eb6c02af6a613070abf..87e40dd0cd77b01a8478ea649e2e97e8cb374590 100755 --- a/dynamics_learning/entrypoint.sh +++ b/dynamics_learning/entrypoint.sh @@ -1,20 +1,19 @@ #!/bin/bash -# Define the path to your Python script -PYTHON_SCRIPT_PATH="/app/dynamics_learning/foundation_model.py" -/usr/bin/python3 $PYTHON_SCRIPT_PATH +# export env variables +printenv >> /etc/environment -# Create a cron job file -CRON_JOB="0 2 * * * /usr/bin/python3 $PYTHON_SCRIPT_PATH >> /var/log/cron.log 2>&1" +# Write out the cron job to a file +echo "* * * * * /usr/bin/env python3 /app/dynamics_learning/foundation_model.py >> /var/log/cron.log 2>&1" > /etc/cron.d/mycron -# Write out the cron job to a new cron file -echo "$CRON_JOB" > cronjob +# Apply cron job +crontab /etc/cron.d/mycron -# Install the cron job -crontab cronjob +# Give execution rights on the cron job file +chmod 0644 /etc/cron.d/mycron -# Remove the cron job file as it's no longer needed -rm cronjob +# Create the log file to be able to run tail +touch /var/log/cron.log # Ensure cron is running cron diff --git a/dynamics_learning/foundation_model.py b/dynamics_learning/foundation_model.py index c1718d5ff0eded9d872a996fd19869057b98e826..1e49ed4b8224a0d50f5b87a45f8adbf7b900e799 100644 --- a/dynamics_learning/foundation_model.py +++ b/dynamics_learning/foundation_model.py @@ -91,5 +91,5 @@ if __name__ == "__main__": train_save_upload_with_args, project=WANDB_PROJECT, entity=WANDB_ENTITY, - count=5, + # count=NUM_MODELS, )