Compare analytical and multi-body models

This commit is contained in:
Thomas Dehaeze 2025-02-10 19:38:32 +01:00
parent fca54e3d88
commit 95b9b460f7
10 changed files with 4544 additions and 135 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

View File

@ -14,7 +14,7 @@ function [nano_hexapod] = initializeSimplifiedNanoHexapod(args)
%% Actuators %% Actuators
args.actuator_type char {mustBeMember(args.actuator_type,{'1dof', '2dof', 'flexible'})} = '1dof' args.actuator_type char {mustBeMember(args.actuator_type,{'1dof', '2dof', 'flexible'})} = '1dof'
args.actuator_k (1,1) double {mustBeNumeric, mustBePositive} = 1e6 args.actuator_k (1,1) double {mustBeNumeric, mustBePositive} = 1e6
args.actuator_kp (1,1) double {mustBeNumeric, mustBeNonnegative} = 5e4 args.actuator_kp (1,1) double {mustBeNumeric, mustBeNonnegative} = 1e4
args.actuator_ke (1,1) double {mustBeNumeric, mustBePositive} = 4952605 args.actuator_ke (1,1) double {mustBeNumeric, mustBePositive} = 4952605
args.actuator_ka (1,1) double {mustBeNumeric, mustBePositive} = 2476302 args.actuator_ka (1,1) double {mustBeNumeric, mustBePositive} = 2476302
args.actuator_c (1,1) double {mustBeNumeric, mustBePositive} = 50 args.actuator_c (1,1) double {mustBeNumeric, mustBePositive} = 50

View File

