Start the standardize the folder. Add org-mode files.
This commit is contained in:
@@ -1,3 +1,14 @@
|
||||
% computePsdDispl
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/computePsdDispl.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:computePsdDispl>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/computePsdDispl.m][here]].
|
||||
|
||||
|
||||
function [psd_object] = computePsdDispl(sys_data, t_init, n_av)
|
||||
i_init = find(sys_data.time > t_init, 1);
|
||||
|
||||
|
70
src/computeSetpoint.m
Normal file
70
src/computeSetpoint.m
Normal file
@@ -0,0 +1,70 @@
|
||||
% computeSetpoint
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/computeSetpoint.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:computeSetpoint>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/computeSetpoint.m][here]].
|
||||
|
||||
|
||||
function setpoint = computeSetpoint(ty, ry, rz)
|
||||
%%
|
||||
setpoint = zeros(6, 1);
|
||||
|
||||
%% Ty
|
||||
Ty = [1 0 0 0 ;
|
||||
0 1 0 ty ;
|
||||
0 0 1 0 ;
|
||||
0 0 0 1 ];
|
||||
|
||||
% Tyinv = [1 0 0 0 ;
|
||||
% 0 1 0 -ty ;
|
||||
% 0 0 1 0 ;
|
||||
% 0 0 0 1 ];
|
||||
|
||||
%% Ry
|
||||
Ry = [ cos(ry) 0 sin(ry) 0 ;
|
||||
0 1 0 0 ;
|
||||
-sin(ry) 0 cos(ry) 0 ;
|
||||
0 0 0 1 ];
|
||||
|
||||
% TMry = Ty*Ry*Tyinv;
|
||||
|
||||
%% Rz
|
||||
Rz = [cos(rz) -sin(rz) 0 0 ;
|
||||
sin(rz) cos(rz) 0 0 ;
|
||||
0 0 1 0 ;
|
||||
0 0 0 1 ];
|
||||
|
||||
% TMrz = Ty*TMry*Rz*TMry'*Tyinv;
|
||||
|
||||
%% All stages
|
||||
% TM = TMrz*TMry*Ty;
|
||||
|
||||
TM = Ty*Ry*Rz;
|
||||
|
||||
[thetax, thetay, thetaz] = RM2angle(TM(1:3, 1:3));
|
||||
|
||||
setpoint(1:3) = TM(1:3, 4);
|
||||
setpoint(4:6) = [thetax, thetay, thetaz];
|
||||
|
||||
%% Custom Functions
|
||||
function [thetax, thetay, thetaz] = RM2angle(R)
|
||||
if abs(abs(R(3, 1)) - 1) > 1e-6 % R31 != 1 and R31 != -1
|
||||
thetay = -asin(R(3, 1));
|
||||
thetax = atan2(R(3, 2)/cos(thetay), R(3, 3)/cos(thetay));
|
||||
thetaz = atan2(R(2, 1)/cos(thetay), R(1, 1)/cos(thetay));
|
||||
else
|
||||
thetaz = 0;
|
||||
if abs(R(3, 1)+1) < 1e-6 % R31 = -1
|
||||
thetay = pi/2;
|
||||
thetax = thetaz + atan2(R(1, 2), R(1, 3));
|
||||
else
|
||||
thetay = -pi/2;
|
||||
thetax = -thetaz + atan2(-R(1, 2), -R(1, 3));
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
136
src/converErrorBasis.m
Normal file
136
src/converErrorBasis.m
Normal file
@@ -0,0 +1,136 @@
|
||||
% converErrorBasis
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/converErrorBasis.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:converErrorBasis>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/converErrorBasis.m][here]].
|
||||
|
||||
|
||||
function error_nass = convertErrorBasis(pos, setpoint, ty, ry, rz)
|
||||
% convertErrorBasis -
|
||||
%
|
||||
% Syntax: convertErrorBasis(p_error, ty, ry, rz)
|
||||
%
|
||||
% Inputs:
|
||||
% - p_error - Position error of the sample w.r.t. the granite [m, rad]
|
||||
% - ty - Measured translation of the Ty stage [m]
|
||||
% - ry - Measured rotation of the Ry stage [rad]
|
||||
% - rz - Measured rotation of the Rz stage [rad]
|
||||
%
|
||||
% Outputs:
|
||||
% - P_nass - Position error of the sample w.r.t. the NASS base [m]
|
||||
% - R_nass - Rotation error of the sample w.r.t. the NASS base [rad]
|
||||
%
|
||||
% Example:
|
||||
%
|
||||
|
||||
%% If line vector => column vector
|
||||
if size(pos, 2) == 6
|
||||
pos = pos';
|
||||
end
|
||||
|
||||
if size(setpoint, 2) == 6
|
||||
setpoint = setpoint';
|
||||
end
|
||||
|
||||
%% Position of the sample in the frame fixed to the Granite
|
||||
P_granite = [pos(1:3); 1]; % Position [m]
|
||||
R_granite = [setpoint(1:3); 1]; % Reference [m]
|
||||
|
||||
%% Transformation matrices of the stages
|
||||
% T-y
|
||||
TMty = [1 0 0 0 ;
|
||||
0 1 0 ty ;
|
||||
0 0 1 0 ;
|
||||
0 0 0 1 ];
|
||||
|
||||
% R-y
|
||||
TMry = [ cos(ry) 0 sin(ry) 0 ;
|
||||
0 1 0 0 ;
|
||||
-sin(ry) 0 cos(ry) 0 ;
|
||||
0 0 0 1 ];
|
||||
|
||||
% R-z
|
||||
TMrz = [cos(rz) -sin(rz) 0 0 ;
|
||||
sin(rz) cos(rz) 0 0 ;
|
||||
0 0 1 0 ;
|
||||
0 0 0 1 ];
|
||||
|
||||
%% Compute Point coordinates in the new reference fixed to the NASS base
|
||||
% P_nass = TMrz*TMry*TMty*P_granite;
|
||||
P_nass = TMrz\TMry\TMty\P_granite;
|
||||
R_nass = TMrz\TMry\TMty\R_granite;
|
||||
|
||||
dx = R_nass(1)-P_nass(1);
|
||||
dy = R_nass(2)-P_nass(2);
|
||||
dz = R_nass(3)-P_nass(3);
|
||||
|
||||
%% Compute new basis vectors linked to the NASS base
|
||||
% ux_nass = TMrz*TMry*TMty*[1; 0; 0; 0];
|
||||
% ux_nass = ux_nass(1:3);
|
||||
% uy_nass = TMrz*TMry*TMty*[0; 1; 0; 0];
|
||||
% uy_nass = uy_nass(1:3);
|
||||
% uz_nass = TMrz*TMry*TMty*[0; 0; 1; 0];
|
||||
% uz_nass = uz_nass(1:3);
|
||||
|
||||
ux_nass = TMrz\TMry\TMty\[1; 0; 0; 0];
|
||||
ux_nass = ux_nass(1:3);
|
||||
uy_nass = TMrz\TMry\TMty\[0; 1; 0; 0];
|
||||
uy_nass = uy_nass(1:3);
|
||||
uz_nass = TMrz\TMry\TMty\[0; 0; 1; 0];
|
||||
uz_nass = uz_nass(1:3);
|
||||
|
||||
%% Rotations error w.r.t. granite Frame
|
||||
% Rotations error w.r.t. granite Frame
|
||||
rx_nass = pos(4);
|
||||
ry_nass = pos(5);
|
||||
rz_nass = pos(6);
|
||||
|
||||
% Rotation matrices of the Sample w.r.t. the Granite
|
||||
Mrx_error = [1 0 0 ;
|
||||
0 cos(-rx_nass) -sin(-rx_nass) ;
|
||||
0 sin(-rx_nass) cos(-rx_nass)];
|
||||
|
||||
Mry_error = [ cos(-ry_nass) 0 sin(-ry_nass) ;
|
||||
0 1 0 ;
|
||||
-sin(-ry_nass) 0 cos(-ry_nass)];
|
||||
|
||||
Mrz_error = [cos(-rz_nass) -sin(-rz_nass) 0 ;
|
||||
sin(-rz_nass) cos(-rz_nass) 0 ;
|
||||
0 0 1];
|
||||
|
||||
% Rotation matrix of the Sample w.r.t. the Granite
|
||||
Mr_error = Mrz_error*Mry_error*Mrx_error;
|
||||
|
||||
%% Use matrix to solve
|
||||
R = Mr_error/[ux_nass, uy_nass, uz_nass]; % Rotation matrix from NASS base to Sample
|
||||
|
||||
[thetax, thetay, thetaz] = RM2angle(R);
|
||||
|
||||
error_nass = [dx; dy; dz; thetax; thetay; thetaz];
|
||||
|
||||
%% Custom Functions
|
||||
function [thetax, thetay, thetaz] = RM2angle(R)
|
||||
if abs(abs(R(3, 1)) - 1) > 1e-6 % R31 != 1 and R31 != -1
|
||||
thetay = -asin(R(3, 1));
|
||||
% thetaybis = pi-thetay;
|
||||
thetax = atan2(R(3, 2)/cos(thetay), R(3, 3)/cos(thetay));
|
||||
% thetaxbis = atan2(R(3, 2)/cos(thetaybis), R(3, 3)/cos(thetaybis));
|
||||
thetaz = atan2(R(2, 1)/cos(thetay), R(1, 1)/cos(thetay));
|
||||
% thetazbis = atan2(R(2, 1)/cos(thetaybis), R(1, 1)/cos(thetaybis));
|
||||
else
|
||||
thetaz = 0;
|
||||
if abs(R(3, 1)+1) < 1e-6 % R31 = -1
|
||||
thetay = pi/2;
|
||||
thetax = thetaz + atan2(R(1, 2), R(1, 3));
|
||||
else
|
||||
thetay = -pi/2;
|
||||
thetax = -thetaz + atan2(-R(1, 2), -R(1, 3));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@@ -1,3 +1,14 @@
|
||||
% generateDiagPidControl
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/generateDiagPidControl.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:generateDiagPidControl>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/generateDiagPidControl.m][here]].
|
||||
|
||||
|
||||
function [K] = generateDiagPidControl(G, fs)
|
||||
%%
|
||||
pid_opts = pidtuneOptions(...
|
||||
|
@@ -1,3 +1,14 @@
|
||||
% identifyPlant
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/identifyPlant.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:identifyPlant>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/identifyPlant.m][here]].
|
||||
|
||||
|
||||
function [sys] = identifyPlant(opts_param)
|
||||
%% Default values for opts
|
||||
opts = struct();
|
||||
|
19
src/init_simulation.m
Normal file
19
src/init_simulation.m
Normal file
@@ -0,0 +1,19 @@
|
||||
% Simulation Initialization
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/init_simulation.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:init_simulation>>
|
||||
|
||||
% This Matlab script is accessible [[file:src/init_simulation.m][here]].
|
||||
|
||||
% This script runs just before the simulation is started.
|
||||
% It is used to load the simulation configuration and the controllers used for the simulation.
|
||||
|
||||
|
||||
%% Load all the data used for the simulation
|
||||
load('./mat/sim_conf.mat');
|
||||
|
||||
%% Load Controller
|
||||
load('./mat/controllers.mat');
|
42
src/initializeAxisc.m
Normal file
42
src/initializeAxisc.m
Normal file
@@ -0,0 +1,42 @@
|
||||
% Center of gravity compensation
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/initializeAxisc.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:initializeAxisc>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/initializeAxisc.m][here]].
|
||||
|
||||
|
||||
function [axisc] = initializeAxisc()
|
||||
%%
|
||||
axisc = struct();
|
||||
|
||||
%% Axis Compensator - Static Properties
|
||||
% Structure
|
||||
axisc.structure.density = 3400; % [kg/m3]
|
||||
axisc.structure.color = [0.792 0.820 0.933];
|
||||
axisc.structure.STEP = './STEPS/axisc/axisc_structure.STEP';
|
||||
% Wheel
|
||||
axisc.wheel.density = 2700; % [kg/m3]
|
||||
axisc.wheel.color = [0.753 0.753 0.753];
|
||||
axisc.wheel.STEP = './STEPS/axisc/axisc_wheel.STEP';
|
||||
% Mass
|
||||
axisc.mass.density = 7800; % [kg/m3]
|
||||
axisc.mass.color = [0.792 0.820 0.933];
|
||||
axisc.mass.STEP = './STEPS/axisc/axisc_mass.STEP';
|
||||
% Gear
|
||||
axisc.gear.density = 7800; % [kg/m3]
|
||||
axisc.gear.color = [0.792 0.820 0.933];
|
||||
axisc.gear.STEP = './STEPS/axisc/axisc_gear.STEP';
|
||||
|
||||
axisc.m = 40; % TODO [kg]
|
||||
|
||||
%% Axis Compensator - Dynamical Properties
|
||||
axisc.k.ax = 1; % TODO [N*m/deg)]
|
||||
axisc.c.ax = (1/1)*sqrt(axisc.k.ax/axisc.m);
|
||||
|
||||
%% Save
|
||||
save('./mat/stages.mat', 'axisc', '-append');
|
||||
end
|
38
src/initializeExperiment.m
Normal file
38
src/initializeExperiment.m
Normal file
@@ -0,0 +1,38 @@
|
||||
% Experiment
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/initializeExperiment.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:initializeExperiment>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/initializeExperiment.m][here]].
|
||||
|
||||
|
||||
function [] = initializeExperiment(exp_name, sys_mass)
|
||||
if strcmp(exp_name, 'tomography')
|
||||
opts_sim = struct(...
|
||||
'Tsim', 5, ...
|
||||
'cl_time', 5 ...
|
||||
);
|
||||
initializeSimConf(opts_sim);
|
||||
|
||||
if strcmp(sys_mass, 'light')
|
||||
opts_inputs = struct(...
|
||||
'Dw', true, ...
|
||||
'Rz', 60 ... % rpm
|
||||
);
|
||||
elseif strcpm(sys_mass, 'heavy')
|
||||
opts_inputs = struct(...
|
||||
'Dw', true, ...
|
||||
'Rz', 1 ... % rpm
|
||||
);
|
||||
else
|
||||
error('sys_mass should be light or heavy');
|
||||
end
|
||||
|
||||
initializeInputs(opts_inputs);
|
||||
else
|
||||
error('exp_name is only configured for tomography');
|
||||
end
|
||||
end
|
38
src/initializeGranite.m
Normal file
38
src/initializeGranite.m
Normal file
@@ -0,0 +1,38 @@
|
||||
% Granite
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/initializeGranite.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:initializeGranite>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/initializeGranite.m][here]].
|
||||
|
||||
|
||||
function [granite] = initializeGranite()
|
||||
%%
|
||||
granite = struct();
|
||||
|
||||
%% Static Properties
|
||||
granite.density = 2800; % [kg/m3]
|
||||
granite.volume = 0.72; % [m3] TODO - should
|
||||
granite.mass = granite.density*granite.volume; % [kg]
|
||||
granite.color = [1 1 1];
|
||||
granite.STEP = './STEPS/granite/granite.STEP';
|
||||
|
||||
%% Dynamical Properties
|
||||
granite.k.x = 1e8; % [N/m]
|
||||
granite.c.x = 1e4; % [N/(m/s)]
|
||||
|
||||
granite.k.y = 1e8; % [N/m]
|
||||
granite.c.y = 1e4; % [N/(m/s)]
|
||||
|
||||
granite.k.z = 1e8; % [N/m]
|
||||
granite.c.z = 1e4; % [N/(m/s)]
|
||||
|
||||
%% Positioning parameters
|
||||
granite.sample_pos = 0.8; % Z-offset for the initial position of the sample [m]
|
||||
|
||||
%% Save
|
||||
save('./mat/stages.mat', 'granite', '-append');
|
||||
end
|
22
src/initializeGround.m
Normal file
22
src/initializeGround.m
Normal file
@@ -0,0 +1,22 @@
|
||||
% Ground
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/initializeGround.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:initializeGround>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/initializeGround.m][here]].
|
||||
|
||||
|
||||
function [ground] = initializeGround()
|
||||
%%
|
||||
ground = struct();
|
||||
|
||||
ground.shape = [2, 2, 0.5]; % [m]
|
||||
ground.density = 2800; % [kg/m3]
|
||||
ground.color = [0.5, 0.5, 0.5];
|
||||
|
||||
%% Save
|
||||
save('./mat/stages.mat', 'ground', '-append');
|
||||
end
|
186
src/initializeInputs.m
Normal file
186
src/initializeInputs.m
Normal file
@@ -0,0 +1,186 @@
|
||||
% Inputs
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/initializeInputs.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:initializeInputs>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/initializeInputs.m][here]].
|
||||
|
||||
|
||||
function [inputs] = initializeInputs(opts_param)
|
||||
%% Default values for opts
|
||||
opts = struct( ...
|
||||
'Dw', false, ...
|
||||
'Dy', false, ...
|
||||
'Ry', false, ...
|
||||
'Rz', false, ...
|
||||
'Dh', false, ...
|
||||
'Rm', false, ...
|
||||
'Dn', false ...
|
||||
);
|
||||
|
||||
%% Populate opts with input parameters
|
||||
if exist('opts_param','var')
|
||||
for opt = fieldnames(opts_param)'
|
||||
opts.(opt{1}) = opts_param.(opt{1});
|
||||
end
|
||||
end
|
||||
|
||||
%% Load Sampling Time and Simulation Time
|
||||
load('./mat/sim_conf.mat', 'sim_conf');
|
||||
|
||||
%% Define the time vector
|
||||
t = 0:sim_conf.Ts:sim_conf.Tsim;
|
||||
|
||||
%% Ground motion - Dw
|
||||
if islogical(opts.Dw) && opts.Dw == true
|
||||
load('./mat/perturbations.mat', 'Wxg');
|
||||
Dw = 1/sqrt(2)*100*random('norm', 0, 1, length(t), 3);
|
||||
Dw(:, 1) = lsim(Wxg, Dw(:, 1), t);
|
||||
Dw(:, 2) = lsim(Wxg, Dw(:, 2), t);
|
||||
Dw(:, 3) = lsim(Wxg, Dw(:, 3), t);
|
||||
elseif islogical(opts.Dw) && opts.Dw == false
|
||||
Dw = zeros(length(t), 3);
|
||||
else
|
||||
Dw = opts.Dw;
|
||||
end
|
||||
|
||||
%% Translation stage - Dy
|
||||
if islogical(opts.Dy) && opts.Dy == true
|
||||
Dy = zeros(length(t), 1);
|
||||
elseif islogical(opts.Dy) && opts.Dy == false
|
||||
Dy = zeros(length(t), 1);
|
||||
else
|
||||
Dy = opts.Dy;
|
||||
end
|
||||
|
||||
%% Tilt Stage - Ry
|
||||
if islogical(opts.Ry) && opts.Ry == true
|
||||
Ry = 3*(2*pi/360)*sin(2*pi*0.2*t);
|
||||
elseif islogical(opts.Ry) && opts.Ry == false
|
||||
Ry = zeros(length(t), 1);
|
||||
elseif isnumeric(opts.Ry) && length(opts.Ry) == 1
|
||||
Ry = opts.Ry*(2*pi/360)*ones(length(t), 1);
|
||||
else
|
||||
Ry = opts.Ry;
|
||||
end
|
||||
|
||||
%% Spindle - Rz
|
||||
if islogical(opts.Rz) && opts.Rz == true
|
||||
Rz = 2*pi*0.5*t;
|
||||
elseif islogical(opts.Rz) && opts.Rz == false
|
||||
Rz = zeros(length(t), 1);
|
||||
elseif isnumeric(opts.Rz) && length(opts.Rz) == 1
|
||||
Rz = opts.Rz*(2*pi/60)*t;
|
||||
else
|
||||
Rz = opts.Rz;
|
||||
end
|
||||
|
||||
%% Micro Hexapod - Dh
|
||||
if islogical(opts.Dh) && opts.Dh == true
|
||||
Dh = zeros(length(t), 6);
|
||||
elseif islogical(opts.Dh) && opts.Dh == false
|
||||
Dh = zeros(length(t), 6);
|
||||
else
|
||||
Dh = opts.Dh;
|
||||
end
|
||||
|
||||
%% Axis Compensation - Rm
|
||||
if islogical(opts.Rm)
|
||||
Rm = zeros(length(t), 2);
|
||||
Rm(:, 2) = pi*ones(length(t), 1);
|
||||
else
|
||||
Rm = opts.Rm;
|
||||
end
|
||||
|
||||
%% Nano Hexapod - Dn
|
||||
if islogical(opts.Dn) && opts.Dn == true
|
||||
Dn = zeros(length(t), 6);
|
||||
elseif islogical(opts.Dn) && opts.Dn == false
|
||||
Dn = zeros(length(t), 6);
|
||||
else
|
||||
Dn = opts.Dn;
|
||||
end
|
||||
|
||||
%% Setpoint - Ds
|
||||
Ds = zeros(length(t), 6);
|
||||
for i = 1:length(t)
|
||||
Ds(i, :) = computeSetpoint(Dy(i), Ry(i), Rz(i));
|
||||
end
|
||||
|
||||
%% External Forces applied on the Granite
|
||||
Fg = zeros(length(t), 3);
|
||||
|
||||
%% External Forces applied on the Sample
|
||||
Fs = zeros(length(t), 6);
|
||||
|
||||
%% Create the input Structure that will contain all the inputs
|
||||
inputs = struct( ...
|
||||
'Ts', sim_conf.Ts, ...
|
||||
'Dw', timeseries(Dw, t), ...
|
||||
'Dy', timeseries(Dy, t), ...
|
||||
'Ry', timeseries(Ry, t), ...
|
||||
'Rz', timeseries(Rz, t), ...
|
||||
'Dh', timeseries(Dh, t), ...
|
||||
'Rm', timeseries(Rm, t), ...
|
||||
'Dn', timeseries(Dn, t), ...
|
||||
'Ds', timeseries(Ds, t), ...
|
||||
'Fg', timeseries(Fg, t), ...
|
||||
'Fs', timeseries(Fs, t) ...
|
||||
);
|
||||
|
||||
%% Save
|
||||
save('./mat/inputs.mat', 'inputs');
|
||||
|
||||
%% Custom Functions
|
||||
function setpoint = computeSetpoint(ty, ry, rz)
|
||||
%%
|
||||
setpoint = zeros(6, 1);
|
||||
|
||||
%% Ty
|
||||
TMTy = [1 0 0 0 ;
|
||||
0 1 0 ty ;
|
||||
0 0 1 0 ;
|
||||
0 0 0 1 ];
|
||||
|
||||
%% Ry
|
||||
TMRy = [ cos(ry) 0 sin(ry) 0 ;
|
||||
0 1 0 0 ;
|
||||
-sin(ry) 0 cos(ry) 0 ;
|
||||
0 0 0 1 ];
|
||||
|
||||
%% Rz
|
||||
TMRz = [cos(rz) -sin(rz) 0 0 ;
|
||||
sin(rz) cos(rz) 0 0 ;
|
||||
0 0 1 0 ;
|
||||
0 0 0 1 ];
|
||||
|
||||
%% All stages
|
||||
TM = TMTy*TMRy*TMRz;
|
||||
|
||||
[thetax, thetay, thetaz] = RM2angle(TM(1:3, 1:3));
|
||||
|
||||
setpoint(1:3) = TM(1:3, 4);
|
||||
setpoint(4:6) = [thetax, thetay, thetaz];
|
||||
|
||||
%% Custom Functions
|
||||
function [thetax, thetay, thetaz] = RM2angle(R)
|
||||
if abs(abs(R(3, 1)) - 1) > 1e-6 % R31 != 1 and R31 != -1
|
||||
thetay = -asin(R(3, 1));
|
||||
thetax = atan2(R(3, 2)/cos(thetay), R(3, 3)/cos(thetay));
|
||||
thetaz = atan2(R(2, 1)/cos(thetay), R(1, 1)/cos(thetay));
|
||||
else
|
||||
thetaz = 0;
|
||||
if abs(R(3, 1)+1) < 1e-6 % R31 = -1
|
||||
thetay = pi/2;
|
||||
thetax = thetaz + atan2(R(1, 2), R(1, 3));
|
||||
else
|
||||
thetay = -pi/2;
|
||||
thetax = -thetaz + atan2(-R(1, 2), -R(1, 3));
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
204
src/initializeMicroHexapod.m
Normal file
204
src/initializeMicroHexapod.m
Normal file
@@ -0,0 +1,204 @@
|
||||
% Micro Hexapod
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/initializeMicroHexapod.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:initializeMicroHexapod>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/initializeMicroHexapod.m][here]].
|
||||
|
||||
|
||||
function [micro_hexapod] = initializeMicroHexapod(opts_param)
|
||||
%% Default values for opts
|
||||
opts = struct();
|
||||
|
||||
%% Populate opts with input parameters
|
||||
if exist('opts_param','var')
|
||||
for opt = fieldnames(opts_param)'
|
||||
opts.(opt{1}) = opts_param.(opt{1});
|
||||
end
|
||||
end
|
||||
|
||||
%% Stewart Object
|
||||
micro_hexapod = struct();
|
||||
micro_hexapod.h = 350; % Total height of the platform [mm]
|
||||
% micro_hexapod.jacobian = 269.26; % Distance from the top platform to the Jacobian point [mm]
|
||||
micro_hexapod.jacobian = 270; % Distance from the top platform to the Jacobian point [mm]
|
||||
|
||||
%% Bottom Plate - Mechanical Design
|
||||
BP = struct();
|
||||
|
||||
BP.rad.int = 110; % Internal Radius [mm]
|
||||
BP.rad.ext = 207.5; % External Radius [mm]
|
||||
BP.thickness = 26; % Thickness [mm]
|
||||
BP.leg.rad = 175.5; % Radius where the legs articulations are positionned [mm]
|
||||
BP.leg.ang = 9.5; % Angle Offset [deg]
|
||||
BP.density = 8000; % Density of the material [kg/m^3]
|
||||
BP.color = [0.6 0.6 0.6]; % Color [rgb]
|
||||
BP.shape = [BP.rad.int BP.thickness; BP.rad.int 0; BP.rad.ext 0; BP.rad.ext BP.thickness];
|
||||
|
||||
%% Top Plate - Mechanical Design
|
||||
TP = struct();
|
||||
|
||||
TP.rad.int = 82; % Internal Radius [mm]
|
||||
TP.rad.ext = 150; % Internal Radius [mm]
|
||||
TP.thickness = 26; % Thickness [mm]
|
||||
TP.leg.rad = 118; % Radius where the legs articulations are positionned [mm]
|
||||
TP.leg.ang = 12.1; % Angle Offset [deg]
|
||||
TP.density = 8000; % Density of the material [kg/m^3]
|
||||
TP.color = [0.6 0.6 0.6]; % Color [rgb]
|
||||
TP.shape = [TP.rad.int TP.thickness; TP.rad.int 0; TP.rad.ext 0; TP.rad.ext TP.thickness];
|
||||
|
||||
%% Struts
|
||||
Leg = struct();
|
||||
|
||||
Leg.stroke = 10e-3; % Maximum Stroke of each leg [m]
|
||||
Leg.k.ax = 5e7; % Stiffness of each leg [N/m]
|
||||
Leg.ksi.ax = 3; % Maximum amplification at resonance []
|
||||
Leg.rad.bottom = 25; % Radius of the cylinder of the bottom part [mm]
|
||||
Leg.rad.top = 17; % Radius of the cylinder of the top part [mm]
|
||||
Leg.density = 8000; % Density of the material [kg/m^3]
|
||||
Leg.color.bottom = [0.5 0.5 0.5]; % Color [rgb]
|
||||
Leg.color.top = [0.5 0.5 0.5]; % Color [rgb]
|
||||
|
||||
Leg.sphere.bottom = Leg.rad.bottom; % Size of the sphere at the end of the leg [mm]
|
||||
Leg.sphere.top = Leg.rad.top; % Size of the sphere at the end of the leg [mm]
|
||||
Leg.m = TP.density*((pi*(TP.rad.ext/1000)^2)*(TP.thickness/1000)-(pi*(TP.rad.int/1000^2))*(TP.thickness/1000))/6; % TODO [kg]
|
||||
Leg = updateDamping(Leg);
|
||||
|
||||
|
||||
%% Sphere
|
||||
SP = struct();
|
||||
|
||||
SP.height.bottom = 27; % [mm]
|
||||
SP.height.top = 27; % [mm]
|
||||
SP.density.bottom = 8000; % [kg/m^3]
|
||||
SP.density.top = 8000; % [kg/m^3]
|
||||
SP.color.bottom = [0.6 0.6 0.6]; % [rgb]
|
||||
SP.color.top = [0.6 0.6 0.6]; % [rgb]
|
||||
SP.k.ax = 0; % [N*m/deg]
|
||||
SP.ksi.ax = 10;
|
||||
|
||||
SP.thickness.bottom = SP.height.bottom-Leg.sphere.bottom; % [mm]
|
||||
SP.thickness.top = SP.height.top-Leg.sphere.top; % [mm]
|
||||
SP.rad.bottom = Leg.sphere.bottom; % [mm]
|
||||
SP.rad.top = Leg.sphere.top; % [mm]
|
||||
SP.m = SP.density.bottom*2*pi*((SP.rad.bottom*1e-3)^2)*(SP.height.bottom*1e-3); % TODO [kg]
|
||||
|
||||
SP = updateDamping(SP);
|
||||
|
||||
%%
|
||||
Leg.support.bottom = [0 SP.thickness.bottom; 0 0; SP.rad.bottom 0; SP.rad.bottom SP.height.bottom];
|
||||
Leg.support.top = [0 SP.thickness.top; 0 0; SP.rad.top 0; SP.rad.top SP.height.top];
|
||||
|
||||
%%
|
||||
micro_hexapod.BP = BP;
|
||||
micro_hexapod.TP = TP;
|
||||
micro_hexapod.Leg = Leg;
|
||||
micro_hexapod.SP = SP;
|
||||
|
||||
%%
|
||||
micro_hexapod = initializeParameters(micro_hexapod);
|
||||
|
||||
%% Save
|
||||
save('./mat/stages.mat', 'micro_hexapod', '-append');
|
||||
|
||||
%%
|
||||
function [element] = updateDamping(element)
|
||||
field = fieldnames(element.k);
|
||||
for i = 1:length(field)
|
||||
element.c.(field{i}) = 1/element.ksi.(field{i})*sqrt(element.k.(field{i})/element.m);
|
||||
end
|
||||
end
|
||||
|
||||
%%
|
||||
function [stewart] = initializeParameters(stewart)
|
||||
%% Connection points on base and top plate w.r.t. World frame at the center of the base plate
|
||||
stewart.pos_base = zeros(6, 3);
|
||||
stewart.pos_top = zeros(6, 3);
|
||||
|
||||
alpha_b = stewart.BP.leg.ang*pi/180; % angle de décalage par rapport à 120 deg (pour positionner les supports bases)
|
||||
alpha_t = stewart.TP.leg.ang*pi/180; % +- offset angle from 120 degree spacing on top
|
||||
|
||||
height = (stewart.h-stewart.BP.thickness-stewart.TP.thickness-stewart.Leg.sphere.bottom-stewart.Leg.sphere.top-stewart.SP.thickness.bottom-stewart.SP.thickness.top)*0.001; % TODO
|
||||
|
||||
radius_b = stewart.BP.leg.rad*0.001; % rayon emplacement support base
|
||||
radius_t = stewart.TP.leg.rad*0.001; % top radius in meters
|
||||
|
||||
for i = 1:3
|
||||
% base points
|
||||
angle_m_b = (2*pi/3)* (i-1) - alpha_b;
|
||||
angle_p_b = (2*pi/3)* (i-1) + alpha_b;
|
||||
stewart.pos_base(2*i-1,:) = [radius_b*cos(angle_m_b), radius_b*sin(angle_m_b), 0.0];
|
||||
stewart.pos_base(2*i,:) = [radius_b*cos(angle_p_b), radius_b*sin(angle_p_b), 0.0];
|
||||
|
||||
% top points
|
||||
% Top points are 60 degrees offset
|
||||
angle_m_t = (2*pi/3)* (i-1) - alpha_t + 2*pi/6;
|
||||
angle_p_t = (2*pi/3)* (i-1) + alpha_t + 2*pi/6;
|
||||
stewart.pos_top(2*i-1,:) = [radius_t*cos(angle_m_t), radius_t*sin(angle_m_t), height];
|
||||
stewart.pos_top(2*i,:) = [radius_t*cos(angle_p_t), radius_t*sin(angle_p_t), height];
|
||||
end
|
||||
|
||||
% permute pos_top points so that legs are end points of base and top points
|
||||
stewart.pos_top = [stewart.pos_top(6,:); stewart.pos_top(1:5,:)]; %6th point on top connects to 1st on bottom
|
||||
stewart.pos_top_tranform = stewart.pos_top - height*[zeros(6, 2),ones(6, 1)];
|
||||
|
||||
%% leg vectors
|
||||
legs = stewart.pos_top - stewart.pos_base;
|
||||
leg_length = zeros(6, 1);
|
||||
leg_vectors = zeros(6, 3);
|
||||
for i = 1:6
|
||||
leg_length(i) = norm(legs(i,:));
|
||||
leg_vectors(i,:) = legs(i,:) / leg_length(i);
|
||||
end
|
||||
|
||||
stewart.Leg.lenght = 1000*leg_length(1)/1.5;
|
||||
stewart.Leg.shape.bot = [0 0; ...
|
||||
stewart.Leg.rad.bottom 0; ...
|
||||
stewart.Leg.rad.bottom stewart.Leg.lenght; ...
|
||||
stewart.Leg.rad.top stewart.Leg.lenght; ...
|
||||
stewart.Leg.rad.top 0.2*stewart.Leg.lenght; ...
|
||||
0 0.2*stewart.Leg.lenght];
|
||||
|
||||
%% Calculate revolute and cylindrical axes
|
||||
rev1 = zeros(6, 3);
|
||||
rev2 = zeros(6, 3);
|
||||
cyl1 = zeros(6, 3);
|
||||
for i = 1:6
|
||||
rev1(i,:) = cross(leg_vectors(i,:), [0 0 1]);
|
||||
rev1(i,:) = rev1(i,:) / norm(rev1(i,:));
|
||||
|
||||
rev2(i,:) = - cross(rev1(i,:), leg_vectors(i,:));
|
||||
rev2(i,:) = rev2(i,:) / norm(rev2(i,:));
|
||||
|
||||
cyl1(i,:) = leg_vectors(i,:);
|
||||
end
|
||||
|
||||
|
||||
%% Coordinate systems
|
||||
stewart.lower_leg = struct('rotation', eye(3));
|
||||
stewart.upper_leg = struct('rotation', eye(3));
|
||||
|
||||
for i = 1:6
|
||||
stewart.lower_leg(i).rotation = [rev1(i,:)', rev2(i,:)', cyl1(i,:)'];
|
||||
stewart.upper_leg(i).rotation = [rev1(i,:)', rev2(i,:)', cyl1(i,:)'];
|
||||
end
|
||||
|
||||
%% Position Matrix
|
||||
stewart.M_pos_base = stewart.pos_base + (height+(stewart.TP.thickness+stewart.Leg.sphere.top+stewart.SP.thickness.top+stewart.jacobian)*1e-3)*[zeros(6, 2),ones(6, 1)];
|
||||
|
||||
%% Compute Jacobian Matrix
|
||||
aa = stewart.pos_top_tranform + (stewart.jacobian - stewart.TP.thickness - stewart.SP.height.top)*1e-3*[zeros(6, 2),ones(6, 1)];
|
||||
stewart.J = getJacobianMatrix(leg_vectors', aa');
|
||||
end
|
||||
|
||||
function J = getJacobianMatrix(RM,M_pos_base)
|
||||
% RM: [3x6] unit vector of each leg in the fixed frame
|
||||
% M_pos_base: [3x6] vector of the leg connection at the top platform location in the fixed frame
|
||||
J = zeros(6);
|
||||
J(:, 1:3) = RM';
|
||||
J(:, 4:6) = cross(M_pos_base, RM)';
|
||||
end
|
||||
end
|
64
src/initializeMirror.m
Normal file
64
src/initializeMirror.m
Normal file
@@ -0,0 +1,64 @@
|
||||
% Mirror
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/initializeMirror.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:initializeMirror>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/initializeMirror.m][here]].
|
||||
|
||||
|
||||
function [] = initializeMirror(opts_param)
|
||||
%% Default values for opts
|
||||
opts = struct(...
|
||||
'shape', 'spherical', ... % spherical or conical
|
||||
'angle', 45 ...
|
||||
);
|
||||
|
||||
%% Populate opts with input parameters
|
||||
if exist('opts_param','var')
|
||||
for opt = fieldnames(opts_param)'
|
||||
opts.(opt{1}) = opts_param.(opt{1});
|
||||
end
|
||||
end
|
||||
|
||||
%%
|
||||
mirror = struct();
|
||||
mirror.h = 50; % height of the mirror [mm]
|
||||
mirror.thickness = 25; % Thickness of the plate supporting the sample [mm]
|
||||
mirror.hole_rad = 120; % radius of the hole in the mirror [mm]
|
||||
mirror.support_rad = 100; % radius of the support plate [mm]
|
||||
mirror.jacobian = 150; % point of interest offset in z (above the top surfave) [mm]
|
||||
mirror.rad = 180; % radius of the mirror (at the bottom surface) [mm]
|
||||
|
||||
mirror.density = 2400; % Density of the mirror [kg/m3]
|
||||
mirror.color = [0.4 1.0 1.0]; % Color of the mirror
|
||||
|
||||
mirror.cone_length = mirror.rad*tand(opts.angle)+mirror.h+mirror.jacobian; % Distance from Apex point of the cone to jacobian point
|
||||
|
||||
%% Shape
|
||||
mirror.shape = [...
|
||||
0 mirror.h-mirror.thickness
|
||||
mirror.hole_rad mirror.h-mirror.thickness; ...
|
||||
mirror.hole_rad 0; ...
|
||||
mirror.rad 0 ...
|
||||
];
|
||||
|
||||
if strcmp(opts.shape, 'spherical')
|
||||
mirror.sphere_radius = sqrt((mirror.jacobian+mirror.h)^2+mirror.rad^2); % Radius of the sphere [mm]
|
||||
|
||||
for z = linspace(0, mirror.h, 101)
|
||||
mirror.shape = [mirror.shape; sqrt(mirror.sphere_radius^2-(z-mirror.jacobian-mirror.h)^2) z];
|
||||
end
|
||||
elseif strcmp(opts.shape, 'conical')
|
||||
mirror.shape = [mirror.shape; mirror.rad+mirror.h/tand(opts.angle) mirror.h];
|
||||
else
|
||||
error('Shape should be either conical or spherical');
|
||||
end
|
||||
|
||||
mirror.shape = [mirror.shape; 0 mirror.h];
|
||||
|
||||
%% Save
|
||||
save('./mat/stages.mat', 'mirror', '-append');
|
||||
end
|
211
src/initializeNanoHexapod.m
Normal file
211
src/initializeNanoHexapod.m
Normal file
@@ -0,0 +1,211 @@
|
||||
% Nano Hexapod
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/initializeNanoHexapod.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:initializeNanoHexapod>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/initializeNanoHexapod.m][here]].
|
||||
|
||||
|
||||
function [nano_hexapod] = initializeNanoHexapod(opts_param)
|
||||
%% Default values for opts
|
||||
opts = struct('actuator', 'piezo');
|
||||
|
||||
%% Populate opts with input parameters
|
||||
if exist('opts_param','var')
|
||||
for opt = fieldnames(opts_param)'
|
||||
opts.(opt{1}) = opts_param.(opt{1});
|
||||
end
|
||||
end
|
||||
|
||||
%% Stewart Object
|
||||
nano_hexapod = struct();
|
||||
nano_hexapod.h = 90; % Total height of the platform [mm]
|
||||
nano_hexapod.jacobian = 175; % Point where the Jacobian is computed => Center of rotation [mm]
|
||||
% nano_hexapod.jacobian = 174.26; % Point where the Jacobian is computed => Center of rotation [mm]
|
||||
|
||||
%% Bottom Plate
|
||||
BP = struct();
|
||||
|
||||
BP.rad.int = 0; % Internal Radius [mm]
|
||||
BP.rad.ext = 150; % External Radius [mm]
|
||||
BP.thickness = 10; % Thickness [mm]
|
||||
BP.leg.rad = 100; % Radius where the legs articulations are positionned [mm]
|
||||
BP.leg.ang = 5; % Angle Offset [deg]
|
||||
BP.density = 8000;% Density of the material [kg/m^3]
|
||||
BP.color = [0.7 0.7 0.7]; % Color [rgb]
|
||||
BP.shape = [BP.rad.int BP.thickness; BP.rad.int 0; BP.rad.ext 0; BP.rad.ext BP.thickness];
|
||||
|
||||
%% Top Plate
|
||||
TP = struct();
|
||||
|
||||
TP.rad.int = 0; % Internal Radius [mm]
|
||||
TP.rad.ext = 100; % Internal Radius [mm]
|
||||
TP.thickness = 10; % Thickness [mm]
|
||||
TP.leg.rad = 90; % Radius where the legs articulations are positionned [mm]
|
||||
TP.leg.ang = 5; % Angle Offset [deg]
|
||||
TP.density = 8000;% Density of the material [kg/m^3]
|
||||
TP.color = [0.7 0.7 0.7]; % Color [rgb]
|
||||
TP.shape = [TP.rad.int TP.thickness; TP.rad.int 0; TP.rad.ext 0; TP.rad.ext TP.thickness];
|
||||
|
||||
%% Leg
|
||||
Leg = struct();
|
||||
|
||||
Leg.stroke = 80e-6; % Maximum Stroke of each leg [m]
|
||||
if strcmp(opts.actuator, 'piezo')
|
||||
Leg.k.ax = 1e7; % Stiffness of each leg [N/m]
|
||||
elseif strcmp(opts.actuator, 'lorentz')
|
||||
Leg.k.ax = 1e4; % Stiffness of each leg [N/m]
|
||||
else
|
||||
error('opts.actuator should be piezo or lorentz');
|
||||
end
|
||||
Leg.ksi.ax = 10; % Maximum amplification at resonance []
|
||||
Leg.rad.bottom = 12; % Radius of the cylinder of the bottom part [mm]
|
||||
Leg.rad.top = 10; % Radius of the cylinder of the top part [mm]
|
||||
Leg.density = 8000; % Density of the material [kg/m^3]
|
||||
Leg.color.bottom = [0.5 0.5 0.5]; % Color [rgb]
|
||||
Leg.color.top = [0.5 0.5 0.5]; % Color [rgb]
|
||||
|
||||
Leg.sphere.bottom = Leg.rad.bottom; % Size of the sphere at the end of the leg [mm]
|
||||
Leg.sphere.top = Leg.rad.top; % Size of the sphere at the end of the leg [mm]
|
||||
Leg.m = TP.density*((pi*(TP.rad.ext/1000)^2)*(TP.thickness/1000)-(pi*(TP.rad.int/1000^2))*(TP.thickness/1000))/6; % TODO [kg]
|
||||
|
||||
Leg = updateDamping(Leg);
|
||||
|
||||
|
||||
%% Sphere
|
||||
SP = struct();
|
||||
|
||||
SP.height.bottom = 15; % [mm]
|
||||
SP.height.top = 15; % [mm]
|
||||
SP.density.bottom = 8000; % [kg/m^3]
|
||||
SP.density.top = 8000; % [kg/m^3]
|
||||
SP.color.bottom = [0.7 0.7 0.7]; % [rgb]
|
||||
SP.color.top = [0.7 0.7 0.7]; % [rgb]
|
||||
SP.k.ax = 0; % [N*m/deg]
|
||||
SP.ksi.ax = 3;
|
||||
|
||||
SP.thickness.bottom = SP.height.bottom-Leg.sphere.bottom; % [mm]
|
||||
SP.thickness.top = SP.height.top-Leg.sphere.top; % [mm]
|
||||
SP.rad.bottom = Leg.sphere.bottom; % [mm]
|
||||
SP.rad.top = Leg.sphere.top; % [mm]
|
||||
SP.m = SP.density.bottom*2*pi*((SP.rad.bottom*1e-3)^2)*(SP.height.bottom*1e-3); % TODO [kg]
|
||||
|
||||
SP = updateDamping(SP);
|
||||
|
||||
%%
|
||||
Leg.support.bottom = [0 SP.thickness.bottom; 0 0; SP.rad.bottom 0; SP.rad.bottom SP.height.bottom];
|
||||
Leg.support.top = [0 SP.thickness.top; 0 0; SP.rad.top 0; SP.rad.top SP.height.top];
|
||||
|
||||
%%
|
||||
nano_hexapod.BP = BP;
|
||||
nano_hexapod.TP = TP;
|
||||
nano_hexapod.Leg = Leg;
|
||||
nano_hexapod.SP = SP;
|
||||
|
||||
%%
|
||||
nano_hexapod = initializeParameters(nano_hexapod);
|
||||
|
||||
%% Save
|
||||
save('./mat/stages.mat', 'nano_hexapod', '-append');
|
||||
|
||||
%%
|
||||
function [element] = updateDamping(element)
|
||||
field = fieldnames(element.k);
|
||||
for i = 1:length(field)
|
||||
element.c.(field{i}) = 1/element.ksi.(field{i})*sqrt(element.k.(field{i})/element.m);
|
||||
end
|
||||
end
|
||||
|
||||
%%
|
||||
function [stewart] = initializeParameters(stewart)
|
||||
%% Connection points on base and top plate w.r.t. World frame at the center of the base plate
|
||||
stewart.pos_base = zeros(6, 3);
|
||||
stewart.pos_top = zeros(6, 3);
|
||||
|
||||
alpha_b = stewart.BP.leg.ang*pi/180; % angle de décalage par rapport à 120 deg (pour positionner les supports bases)
|
||||
alpha_t = stewart.TP.leg.ang*pi/180; % +- offset angle from 120 degree spacing on top
|
||||
|
||||
height = (stewart.h-stewart.BP.thickness-stewart.TP.thickness-stewart.Leg.sphere.bottom-stewart.Leg.sphere.top-stewart.SP.thickness.bottom-stewart.SP.thickness.top)*0.001; % TODO
|
||||
|
||||
radius_b = stewart.BP.leg.rad*0.001; % rayon emplacement support base
|
||||
radius_t = stewart.TP.leg.rad*0.001; % top radius in meters
|
||||
|
||||
for i = 1:3
|
||||
% base points
|
||||
angle_m_b = (2*pi/3)* (i-1) - alpha_b;
|
||||
angle_p_b = (2*pi/3)* (i-1) + alpha_b;
|
||||
stewart.pos_base(2*i-1,:) = [radius_b*cos(angle_m_b), radius_b*sin(angle_m_b), 0.0];
|
||||
stewart.pos_base(2*i,:) = [radius_b*cos(angle_p_b), radius_b*sin(angle_p_b), 0.0];
|
||||
|
||||
% top points
|
||||
% Top points are 60 degrees offset
|
||||
angle_m_t = (2*pi/3)* (i-1) - alpha_t + 2*pi/6;
|
||||
angle_p_t = (2*pi/3)* (i-1) + alpha_t + 2*pi/6;
|
||||
stewart.pos_top(2*i-1,:) = [radius_t*cos(angle_m_t), radius_t*sin(angle_m_t), height];
|
||||
stewart.pos_top(2*i,:) = [radius_t*cos(angle_p_t), radius_t*sin(angle_p_t), height];
|
||||
end
|
||||
|
||||
% permute pos_top points so that legs are end points of base and top points
|
||||
stewart.pos_top = [stewart.pos_top(6,:); stewart.pos_top(1:5,:)]; %6th point on top connects to 1st on bottom
|
||||
stewart.pos_top_tranform = stewart.pos_top - height*[zeros(6, 2),ones(6, 1)];
|
||||
|
||||
%% leg vectors
|
||||
legs = stewart.pos_top - stewart.pos_base;
|
||||
leg_length = zeros(6, 1);
|
||||
leg_vectors = zeros(6, 3);
|
||||
for i = 1:6
|
||||
leg_length(i) = norm(legs(i,:));
|
||||
leg_vectors(i,:) = legs(i,:) / leg_length(i);
|
||||
end
|
||||
|
||||
stewart.Leg.lenght = 1000*leg_length(1)/1.5;
|
||||
stewart.Leg.shape.bot = [0 0; ...
|
||||
stewart.Leg.rad.bottom 0; ...
|
||||
stewart.Leg.rad.bottom stewart.Leg.lenght; ...
|
||||
stewart.Leg.rad.top stewart.Leg.lenght; ...
|
||||
stewart.Leg.rad.top 0.2*stewart.Leg.lenght; ...
|
||||
0 0.2*stewart.Leg.lenght];
|
||||
|
||||
%% Calculate revolute and cylindrical axes
|
||||
rev1 = zeros(6, 3);
|
||||
rev2 = zeros(6, 3);
|
||||
cyl1 = zeros(6, 3);
|
||||
for i = 1:6
|
||||
rev1(i,:) = cross(leg_vectors(i,:), [0 0 1]);
|
||||
rev1(i,:) = rev1(i,:) / norm(rev1(i,:));
|
||||
|
||||
rev2(i,:) = - cross(rev1(i,:), leg_vectors(i,:));
|
||||
rev2(i,:) = rev2(i,:) / norm(rev2(i,:));
|
||||
|
||||
cyl1(i,:) = leg_vectors(i,:);
|
||||
end
|
||||
|
||||
|
||||
%% Coordinate systems
|
||||
stewart.lower_leg = struct('rotation', eye(3));
|
||||
stewart.upper_leg = struct('rotation', eye(3));
|
||||
|
||||
for i = 1:6
|
||||
stewart.lower_leg(i).rotation = [rev1(i,:)', rev2(i,:)', cyl1(i,:)'];
|
||||
stewart.upper_leg(i).rotation = [rev1(i,:)', rev2(i,:)', cyl1(i,:)'];
|
||||
end
|
||||
|
||||
%% Position Matrix
|
||||
stewart.M_pos_base = stewart.pos_base + (height+(stewart.TP.thickness+stewart.Leg.sphere.top+stewart.SP.thickness.top+stewart.jacobian)*1e-3)*[zeros(6, 2),ones(6, 1)];
|
||||
|
||||
%% Compute Jacobian Matrix
|
||||
aa = stewart.pos_top_tranform + (stewart.jacobian - stewart.TP.thickness - stewart.SP.height.top)*1e-3*[zeros(6, 2),ones(6, 1)];
|
||||
stewart.J = getJacobianMatrix(leg_vectors', aa');
|
||||
end
|
||||
|
||||
function J = getJacobianMatrix(RM,M_pos_base)
|
||||
% RM: [3x6] unit vector of each leg in the fixed frame
|
||||
% M_pos_base: [3x6] vector of the leg connection at the top platform location in the fixed frame
|
||||
J = zeros(6);
|
||||
J(:, 1:3) = RM';
|
||||
J(:, 4:6) = cross(M_pos_base, RM)';
|
||||
end
|
||||
end
|
67
src/initializeRy.m
Normal file
67
src/initializeRy.m
Normal file
@@ -0,0 +1,67 @@
|
||||
% Tilt Stage
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/initializeRy.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:initializeRy>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/initializeRy.m][here]].
|
||||
|
||||
|
||||
function [ry] = initializeRy(opts_param)
|
||||
%% Default values for opts
|
||||
opts = struct('rigid', false);
|
||||
|
||||
%% Populate opts with input parameters
|
||||
if exist('opts_param','var')
|
||||
for opt = fieldnames(opts_param)'
|
||||
opts.(opt{1}) = opts_param.(opt{1});
|
||||
end
|
||||
end
|
||||
|
||||
%%
|
||||
ry = struct();
|
||||
|
||||
%% Tilt Stage - Static Properties
|
||||
% Ry - Guide for the tilt stage
|
||||
ry.guide.density = 7800; % [kg/m3]
|
||||
ry.guide.color = [0.792 0.820 0.933];
|
||||
ry.guide.STEP = './STEPS/ry/Tilt_Guide.STEP';
|
||||
% Ry - Rotor of the motor
|
||||
ry.rotor.density = 2400; % [kg/m3]
|
||||
ry.rotor.color = [0.792 0.820 0.933];
|
||||
ry.rotor.STEP = './STEPS/ry/Tilt_Motor_Axis.STEP';
|
||||
% Ry - Motor
|
||||
ry.motor.density = 3200; % [kg/m3]
|
||||
ry.motor.color = [0.792 0.820 0.933];
|
||||
ry.motor.STEP = './STEPS/ry/Tilt_Motor.STEP';
|
||||
% Ry - Plateau Tilt
|
||||
ry.stage.density = 7800; % [kg/m3]
|
||||
ry.stage.color = [0.792 0.820 0.933];
|
||||
ry.stage.STEP = './STEPS/ry/Tilt_Stage.STEP';
|
||||
|
||||
ry.m = 200; % TODO [kg]
|
||||
|
||||
%% Tilt Stage - Dynamical Properties
|
||||
if opts.rigid
|
||||
ry.k.tilt = 1e10; % Rotation stiffness around y [N*m/deg]
|
||||
else
|
||||
ry.k.tilt = 1e4; % Rotation stiffness around y [N*m/deg]
|
||||
end
|
||||
|
||||
ry.k.h = 357e6/4; % Stiffness in the direction of the guidance [N/m]
|
||||
ry.k.rad = 555e6/4; % Stiffness in the top direction [N/m]
|
||||
ry.k.rrad = 238e6/4; % Stiffness in the side direction [N/m]
|
||||
|
||||
ry.c.h = 10*(1/5)*sqrt(ry.k.h/ry.m);
|
||||
ry.c.rad = 10*(1/5)*sqrt(ry.k.rad/ry.m);
|
||||
ry.c.rrad = 10*(1/5)*sqrt(ry.k.rrad/ry.m);
|
||||
ry.c.tilt = 10*(1/1)*sqrt(ry.k.tilt/ry.m);
|
||||
|
||||
%% Positioning parameters
|
||||
ry.z_offset = 0.58178; % Z-Offset so that the center of rotation matches the sample center [m]
|
||||
|
||||
%% Save
|
||||
save('./mat/stages.mat', 'ry', '-append');
|
||||
end
|
63
src/initializeRz.m
Normal file
63
src/initializeRz.m
Normal file
@@ -0,0 +1,63 @@
|
||||
% Spindle
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/initializeRz.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:initializeRz>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/initializeRz.m][here]].
|
||||
|
||||
|
||||
function [rz] = initializeRz(opts_param)
|
||||
%% Default values for opts
|
||||
opts = struct('rigid', false);
|
||||
|
||||
%% Populate opts with input parameters
|
||||
if exist('opts_param','var')
|
||||
for opt = fieldnames(opts_param)'
|
||||
opts.(opt{1}) = opts_param.(opt{1});
|
||||
end
|
||||
end
|
||||
|
||||
%%
|
||||
rz = struct();
|
||||
|
||||
%% Spindle - Static Properties
|
||||
% Spindle - Slip Ring
|
||||
rz.slipring.density = 7800; % [kg/m3]
|
||||
rz.slipring.color = [0.792 0.820 0.933];
|
||||
rz.slipring.STEP = './STEPS/rz/Spindle_Slip_Ring.STEP';
|
||||
% Spindle - Rotor
|
||||
rz.rotor.density = 7800; % [kg/m3]
|
||||
rz.rotor.color = [0.792 0.820 0.933];
|
||||
rz.rotor.STEP = './STEPS/rz/Spindle_Rotor.STEP';
|
||||
% Spindle - Stator
|
||||
rz.stator.density = 7800; % [kg/m3]
|
||||
rz.stator.color = [0.792 0.820 0.933];
|
||||
rz.stator.STEP = './STEPS/rz/Spindle_Stator.STEP';
|
||||
|
||||
% Estimated mass of the mooving part
|
||||
rz.m = 250; % [kg]
|
||||
|
||||
%% Spindle - Dynamical Properties
|
||||
% Estimated stiffnesses
|
||||
rz.k.ax = 2e9; % Axial Stiffness [N/m]
|
||||
rz.k.rad = 7e8; % Radial Stiffness [N/m]
|
||||
rz.k.rot = 100e6*2*pi/360; % Rotational Stiffness [N*m/deg]
|
||||
|
||||
if opts.rigid
|
||||
rz.k.tilt = 1e10; % Vertical Rotational Stiffness [N*m/deg]
|
||||
else
|
||||
rz.k.tilt = 1e2; % TODO what value should I put? [N*m/deg]
|
||||
end
|
||||
|
||||
% TODO
|
||||
rz.c.ax = 2*sqrt(rz.k.ax/rz.m);
|
||||
rz.c.rad = 2*sqrt(rz.k.rad/rz.m);
|
||||
rz.c.tilt = 100*sqrt(rz.k.tilt/rz.m);
|
||||
rz.c.rot = 100*sqrt(rz.k.rot/rz.m);
|
||||
|
||||
%% Save
|
||||
save('./mat/stages.mat', 'rz', '-append');
|
||||
end
|
40
src/initializeSample.m
Normal file
40
src/initializeSample.m
Normal file
@@ -0,0 +1,40 @@
|
||||
% Sample
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/initializeSample.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:initializeSample>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/initializeSample.m][here]].
|
||||
|
||||
|
||||
function [sample] = initializeSample(opts_param)
|
||||
%% Default values for opts
|
||||
sample = struct('radius', 100, ...
|
||||
'height', 300, ...
|
||||
'mass', 50, ...
|
||||
'offset', 0, ...
|
||||
'color', [0.45, 0.45, 0.45] ...
|
||||
);
|
||||
|
||||
%% Populate opts with input parameters
|
||||
if exist('opts_param','var')
|
||||
for opt = fieldnames(opts_param)'
|
||||
sample.(opt{1}) = opts_param.(opt{1});
|
||||
end
|
||||
end
|
||||
|
||||
%%
|
||||
sample.k.x = 1e8;
|
||||
sample.c.x = sqrt(sample.k.x*sample.mass)/10;
|
||||
|
||||
sample.k.y = 1e8;
|
||||
sample.c.y = sqrt(sample.k.y*sample.mass)/10;
|
||||
|
||||
sample.k.z = 1e8;
|
||||
sample.c.z = sqrt(sample.k.y*sample.mass)/10;
|
||||
|
||||
%% Save
|
||||
save('./mat/stages.mat', 'sample', '-append');
|
||||
end
|
44
src/initializeSimConf.m
Normal file
44
src/initializeSimConf.m
Normal file
@@ -0,0 +1,44 @@
|
||||
% Simulation Configuration
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/initializeSimConf.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:initializeSimConf>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/initializeSimConf.m][here]].
|
||||
|
||||
|
||||
function [] = initializeSimConf(opts_param)
|
||||
%% Default values for opts
|
||||
opts = struct('Ts', 1e-4, ... % Sampling time [s]
|
||||
'Tsim', 10, ... % Simulation time [s]
|
||||
'cl_time', 0, ... % Close Loop time [s]
|
||||
'gravity', false ... % Gravity along the z axis
|
||||
);
|
||||
|
||||
%% Populate opts with input parameters
|
||||
if exist('opts_param','var')
|
||||
for opt = fieldnames(opts_param)'
|
||||
opts.(opt{1}) = opts_param.(opt{1});
|
||||
end
|
||||
end
|
||||
|
||||
%%
|
||||
sim_conf = struct();
|
||||
|
||||
%%
|
||||
sim_conf.Ts = opts.Ts;
|
||||
sim_conf.Tsim = opts.Tsim;
|
||||
sim_conf.cl_time = opts.cl_time;
|
||||
|
||||
%% Gravity
|
||||
if opts.gravity
|
||||
sim_conf.g = -9.8; %#ok
|
||||
else
|
||||
sim_conf.g = 0; %#ok
|
||||
end
|
||||
|
||||
%% Save
|
||||
save('./mat/sim_conf.mat', 'sim_conf');
|
||||
end
|
79
src/initializeTy.m
Normal file
79
src/initializeTy.m
Normal file
@@ -0,0 +1,79 @@
|
||||
% Translation Stage
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/initializeTy.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:initializeTy>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/initializeTy.m][here]].
|
||||
|
||||
|
||||
function [ty] = initializeTy(opts_param)
|
||||
%% Default values for opts
|
||||
opts = struct('rigid', false);
|
||||
|
||||
%% Populate opts with input parameters
|
||||
if exist('opts_param','var')
|
||||
for opt = fieldnames(opts_param)'
|
||||
opts.(opt{1}) = opts_param.(opt{1});
|
||||
end
|
||||
end
|
||||
|
||||
%%
|
||||
ty = struct();
|
||||
|
||||
%% Y-Translation - Static Properties
|
||||
% Ty Granite frame
|
||||
ty.granite_frame.density = 7800; % [kg/m3]
|
||||
ty.granite_frame.color = [0.753 1 0.753];
|
||||
ty.granite_frame.STEP = './STEPS/Ty/Ty_Granite_Frame.STEP';
|
||||
% Guide Translation Ty
|
||||
ty.guide.density = 7800; % [kg/m3]
|
||||
ty.guide.color = [0.792 0.820 0.933];
|
||||
ty.guide.STEP = './STEPS/ty/Ty_Guide.STEP';
|
||||
% Ty - Guide_Translation12
|
||||
ty.guide12.density = 7800; % [kg/m3]
|
||||
ty.guide12.color = [0.792 0.820 0.933];
|
||||
ty.guide12.STEP = './STEPS/Ty/Ty_Guide_12.STEP';
|
||||
% Ty - Guide_Translation11
|
||||
ty.guide11.density = 7800; % [kg/m3]
|
||||
ty.guide11.color = [0.792 0.820 0.933];
|
||||
ty.guide11.STEP = './STEPS/ty/Ty_Guide_11.STEP';
|
||||
% Ty - Guide_Translation22
|
||||
ty.guide22.density = 7800; % [kg/m3]
|
||||
ty.guide22.color = [0.792 0.820 0.933];
|
||||
ty.guide22.STEP = './STEPS/ty/Ty_Guide_22.STEP';
|
||||
% Ty - Guide_Translation21
|
||||
ty.guide21.density = 7800; % [kg/m3]
|
||||
ty.guide21.color = [0.792 0.820 0.933];
|
||||
ty.guide21.STEP = './STEPS/Ty/Ty_Guide_21.STEP';
|
||||
% Ty - Plateau translation
|
||||
ty.frame.density = 7800; % [kg/m3]
|
||||
ty.frame.color = [0.792 0.820 0.933];
|
||||
ty.frame.STEP = './STEPS/ty/Ty_Stage.STEP';
|
||||
% Ty Stator Part
|
||||
ty.stator.density = 5400; % [kg/m3]
|
||||
ty.stator.color = [0.792 0.820 0.933];
|
||||
ty.stator.STEP = './STEPS/ty/Ty_Motor_Stator.STEP';
|
||||
% Ty Rotor Part
|
||||
ty.rotor.density = 5400; % [kg/m3]
|
||||
ty.rotor.color = [0.792 0.820 0.933];
|
||||
ty.rotor.STEP = './STEPS/ty/Ty_Motor_Rotor.STEP';
|
||||
|
||||
ty.m = 250; % TODO [kg]
|
||||
|
||||
%% Y-Translation - Dynamicals Properties
|
||||
if opts.rigid
|
||||
ty.k.ax = 1e10; % Axial Stiffness for each of the 4 guidance (y) [N/m]
|
||||
else
|
||||
ty.k.ax = 1e7/4; % Axial Stiffness for each of the 4 guidance (y) [N/m]
|
||||
end
|
||||
ty.k.rad = 9e9/4; % Radial Stiffness for each of the 4 guidance (x-z) [N/m]
|
||||
|
||||
ty.c.ax = 100*(1/5)*sqrt(ty.k.ax/ty.m);
|
||||
ty.c.rad = 100*(1/5)*sqrt(ty.k.rad/ty.m);
|
||||
|
||||
%% Save
|
||||
save('./mat/stages.mat', 'ty', '-append');
|
||||
end
|
5
src/project_shutdown.m
Normal file
5
src/project_shutdown.m
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
% When the project closes, it runs the =project_shutdown.m= script defined below.
|
||||
|
||||
Simulink.fileGenControl('reset');
|
21
src/project_startup.m
Normal file
21
src/project_startup.m
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
|
||||
% When the project opens, a startup script is ran.
|
||||
% The startup script is defined below and is exported to the =project_startup.m= script.
|
||||
|
||||
%%
|
||||
freqs = logspace(-1, 3, 1000);
|
||||
save_fig = false;
|
||||
save('./mat/config.mat', 'freqs', 'save_fig');
|
||||
|
||||
%%
|
||||
project = simulinkproject;
|
||||
projectRoot = project.RootFolder;
|
||||
|
||||
myCacheFolder = fullfile(projectRoot, '.SimulinkCache');
|
||||
myCodeFolder = fullfile(projectRoot, '.SimulinkCode');
|
||||
|
||||
Simulink.fileGenControl('set',...
|
||||
'CacheFolder', myCacheFolder,...
|
||||
'CodeGenFolder', myCodeFolder,...
|
||||
'createDir', true);
|
@@ -1,3 +1,14 @@
|
||||
% runSimulation
|
||||
% :PROPERTIES:
|
||||
% :header-args:matlab+: :tangle src/runSimulation.m
|
||||
% :header-args:matlab+: :comments org :mkdirp yes
|
||||
% :header-args:matlab+: :eval no :results none
|
||||
% :END:
|
||||
% <<sec:runSimulation>>
|
||||
|
||||
% This Matlab function is accessible [[file:src/runSimulation.m][here]].
|
||||
|
||||
|
||||
function [] = runSimulation(sys_name, sys_mass, ctrl_type, act_damp)
|
||||
%% Load the controller and save it for the simulation
|
||||
if strcmp(ctrl_type, 'cl') && strcmp(act_damp, 'none')
|
||||
@@ -27,7 +38,7 @@ function [] = runSimulation(sys_name, sys_mass, ctrl_type, act_damp)
|
||||
|
||||
%%
|
||||
if strcmp(sys_name, 'pz')
|
||||
initializeNanoHexapod(struct('actuator', 'piezo'));
|
||||
initializeNanoHexapod(struct('actuator', 'piezo'));
|
||||
elseif strcmp(sys_name, 'vc')
|
||||
initializeNanoHexapod(struct('actuator', 'lorentz'));
|
||||
else
|
||||
@@ -35,7 +46,7 @@ function [] = runSimulation(sys_name, sys_mass, ctrl_type, act_damp)
|
||||
end
|
||||
|
||||
if strcmp(sys_mass, 'light')
|
||||
initializeSample(struct('mass', 1));
|
||||
initializeSample(struct('mass', 1));
|
||||
elseif strcmp(sys_mass, 'heavy')
|
||||
initializeSample(struct('mass', 50));
|
||||
else
|
||||
|
Reference in New Issue
Block a user