Skip to content

Commit

Permalink
add files via git linux
Browse files Browse the repository at this point in the history
  • Loading branch information
wissem01chiha committed Jul 25, 2024
1 parent 3834bb9 commit bb70ae7
Show file tree
Hide file tree
Showing 84 changed files with 123,150 additions and 3,330 deletions.
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,23 @@
[![Licence](https://img.shields.io/github/license/justintime50/python-template)](LICENSE)
</div>

This project aims to provide an extensive framework for developing complex dynamic models for collaborative manipulators. The available solutions, which can be found here [softwares](/docs/README.md), do not support advanced modeling of friction, stiffness, noise, and robotic joint actuator/transmission systems. This project also aims to provide a comprehensive interface for state-space modeling approaches and transfer functions, rather than standard dynamic equations. Regading the complxity of this models, it offers a method to solve and optimize them, to find the best trajectory directions and configurations that excite the robot dynamics.
The main objective of this project is to provide an extensive framework for modeling and identificationof the dynamics of
collaborative serial manipulators.The code extends the classical linear identification methods (IDDIM, CLOE, ...) to non linear dynamics
The available solutions, which can be found here [softwares](/docs/README.md), do not support advanced modeling of friction, stiffness, noise,
and robotic joint actuator/transmission systems. This project also aims to provide a comprehensive interface for state-space modeling
approaches and transfer functions, rather than standard inverse dynamics equations. Regading the complxity of this models, it offers a method to
solve and optimize them, to find the best trajectory directions and joints configurations that excite the robot dynamics.
### Getting started

### Package structure
all software base structures and functions are in the [source](/src/) folder, specific robot configuration/functions scripts are in [exemple](/exemple/) folder.
### Features
- trajectory data processing
- find optimized excitation trajectories with non-linear optimization
- manipulator state space model implentation
- compute optimized excitation trajectories with non-linear optimization
- compute manipulator state space model
- state space identification based methods
- transfer function manipulator models
- dynamic model including effects of frictions, actuator inertia, joint stiffness, and torque offset.
- computation of manipulators transfer functions
- dynamic modeling with effects of frictions, actuator inertia, joint stiffness, and torque offset.
- generation of optimal exciting trajectories.
- calculation of physically consistent standard inertial parameters.
### Documentation
Expand All @@ -28,13 +33,14 @@ see [documentation](docs/README.md) file.
all simulation scripts examples are in the [exemple](/exemple/)
the, at the the for [kinova Gen3-R07](https://www.kinovarobotics.com/uploads/User-Guide-Gen3-R07.pdf) robot can be found in the [examples](exemple/kinova/) directory.
### Prerequisites
the code was tested sucessfuly on the flowing platform :
- Windows 11 ( python 3.12.4 - miniconda 4.5.0 - cuda 12.50)
the code was tested sucessfuly on the flowing platform : Windows 11 ( python 3.12.4 - miniconda 4.5.0 - cuda 12.50)

- CUDA Compilation Toolkit > 11
- Python interpreter > 3.12
- Conda > 4.5.0
### Installation
the code will be soon available to installation with python package magners like pip or conda,
now:
create a new conda environment and install all the dependencies:
```shell
conda env create -f environment.yml
Expand Down
2,000 changes: 1,000 additions & 1,000 deletions autogen/computed_fourier_traj_acceleration.csv

Large diffs are not rendered by default.

2,000 changes: 1,000 additions & 1,000 deletions autogen/computed_fourier_traj_position.csv

Large diffs are not rendered by default.

2,000 changes: 1,000 additions & 1,000 deletions autogen/computed_fourier_traj_velocity.csv

Large diffs are not rendered by default.

Binary file modified autogen/traj_paramters.npy
Binary file not shown.
111 changes: 111 additions & 0 deletions exemple/generate_trajectory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#############################################################################################
# pour les paramters optimizées trouver le meilleur trajectoire identifable
# genrer beaucoup des trajs ---- Fourier , enregister leur params, ( coeffs, criteria
# cond(W) )
# sur chaqun excuetr l optimisation ---> error RMSE model-reel ,
# save the final RMSE of each traj
# TODO : plot : 2D plot of the RMSe (y) en fontion du frequance du traj (FHz)
# TODO : plot : 2D plot of the RMSE (y) en fonction du sampling rate du traj (Fs)
# TODO : plot : 3D plot of the RMSE en fonction du FHz and Fs
# TODO : for the linear model : plot of the RMSE with the Cond(W) or the crteria choosen
# NOTE: to compute the RMSE of a traj we nedd the real data of the robot suiving the traj
##############################################################################################
import sys
import os
import logging
import nlopt
import matplotlib.pyplot as plt
import numpy as np

traj_parms_path = "/home/wissem/dynamic-identification/autogen/traj_paramters.npy"
figureFolderPath="/home/wissem/dynamic-identification/figure/kinova"
config_file_path="/home/wissem/dynamic-identification/exemple/kinova/config.yml"
params_file_path = "/home/wissem/dynamic-identification/autogen/initial_guess_nlopt_best_torque_current.npy"
src_folder = os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)),'../src'))
sys.path.append(src_folder)
if not os.path.exists(figureFolderPath):
os.makedirs(figureFolderPath)

from dynamics import Robot, Regressor
from trajectory import FourierGenerator
from utils import RobotData, plot2Arrays, plotElementWiseArray, yaml2dict, RMSE, MAE

dynamics_logger = logging.getLogger('dynamics')
dynamics_logger.setLevel(logging.ERROR)

# TODO : plot the evolution par time of the trajectory identification criteria J
# and the RMSE evolution
dim = 209


if os.path.exists(params_file_path):
x = np.load(params_file_path)
print("Loaded initial params guess from file.")
else:
x= np.random.rand(dim)
print("Using random initial guess.")

config_params = yaml2dict(config_file_path)
traj = FourierGenerator(config_params['trajectory'])
tspan = (traj.trajectory_params['samples'] +1)* 0.001
q0 = np.zeros(7)
qp0 =np.zeros(7)
qpp0 = np.zeros(7)
Q, Qp, Qpp = traj.computeFullTrajectory(0,tspan,q0,qp0,qpp0)
iteration_counter = 0

def computeTrajectoryError(traj_parms,grad):
"""this function compute the best forier paramters (ie trajectory) on wich the differentiation
error du non linear torques function est min , this is designed to work with nlopt
traj_parms = 7*10 = 70
"""
global q0, qp0, qpp0, tspan, config_params, iteration_counter
traj = FourierGenerator(config_params['trajectory'])
traj.trajectory_params['frequancy'] = 1
traj.trajectory_params['Aij'] = np.reshape(traj_parms[1:36],(-1,5))
traj.trajectory_params['Bij'] = np.reshape(traj_parms[36:71],(-1,5))
err = traj.computeConstraintedDifferentiationError(0,tspan,x,q0,qp0,qpp0)
print(
f"Iteration {iteration_counter}: "
f"RMSE = {err:.5f}"
)
iteration_counter +=1
return err

###########################################################################
max_iter = 20
opt = nlopt.opt(nlopt.LN_NELDERMEAD, 71)
opt.set_min_objective(computeTrajectoryError)
opt.set_maxeval(max_iter) # Maximum number of evaluations
opt.set_ftol_rel(1e-6) # Relative tolerance on function value
opt.set_xtol_rel(1e-6)
lower_bounds = np.full(71,-100)
upper_bounds = np.full(71, 100)
#opt.set_lower_bounds(lower_bounds)
#opt.set_upper_bounds(upper_bounds)

if os.path.exists(traj_parms_path):
initial_guess = np.load(traj_parms_path)
print("Loaded initial guess from file.")

x_opt = opt.optimize(initial_guess)
min_value = opt.last_optimum_value()
result_code = opt.last_optimize_result()
print(f'paramters values : {x_opt}')
print(f'minimum value de la fonction objective: {min_value}')
np.save(traj_parms_path, x_opt)
print("Saved optimized parameters to file.")

# vis the computed traj
best_traj_parms = np.load(traj_parms_path)
traj = FourierGenerator(config_params['trajectory'])
traj.trajectory_params['frequancy'] = 1
traj.trajectory_params['Aij'] = np.reshape(best_traj_parms[1:36],(-1,5))
traj.trajectory_params['Bij'] = np.reshape(best_traj_parms[36:71],(-1,5))

traj.visualizeTrajectory(0,tspan,q0,qp0,qpp0,figureFolderPath)
q, qp, qpp = traj.computeFullTrajectory(0,tspan,q0,qp0,qpp0)
np.savetxt('/home/wissem/dynamic-identification/autogen/computed_fourier_traj_position.csv',q)
np.savetxt('/home/wissem/dynamic-identification/autogen/computed_fourier_traj_velocity.csv',qp)
np.savetxt('/home/wissem/dynamic-identification/autogen/computed_fourier_traj_acceleration.csv',qpp)
plt.show()
66 changes: 32 additions & 34 deletions exemple/inverse_dynamics_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
# with pataerts stored in config.yml file
# all figures are saved in figure/pyDynamapp
#
#
#
#
# models paramters used the defaults stored in the autogen directory if not
# empty output error 'run identification first or provide paramters files path
#
# TODO: replace all models computing function with
# 'computeIdentificationModel' function from class Robot.
# Author: Wissem CHIHA ©
# 2024
##########################################################################

import argparse
import sys
import os
Expand All @@ -24,17 +23,17 @@
parser.add_argument('--v',type=bool)
parser.add_argument('--data_file',type=str,default='b')
parser.add_argument('--show_figures', type=bool,default=False)
parser.add_argument('cutoff_frequency', type=float, default=3)
parser.add_argument('--cutoff_frequency', type=float, default=3)
args = parser.parse_args()

base_dir = os.path.dirname(os.path.realpath(__file__))
base_dir = os. getcwd()
figure_path = os.path.join(base_dir,"figure/kinova")
config_file_path = os.path.join(base_dir,"exemple/kinova/config.yml")

figureFolderPath="C:/Users/chiha/OneDrive/Bureau/Dynamium/dynamic-identification/figure/kinova"
config_file_path="C:/Users/chiha/OneDrive/Bureau/Dynamium/dynamic-identification/exemple/kinova/config.yml"
src_folder = os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)),'../src'))
src_folder = os.path.join(base_dir,"src")
sys.path.append(src_folder)
if not os.path.exists(figureFolderPath):
os.makedirs(figureFolderPath)
if not os.path.exists(figure_path):
os.makedirs(figure_path)

from dynamics import Robot, Regressor
from utils import RobotData, plot2Arrays, plotElementWiseArray, yaml2dict, RMSE, MAE
Expand All @@ -43,12 +42,13 @@
logging.basicConfig(level='INFO')
mlogger.setLevel(logging.WARNING)

cutoff_frequency = 3
cutoff_frequency = args.cutoff_frequency
config_params = yaml2dict(config_file_path)

data = RobotData(config_params['identification']['dataFilePath'])
fildata = data.lowPassfilter(cutoff_frequency)
kinova = Robot()
q_f = fildata ['position']
q_f = fildata['position']
qp_f = fildata['velocity']
qpp_f = fildata['desiredAcceleration']
current_f = fildata['current']
Expand All @@ -60,34 +60,33 @@
current = data.current
torque = data.torque


# Visualize the recorded trajectory data of the system.
plot2Arrays(q, q_f, "true", "filtred", f"Joints Positions, cutoff frequency = {cutoff_frequency} Hz")
plt.savefig(os.path.join(figureFolderPath,'joints_positions'))
plt.savefig(os.path.join(figure_path,'joints_positions'))
plot2Arrays(qp, qp_f, "true", "filtred", f"Joints Velocity, cutoff frequency = {cutoff_frequency} Hz")
plt.savefig(os.path.join(figureFolderPath,'joints_velocity'))
plt.savefig(os.path.join(figure_path,'joints_velocity'))
plot2Arrays(qpp, qpp_f, "true", "filtred", f"Joints Acceleration, cutoff frequency = {cutoff_frequency} Hz")
plt.savefig(os.path.join(figureFolderPath,'joints_acceleration'))
plt.savefig(os.path.join(figure_path,'joints_acceleration'))
plot2Arrays(torque, torque_f , "true", "filtred", f"Joints Torques, cutoff frequency = {cutoff_frequency} Hz")
plt.savefig(os.path.join(figureFolderPath,'joints_torques'))
plt.savefig(os.path.join(figure_path,'joints_torques'))
plot2Arrays(current, current_f , "true", "filtred", f"Joints Current, cutoff frequency = {cutoff_frequency} Hz")
plt.savefig(os.path.join(figureFolderPath,'joints_current'))
plt.savefig(os.path.join(figure_path,'joints_current'))

# Visualize the Correlation between torques data
data.visualizeCorrelation('torque')
plt.savefig(os.path.join(figureFolderPath,'sensor_torques_correlation'))
plt.savefig(os.path.join(figure_path,'sensor_torques_correlation'))
data.visualizeCorrelation('torque_rne')
plt.savefig(os.path.join(figureFolderPath,'blast_rne_torques_correlation'))
plt.savefig(os.path.join(figure_path,'blast_rne_torques_correlation'))
data.visualizeCorrelation('torque_cur')
plt.savefig(os.path.join(figureFolderPath,'current_torques_correlation'))
plt.savefig(os.path.join(figure_path,'current_torques_correlation'))

# Compute and plot the RMSE between the actual RNEA model (Blast) and the
# torque sensor output.
rmse_joint = RMSE(torque, data.torque_rne).flatten()
rmse_time = RMSE(torque, data.torque_rne,axis=1)
plotElementWiseArray(rmse_joint,'Error between Blast RNEA and Sensor Torques per Joint'\
,'Joint Index','RMSE')
plt.savefig(os.path.join(figureFolderPath,'blast_RNEA_vs_sensor_torques'))
plt.savefig(os.path.join(figure_path,'blast_RNEA_vs_sensor_torques'))


# Compute and plot the standard manipulator model :
Expand All @@ -98,9 +97,9 @@
rmse_per_joint = RMSE(tau_sim,torque).flatten()
plotElementWiseArray(rmse_per_joint,"Standard Manipulator Model Error per Joint"\
,'Joint Index','RMSE')
plt.savefig(os.path.join(figureFolderPath,'standard_model_error_joint'))
plt.savefig(os.path.join(figure_path,'standard_model_error_joint'))
plot2Arrays(torque_f,tau_sim,"true","simulation","Standard Manipulator Model")
plt.savefig(os.path.join(figureFolderPath,'standard_model'))
plt.savefig(os.path.join(figure_path,'standard_model'))


# Compute and plot the standard manipulator model with friction effect:
Expand All @@ -112,9 +111,9 @@
rmse_per_joint = RMSE(tau_sim,torque).flatten()
plotElementWiseArray(rmse_per_joint,"Standard Manipulator Model with Friction Error per Joint"\
,'Joint Index','RMSE')
plt.savefig(os.path.join(figureFolderPath,'standard_model_friction_error_joint'))
plt.savefig(os.path.join(figure_path,'standard_model_friction_error_joint'))
plot2Arrays(torque_f,tau_sim,"true","simulation","Standard manipulator model with friction")
plt.savefig(os.path.join(figureFolderPath,'standard_model_with_friction'))
plt.savefig(os.path.join(figure_path,'standard_model_with_friction'))


# Compute and plot the standard manipulator model with stiffness:
Expand All @@ -127,8 +126,8 @@
plotElementWiseArray(rmse_per_joint,"Standard Manipulator Model with Stiffness Error per Joint"\
,'Joint Index','RMSE')
plot2Arrays(torque_f,tau_sim,"true","simulation","Standard manipulator model with stiffness")
plt.savefig(os.path.join(figureFolderPath,'standard_model_stiffness_error_joint'))
plt.savefig(os.path.join(figureFolderPath,'standard_model_stiffness'))
plt.savefig(os.path.join(figure_path,'standard_model_stiffness_error_joint'))
plt.savefig(os.path.join(figure_path,'standard_model_stiffness'))


# Compute and plot the standard manipulator model with stiffness and friction:
Expand All @@ -139,7 +138,7 @@
tau_s = kinova.computeStiffnessTorques(q[i,:])
tau_sim[i,:] = 3*(kinova.computeDifferentialModel(q_f[i,:],qp_f[i,:],qpp_f[i,:]) + tau_s + tau_f[i,:])
plot2Arrays(torque_f,tau_sim,"true","simulation","Standard model with stiffness and friction")
plt.savefig(os.path.join(figureFolderPath,'standard_model_stiffness_friction'))
plt.savefig(os.path.join(figure_path,'standard_model_stiffness_friction'))


# Compute and plot the standard manipulator model with actuator and friction:
Expand All @@ -153,7 +152,7 @@
for i in range(tau_sim.shape[0]):
tau_sim[i,:] -= Jm @ qpp[i,:]
plot2Arrays(torque_f,tau_sim,"true","simulation","Standard model with actuator and friction")
plt.savefig(os.path.join(figureFolderPath,'standard_model_actuator_friction'))
plt.savefig(os.path.join(figure_path,'standard_model_actuator_friction'))


# Compute and plot the standard manipulator model with actuator, friction and stiffness
Expand All @@ -170,16 +169,15 @@
W = reg.computeFullRegressor(q_f,qp_f,qpp_f)
tau_sim = (W @ x).reshape((torque.shape[0],kinova.model.nq))
plot2Arrays(torque_f,tau_sim,"true","simulation","Standard regression model")
plt.savefig(os.path.join(figureFolderPath,'standard_regression_model'))
plt.savefig(os.path.join(figure_path,'standard_regression_model'))

# Compute and plot the non linear manipultaor regression model
# τ = f(q,qp,qpp,x)
kinova.setIdentificationModelData(q_f,qp_f,qpp_f)
x = np.random.rand(209)
tau_sim = kinova.computeIdentificationModel(x)
plot2Arrays(torque_f,tau_sim,"true","simulation","Manipulator Non Linear model")
plt.savefig(os.path.join(figureFolderPath,'non_Linear_model'))

plt.savefig(os.path.join(figure_path,'non_Linear_model'))

if args.show_figures:
plt.show()
Expand Down
10 changes: 5 additions & 5 deletions exemple/kinova/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ robot_params:
has_joint_offset : True
offset : [3.92e-1, 1.37, 3.26e-1, -1.02e-1, -2.88e-2, 1.27e-1]
identification:
dataFilePath : /home/wissem/dynamic-identification/data/kinova/validation_data/blast_traj_AHA.csv
dataFilePath : /home/wissem/dynamic-identification/data/kinova/identification_data/blast_traj.csv
problem_params:
has_friction : True
has_stiffness : False
Expand Down Expand Up @@ -69,10 +69,10 @@ noise_params:
poisson:
lamda : 1
state_space_params:
poles : [-3.16192733e-06, -3.66207387e-02, -1.18134652e-01, -5.22457369e-02,
-1.20315307e-01, -1.52413136e-01, -4.54143280e-02, -1.01978176e-01,
-2.34472352e-01, -8.16376366e-01, -9.34581208e-01, -6.70722799e-01,
-1.84597460e-01, -5.69609866e-01]
poles : [-3.16192733e-01, -3.66207387e-01, -1.18134652e-01, -3.22457369e-01,
-1.20315307e-01, -1.52413136e-01, -1.54143280e-01, -1.01978176e-01,
-2.34472352e-01, -1.16376366e-01, -1.34581208e-01, -2.70722799e-01,
-1.84597460e-01, -2.69609866e-01]
trajectory:
frequancy : 1
samples : 1000
Expand Down
Loading

0 comments on commit bb70ae7

Please sign in to comment.