@ -750,7 +750,7 @@ The primary forces acting on the system are actuator forces $\bm{\tau}$, elastic
Combining these forces and using eqref:eq:nhexa_forward_kinematics_approximate yields the complete dynamic equation eqref:eq:nhexa_dynamical_equations. Combining these forces and using eqref:eq:nhexa_forward_kinematics_approximate yields the complete dynamic equation eqref:eq:nhexa_dynamical_equations.
\begin{equation}\label{eq:nhexa_dynamical_equations} \begin{equation}\label{eq:nhexa_dynamical_equations}
M s^2 \mathcal{X} = \mathcal{F} - J^T \mathcal{K} J \mathcal{X} - J^T \mathcal{C} J s \mathcal{X} \bm{M} s^2 \bm{\mathcal{X}} = \bm{\mathcal{F}} - \bm{J}^T \bm{\mathcal{K}} \bm{J} \bm{\mathcal{X}} - \bm{J}^T \bm{\mathcal{C}} \bm{J} s \bm{\mathcal{X}}
\end{equation} \end{equation}
The transfer function in the Cartesian frame becomes eqref:eq:nhexa_transfer_function_cart. The transfer function in the Cartesian frame becomes eqref:eq:nhexa_transfer_function_cart.
@ -804,6 +804,9 @@ While a reasonable geometric configuration will be used to validate the NASS dur
Complex because has to model the inertia of the struts. Complex because has to model the inertia of the struts.
Cite papers that tries to model the stewart platform analytically Cite papers that tries to model the stewart platform analytically
Advantage: it will be easily included in the model of the NASS Advantage: it will be easily included in the model of the NASS
- Model definition (Section ref:ssec:nhexa_model_def)
- Validation of the model by comparing with analytical equations (Section ref:ssec:nhexa_model_validation)
- Dynamics of the nano-hexapod used for conceptual analysis: (Section ref:ssec:nhexa_model_dynamics)
** Matlab Init :noexport:ignore: ** Matlab Init :noexport:ignore:
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
@ -834,10 +837,6 @@ While a reasonable geometric configuration will be used to validate the NASS dur
<<ssec:nhexa_model_def>> <<ssec:nhexa_model_def>>
**** Geometry **** Geometry
#+begin_src matlab
nano_hexapod = initializeSimplifiedNanoHexapod();
#+end_src
The geometry of the Stewart platform (see Figure ref:fig:nhexa_stewart_model_def) is defined by the position of frame $\{F\}$ with respect to $\{M\}$ and by the locations of the joints ${}^Fa_i$ and ${}^Mb_i$. The geometry of the Stewart platform (see Figure ref:fig:nhexa_stewart_model_def) is defined by the position of frame $\{F\}$ with respect to $\{M\}$ and by the locations of the joints ${}^Fa_i$ and ${}^Mb_i$.
The point of interest, indicated by frame $\{A\}$ is located $150\,mm$ above the top platform (i.e. above the $\{M\}$ frame). The point of interest, indicated by frame $\{A\}$ is located $150\,mm$ above the top platform (i.e. above the $\{M\}$ frame).
Parameters that defines the geometry of the nano-hexapod multi-body models are summarized in Table ref:tab:nhexa_stewart_model_geometry. Parameters that defines the geometry of the nano-hexapod multi-body models are summarized in Table ref:tab:nhexa_stewart_model_geometry.
@ -928,15 +927,11 @@ Thanks to the flexibility of the multi-body model, the model of the actuators ca
#+end_scriptsize #+end_scriptsize
#+end_minipage #+end_minipage
** Model Dynamics ** Validation of the multi-body model
<<ssec:nhexa_model_dynamics>> <<ssec:nhexa_model_validation>>
- If all is perfect (mass-less struts, perfect joints, etc...), maybe compare analytical model with simscape model? The obtained multi-body model can schematically be represented as in Figure ref:fig:nhexa_stewart_model_input_outputs with actuator inputs $\bm{f}$, force sensor outputs $\bm{f}_m$ and relative displacement outputs $\bm{d}_L$.
- Say something about the model order The 3D representation of the Stewart platform using the multi-body model is shown in Figure ref:fig:nhexa_simscape_screenshot.
Model order is 12, and that we can compute modes from matrices M and K, compare with the Simscape model
- 4 observed modes (due to symmetry, in reality 6 modes)
- Compare with analytical formulas (see number of states)
- [ ] Effect of parallel on IFF plant?
#+attr_latex: :options [b]{0.6\linewidth} #+attr_latex: :options [b]{0.6\linewidth}
#+begin_minipage #+begin_minipage
@ -954,6 +949,32 @@ Thanks to the flexibility of the multi-body model, the model of the actuators ca
[[file:figs/nhexa_simscape_screenshot.jpg]] [[file:figs/nhexa_simscape_screenshot.jpg]]
#+end_minipage #+end_minipage
To validate the multi-body model of the Stewart platform, the simplest Stewart platform configuration is used to compare the multi-body dynamics with the analytical transfer functions obtained in Section ref:ssec:nhexa_stewart_platform_dynamics.
The bottom joints are universal joints while the top joints are spherical joints. All joints mass-less and have zero stiffness in the free DoF.
The struts are modelled with a stiffness equal to $k_a = 1\,N/\mu m$, damping $c_a = 10\,N/(m/s)$, and are mass-less.
The geometry used is shown in Table ref:tab:nhexa_actuator_parameters.
The top platform is considered mass-less, but a payload with mass $m = 10\,kg$ is added on top of the Stewart platform.
The payload is cylindrical with a radius of $r = 110\,mm$ and a height $h = 300\,mm$ such that its center of mass coincide with $\{A\}$.
Stiffness, damping and mass matrices for the analytical equations are summarized in eqref:eq:nhexa_analytical_matrices.
The transfer functions from actuator forces to displacement of each strut can then be computed using eqref:eq:nhexa_transfer_function_struts.
\begin{subequations}\label{eq:nhexa_analytical_matrices}
\begin{align}
\bm{K} &= \text{diag}(k_a,\ k_a,\ k_a,\ k_a,\ k_a,\ k_a) \\
\bm{C} &= \text{diag}(c_a,\ c_a,\ c_a,\ c_a,\ c_a,\ c_a) \\
\bm{M} &= \text{diag}\left(m,\ m,\ m,\ \frac{1}{12}m(3r^2 + h^2),\ \frac{1}{12}m(3r^2 + h^2),\ \frac{1}{2}mr^2\right)
\end{align}
\end{subequations}
The same transfer functions are extracted from the multi-body model.
The obtained state-space model has 12 states which corresponds to the 6-DoF of the top platform.
The transfer functions from the first actuator to the displacement of the 6 struts are compared in Figure ref:fig:nhexa_comp_multi_body_analytical.
A good match can be observed between the analytical formulas and the multi-body model therefore validating the multi-body model.
#+begin_src matlab #+begin_src matlab
%% Plant using Analytical Equations %% Plant using Analytical Equations
% Stewart platform definition % Stewart platform definition
@ -964,7 +985,7 @@ stewart = initializeSimplifiedNanoHexapod(...
'Mpm', 1e-3, ... 'Mpm', 1e-3, ...
'actuator_type', '1dof', ... 'actuator_type', '1dof', ...
'actuator_k', k, ... 'actuator_k', k, ...
'actuator_kp', 1e4, ... 'actuator_kp', 0, ...
'actuator_c', c ... 'actuator_c', c ...
); );
@ -1004,62 +1025,35 @@ G_simscape.InputName = {'f1', 'f2', 'f3', 'f4', 'f5', 'f6'};
G_simscape.OutputName = {'dL1', 'dL2', 'dL3', 'dL4', 'dL5', 'dL6'}; G_simscape.OutputName = {'dL1', 'dL2', 'dL3', 'dL4', 'dL5', 'dL6'};
#+end_src #+end_src
#+begin_src matlab #+begin_src matlab :exports none :results none
bodeFig({G_analytical(1,1), G_simscape(1,1), G_analytical(1,2), G_simscape(1,2)}) %% Comparison of the analytical transfer functions and the multi-body model
#+end_src
#+begin_src matlab
% initializeSimplifiedNanoHexapod('flex_type_F', '2dof', 'flex_type_M', '3dof', 'actuator_type', '1dof');
% initializeSample('type', 'cylindrical', 'm', 50, 'H', 300e-3);
% initializeLoggingConfiguration('log', 'none');
% initializeController('type', 'open-loop');
% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs [N]
io(io_i) = linio([mdl, '/plant'], 2, 'openoutput', [], 'dL'); io_i = io_i + 1; % Encoders [m]
io(io_i) = linio([mdl, '/plant'], 2, 'openoutput', [], 'fn'); io_i = io_i + 1; % Force Sensors [N]
% With no payload
G = linearize(mdl, io);
G.InputName = {'f1', 'f2', 'f3', 'f4', 'f5', 'f6'};
G.OutputName = {'dL1', 'dL2', 'dL3', 'dL4', 'dL5', 'dL6', ...
'fn1', 'fn2', 'fn3', 'fn4', 'fn5', 'fn6'};
size(G)
#+end_src
#+begin_src matlab :exports none
%% Diagonal elements of the FRF matrix from u to de
figure; figure;
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
ax1 = nexttile([2,1]); ax1 = nexttile([2,1]);
hold on; hold on;
plot(freqs, abs(squeeze(freqresp(G(1,1), freqs, 'Hz'))), 'color', colors(2,:), ... for i = 1:6
'DisplayName', '$d_{ei}/u_i$ - Model') plot(freqs, abs(squeeze(freqresp(G_simscape(i,1), freqs, 'Hz'))), 'color', [colors(i,:), 0.5], ...
for i = 2:6 'DisplayName', sprintf('$d_{L%i}/f_1$ - Multi-Body', i))
plot(freqs, abs(squeeze(freqresp(G(i,i), freqs, 'Hz'))), 'color', colors(2,:), ...
'HandleVisibility', 'off');
end end
for i = 1:5 for i = 1:6
for j = i+1:6 plot(freqs, abs(squeeze(freqresp(G_analytical(i,1), freqs, 'Hz'))), '--', 'color', [colors(i,:)], ...
plot(freqs, abs(squeeze(freqresp(G(i,j), freqs, 'Hz'))), 'color', [0, 0, 0, 0.2], ... 'DisplayName', sprintf('$d_{L%i}/f_1$ - Analytical', i))
'HandleVisibility', 'off');
end
end end
hold off; hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
ylim([1e-9, 1e-4]); ylim([1e-9, 1e-4]);
leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); leg = legend('location', 'northwest', 'FontSize', 6, 'NumColumns', 1);
leg.ItemTokenSize(1) = 15; leg.ItemTokenSize(1) = 15;
ax2 = nexttile; ax2 = nexttile;
hold on; hold on;
for i = 1:6 for i = 1:6
plot(freqs, 180/pi*angle(squeeze(freqresp(G(i,i), freqs, 'Hz'))), 'color', [colors(2,:),0.5]); plot(freqs, 180/pi*angle(squeeze(freqresp(G_simscape(i,1), freqs, 'Hz'))), 'color', [colors(i,:),0.5]);
end
for i = 1:6
plot(freqs, 180/pi*angle(squeeze(freqresp(G_analytical(i,1), freqs, 'Hz'))), '--', 'color', colors(i,:));
end end
hold off; hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
@ -1071,57 +1065,43 @@ linkaxes([ax1,ax2],'x');
xlim([freqs(1), freqs(end)]); xlim([freqs(1), freqs(end)]);
#+end_src #+end_src
#+begin_src matlab :exports none #+begin_src matlab :tangle no :exports results :results file replace
%% Diagonal elements of the FRF matrix from u to de exportFig('figs/nhexa_comp_multi_body_analytical.pdf', 'width', 'wide', 'height', 600);
figure;
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
ax1 = nexttile([2,1]);
hold on;
plot(freqs, abs(squeeze(freqresp(G(6+1,1), freqs, 'Hz'))), 'color', colors(2,:), ...
'DisplayName', '$d_{ei}/u_i$ - Model')
for i = 2:6
plot(freqs, abs(squeeze(freqresp(G(6+i,i), freqs, 'Hz'))), 'color', colors(2,:), ...
'HandleVisibility', 'off');
end
for i = 1:5
for j = i+1:6
plot(freqs, abs(squeeze(freqresp(G(6+i,j), freqs, 'Hz'))), 'color', [0, 0, 0, 0.2], ...
'HandleVisibility', 'off');
end
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [N/N]'); set(gca, 'XTickLabel',[]);
ylim([1e-5, 1e2]);
leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1);
leg.ItemTokenSize(1) = 15;
ax2 = nexttile;
hold on;
for i = 1:6
plot(freqs, 180/pi*angle(squeeze(freqresp(G(6+i,i), freqs, 'Hz'))), 'color', [colors(2,:),0.5]);
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
ylabel('Phase [deg]'); xlabel('Frequency [Hz]');
ylim([-180, 180]);
yticks([-180, -90, 0, 90, 180]);
linkaxes([ax1,ax2],'x');
xlim([freqs(1), freqs(end)]);
#+end_src #+end_src
** Nano Hexapod #+name: fig:nhexa_comp_multi_body_analytical
#+caption: Comparison of the analytical transfer functions and the multi-body model
#+RESULTS:
[[file:figs/nhexa_comp_multi_body_analytical.png]]
** Nano Hexapod Dynamics
<<ssec:nhexa_model_dynamics>>
Now that the multi-body model is validated, it can be used to study the dynamics of the nano-hexapod.
The model is initialized as described in Section ref:ssec:nhexa_model_def with a $10\,kg$ payload, and the transfer functions from $\bm{f}$ to $\bm{f}_m$ and $\bm{d}_e$ are computed from the multi-body model.
- [X] What payload to use?
10kg payload
- [ ] Transfer function from f to de:
- [ ] All diagonal terms equal (thanks to symmetry and having the same struts)
- [ ] 4 observed modes (due to symmetry, in reality 6 modes)
- [ ] Decoupled at low frequency $G(j\omega) \xrightarrow[\omega \to 0]{} \mathcal{K}^{-1}$ (low frequency gain is K)
- [ ] High frequency gain is $G(j\omega) \xrightarrow[\omega \to \infty]{} J M^{-T} J^T \frac{-1}{\omega^2}$, which is in general not diagonal
- [ ] Transfer function from f to fm:
- [ ] Alternating poles and zeros
- [ ] Effect of parallel stiffness on IFF plant?
- [ ] Validation of compliance matrix?
#+begin_src matlab #+begin_src matlab
initializeSimplifiedNanoHexapod(); %% Multi-Body model of the Nano-Hexapod
initializeSample('type', 'cylindrical', 'm', 50); % Initialize 1DoF
initializeSimplifiedNanoHexapod('flex_type_F', '2dof', 'flex_type_M', '3dof', 'actuator_type', '1dof');
initializeSample('type', 'cylindrical', 'm', 10, 'H', 300e-3);
initializeLoggingConfiguration('log', 'none'); initializeLoggingConfiguration('log', 'none');
initializeController('type', 'open-loop'); initializeController('type', 'open-loop');
#+end_src
#+begin_src matlab
% Input/Output definition % Input/Output definition
clear io; io_i = 1; clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs [N] io(io_i) = linio([mdl, '/Controller'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs [N]
@ -1135,36 +1115,50 @@ G.OutputName = {'dL1', 'dL2', 'dL3', 'dL4', 'dL5', 'dL6', ...
'fn1', 'fn2', 'fn3', 'fn4', 'fn5', 'fn6'}; 'fn1', 'fn2', 'fn3', 'fn4', 'fn5', 'fn6'};
#+end_src #+end_src
#+begin_src matlab :exports none #+begin_src matlab
%% Diagonal elements of the FRF matrix from u to de %% Multi-Body model of the Nano-Hexapod without parallel stiffness
% Initialize 1DoF
initializeSimplifiedNanoHexapod('flex_type_F', '2dof', 'flex_type_M', '3dof', 'actuator_type', '1dof', 'actuator_kp', 0);
% With no payload
G_no_kp = linearize(mdl, io);
G_no_kp.InputName = {'f1', 'f2', 'f3', 'f4', 'f5', 'f6'};
G_no_kp.OutputName = {'dL1', 'dL2', 'dL3', 'dL4', 'dL5', 'dL6', ...
'fn1', 'fn2', 'fn3', 'fn4', 'fn5', 'fn6'};
#+end_src
#+begin_src matlab :exports none :results none
%% Transfer function from actuator force inputs to displacement of each strut
figure; figure;
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
ax1 = nexttile([2,1]); ax1 = nexttile([2,1]);
hold on; hold on;
plot(freqs, abs(squeeze(freqresp(G(1,1), freqs, 'Hz'))), 'color', colors(2,:), ...
'DisplayName', '$d_{ei}/u_i$ - Model')
for i = 2:6
plot(freqs, abs(squeeze(freqresp(G(i,i), freqs, 'Hz'))), 'color', colors(2,:), ...
'HandleVisibility', 'off');
end
for i = 1:5 for i = 1:5
for j = i+1:6 for j = i+1:6
plot(freqs, abs(squeeze(freqresp(G(i,j), freqs, 'Hz'))), 'color', [0, 0, 0, 0.2], ... plot(freqs, abs(squeeze(freqresp(G(i,j), freqs, 'Hz'))), 'color', [0, 0, 0, 0.2], ...
'HandleVisibility', 'off'); 'HandleVisibility', 'off');
end end
end end
plot(freqs, abs(squeeze(freqresp(G(1,1), freqs, 'Hz'))), 'color', colors(1,:), ...
'DisplayName', '$d_{ei}/f_i$')
for i = 2:6
plot(freqs, abs(squeeze(freqresp(G(i,i), freqs, 'Hz'))), 'color', colors(1,:), ...
'HandleVisibility', 'off');
end
plot(freqs, abs(squeeze(freqresp(G(1,2), freqs, 'Hz'))), 'color', [0, 0, 0, 0.2], ...
'DisplayName', '$d_{ei}/f_j$')
hold off; hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]); ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
ylim([1e-9, 1e-4]); ylim([1e-9, 1e-4]);
leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); leg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1);
leg.ItemTokenSize(1) = 15; leg.ItemTokenSize(1) = 15;
ax2 = nexttile; ax2 = nexttile;
hold on; hold on;
for i = 1:6 for i = 1:6
plot(freqs, 180/pi*angle(squeeze(freqresp(G(i,i), freqs, 'Hz'))), 'color', [colors(2,:),0.5]); plot(freqs, 180/pi*angle(squeeze(freqresp(G(i,i), freqs, 'Hz'))), 'color', [colors(1,:),0.5]);
end end
hold off; hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
@ -1176,36 +1170,47 @@ linkaxes([ax1,ax2],'x');
xlim([freqs(1), freqs(end)]); xlim([freqs(1), freqs(end)]);
#+end_src #+end_src
#+begin_src matlab :exports none #+begin_src matlab :tangle no :exports results :results file none
%% Diagonal elements of the FRF matrix from u to de exportFig('figs/nhexa_multi_body_plant_dL.pdf', 'width', 'half', 'height', 600);
#+end_src
#+begin_src matlab :exports none :results none
%% Transfer function from actuator force inputs to force sensor in each strut
figure; figure;
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
ax1 = nexttile([2,1]); ax1 = nexttile([2,1]);
hold on; hold on;
plot(freqs, abs(squeeze(freqresp(G(6+1,1), freqs, 'Hz'))), 'color', colors(2,:), ...
'DisplayName', '$d_{ei}/u_i$ - Model')
for i = 2:6
plot(freqs, abs(squeeze(freqresp(G(6+i,i), freqs, 'Hz'))), 'color', colors(2,:), ...
'HandleVisibility', 'off');
end
for i = 1:5 for i = 1:5
for j = i+1:6 for j = i+1:6
plot(freqs, abs(squeeze(freqresp(G(6+i,j), freqs, 'Hz'))), 'color', [0, 0, 0, 0.2], ... plot(freqs, abs(squeeze(freqresp(G(6+i,j), freqs, 'Hz'))), 'color', [0, 0, 0, 0.2], ...
'HandleVisibility', 'off'); 'HandleVisibility', 'off');
end end
end end
plot(freqs, abs(squeeze(freqresp(G(7,1), freqs, 'Hz'))), 'color', colors(1,:), ...
'DisplayName', '$f_{mi}/f_i$')
plot(freqs, abs(squeeze(freqresp(G_no_kp(7,1), freqs, 'Hz'))), 'color', colors(2,:), ...
'DisplayName', '$f_{mi}/f_i$ (no $k_p$)')
for i = 2:6
plot(freqs, abs(squeeze(freqresp(G(6+i,i), freqs, 'Hz'))), 'color', colors(1,:), ...
'HandleVisibility', 'off');
plot(freqs, abs(squeeze(freqresp(G_no_kp(6+i,i), freqs, 'Hz'))), 'color', colors(2,:), ...
'HandleVisibility', 'off');
end
plot(freqs, abs(squeeze(freqresp(G(7,2), freqs, 'Hz'))), 'color', [0, 0, 0, 0.2], ...
'DisplayName', '$f_{mi}/f_j$')
hold off; hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [N/N]'); set(gca, 'XTickLabel',[]); ylabel('Amplitude [N/N]'); set(gca, 'XTickLabel',[]);
ylim([1e-5, 1e2]); ylim([1e-4, 1e2]);
leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); leg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1);
leg.ItemTokenSize(1) = 15; leg.ItemTokenSize(1) = 15;
ax2 = nexttile; ax2 = nexttile;
hold on; hold on;
for i = 1:6 for i = 1:6
plot(freqs, 180/pi*angle(squeeze(freqresp(G(6+i,i), freqs, 'Hz'))), 'color', [colors(2,:),0.5]); plot(freqs, 180/pi*angle(squeeze(freqresp(G(6+i,i), freqs, 'Hz'))), 'color', colors(1,:));
plot(freqs, 180/pi*angle(squeeze(freqresp(G_no_kp(6+i,i), freqs, 'Hz'))), 'color', colors(2,:));
end end
hold off; hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
@ -1217,6 +1222,28 @@ linkaxes([ax1,ax2],'x');
xlim([freqs(1), freqs(end)]); xlim([freqs(1), freqs(end)]);
#+end_src #+end_src
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/nhexa_multi_body_plant_fm.pdf', 'width', 'half', 'height', 600);
#+end_src
#+name: fig:nhexa_multi_body_plant
#+caption: Bode plot of the transfer functions computed from the nano-hexapod multi-body model
#+attr_latex: :options [htbp]
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:nhexa_multi_body_plant_dL}$f_i$ to $d_{Li}$}
#+attr_latex: :options {0.48\textwidth}
#+begin_subfigure
#+attr_latex: :width \linewidth
[[file:figs/nhexa_multi_body_plant_dL.png]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:nhexa_multi_body_plant_fm}$f_i$ to $f_{mi}$}
#+attr_latex: :options {0.48\textwidth}
#+begin_subfigure
#+attr_latex: :width \linewidth
[[file:figs/nhexa_multi_body_plant_fm.png]]
#+end_subfigure
#+end_figure
** Conclusion ** Conclusion
:properties: :properties:
:unnumbered: t :unnumbered: t
@ -1244,6 +1271,8 @@ Different ways to try to decouple a MIMO plant.
Reference book: [[cite:&skogestad07_multiv_feedb_contr]] Reference book: [[cite:&skogestad07_multiv_feedb_contr]]
Control will be more detailed in chapter 2.
** Matlab Init :noexport:ignore: ** Matlab Init :noexport:ignore:
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
<<matlab-dir>> <<matlab-dir>>
@ -1575,7 +1604,7 @@ function [nano_hexapod] = initializeSimplifiedNanoHexapod(args)
%% Actuators %% Actuators
args.actuator_type char {mustBeMember(args.actuator_type,{'1dof', '2dof', 'flexible'})} = '1dof' args.actuator_type char {mustBeMember(args.actuator_type,{'1dof', '2dof', 'flexible'})} = '1dof'
args.actuator_k (1,1) double {mustBeNumeric, mustBePositive} = 1e6 args.actuator_k (1,1) double {mustBeNumeric, mustBePositive} = 1e6
args.actuator_kp (1,1) double {mustBeNumeric, mustBeNonnegative} = 5e4 args.actuator_kp (1,1) double {mustBeNumeric, mustBeNonnegative} = 1e4
args.actuator_ke (1,1) double {mustBeNumeric, mustBePositive} = 4952605 args.actuator_ke (1,1) double {mustBeNumeric, mustBePositive} = 4952605
args.actuator_ka (1,1) double {mustBeNumeric, mustBePositive} = 2476302 args.actuator_ka (1,1) double {mustBeNumeric, mustBePositive} = 2476302
args.actuator_c (1,1) double {mustBeNumeric, mustBePositive} = 50 args.actuator_c (1,1) double {mustBeNumeric, mustBePositive} = 50

