2020-02-28 17:35:44 +01:00
#+TITLE : Stewart Platform - Vibration Isolation
2020-01-20 16:29:48 +01:00
:DRAWER:
2020-02-11 15:50:52 +01:00
#+STARTUP : overview
#+LANGUAGE : en
#+EMAIL : dehaeze.thomas@gmail.com
#+AUTHOR : Dehaeze Thomas
2020-01-20 16:29:48 +01:00
#+HTML_LINK_HOME : ./index.html
#+HTML_LINK_UP : ./index.html
2021-01-08 15:34:53 +01:00
#+HTML_HEAD : <link rel="stylesheet" type="text/css" href="https://research.tdehaeze.xyz/css/style.css"/>
#+HTML_HEAD : <script type="text/javascript" src="https://research.tdehaeze.xyz/js/script.js"></script>
2020-01-20 16:29:48 +01:00
#+PROPERTY : header-args:matlab :session *MATLAB*
#+PROPERTY : header-args:matlab+ :comments org
#+PROPERTY : header-args:matlab+ :exports both
#+PROPERTY : header-args:matlab+ :results none
#+PROPERTY : header-args:matlab+ :eval no-export
#+PROPERTY : header-args:matlab+ :noweb yes
#+PROPERTY : header-args:matlab+ :mkdirp yes
#+PROPERTY : header-args:matlab+ :output-dir figs
2020-08-05 13:26:06 +02:00
#+PROPERTY : header-args:latex :headers '("\\usepackage{tikz}" "\\usepackage{import}" "\\import{$HOME/Cloud/tikz/org/}{config.tex}")
2020-01-20 16:29:48 +01:00
#+PROPERTY : header-args:latex+ :imagemagick t :fit yes
#+PROPERTY : header-args:latex+ :iminoptions -scale 100% -density 150
#+PROPERTY : header-args:latex+ :imoutoptions -quality 100
#+PROPERTY : header-args:latex+ :results file raw replace
#+PROPERTY : header-args:latex+ :buffer no
#+PROPERTY : header-args:latex+ :eval no-export
2020-02-11 15:50:52 +01:00
#+PROPERTY : header-args:latex+ :exports results
2020-01-20 16:29:48 +01:00
#+PROPERTY : header-args:latex+ :mkdirp yes
#+PROPERTY : header-args:latex+ :output-dir figs
#+PROPERTY : header-args:latex+ :post pdf2svg(file=*this*, ext="png")
:END:
2020-03-11 18:58:56 +01:00
* Introduction :ignore:
2020-02-28 17:35:44 +01:00
* HAC-LAC (Cascade) Control - Integral Control
** Introduction
In this section, we wish to study the use of the High Authority Control - Low Authority Control (HAC-LAC) architecture on the Stewart platform.
The control architectures are shown in Figures [[fig:control_arch_hac_iff ]] and [[fig:control_arch_hac_dvf ]].
First, the LAC loop is closed (the LAC control is described [[file:active-damping.org ][here ]]), and then the HAC controller is designed and the outer loop is closed.
#+begin_src latex :file control_arch_hac_iff.pdf
2021-01-08 15:54:58 +01:00
\begin{tikzpicture}
% Blocs
\node[block={2.0cm}{2.0cm}] (P) {};
\node[above] at (P.north) {Plant};
\node[block, below=0.7 of P] (Kiff) {$\bm{K}_\text{IFF}$};
\node[block, below=0.7 of Kiff] (Khac) {$\bm{K}_\text{HAC}$};
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
% Add
\node[addb, left=1 of P] (add) {};
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
\node[block, left=1 of add] (J) {$\bm{J}^{-T}$};
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
% Input and outputs coordinates
\coordinate[] (outputhac) at ($(P.south east)!0.75!(P.north east)$);
\coordinate[] (outputiff) at ($(P.south east)!0.25!(P.north east)$);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
\draw[->] (outputiff) node[above right]{$\bm{\tau}_m$} -- ++(0.8, 0) |- (Kiff.east);
\draw[->] (outputhac) node[above right]{$\bm{\mathcal{X}}$} -- ++(1.6, 0) |- (Khac.east);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
\draw[->] (Kiff.west) -| (add.south);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
\draw[->] (J.east) -- (add.west);
\draw[<-] (J.west) node[above left]{$\bm{\mathcal{F}}$} -- ++(-0.8, 0) |- (Khac.west);
\draw[->] (add.east) -- (P.west) node[above left]{$\bm{\tau}$};
\end{tikzpicture}
2020-02-28 17:35:44 +01:00
#+end_src
#+name : fig:control_arch_hac_iff
#+caption : HAC-LAC architecture with IFF
#+RESULTS :
[[file:figs/control_arch_hac_iff.png ]]
#+begin_src latex :file control_arch_hac_dvf.pdf
2021-01-08 15:54:58 +01:00
\begin{tikzpicture}
% Blocs
\node[block={2.0cm}{2.0cm}] (P) {};
\node[above] at (P.north) {Plant};
\node[block, below=0.7 of P] (Kdvf) {$\bm{K}_\text{DVF}$};
\node[block, below=0.7 of Kdvf] (Khac) {$\bm{K}_\text{HAC}$};
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
% Add
\node[addb, left=1 of P] (add) {};
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
\node[block, left=1 of add] (J) {$\bm{J}^{-T}$};
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
% Input and outputs coordinates
\coordinate[] (outputhac) at ($(P.south east)!0.75!(P.north east)$);
\coordinate[] (outputdvf) at ($(P.south east)!0.25!(P.north east)$);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
\draw[->] (outputdvf) node[above right]{$\delta \bm{\mathcal{L}}_m$} -- ++(0.8, 0) |- (Kdvf.east);
\draw[->] (outputhac) node[above right]{$\bm{\mathcal{X}}$} -- ++(1.6, 0) |- (Khac.east);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
\draw[->] (Kdvf.west) -| (add.south);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
\draw[->] (J.east) -- (add.west);
\draw[<-] (J.west) node[above left]{$\bm{\mathcal{F}}$} -- ++(-0.8, 0) |- (Khac.west);
\draw[->] (add.east) -- (P.west) node[above left]{$\bm{\tau}$};
\end{tikzpicture}
2020-02-28 17:35:44 +01:00
#+end_src
#+name : fig:control_arch_hac_dvf
#+caption : HAC-LAC architecture with DVF
#+RESULTS :
[[file:figs/control_arch_hac_dvf.png ]]
2020-01-20 16:29:48 +01:00
** Matlab Init :noexport:
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
2021-01-08 15:54:58 +01:00
<<matlab-dir >>
2020-01-20 16:29:48 +01:00
#+end_src
#+begin_src matlab :exports none :results silent :noweb yes
2021-01-08 15:54:58 +01:00
<<matlab-init >>
2020-01-20 16:29:48 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
simulinkproject('../');
2020-01-20 16:29:48 +01:00
#+end_src
2020-02-28 17:35:44 +01:00
#+begin_src matlab
2021-01-08 15:54:58 +01:00
open('stewart_platform_model.slx')
2020-01-20 16:29:48 +01:00
#+end_src
2020-02-28 17:35:44 +01:00
** Initialization
We first initialize the Stewart platform.
2020-01-20 16:29:48 +01:00
#+begin_src matlab
2021-01-08 15:54:58 +01:00
stewart = initializeStewartPlatform();
stewart = initializeFramesPositions(stewart, 'H', 90e-3, 'MO_B', 45e-3);
stewart = generateGeneralConfiguration(stewart);
stewart = computeJointsPose(stewart);
stewart = initializeStrutDynamics(stewart);
stewart = initializeJointDynamics(stewart, 'type_F', 'universal', 'type_M', 'spherical');
stewart = initializeCylindricalPlatforms(stewart);
stewart = initializeCylindricalStruts(stewart);
stewart = computeJacobian(stewart);
stewart = initializeStewartPose(stewart);
stewart = initializeInertialSensor(stewart, 'type', 'none');
2020-02-13 14:51:49 +01:00
#+end_src
2020-02-28 17:35:44 +01:00
The rotation point of the ground is located at the origin of frame $\{A\}$.
2020-02-13 14:51:49 +01:00
#+begin_src matlab
2021-01-08 15:54:58 +01:00
ground = initializeGround('type', 'rigid', 'rot_point', stewart.platform_F.FO_A);
payload = initializePayload('type', 'none');
2020-01-22 13:26:58 +01:00
#+end_src
2020-02-28 17:35:44 +01:00
** Identification
*** Introduction :ignore:
We identify the transfer function from the actuator forces $\bm{\tau}$ to the absolute displacement of the mobile platform $\bm{\mathcal{X}}$ in three different cases:
- Open Loop plant
- Already damped plant using Integral Force Feedback
- Already damped plant using Direct velocity feedback
*** HAC - Without LAC
2020-01-20 16:29:48 +01:00
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'open-loop');
2020-02-28 17:35:44 +01:00
#+end_src
2020-01-20 16:29:48 +01:00
2020-02-28 17:35:44 +01:00
#+begin_src matlab
2021-01-08 15:54:58 +01:00
%% Name of the Simulink File
mdl = 'stewart_platform_model';
2020-01-20 16:29:48 +01:00
2021-01-08 15:54:58 +01:00
%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'input'); io_i = io_i + 1; % Actuator Force Inputs [N]
io(io_i) = linio([mdl, '/Absolute Motion Sensor'], 1, 'openoutput'); io_i = io_i + 1; % Absolute Sensor [m, rad]
2020-01-20 16:29:48 +01:00
2021-01-08 15:54:58 +01:00
%% Run the linearization
G_ol = linearize(mdl, io);
G_ol.InputName = {'F1', 'F2', 'F3', 'F4', 'F5', 'F6'};
G_ol.OutputName = {'Dx', 'Dy', 'Dz', 'Rx', 'Ry', 'Rz'};
2020-01-20 16:29:48 +01:00
#+end_src
2020-02-28 17:35:44 +01:00
*** HAC - IFF
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'iff');
K_iff = -(1e4/s)*eye(6);
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
%% Name of the Simulink File
mdl = 'stewart_platform_model';
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'input'); io_i = io_i + 1; % Actuator Force Inputs [N]
io(io_i) = linio([mdl, '/Absolute Motion Sensor'], 1, 'openoutput'); io_i = io_i + 1; % Absolute Sensor [m, rad]
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
%% Run the linearization
G_iff = linearize(mdl, io);
G_iff.InputName = {'F1', 'F2', 'F3', 'F4', 'F5', 'F6'};
G_iff.OutputName = {'Dx', 'Dy', 'Dz', 'Rx', 'Ry', 'Rz'};
2020-02-28 17:35:44 +01:00
#+end_src
*** HAC - DVF
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'dvf');
K_dvf = -1e4*s/(1+s/2/pi/5000)*eye(6);
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
%% Name of the Simulink File
mdl = 'stewart_platform_model';
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'input'); io_i = io_i + 1; % Actuator Force Inputs [N]
io(io_i) = linio([mdl, '/Absolute Motion Sensor'], 1, 'openoutput'); io_i = io_i + 1; % Absolute Sensor [m, rad]
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
%% Run the linearization
G_dvf = linearize(mdl, io);
G_dvf.InputName = {'F1', 'F2', 'F3', 'F4', 'F5', 'F6'};
G_dvf.OutputName = {'Dx', 'Dy', 'Dz', 'Rx', 'Ry', 'Rz'};
2020-02-28 17:35:44 +01:00
#+end_src
** Control Architecture
We use the Jacobian to express the actuator forces in the cartesian frame, and thus we obtain the transfer functions from $\bm{\mathcal{F}}$ to $\bm{\mathcal{X}}$.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
Gc_ol = minreal(G_ol)/stewart.kinematics.J';
Gc_ol.InputName = {'Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz'};
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
Gc_iff = minreal(G_iff)/stewart.kinematics.J';
Gc_iff.InputName = {'Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz'};
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
Gc_dvf = minreal(G_dvf)/stewart.kinematics.J';
Gc_dvf.InputName = {'Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz'};
2020-02-28 17:35:44 +01:00
#+end_src
We then design a controller based on the transfer functions from $\bm{\mathcal{F}}$ to $\bm{\mathcal{X}}$, finally, we will pre-multiply the controller by $\bm{J}^{-T}$.
** 6x6 Plant Comparison
#+begin_src matlab :exports none
2021-01-08 15:54:58 +01:00
p_handle = zeros(6*6,1);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
fig = figure;
for ix = 1:6
2020-02-28 17:35:44 +01:00
for iy = 1:6
2021-01-08 15:54:58 +01:00
p_handle((ix-1)*6 + iy) = subplot(6, 6, (ix-1)*6 + iy);
hold on;
set(gca,'ColorOrderIndex',1);
plot(freqs, abs(squeeze(freqresp(Gc_ol(ix, iy), freqs, 'Hz'))));
set(gca,'ColorOrderIndex',2);
plot(freqs, abs(squeeze(freqresp(Gc_iff(ix, iy), freqs, 'Hz'))));
set(gca,'ColorOrderIndex',3);
plot(freqs, abs(squeeze(freqresp(Gc_dvf(ix, iy), freqs, 'Hz'))));
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
if ix < 6
xticklabels({});
end
if iy > 1
yticklabels({});
end
2020-02-28 17:35:44 +01:00
end
2021-01-08 15:54:58 +01:00
end
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
linkaxes(p_handle, 'xy')
xlim([freqs(1), freqs(end)]);
ylim([1e-9 1e-3]);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
han = axes(fig, 'visible', 'off');
han.XLabel.Visible = 'on';
han.YLabel.Visible = 'on';
xlabel(han, 'Frequency [Hz]');
ylabel(han, 'Plant');
2020-02-28 17:35:44 +01:00
#+end_src
#+header : :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/hac_lac_coupling_jacobian.pdf" :var figsize= "full-tall" :post pdf2svg(file=*this*, ext= "png")
<<plt-matlab >>
#+end_src
#+name : fig:hac_lac_coupling_jacobian
#+caption : Norm of the transfer functions from $\bm{\mathcal{F}}$ to $\bm{\mathcal{X}}$ ([[./figs/hac_lac_coupling_jacobian.png][png]], [[./figs/hac_lac_coupling_jacobian.pdf][pdf]])
[[file:figs/hac_lac_coupling_jacobian.png ]]
** HAC - DVF
*** Plant
2020-01-20 16:29:48 +01:00
#+begin_src matlab :exports none
2021-01-08 15:54:58 +01:00
freqs = logspace(1, 4, 1000);
figure;
ax1 = subplot(2, 1, 1);
hold on;
plot(freqs, abs(squeeze(freqresp(Gc_dvf('Dx', 'Fx'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc_dvf('Dy', 'Fy'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc_dvf('Dz', 'Fz'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc_dvf('Rx', 'Mx'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc_dvf('Ry', 'My'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc_dvf('Rz', 'Mz'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
ax2 = subplot(2, 1, 2);
hold on;
plot(freqs, 180/pi*angle(squeeze(freqresp(Gc_dvf('Dx', 'Fx'), freqs, 'Hz'))), 'DisplayName', 'Dx/Fx');
plot(freqs, 180/pi*angle(squeeze(freqresp(Gc_dvf('Dy', 'Fy'), freqs, 'Hz'))), 'DisplayName', 'Dy/Fy');
plot(freqs, 180/pi*angle(squeeze(freqresp(Gc_dvf('Dz', 'Fz'), freqs, 'Hz'))), 'DisplayName', 'Dz/Fz');
plot(freqs, 180/pi*angle(squeeze(freqresp(Gc_dvf('Rx', 'Mx'), freqs, 'Hz'))), 'DisplayName', 'Rx/Mx');
plot(freqs, 180/pi*angle(squeeze(freqresp(Gc_dvf('Ry', 'My'), freqs, 'Hz'))), 'DisplayName', 'Ry/My');
plot(freqs, 180/pi*angle(squeeze(freqresp(Gc_dvf('Rz', 'Mz'), freqs, 'Hz'))), 'DisplayName', 'Rz/Mz');
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');
legend('location', 'northeast');
2020-02-28 17:35:44 +01:00
#+end_src
#+header : :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/hac_lac_plant_dvf.pdf" :var figsize= "full-tall" :post pdf2svg(file=*this*, ext= "png")
<<plt-matlab >>
#+end_src
#+name : fig:hac_lac_plant_dvf
#+caption : Diagonal elements of the plant for HAC control when DVF is previously applied ([[./figs/hac_lac_plant_dvf.png][png]], [[./figs/hac_lac_plant_dvf.pdf][pdf]])
[[file:figs/hac_lac_plant_dvf.png ]]
*** Controller Design
We design a diagonal controller with equal bandwidth for the 6 terms.
The controller is a pure integrator with a small lead near the crossover.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
wc = 2*pi*300; % Wanted Bandwidth [rad/s]
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
h = 1.2;
H_lead = 1/h*(1 + s/ (wc/h))/(1 + s/ (wc*h));
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
Kd_dvf = diag(1./abs(diag(freqresp(1/s*Gc_dvf, wc)))) .* H_lead .* 1/s;
2020-01-20 16:29:48 +01:00
#+end_src
#+begin_src matlab :exports none
2021-01-08 15:54:58 +01:00
freqs = logspace(1, 4, 1000);
figure;
ax1 = subplot(2, 1, 1);
hold on;
plot(freqs, abs(squeeze(freqresp(Kd_dvf(1,1)*Gc_dvf('Dx', 'Fx'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Kd_dvf(2,2)*Gc_dvf('Dy', 'Fy'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Kd_dvf(3,3)*Gc_dvf('Dz', 'Fz'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Kd_dvf(4,4)*Gc_dvf('Rx', 'Mx'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Kd_dvf(5,5)*Gc_dvf('Ry', 'My'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Kd_dvf(6,6)*Gc_dvf('Rz', 'Mz'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Loop Gain'); set(gca, 'XTickLabel',[]);
ax2 = subplot(2, 1, 2);
hold on;
plot(freqs, 180/pi*angle(squeeze(freqresp(Kd_dvf(1,1)*Gc_dvf('Dx', 'Fx'), freqs, 'Hz'))), 'DisplayName', 'Dx/Fx');
plot(freqs, 180/pi*angle(squeeze(freqresp(Kd_dvf(2,2)*Gc_dvf('Dy', 'Fy'), freqs, 'Hz'))), 'DisplayName', 'Dy/Fy');
plot(freqs, 180/pi*angle(squeeze(freqresp(Kd_dvf(3,3)*Gc_dvf('Dz', 'Fz'), freqs, 'Hz'))), 'DisplayName', 'Dz/Fz');
plot(freqs, 180/pi*angle(squeeze(freqresp(Kd_dvf(4,4)*Gc_dvf('Rx', 'Mx'), freqs, 'Hz'))), 'DisplayName', 'Rx/Mx');
plot(freqs, 180/pi*angle(squeeze(freqresp(Kd_dvf(5,5)*Gc_dvf('Ry', 'My'), freqs, 'Hz'))), 'DisplayName', 'Ry/My');
plot(freqs, 180/pi*angle(squeeze(freqresp(Kd_dvf(6,6)*Gc_dvf('Rz', 'Mz'), freqs, 'Hz'))), 'DisplayName', 'Rz/Mz');
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');
legend('location', 'northeast');
2020-02-28 17:35:44 +01:00
#+end_src
#+header : :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/hac_lac_loop_gain_dvf.pdf" :var figsize= "full-tall" :post pdf2svg(file=*this*, ext= "png")
<<plt-matlab >>
2020-01-20 16:29:48 +01:00
#+end_src
2020-02-28 17:35:44 +01:00
#+name : fig:hac_lac_loop_gain_dvf
#+caption : Diagonal elements of the Loop Gain for the HAC control ([[./figs/hac_lac_loop_gain_dvf.png][png]], [[./figs/hac_lac_loop_gain_dvf.pdf][pdf]])
[[file:figs/hac_lac_loop_gain_dvf.png ]]
2020-01-20 16:29:48 +01:00
2020-02-28 17:35:44 +01:00
Finally, we pre-multiply the diagonal controller by $\bm{J}^{-T}$ prior implementation.
2020-01-20 16:29:48 +01:00
#+begin_src matlab
2021-01-08 15:54:58 +01:00
K_hac_dvf = inv(stewart.kinematics.J')*Kd_dvf;
2020-02-28 17:35:44 +01:00
#+end_src
2020-01-20 16:29:48 +01:00
2020-02-28 17:35:44 +01:00
*** Obtained Performance
We identify the transmissibility and compliance of the system.
2020-01-20 16:29:48 +01:00
2020-02-28 17:35:44 +01:00
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'open-loop');
[T_ol, T_norm_ol, freqs] = computeTransmissibility();
[C_ol, C_norm_ol, ~] = computeCompliance();
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'dvf');
[T_dvf, T_norm_dvf, ~] = computeTransmissibility();
[C_dvf, C_norm_dvf, ~] = computeCompliance();
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'hac-dvf');
[T_hac_dvf, T_norm_hac_dvf, ~] = computeTransmissibility();
[C_hac_dvf, C_norm_hac_dvf, ~] = computeCompliance();
2020-01-20 16:29:48 +01:00
#+end_src
#+begin_src matlab :exports none
2021-01-08 15:54:58 +01:00
figure;
subplot(1,2,1);
hold on;
plot(freqs, T_norm_ol)
plot(freqs, T_norm_dvf)
plot(freqs, T_norm_hac_dvf)
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('Transmissibility - Frobenius Norm');
subplot(1,2,2);
hold on;
plot(freqs, C_norm_ol, 'DisplayName', 'OL')
plot(freqs, C_norm_dvf, 'DisplayName', 'DVF')
plot(freqs, C_norm_hac_dvf, 'DisplayName', 'HAC-DVF')
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('Compliance - Frobenius Norm');
legend();
2020-02-28 17:35:44 +01:00
#+end_src
#+header : :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/hac_lac_C_T_dvf.pdf" :var figsize= "full-tall" :post pdf2svg(file=*this*, ext= "png")
<<plt-matlab >>
#+end_src
#+name : fig:hac_lac_C_T_dvf
#+caption : Obtained Compliance and Transmissibility ([[./figs/hac_lac_C_T_dvf.png][png]], [[./figs/hac_lac_C_T_dvf.pdf][pdf]])
[[file:figs/hac_lac_C_T_dvf.png ]]
** HAC - IFF
*** Plant
#+begin_src matlab :exports none
2021-01-08 15:54:58 +01:00
freqs = logspace(1, 4, 1000);
figure;
ax1 = subplot(2, 1, 1);
hold on;
plot(freqs, abs(squeeze(freqresp(Gc_iff('Dx', 'Fx'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc_iff('Dy', 'Fy'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc_iff('Dz', 'Fz'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc_iff('Rx', 'Mx'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc_iff('Ry', 'My'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc_iff('Rz', 'Mz'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
ax2 = subplot(2, 1, 2);
hold on;
plot(freqs, 180/pi*angle(squeeze(freqresp(Gc_iff('Dx', 'Fx'), freqs, 'Hz'))), 'DisplayName', 'Dx/Fx');
plot(freqs, 180/pi*angle(squeeze(freqresp(Gc_iff('Dy', 'Fy'), freqs, 'Hz'))), 'DisplayName', 'Dy/Fy');
plot(freqs, 180/pi*angle(squeeze(freqresp(Gc_iff('Dz', 'Fz'), freqs, 'Hz'))), 'DisplayName', 'Dz/Fz');
plot(freqs, 180/pi*angle(squeeze(freqresp(Gc_iff('Rx', 'Mx'), freqs, 'Hz'))), 'DisplayName', 'Rx/Mx');
plot(freqs, 180/pi*angle(squeeze(freqresp(Gc_iff('Ry', 'My'), freqs, 'Hz'))), 'DisplayName', 'Ry/My');
plot(freqs, 180/pi*angle(squeeze(freqresp(Gc_iff('Rz', 'Mz'), freqs, 'Hz'))), 'DisplayName', 'Rz/Mz');
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');
legend('location', 'northeast');
2020-02-28 17:35:44 +01:00
#+end_src
#+header : :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/hac_lac_plant_iff.pdf" :var figsize= "full-tall" :post pdf2svg(file=*this*, ext= "png")
<<plt-matlab >>
#+end_src
#+name : fig:hac_lac_plant_iff
#+caption : Diagonal elements of the plant for HAC control when IFF is previously applied ([[./figs/hac_lac_plant_iff.png][png]], [[./figs/hac_lac_plant_iff.pdf][pdf]])
[[file:figs/hac_lac_plant_iff.png ]]
*** Controller Design
We design a diagonal controller with equal bandwidth for the 6 terms.
The controller is a pure integrator with a small lead near the crossover.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
wc = 2*pi*300; % Wanted Bandwidth [rad/s]
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
h = 1.2;
H_lead = 1/h*(1 + s/ (wc/h))/ (1 + s/(wc*h));
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
Kd_iff = diag(1./abs(diag(freqresp(1/s*Gc_iff, wc)))) .* H_lead .* 1/s;
2020-01-20 16:29:48 +01:00
#+end_src
#+begin_src matlab :exports none
2021-01-08 15:54:58 +01:00
freqs = logspace(1, 4, 1000);
figure;
ax1 = subplot(2, 1, 1);
hold on;
plot(freqs, abs(squeeze(freqresp(Kd_iff(1,1)*Gc_iff('Dx', 'Fx'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Kd_iff(2,2)*Gc_iff('Dy', 'Fy'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Kd_iff(3,3)*Gc_iff('Dz', 'Fz'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Kd_iff(4,4)*Gc_iff('Rx', 'Mx'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Kd_iff(5,5)*Gc_iff('Ry', 'My'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Kd_iff(6,6)*Gc_iff('Rz', 'Mz'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Loop Gain'); set(gca, 'XTickLabel',[]);
ax2 = subplot(2, 1, 2);
hold on;
plot(freqs, 180/pi*angle(squeeze(freqresp(Kd_iff(1,1)*Gc_iff('Dx', 'Fx'), freqs, 'Hz'))), 'DisplayName', 'Dx/Fx');
plot(freqs, 180/pi*angle(squeeze(freqresp(Kd_iff(2,2)*Gc_iff('Dy', 'Fy'), freqs, 'Hz'))), 'DisplayName', 'Dy/Fy');
plot(freqs, 180/pi*angle(squeeze(freqresp(Kd_iff(3,3)*Gc_iff('Dz', 'Fz'), freqs, 'Hz'))), 'DisplayName', 'Dz/Fz');
plot(freqs, 180/pi*angle(squeeze(freqresp(Kd_iff(4,4)*Gc_iff('Rx', 'Mx'), freqs, 'Hz'))), 'DisplayName', 'Rx/Mx');
plot(freqs, 180/pi*angle(squeeze(freqresp(Kd_iff(5,5)*Gc_iff('Ry', 'My'), freqs, 'Hz'))), 'DisplayName', 'Ry/My');
plot(freqs, 180/pi*angle(squeeze(freqresp(Kd_iff(6,6)*Gc_iff('Rz', 'Mz'), freqs, 'Hz'))), 'DisplayName', 'Rz/Mz');
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');
legend('location', 'northeast');
2020-02-28 17:35:44 +01:00
#+end_src
#+header : :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/hac_lac_loop_gain_iff.pdf" :var figsize= "full-tall" :post pdf2svg(file=*this*, ext= "png")
<<plt-matlab >>
#+end_src
#+name : fig:hac_lac_loop_gain_iff
#+caption : Diagonal elements of the Loop Gain for the HAC control ([[./figs/hac_lac_loop_gain_iff.png][png]], [[./figs/hac_lac_loop_gain_iff.pdf][pdf]])
[[file:figs/hac_lac_loop_gain_iff.png ]]
Finally, we pre-multiply the diagonal controller by $\bm{J}^{-T}$ prior implementation.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
K_hac_iff = inv(stewart.kinematics.J')*Kd_iff;
2020-02-28 17:35:44 +01:00
#+end_src
*** Obtained Performance
We identify the transmissibility and compliance of the system.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'open-loop');
[T_ol, T_norm_ol, freqs] = computeTransmissibility();
[C_ol, C_norm_ol, ~] = computeCompliance();
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'iff');
[T_iff, T_norm_iff, ~] = computeTransmissibility();
[C_iff, C_norm_iff, ~] = computeCompliance();
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'hac-iff');
[T_hac_iff, T_norm_hac_iff, ~] = computeTransmissibility();
[C_hac_iff, C_norm_hac_iff, ~] = computeCompliance();
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab :exports none
2021-01-08 15:54:58 +01:00
figure;
subplot(1,2,1);
hold on;
plot(freqs, T_norm_ol)
plot(freqs, T_norm_iff)
plot(freqs, T_norm_hac_iff)
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('Transmissibility - Frobenius Norm');
subplot(1,2,2);
hold on;
plot(freqs, C_norm_ol, 'DisplayName', 'OL')
plot(freqs, C_norm_iff, 'DisplayName', 'IFF')
plot(freqs, C_norm_hac_iff, 'DisplayName', 'HAC-IFF')
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('Compliance - Frobenius Norm');
legend();
2020-02-28 17:35:44 +01:00
#+end_src
#+header : :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/hac_lac_C_T_iff.pdf" :var figsize= "full-tall" :post pdf2svg(file=*this*, ext= "png")
<<plt-matlab >>
#+end_src
#+name : fig:hac_lac_C_T_iff
#+caption : Obtained Compliance and Transmissibility ([[./figs/hac_lac_C_T_iff.png][png]], [[./figs/hac_lac_C_T_iff.pdf][pdf]])
[[file:figs/hac_lac_C_T_iff.png ]]
** Comparison
#+begin_src matlab :exports none
2021-01-08 15:54:58 +01:00
p_handle = zeros(6*6,1);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
fig = figure;
for ix = 1:6
2020-02-28 17:35:44 +01:00
for iy = 1:6
2021-01-08 15:54:58 +01:00
p_handle((ix-1)*6 + iy) = subplot(6, 6, (ix-1)*6 + iy);
hold on;
set(gca,'ColorOrderIndex',1);
plot(freqs, abs(squeeze(freqresp(C_ol(ix, iy), freqs, 'Hz'))));
set(gca,'ColorOrderIndex',2);
plot(freqs, abs(squeeze(freqresp(C_hac_dvf(ix, iy), freqs, 'Hz'))));
set(gca,'ColorOrderIndex',3);
plot(freqs, abs(squeeze(freqresp(C_hac_iff(ix, iy), freqs, 'Hz'))));
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
if ix < 6
xticklabels({});
end
if iy > 1
yticklabels({});
end
2020-02-28 17:35:44 +01:00
end
2021-01-08 15:54:58 +01:00
end
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
linkaxes(p_handle, 'xy')
ylim([1e-10, 1e-3]);
xlim([freqs(1), freqs(end)]);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
han = axes(fig, 'visible', 'off');
han.XLabel.Visible = 'on';
han.YLabel.Visible = 'on';
xlabel(han, 'Frequency [Hz]');
ylabel(han, 'Compliance');
2020-02-28 17:35:44 +01:00
#+end_src
#+header : :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/hac_lac_C_full_comparison.pdf" :var figsize= "full-tall" :post pdf2svg(file=*this*, ext= "png")
<<plt-matlab >>
#+end_src
#+name : fig:hac_lac_C_full_comparison
#+caption : Comparison of the norm of the Compliance matrices for the HAC-LAC architecture ([[./figs/hac_lac_C_full_comparison.png][png]], [[./figs/hac_lac_C_full_comparison.pdf][pdf]])
[[file:figs/hac_lac_C_full_comparison.png ]]
#+begin_src matlab :exports none
2021-01-08 15:54:58 +01:00
p_handle = zeros(6*6,1);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
fig = figure;
for ix = 1:6
2020-02-28 17:35:44 +01:00
for iy = 1:6
2021-01-08 15:54:58 +01:00
p_handle((ix-1)*6 + iy) = subplot(6, 6, (ix-1)*6 + iy);
hold on;
set(gca,'ColorOrderIndex',1);
plot(freqs, abs(squeeze(freqresp(T_ol(ix, iy), freqs, 'Hz'))));
set(gca,'ColorOrderIndex',2);
plot(freqs, abs(squeeze(freqresp(T_hac_dvf(ix, iy), freqs, 'Hz'))));
set(gca,'ColorOrderIndex',3);
plot(freqs, abs(squeeze(freqresp(T_hac_iff(ix, iy), freqs, 'Hz'))));
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
if ix < 6
xticklabels({});
end
if iy > 1
yticklabels({});
end
2020-01-20 16:29:48 +01:00
end
2021-01-08 15:54:58 +01:00
end
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
linkaxes(p_handle, 'xy')
ylim([1e-5, 10]);
xlim([freqs(1), freqs(end)]);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
han = axes(fig, 'visible', 'off');
han.XLabel.Visible = 'on';
han.YLabel.Visible = 'on';
xlabel(han, 'Frequency [Hz]');
ylabel(han, 'Transmissibility');
2020-02-28 17:35:44 +01:00
#+end_src
#+header : :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/hac_lac_T_full_comparison.pdf" :var figsize= "full-tall" :post pdf2svg(file=*this*, ext= "png")
<<plt-matlab >>
#+end_src
#+name : fig:hac_lac_T_full_comparison
#+caption : Comparison of the norm of the Transmissibility matrices for the HAC-LAC architecture ([[./figs/hac_lac_T_full_comparison.png][png]], [[./figs/hac_lac_T_full_comparison.pdf][pdf]])
[[file:figs/hac_lac_T_full_comparison.png ]]
#+begin_src matlab :exports none
2021-01-08 15:54:58 +01:00
figure;
subplot(1,2,1);
hold on;
plot(freqs, T_norm_ol)
plot(freqs, T_norm_hac_dvf)
plot(freqs, T_norm_hac_iff)
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('Transmissibility - Frobenius Norm');
subplot(1,2,2);
hold on;
plot(freqs, C_norm_ol, 'DisplayName', 'OL')
plot(freqs, C_norm_hac_dvf, 'DisplayName', 'HAC-DVF')
plot(freqs, C_norm_hac_iff, 'DisplayName', 'HAC-IFF')
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('Compliance - Frobenius Norm');
legend();
2020-02-28 17:35:44 +01:00
#+end_src
#+header : :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/hac_lac_C_T_comparison.pdf" :var figsize= "full-tall" :post pdf2svg(file=*this*, ext= "png")
<<plt-matlab >>
#+end_src
#+name : fig:hac_lac_C_T_comparison
#+caption : Comparison of the Frobenius norm of the Compliance and Transmissibility for the HAC-LAC architecture with both IFF and DVF ([[./figs/hac_lac_C_T_comparison.png][png]], [[./figs/hac_lac_C_T_comparison.pdf][pdf]])
[[file:figs/hac_lac_C_T_comparison.png ]]
* MIMO Analysis
** Introduction :ignore:
Let's define the system as shown in figure [[fig:general_control_names ]].
#+begin_src latex :file general_control_names.pdf
2021-01-08 15:54:58 +01:00
\begin{tikzpicture}
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
% Blocs
\node[block={2.0cm}{2.0cm}] (P) {$P$};
\node[block={1.5cm}{1.5cm}, below=0.7 of P] (K) {$K$};
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
% Input and outputs coordinates
\coordinate[] (inputw) at ($(P.south west)!0.75!(P.north west)$);
\coordinate[] (inputu) at ($(P.south west)!0.25!(P.north west)$);
\coordinate[] (outputz) at ($(P.south east)!0.75!(P.north east)$);
\coordinate[] (outputv) at ($(P.south east)!0.25!(P.north east)$);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
% Connections and labels
\draw[<-] (inputw) node[above left, align=right]{(weighted)\\exogenous inputs\\$w$} -- ++(-1.5, 0);
\draw[<-] (inputu) -- ++(-0.8, 0) |- node[left, near start, align=right]{control signals\\$u$} (K.west);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
\draw[->] (outputz) node[above right, align=left]{(weighted)\\exogenous outputs\\$z$} -- ++(1.5, 0);
\draw[->] (outputv) -- ++(0.8, 0) |- node[right, near start, align=left]{sensed output\\$v$} (K.east);
\end{tikzpicture}
2020-02-28 17:35:44 +01:00
#+end_src
#+name : fig:general_control_names
#+caption : General Control Architecture
#+RESULTS :
[[file:figs/general_control_names.png ]]
#+name : tab:general_plant_signals
#+caption : Signals definition for the generalized plant
2020-03-11 18:58:56 +01:00
| | *Symbol* | *Meaning* |
|---------------------+-----------------------------+----------------------------------------|
2020-02-28 17:35:44 +01:00
| *Exogenous Inputs* | $\bm{\mathcal{X}}_w$ | Ground motion |
| | $\bm{\mathcal{F}}_d$ | External Forces applied to the Payload |
| | $\bm{r}$ | Reference signal for tracking |
|---------------------+-----------------------------+----------------------------------------|
| *Exogenous Outputs* | $\bm{\mathcal{X}}$ | Absolute Motion of the Payload |
| | $\bm{\tau}$ | Actuator Rate |
|---------------------+-----------------------------+----------------------------------------|
| *Sensed Outputs* | $\bm{\tau}_m$ | Force Sensors in each leg |
| | $\delta \bm{\mathcal{L}}_m$ | Measured displacement of each leg |
| | $\bm{\mathcal{X}}$ | Absolute Motion of the Payload |
|---------------------+-----------------------------+----------------------------------------|
| *Control Signals* | $\bm{\tau}$ | Actuator Inputs |
** Matlab Init :noexport:
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
2021-01-08 15:54:58 +01:00
<<matlab-dir >>
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab :exports none :results silent :noweb yes
2021-01-08 15:54:58 +01:00
<<matlab-init >>
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
simulinkproject('../');
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
open('stewart_platform_model.slx')
2020-02-28 17:35:44 +01:00
#+end_src
** Initialization
We first initialize the Stewart platform.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
stewart = initializeStewartPlatform();
stewart = initializeFramesPositions(stewart, 'H', 90e-3, 'MO_B', 45e-3);
stewart = generateGeneralConfiguration(stewart);
stewart = computeJointsPose(stewart);
stewart = initializeStrutDynamics(stewart);
stewart = initializeJointDynamics(stewart, 'type_F', 'universal', 'type_M', 'spherical');
stewart = initializeCylindricalPlatforms(stewart);
stewart = initializeCylindricalStruts(stewart);
stewart = computeJacobian(stewart);
stewart = initializeStewartPose(stewart);
stewart = initializeInertialSensor(stewart, 'type', 'none');
2020-02-28 17:35:44 +01:00
#+end_src
The rotation point of the ground is located at the origin of frame $\{A\}$.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
ground = initializeGround('type', 'rigid', 'rot_point', stewart.platform_F.FO_A);
payload = initializePayload('type', 'none');
2020-02-28 17:35:44 +01:00
#+end_src
** Identification
*** HAC - Without LAC
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'open-loop');
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
%% Name of the Simulink File
mdl = 'stewart_platform_model';
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'input'); io_i = io_i + 1; % Actuator Force Inputs [N]
io(io_i) = linio([mdl, '/Absolute Motion Sensor'], 1, 'openoutput'); io_i = io_i + 1; % Absolute Sensor [m, rad]
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
%% Run the linearization
G_ol = linearize(mdl, io);
G_ol.InputName = {'F1', 'F2', 'F3', 'F4', 'F5', 'F6'};
G_ol.OutputName = {'Dx', 'Dy', 'Dz', 'Rx', 'Ry', 'Rz'};
2020-02-28 17:35:44 +01:00
#+end_src
*** HAC - DVF
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'dvf');
K_dvf = -1e4*s/(1+s/2/pi/5000)*eye(6);
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
%% Name of the Simulink File
mdl = 'stewart_platform_model';
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'input'); io_i = io_i + 1; % Actuator Force Inputs [N]
io(io_i) = linio([mdl, '/Absolute Motion Sensor'], 1, 'openoutput'); io_i = io_i + 1; % Absolute Sensor [m, rad]
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
%% Run the linearization
G_dvf = linearize(mdl, io);
G_dvf.InputName = {'F1', 'F2', 'F3', 'F4', 'F5', 'F6'};
G_dvf.OutputName = {'Dx', 'Dy', 'Dz', 'Rx', 'Ry', 'Rz'};
2020-02-28 17:35:44 +01:00
#+end_src
*** Cartesian Frame
#+begin_src matlab
2021-01-08 15:54:58 +01:00
Gc_ol = minreal(G_ol)/stewart.kinematics.J';
Gc_ol.InputName = {'Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz'};
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
Gc_dvf = minreal(G_dvf)/stewart.kinematics.J';
Gc_dvf.InputName = {'Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz'};
2020-02-28 17:35:44 +01:00
#+end_src
** Singular Value Decomposition
#+begin_src matlab
2021-01-08 15:54:58 +01:00
freqs = logspace(1, 4, 1000);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
U_ol = zeros(6,6,length(freqs));
S_ol = zeros(6,length(freqs));
V_ol = zeros(6,6,length(freqs));
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
U_dvf = zeros(6,6,length(freqs));
S_dvf = zeros(6,length(freqs));
V_dvf = zeros(6,6,length(freqs));
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
for i = 1:length(freqs)
2020-02-28 17:35:44 +01:00
[U,S,V] = svd(freqresp(Gc_ol, freqs(i), 'Hz'));
U_ol(:,:,i) = U;
S_ol(:,i) = diag(S);
V_ol(:,:,i) = V;
[U,S,V] = svd(freqresp(Gc_dvf, freqs(i), 'Hz'));
U_dvf(:,:,i) = U;
S_dvf(:,i) = diag(S);
V_dvf(:,:,i) = V;
2021-01-08 15:54:58 +01:00
end
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab :exports none
2021-01-08 15:54:58 +01:00
figure;
ax1 = subplot(1,2,1);
hold on;
plot(freqs, S_ol(1,:), '-');
plot(freqs, S_ol(2,:), '--');
plot(freqs, S_ol(3,:), '-.');
plot(freqs, S_ol(4,:), '--');
plot(freqs, S_ol(5,:), '-');
plot(freqs, S_ol(6,:), '-.');
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('Singular Values');
title('Undamped Plant');
ax2 = subplot(1,2,2);
hold on;
plot(freqs, S_dvf(1,:), '-' , 'DisplayName', '$\sigma_1$');
plot(freqs, S_dvf(2,:), '--', 'DisplayName', '$\sigma_2$');
plot(freqs, S_dvf(3,:), '-.', 'DisplayName', '$\sigma_3$');
plot(freqs, S_dvf(4,:), '-' , 'DisplayName', '$\sigma_4$');
plot(freqs, S_dvf(5,:), '--', 'DisplayName', '$\sigma_5$');
plot(freqs, S_dvf(6,:), '-.', 'DisplayName', '$\sigma_6$');
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('Singular Values');
title('Damped Plant - DVF');
linkaxes([ax1, ax2], 'xy');
legend();
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab :exports none
2021-01-08 15:54:58 +01:00
figure;
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
ax1 = subplot(1,2,1);
hold on;
for i = 1:6
2020-02-28 17:35:44 +01:00
plot(freqs, abs(squeeze(V_ol(i,1,:))), '-' , 'DisplayName', Gc_ol.InputName{i});
2021-01-08 15:54:58 +01:00
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]');
ylabel('Singular Values');
legend();
ax2 = subplot(1,2,2);
hold on;
for i = 1:6
2020-02-28 17:35:44 +01:00
plot(freqs, abs(squeeze(U_ol(i,1,:))), '-' , 'DisplayName', Gc_ol.OutputName{i});
2021-01-08 15:54:58 +01:00
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
xlabel('Frequency [Hz]');
ylabel('Singular Values');
legend();
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
linkaxes([ax1,ax2], 'x');
2020-02-28 17:35:44 +01:00
#+end_src
* Diagonal Control based on the damped plant
** Introduction :ignore:
From cite:skogestad07_multiv_feedb_contr, a simple approach to multivariable control is the following two-step procedure:
1. *Design a pre-compensator* $W_1$, which counteracts the interactions in the plant and results in a new *shaped plant* $G_S(s) = G(s) W_1(s)$ which is *more diagonal and easier to control* than the original plant $G(s)$.
2. *Design a diagonal controller* $K_S(s)$ for the shaped plant using methods similar to those for SISO systems.
The overall controller is then:
\[ K(s) = W_1(s)K_s(s) \]
There are mainly three different cases:
1. *Dynamic decoupling* : $G_S(s)$ is diagonal at all frequencies. For that we can choose $W_1(s) = G^{-1}(s)$ and this is an inverse-based controller.
2. *Steady-state decoupling* : $G_S(0)$ is diagonal. This can be obtained by selecting $W_1(s) = G^{-1}(0)$.
3. *Approximate decoupling at frequency $\w_0$* : $G_S(j\w_0)$ is as diagonal as possible. Decoupling the system at $\w_0$ is a good choice because the effect on performance of reducing interaction is normally greatest at this frequency.
** Initialization
We first initialize the Stewart platform.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
stewart = initializeStewartPlatform();
stewart = initializeFramesPositions(stewart, 'H', 90e-3, 'MO_B', 45e-3);
stewart = generateGeneralConfiguration(stewart);
stewart = computeJointsPose(stewart);
stewart = initializeStrutDynamics(stewart);
stewart = initializeJointDynamics(stewart, 'type_F', 'universal', 'type_M', 'spherical');
stewart = initializeCylindricalPlatforms(stewart);
stewart = initializeCylindricalStruts(stewart);
stewart = computeJacobian(stewart);
stewart = initializeStewartPose(stewart);
stewart = initializeInertialSensor(stewart, 'type', 'none');
2020-02-28 17:35:44 +01:00
#+end_src
The rotation point of the ground is located at the origin of frame $\{A\}$.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
ground = initializeGround('type', 'rigid', 'rot_point', stewart.platform_F.FO_A);
payload = initializePayload('type', 'none');
2020-02-28 17:35:44 +01:00
#+end_src
** Identification
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'dvf');
K_dvf = -1e4*s/(1+s/2/pi/5000)*eye(6);
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
%% Name of the Simulink File
mdl = 'stewart_platform_model';
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'input'); io_i = io_i + 1; % Actuator Force Inputs [N]
io(io_i) = linio([mdl, '/Absolute Motion Sensor'], 1, 'openoutput'); io_i = io_i + 1; % Absolute Sensor [m, rad]
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
%% Run the linearization
G_dvf = linearize(mdl, io);
G_dvf.InputName = {'F1', 'F2', 'F3', 'F4', 'F5', 'F6'};
G_dvf.OutputName = {'Dx', 'Dy', 'Dz', 'Rx', 'Ry', 'Rz'};
2020-02-28 17:35:44 +01:00
#+end_src
** Steady State Decoupling
*** Pre-Compensator Design
We choose $W_1 = G^{-1}(0)$.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
W1 = inv(freqresp(G_dvf, 0));
2020-02-28 17:35:44 +01:00
#+end_src
The (static) decoupled plant is $G_s(s) = G(s) W_1$.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
Gs = G_dvf*W1;
2020-02-28 17:35:44 +01:00
#+end_src
In the case of the Stewart platform, the pre-compensator for static decoupling is equal to $\mathcal{K} \bm{J}$:
\begin{align*}
W_1 &= \left( \frac{\bm{\mathcal{X}}}{\bm{\tau}}(s=0) \right)^{-1}\\
&= \left( \frac{\bm{\mathcal{X}}}{\bm{\tau}}(s=0) \bm{J}^T \right)^{-1}\\
&= \left( \bm{C} \bm{J}^T \right)^{-1}\\
&= \left( \bm{J}^{-1} \mathcal{K}^{-1} \right)^{-1}\\
&= \mathcal{K} \bm{J}
\end{align*}
The static decoupled plant is schematic shown in Figure [[fig:control_arch_static_decoupling ]] and the bode plots of its diagonal elements are shown in Figure [[fig:static_decoupling_diagonal_plant ]].
#+begin_src latex :file control_arch_static_decoupling.pdf
2021-01-08 15:54:58 +01:00
\begin{tikzpicture}
% Blocs
\node[block] (G) {$G(s)$};
\node[block, left=1 of G] (J) {$\mathcal{K}\bm{J}$};
\node[block, left=1 of J] (Ks) {$\bm{K}_s(s)$};
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
\draw[->] (Ks.east) -- (J.west);
\draw[->] (J.east) -- (G.west) node[above left]{$\bm{\tau}$};
\draw[->] (G.east) node[above right]{$\bm{\mathcal{X}}$} -| ++(0.8, -0.8) -| ($(Ks.west) + (-0.8, 0)$) -- (Ks.west);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
\begin{scope}[on background layer]
\node[fit={(J.north west) (G.south east)}, inner sep=4pt, draw, dashed, fill=black!20!white, label= {$G_s(s)$}] {};
\end{scope}
\end{tikzpicture}
2020-02-28 17:35:44 +01:00
#+end_src
#+name : fig:control_arch_static_decoupling
#+caption : Static Decoupling of the Stewart platform
#+RESULTS :
[[file:figs/control_arch_static_decoupling.png ]]
#+begin_src matlab :exports none
2021-01-08 15:54:58 +01:00
freqs = logspace(1, 4, 1000);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
figure;
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
ax1 = subplot(2, 1, 1);
hold on;
for i = 1:6
2020-02-28 17:35:44 +01:00
plot(freqs, abs(squeeze(freqresp(Gs(i, i), freqs, 'Hz'))));
2021-01-08 15:54:58 +01:00
end
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
ax2 = subplot(2, 1, 2);
hold on;
for i = 1:6
2020-02-28 17:35:44 +01:00
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs(i, i), freqs, 'Hz'))));
2021-01-08 15:54:58 +01:00
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]);
2020-01-20 16:29:48 +01:00
2021-01-08 15:54:58 +01:00
linkaxes([ax1,ax2],'x');
2020-01-20 16:29:48 +01:00
#+end_src
2020-02-27 11:45:54 +01:00
2020-02-28 17:35:44 +01:00
#+header : :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/static_decoupling_diagonal_plant.pdf" :var figsize= "full-tall" :post pdf2svg(file=*this*, ext= "png")
<<plt-matlab >>
#+end_src
#+name : fig:static_decoupling_diagonal_plant
#+caption : Bode plot of the diagonal elements of $G_s(s)$ ([[./figs/static_decoupling_diagonal_plant.png][png]], [[./figs/static_decoupling_diagonal_plant.pdf][pdf]])
[[file:figs/static_decoupling_diagonal_plant.png ]]
*** Diagonal Control Design
We design a diagonal controller $K_s(s)$ that consist of a pure integrator and a lead around the crossover.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
wc = 2*pi*300; % Wanted Bandwidth [rad/s]
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
h = 1.5;
H_lead = 1/h*(1 + s/ (wc/h))/ (1 + s/(wc*h));
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
Ks_dvf = diag(1./abs(diag(freqresp(1/s*Gs, wc)))) .* H_lead .* 1/s;
2020-02-28 17:35:44 +01:00
#+end_src
The overall controller is then $K(s) = W_1 K_s(s)$ as shown in Figure [[fig:control_arch_static_decoupling_K ]].
#+begin_src matlab
2021-01-08 15:54:58 +01:00
K_hac_dvf = W1 * Ks_dvf;
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src latex :file control_arch_static_decoupling_K.pdf
2021-01-08 15:54:58 +01:00
\begin{tikzpicture}
% Blocs
\node[block] (G) {$G(s)$};
\node[block, left=1 of G] (J) {$\mathcal{K}\bm{J}$};
\node[block, left=1 of J] (Ks) {$\bm{K}_s(s)$};
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
\draw[->] (Ks.east) -- (J.west);
\draw[->] (J.east) -- (G.west) node[above left]{$\bm{\tau}$};
\draw[->] (G.east) node[above right]{$\bm{\mathcal{X}}$} -| ++(0.8, -0.8) -| ($(Ks.west) + (-0.8, 0)$) -- (Ks.west);
2020-02-28 17:35:44 +01:00
2021-01-08 15:54:58 +01:00
\begin{scope}[on background layer]
\node[fit={(Ks.north west) (J.south east)}, inner sep=4pt, draw, dashed, fill=black!20!white, label= {$K(s)$}] {};
\end{scope}
\end{tikzpicture}
2020-02-28 17:35:44 +01:00
#+end_src
#+name : fig:control_arch_static_decoupling_K
#+caption : Controller including the static decoupling matrix
#+RESULTS :
[[file:figs/control_arch_static_decoupling_K.png ]]
*** Results
We identify the transmissibility and compliance of the Stewart platform under open-loop and closed-loop control.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'open-loop');
[T_ol, T_norm_ol, freqs] = computeTransmissibility();
[C_ol, C_norm_ol, ~] = computeCompliance();
2020-02-28 17:35:44 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'hac-dvf');
[T_hac_dvf, T_norm_hac_dvf, ~] = computeTransmissibility();
[C_hac_dvf, C_norm_hac_dvf, ~] = computeCompliance();
2020-02-28 17:35:44 +01:00
#+end_src
The results are shown in figure
#+begin_src matlab :exports none
2021-01-08 15:54:58 +01:00
figure;
subplot(1,2,1);
hold on;
plot(freqs, T_norm_ol)
plot(freqs, T_norm_hac_dvf)
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('Transmissibility - Frobenius Norm');
subplot(1,2,2);
hold on;
plot(freqs, C_norm_ol, 'DisplayName', 'OL')
plot(freqs, C_norm_hac_dvf, 'DisplayName', 'HAC-DVF - Static decoupl.')
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('Compliance - Frobenius Norm');
legend();
2020-02-28 17:35:44 +01:00
#+end_src
#+header : :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/static_decoupling_C_T_frobenius_norm.pdf" :var figsize= "full-tall" :post pdf2svg(file=*this*, ext= "png")
<<plt-matlab >>
#+end_src
#+name : fig:static_decoupling_C_T_frobenius_norm
#+caption : Frobenius norm of the Compliance and transmissibility matrices ([[./figs/static_decoupling_C_T_frobenius_norm.png][png]], [[./figs/static_decoupling_C_T_frobenius_norm.pdf][pdf]])
[[file:figs/static_decoupling_C_T_frobenius_norm.png ]]
2020-03-11 18:58:56 +01:00
** TODO Decoupling at Crossover
2020-02-28 17:35:44 +01:00
- [ ] Find a method for real approximation of a complex matrix
2020-03-11 18:58:56 +01:00
* Time Domain Simulation
** Matlab Init :noexport:
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
2021-01-08 15:54:58 +01:00
<<matlab-dir >>
2020-03-11 18:58:56 +01:00
#+end_src
#+begin_src matlab :exports none :results silent :noweb yes
2021-01-08 15:54:58 +01:00
<<matlab-init >>
2020-03-11 18:58:56 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
simulinkproject('../');
2020-03-11 18:58:56 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
open('stewart_platform_model.slx')
2020-03-11 18:58:56 +01:00
#+end_src
** Initialization
We first initialize the Stewart platform.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
stewart = initializeStewartPlatform();
stewart = initializeFramesPositions(stewart, 'H', 90e-3, 'MO_B', 45e-3);
stewart = generateGeneralConfiguration(stewart);
stewart = computeJointsPose(stewart);
stewart = initializeStrutDynamics(stewart);
stewart = initializeJointDynamics(stewart, 'type_F', 'universal', 'type_M', 'spherical');
stewart = initializeCylindricalPlatforms(stewart);
stewart = initializeCylindricalStruts(stewart);
stewart = computeJacobian(stewart);
stewart = initializeStewartPose(stewart);
stewart = initializeInertialSensor(stewart, 'type', 'none');
2020-03-11 18:58:56 +01:00
#+end_src
The rotation point of the ground is located at the origin of frame $\{A\}$.
#+begin_src matlab
2021-01-08 15:54:58 +01:00
ground = initializeGround('type', 'rigid', 'rot_point', stewart.platform_F.FO_A);
payload = initializePayload('type', 'none');
2020-03-11 18:58:56 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
load('./mat/motion_error_ol.mat', 'Eg')
2020-03-11 18:58:56 +01:00
#+end_src
** HAC IFF
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'iff');
K_iff = -(1e4/s)*eye(6);
2020-03-11 18:58:56 +01:00
2021-01-08 15:54:58 +01:00
%% Name of the Simulink File
mdl = 'stewart_platform_model';
2020-03-11 18:58:56 +01:00
2021-01-08 15:54:58 +01:00
%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'input'); io_i = io_i + 1; % Actuator Force Inputs [N]
io(io_i) = linio([mdl, '/Absolute Motion Sensor'], 1, 'openoutput'); io_i = io_i + 1; % Absolute Sensor [m, rad]
2020-03-11 18:58:56 +01:00
2021-01-08 15:54:58 +01:00
%% Run the linearization
G_iff = linearize(mdl, io);
G_iff.InputName = {'F1', 'F2', 'F3', 'F4', 'F5', 'F6'};
G_iff.OutputName = {'Dx', 'Dy', 'Dz', 'Rx', 'Ry', 'Rz'};
2020-03-11 18:58:56 +01:00
2021-01-08 15:54:58 +01:00
Gc_iff = minreal(G_iff)/stewart.kinematics.J';
Gc_iff.InputName = {'Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz'};
2020-03-11 18:58:56 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
wc = 2*pi*100; % Wanted Bandwidth [rad/s]
2020-03-11 18:58:56 +01:00
2021-01-08 15:54:58 +01:00
h = 1.2;
H_lead = 1/h*(1 + s/ (wc/h))/ (1 + s/(wc*h));
2020-03-11 18:58:56 +01:00
2021-01-08 15:54:58 +01:00
Kd_iff = diag(1./abs(diag(freqresp(1/s*Gc_iff, wc)))) .* H_lead .* 1/s;
K_hac_iff = inv(stewart.kinematics.J')*Kd_iff;
2020-03-11 18:58:56 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'hac-iff');
2020-03-11 18:58:56 +01:00
#+end_src
** HAC-DVF
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'dvf');
K_dvf = -1e4*s/(1+s/2/pi/5000)*eye(6);
2020-03-11 18:58:56 +01:00
2021-01-08 15:54:58 +01:00
%% Name of the Simulink File
mdl = 'stewart_platform_model';
2020-03-11 18:58:56 +01:00
2021-01-08 15:54:58 +01:00
%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'input'); io_i = io_i + 1; % Actuator Force Inputs [N]
io(io_i) = linio([mdl, '/Absolute Motion Sensor'], 1, 'openoutput'); io_i = io_i + 1; % Absolute Sensor [m, rad]
2020-03-11 18:58:56 +01:00
2021-01-08 15:54:58 +01:00
%% Run the linearization
G_dvf = linearize(mdl, io);
G_dvf.InputName = {'F1', 'F2', 'F3', 'F4', 'F5', 'F6'};
G_dvf.OutputName = {'Dx', 'Dy', 'Dz', 'Rx', 'Ry', 'Rz'};
2020-03-11 18:58:56 +01:00
2021-01-08 15:54:58 +01:00
Gc_dvf = minreal(G_dvf)/stewart.kinematics.J';
Gc_dvf.InputName = {'Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz'};
2020-03-11 18:58:56 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
wc = 2*pi*100; % Wanted Bandwidth [rad/s]
2020-03-11 18:58:56 +01:00
2021-01-08 15:54:58 +01:00
h = 1.2;
H_lead = 1/h*(1 + s/ (wc/h))/ (1 + s/(wc*h));
2020-03-11 18:58:56 +01:00
2021-01-08 15:54:58 +01:00
Kd_dvf = diag(1./abs(diag(freqresp(1/s*Gc_dvf, wc)))) .* H_lead .* 1/s;
2020-03-11 18:58:56 +01:00
2021-01-08 15:54:58 +01:00
K_hac_dvf = inv(stewart.kinematics.J')*Kd_dvf;
2020-03-11 18:58:56 +01:00
#+end_src
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = initializeController('type', 'hac-dvf');
2020-03-11 18:58:56 +01:00
#+end_src
** Results
#+begin_src matlab
2021-01-08 15:54:58 +01:00
figure;
subplot(1, 2, 1);
hold on;
plot(Eg.Time, Eg.Data(:, 1), 'DisplayName', 'X');
plot(Eg.Time, Eg.Data(:, 2), 'DisplayName', 'Y');
plot(Eg.Time, Eg.Data(:, 3), 'DisplayName', 'Z');
hold off;
xlabel('Time [s]');
ylabel('Position error [m]');
legend();
subplot(1, 2, 2);
hold on;
plot(simout.Xa.Time, simout.Xa.Data(:, 1));
plot(simout.Xa.Time, simout.Xa.Data(:, 2));
plot(simout.Xa.Time, simout.Xa.Data(:, 3));
hold off;
xlabel('Time [s]');
ylabel('Orientation error [rad]');
2020-03-11 18:58:56 +01:00
#+end_src
2020-02-27 11:45:54 +01:00
* Functions
2020-02-27 14:23:09 +01:00
** =initializeController=: Initialize the Controller
2020-02-27 11:45:54 +01:00
:PROPERTIES:
2020-02-27 14:23:09 +01:00
:header-args:matlab+: :tangle ../src/initializeController.m
2020-02-27 11:45:54 +01:00
:header-args:matlab+: :comments none :mkdirp yes :eval no
:END:
2020-02-27 14:23:09 +01:00
<<sec:initializeController >>
2020-02-27 11:45:54 +01:00
*** Function description
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
2021-01-08 15:54:58 +01:00
function [controller] = initializeController(args)
% initializeController - Initialize the Controller
%
% Syntax: [] = initializeController(args)
%
% Inputs:
% - args - Can have the following fields:
2020-02-27 11:45:54 +01:00
#+end_src
*** Optional Parameters
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
2021-01-08 15:54:58 +01:00
arguments
2020-03-12 14:47:31 +01:00
args.type char {mustBeMember(args.type, {'open-loop', 'iff', 'dvf', 'hac-iff', 'hac-dvf', 'ref-track-L', 'ref-track-X', 'ref-track-hac-dvf'})} = 'open-loop'
2021-01-08 15:54:58 +01:00
end
2020-02-27 11:45:54 +01:00
#+end_src
2020-02-27 14:23:09 +01:00
*** Structure initialization
2020-02-27 11:45:54 +01:00
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
2021-01-08 15:54:58 +01:00
controller = struct();
2020-02-27 11:45:54 +01:00
#+end_src
2020-02-27 14:23:09 +01:00
*** Add Type
2020-02-27 11:45:54 +01:00
:PROPERTIES:
:UNNUMBERED: t
:END:
#+begin_src matlab
2021-01-08 15:54:58 +01:00
switch args.type
case 'open-loop'
controller.type = 0;
case 'iff'
controller.type = 1;
case 'dvf'
controller.type = 2;
case 'hac-iff'
controller.type = 3;
case 'hac-dvf'
controller.type = 4;
case 'ref-track-L'
controller.type = 5;
case 'ref-track-X'
controller.type = 6;
case 'ref-track-hac-dvf'
controller.type = 7;
end
2020-02-27 11:45:54 +01:00
#+end_src