Binary file not shown.

View File

@ -1,4 +1,4 @@
% Created 2025-02-10 Mon 17:32 % Created 2025-02-10 Mon 19:03
% Intended LaTeX compiler: pdflatex % Intended LaTeX compiler: pdflatex
\documentclass[a4paper, 10pt, DIV=12, parskip=full, bibliography=totoc]{scrreprt} \documentclass[a4paper, 10pt, DIV=12, parskip=full, bibliography=totoc]{scrreprt}
@ -386,7 +386,7 @@ The primary forces acting on the system are actuator forces \(\bm{\tau}\), elast
Combining these forces and using \eqref{eq:nhexa_forward_kinematics_approximate} yields the complete dynamic equation \eqref{eq:nhexa_dynamical_equations}. Combining these forces and using \eqref{eq:nhexa_forward_kinematics_approximate} yields the complete dynamic equation \eqref{eq:nhexa_dynamical_equations}.
\begin{equation}\label{eq:nhexa_dynamical_equations} \begin{equation}\label{eq:nhexa_dynamical_equations}
M s^2 \mathcal{X} = \mathcal{F} - J^T \mathcal{K} J \mathcal{X} - J^T \mathcal{C} J s \mathcal{X} \bm{M} s^2 \bm{\mathcal{X}} = \bm{\mathcal{F}} - \bm{J}^T \bm{\mathcal{K}} \bm{J} \bm{\mathcal{X}} - \bm{J}^T \bm{\mathcal{C}} \bm{J} s \bm{\mathcal{X}}
\end{equation} \end{equation}
The transfer function in the Cartesian frame becomes \eqref{eq:nhexa_transfer_function_cart}. The transfer function in the Cartesian frame becomes \eqref{eq:nhexa_transfer_function_cart}.
@ -432,6 +432,9 @@ While a reasonable geometric configuration will be used to validate the NASS dur
Complex because has to model the inertia of the struts. Complex because has to model the inertia of the struts.
Cite papers that tries to model the stewart platform analytically Cite papers that tries to model the stewart platform analytically
Advantage: it will be easily included in the model of the NASS Advantage: it will be easily included in the model of the NASS
\item Model definition (Section \ref{ssec:nhexa_model_def})
\item Validation of the model by comparing with analytical equations (Section \ref{ssec:nhexa_model_validation})
\item Dynamics of the nano-hexapod used for conceptual analysis: (Section \ref{ssec:nhexa_model_dynamics})
\end{itemize} \end{itemize}
\section{Model Definition} \section{Model Definition}
\label{ssec:nhexa_model_def} \label{ssec:nhexa_model_def}
@ -527,12 +530,11 @@ Thanks to the flexibility of the multi-body model, the model of the actuators ca
\end{scriptsize} \end{scriptsize}
\end{minipage} \end{minipage}
\section{Model Dynamics} \section{Validation of the multi-body model}
\label{ssec:nhexa_model_dynamics} \label{ssec:nhexa_model_validation}
\begin{itemize} The obtained multi-body model can schematically be represented as in Figure \ref{fig:nhexa_stewart_model_input_outputs} with actuator inputs \(\bm{f}\), force sensor outputs \(\bm{f}_m\) and relative displacement outputs \(\bm{d}_L\).
\item[{$\square$}] Screenshot of the obtained multi-body model ? The 3D representation of the Stewart platform using the multi-body model is shown in Figure \ref{fig:nhexa_simscape_screenshot}.
\end{itemize}
\begin{minipage}[b]{0.6\linewidth} \begin{minipage}[b]{0.6\linewidth}
\begin{center} \begin{center}
@ -548,16 +550,79 @@ Thanks to the flexibility of the multi-body model, the model of the actuators ca
\end{center} \end{center}
\end{minipage} \end{minipage}
To validate the multi-body model of the Stewart platform, the simplest Stewart platform configuration is used to compare the multi-body dynamics with the analytical transfer functions obtained in Section \ref{ssec:nhexa_stewart_platform_dynamics}.
The bottom joints are universal joints while the top joints are spherical joints. All joints mass-less and have zero stiffness in the free DoF.
The struts are modelled with a stiffness equal to \(k_a = 1\,N/\mu m\), damping \(c_a = 10\,N/(m/s)\), and are mass-less.
The geometry used is shown in Table \ref{tab:nhexa_actuator_parameters}.
The top platform is considered mass-less, but a payload with mass \(m = 10\,kg\) is added on top of the Stewart platform.
The payload is cylindrical with a radius of \(r = 110\,mm\) and a height \(h = 300\,mm\) such that its center of mass coincide with \(\{A\}\).
Stiffness, damping and mass matrices for the analytical equations are summarized in \eqref{eq:nhexa_analytical_matrices}.
The transfer functions from actuator forces to displacement of each strut can then be computed using \eqref{eq:nhexa_transfer_function_struts}.
\begin{subequations}\label{eq:nhexa_analytical_matrices}
\begin{align}
\bm{K} &= \text{diag}(k_a,\ k_a,\ k_a,\ k_a,\ k_a,\ k_a) \\
\bm{C} &= \text{diag}(c_a,\ c_a,\ c_a,\ c_a,\ c_a,\ c_a) \\
\bm{M} &= \text{diag}\left(m,\ m,\ m,\ \frac{1}{12}m(3r^2 + h^2),\ \frac{1}{12}m(3r^2 + h^2),\ \frac{1}{2}mr^2\right)
\end{align}
\end{subequations}
The same transfer functions are extracted from the multi-body model.
The obtained state-space model has 12 states which corresponds to the 6-DoF of the top platform.
The transfer functions from the first actuator to the displacement of the 6 struts are compared in Figure \ref{fig:nhexa_comp_multi_body_analytical}.
A good match can be observed between the analytical formulas and the multi-body model therefore validating the multi-body model.
\begin{figure}[htbp]
\centering
\includegraphics[scale=1]{figs/nhexa_comp_multi_body_analytical.png}
\caption{\label{fig:nhexa_comp_multi_body_analytical}Comparison of the analytical transfer functions and the multi-body model}
\end{figure}
\section{Nano Hexapod Dynamics}
\label{ssec:nhexa_model_dynamics}
Now that the multi-body model is validated, it can be used to study the dynamics of the nano-hexapod.
The model is initialized as described in Section \ref{ssec:nhexa_model_def} with a \(10\,kg\) payload, and the transfer functions from \(\bm{f}\) to \(\bm{f}_m\) and \(\bm{d}_e\) are computed from the multi-body model.
\begin{itemize} \begin{itemize}
\item If all is perfect (mass-less struts, perfect joints, etc\ldots{}), maybe compare analytical model with simscape model? \item[{$\boxtimes$}] What payload to use?
\item Say something about the model order 10kg payload
Model order is 12, and that we can compute modes from matrices M and K, compare with the Simscape model \item[{$\square$}] Transfer function from f to de:
\item 4 observed modes (due to symmetry, in reality 6 modes) \begin{itemize}
\item Compare with analytical formulas (see number of states) \item[{$\square$}] All diagonal terms equal (thanks to symmetry and having the same struts)
\item[{$\square$}] Effect of parallel on IFF plant? \item[{$\square$}] 4 observed modes (due to symmetry, in reality 6 modes)
\item[{$\square$}] Decoupled at low frequency \(G(j\omega) \xrightarrow[\omega \to 0]{} \mathcal{K}^{-1}\) (low frequency gain is K)
\item[{$\square$}] High frequency gain is \(G(j\omega) \xrightarrow[\omega \to \infty]{} J M^{-T} J^T \frac{-1}{\omega^2}\), which is in general not diagonal
\end{itemize}
\item[{$\square$}] Transfer function from f to fm:
\begin{itemize}
\item[{$\square$}] Alternating poles and zeros
\item[{$\square$}] Effect of parallel stiffness on IFF plant?
\end{itemize}
\item[{$\square$}] Validation of compliance matrix?
\end{itemize} \end{itemize}
\section{Nano Hexapod} \begin{figure}[htbp]
\begin{subfigure}{0.48\textwidth}
\begin{center}
\includegraphics[scale=1,width=\linewidth]{figs/nhexa_multi_body_plant_dL.png}
\end{center}
\subcaption{\label{fig:nhexa_multi_body_plant_dL}$f_i$ to $d_{Li}$}
\end{subfigure}
\begin{subfigure}{0.48\textwidth}
\begin{center}
\includegraphics[scale=1,width=\linewidth]{figs/nhexa_multi_body_plant_fm.png}
\end{center}
\subcaption{\label{fig:nhexa_multi_body_plant_fm}$f_i$ to $f_{mi}$}
\end{subfigure}
\caption{\label{fig:nhexa_multi_body_plant}Bode plot of the transfer functions computed from the nano-hexapod multi-body model}
\end{figure}
\section*{Conclusion} \section*{Conclusion}
\begin{itemize} \begin{itemize}
@ -580,6 +645,8 @@ Important to have tools to study interaction
Different ways to try to decouple a MIMO plant. Different ways to try to decouple a MIMO plant.
Reference book: \cite{skogestad07_multiv_feedb_contr} Reference book: \cite{skogestad07_multiv_feedb_contr}
Control will be more detailed in chapter 2.
\section{Centralized and Decentralized Control} \section{Centralized and Decentralized Control}
\label{ssec:nhexa_control_centralized_decentralized} \label{ssec:nhexa_control_centralized_decentralized}