#+TITLE: Nano Hexapod - Optimal Geometry
:DRAWER:
#+LANGUAGE: en
#+EMAIL: dehaeze.thomas@gmail.com
#+AUTHOR: Dehaeze Thomas
#+HTML_LINK_HOME: ../index.html
#+HTML_LINK_UP: ../index.html
#+HTML_HEAD:
#+HTML_HEAD:
#+BIND: org-latex-image-default-option "scale=1"
#+BIND: org-latex-image-default-width ""
#+LaTeX_CLASS: scrreprt
#+LaTeX_CLASS_OPTIONS: [a4paper, 10pt, DIV=12, parskip=full, bibliography=totoc]
#+LATEX_HEADER: \input{preamble.tex}
#+LATEX_HEADER_EXTRA: \input{preamble_extra.tex}
#+LATEX_HEADER_EXTRA: \bibliography{nass-geometry.bib}
#+BIND: org-latex-bib-compiler "biber"
#+PROPERTY: header-args:matlab :session *MATLAB*
#+PROPERTY: header-args:matlab+ :comments no
#+PROPERTY: header-args:matlab+ :exports none
#+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
#+PROPERTY: header-args:matlab+ :tangle no
#+PROPERTY: header-args:latex :headers '("\\usepackage{tikz}" "\\usepackage{import}" "\\import{$HOME/Cloud/tikz/org/}{config.tex}")
#+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+ :tangle no
#+PROPERTY: header-args:latex+ :eval no-export
#+PROPERTY: header-args:latex+ :exports results
#+PROPERTY: header-args:latex+ :mkdirp yes
#+PROPERTY: header-args:latex+ :output-dir figs
#+PROPERTY: header-args:latex+ :post pdf2svg(file=*this*, ext="png")
:END:
#+latex: \clearpage
* Build :noexport:
#+NAME: startblock
#+BEGIN_SRC emacs-lisp :results none :tangle no
(add-to-list 'org-latex-classes
'("scrreprt"
"\\documentclass{scrreprt}"
("\\chapter{%s}" . "\\chapter*{%s}")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
))
;; Remove automatic org heading labels
(defun my-latex-filter-removeOrgAutoLabels (text backend info)
"Org-mode automatically generates labels for headings despite explicit use of `#+LABEL`. This filter forcibly removes all automatically generated org-labels in headings."
(when (org-export-derived-backend-p backend 'latex)
(replace-regexp-in-string "\\\\label{sec:org[a-f0-9]+}\n" "" text)))
(add-to-list 'org-export-filter-headline-functions
'my-latex-filter-removeOrgAutoLabels)
;; Remove all org comments in the output LaTeX file
(defun delete-org-comments (backend)
(loop for comment in (reverse (org-element-map (org-element-parse-buffer)
'comment 'identity))
do
(setf (buffer-substring (org-element-property :begin comment)
(org-element-property :end comment))
"")))
(add-hook 'org-export-before-processing-hook 'delete-org-comments)
;; Use no package by default
(setq org-latex-packages-alist nil)
(setq org-latex-default-packages-alist nil)
;; Do not include the subtitle inside the title
(setq org-latex-subtitle-separate t)
(setq org-latex-subtitle-format "\\subtitle{%s}")
(setq org-export-before-parsing-hook '(org-ref-glossary-before-parsing
org-ref-acronyms-before-parsing))
#+END_SRC
* Notes :noexport:
** Notes
Prefix is =detail_kinematics=
Talk about the optimization of the nano-hexapod: geometry, stiffness, etc...
- [ ] [[file:~/Cloud/work-projects/ID31-NASS/documents/state-of-thesis-2020/index.org::*Optimal Nano-Hexapod Design][Optimal Nano-Hexapod Design]]
- [X] file:~/Cloud/work-projects/ID31-NASS/matlab/stewart-simscape/org/kinematic-study.org
- [X] file:~/Cloud/work-projects/ID31-NASS/matlab/stewart-simscape/org/flexible-stewart-platform.org
Not so interesting
- [ ] Talk about what will influence the dynamics
It will influence the mechanical design.
For instance we want to precisely position =bi= with respect to the top platform
Optimal geometry?
- [ ] *Cubic architecture*?
Cubic configuration file:~/Cloud/work-projects/ID31-NASS/matlab/stewart-simscape/org/cubic-configuration.org
https://tdehaeze.github.io/stewart-simscape/cubic-configuration.html
- [ ] Kinematics
- [ ] Trade-off for the strut orientation
- [ ] Requirements in terms of positioning of the joints
- [ ] Not a lot of differences, no specificity of cubic architecture, no specific positioning
- [ ] https://research.tdehaeze.xyz/stewart-simscape/docs/bibliography.html
- [ ] [[file:~/Cloud/work-projects/ID31-NASS/matlab/stewart-simscape/org/kinematic-study.org::*Estimated required actuator stroke from specified platform mobility][Estimated required actuator stroke from specified platform mobility]]
- [ ] [[file:~/Cloud/work-projects/ID31-NASS/matlab/stewart-simscape/org/kinematic-study.org::*Estimation of the Joint required Stroke][Estimation of the Joint required Stroke]]
** TODO [#A] Copy relevant parts of reports
** DONE [#A] Structure the review of Stewart platforms
CLOSED: [2025-03-30 Sun 11:38]
Focus on short stroke (<1 mm) stewart platforms with flexible joints.
- Actuators: voice coil, piezo
- Flexible joints
- Geometry:
- Cubic, non cubic, ...
- Control ? Maybe in the control section ?
** DONE [#B] Finish table about Stewart platforms
CLOSED: [2025-03-30 Sun 11:54]
[[tab:detail_kinematics_stewart_review][tab:detail_kinematics_stewart_review]]
- [ ] Only keep integrated sensor and not external metrology
- [ ] Check for missing information
** TODO [#A] Maybe need to have the Simscape model for the stewart platform?
For what use?
Study of coupling between strut sensor
** DONE [#A] Get analytical formula of stiffness matrix for cubic architecture?
CLOSED: [2025-03-29 Sat 16:31]
- Make some simplifying assumption:
- Cube at the center of the Stewart platform
- Cube size =
- Height of the mobile joints =
#+begin_src latex :file detail_kinematics_cubic_schematic.pdf
\begin{tikzpicture}
\begin{scope}[rotate={45}, shift={(0, 0, -4)}]
% We first define the coordinate of the points of the Cube
\coordinate[] (bot) at (0,0,4);
\coordinate[] (top) at (4,4,0);
\coordinate[] (A1) at (0,0,0);
\coordinate[] (A2) at (4,0,4);
\coordinate[] (A3) at (0,4,4);
\coordinate[] (B1) at (4,0,0);
\coordinate[] (B2) at (4,4,4);
\coordinate[] (B3) at (0,4,0);
% Center of the Cube
\node[] (cubecenter) at ($0.5*(bot) + 0.5*(top)$){$\bullet$};
\node[above right] at (cubecenter){$C$};
% We draw parts of the cube that corresponds to the Stewart platform
\draw[] (A1)node[]{$\bullet$} -- (B1)node[]{$\bullet$} -- (A2)node[]{$\bullet$} -- (B2)node[]{$\bullet$} -- (A3)node[]{$\bullet$} -- (B3)node[]{$\bullet$} -- (A1);
% ai and bi are computed
\def\lfrom{0.1}
\def\lto{0.8}
\coordinate(a1) at ($(A1) - \lfrom*(A1) + \lfrom*(B1)$);
\coordinate(b1) at ($(A1) - \lto*(A1) + \lto*(B1)$);
\coordinate(a2) at ($(A2) - \lfrom*(A2) + \lfrom*(B1)$);
\coordinate(b2) at ($(A2) - \lto*(A2) + \lto*(B1)$);
\coordinate(a3) at ($(A2) - \lfrom*(A2) + \lfrom*(B2)$);
\coordinate(b3) at ($(A2) - \lto*(A2) + \lto*(B2)$);
\coordinate(a4) at ($(A3) - \lfrom*(A3) + \lfrom*(B2)$);
\coordinate(b4) at ($(A3) - \lto*(A3) + \lto*(B2)$);
\coordinate(a5) at ($(A3) - \lfrom*(A3) + \lfrom*(B3)$);
\coordinate(b5) at ($(A3) - \lto*(A3) + \lto*(B3)$);
\coordinate(a6) at ($(A1) - \lfrom*(A1) + \lfrom*(B3)$);
\coordinate(b6) at ($(A1) - \lto*(A1) + \lto*(B3)$);
% Center of the Stewart Platform
% \node[color=colorblue] at ($0.25*(a1) + 0.25*(a6) + 0.25*(b3) + 0.25*(b4)$){$\bullet$};
% We draw the fixed and mobiles platforms
\path[fill=colorblue, opacity=0.2] (a1) -- (a2) -- (a3) -- (a4) -- (a5) -- (a6) -- cycle;
\path[fill=colorblue, opacity=0.2] (b1) -- (b2) -- (b3) -- (b4) -- (b5) -- (b6) -- cycle;
\draw[color=colorblue, dashed] (a1) -- (a2) -- (a3) -- (a4) -- (a5) -- (a6) -- cycle;
\draw[color=colorblue, dashed] (b1) -- (b2) -- (b3) -- (b4) -- (b5) -- (b6) -- cycle;
% The legs of the hexapod are drawn
\draw[color=colorblue] (a1)node{$\bullet$} -- node[midway, right]{$3$} (b1)node{$\bullet$};
\draw[color=colorblue] (a2)node{$\bullet$} -- node[midway, right]{$4$} (b2)node{$\bullet$};
\draw[color=colorblue] (a3)node{$\bullet$} -- node[midway, right]{$5$} (b3)node{$\bullet$};
\draw[color=colorblue] (a4)node{$\bullet$} -- node[midway, right]{$6$} (b4)node{$\bullet$};
\draw[color=colorblue] (a5)node{$\bullet$} -- node[midway, right]{$1$} (b5)node{$\bullet$};
\draw[color=colorblue] (a6)node{$\bullet$} -- node[midway, right]{$2$} (b6)node{$\bullet$};
% Labels
\node[left=0.1 of a5] {$a_i$};
\node[left=0.1 of b5] {$b_i$};
\end{scope}
% Height of the Hexapod
\coordinate[] (sizepos) at ($(a2)+(0.2, 0)$);
\coordinate[] (origin) at (0,0,0);
% \draw[<->, dashed] (a2-|sizepos) -- node[midway, right]{$H$} (b2-|sizepos);
% Height offset
% \draw[<->, dashed] (a2-|sizepos) -- node[midway, right]{$H_0$} (origin-|sizepos);
\draw[->] (0,6,0) node[above right]{$\{M\}$} -- ++(0,0,1);
\draw[->] (0,6,0) -- ++(1,0,0);
\draw[->] (0,6,0) -- ++(0,1,0);
\draw[->] (0,2,0) node[below right]{$\{F\}$}-- ++(0,0,1)node[left]{$x$};
\draw[->] (0,2,0) -- ++(1,0,0)node[above]{$y$};
\draw[->] (0,2,0) -- ++(0,1,0)node[right]{$z$};
\draw[<->, dashed] (0.5,2,0) --node[near end, right]{${}^{F}O_{C}$} ++(0,2,0);
\draw[<->, dashed] (-2,2,0) --node[midway, right]{${}^{F}H_{A}$} ++(0,1,0);
\draw[<->, dashed] (-2,6,0) --node[midway, right]{${}^{M}H_{B}$} ++(0,-1.5,0);
% Useful part of the cube
\draw[<->, dashed] ($(A2)+(0.5,0)$) -- node[midway, right]{$H_{C}$} ($(B1)+(0.5,0)$);
\end{tikzpicture}
#+end_src
#+RESULTS:
[[file:figs/detail_kinematics_cubic_schematic.png]]
Compute:
- [X] si : easy (always the same)
- [ ] bi : should also be easy
- Have to find intersection between struts and top platform (height of the joints)
- Need the equation of the cube's sides?
\begin{equation}
\hat{\bm{s}}_1 = \begin{bmatrix} \sqrt{2}/\sqrt{3} \\ 0 \\ 1/\sqrt{3} \end{bmatrix} \quad
\hat{\bm{s}}_2 = \begin{bmatrix} -1/\sqrt{6} \\ -1/\sqrt{2} \\ 1/\sqrt{3} \end{bmatrix} \quad
\hat{\bm{s}}_3 = \begin{bmatrix} -1/\sqrt{6} \\ 1/\sqrt{2} \\ 1/\sqrt{3} \end{bmatrix} \quad
\hat{\bm{s}}_4 = \begin{bmatrix} \sqrt{2}/\sqrt{3} \\ 0 \\ 1/\sqrt{3} \end{bmatrix} \quad
\hat{\bm{s}}_5 = \begin{bmatrix} -1/\sqrt{6} \\ -1/\sqrt{2} \\ 1/\sqrt{3} \end{bmatrix} \quad
\hat{\bm{s}}_6 = \begin{bmatrix} -1/\sqrt{6} \\ 1/\sqrt{2} \\ 1/\sqrt{3} \end{bmatrix}
\end{equation}
\begin{equation}
\sum_{i = 1}^{6} \hat{\bm{s}}_i \cdot \hat{\bm{s}}_i^T = 2 \bm{I}_3
\end{equation}
Need to include size of the cube for bi:
This is wrong, check from matlab script
\begin{equation}
\bm{b}_1 = \begin{bmatrix} \sqrt{2}/\sqrt{3} \\ 0 \\ 1/\sqrt{3} \end{bmatrix} \quad
\bm{b}_2 = \begin{bmatrix} -1/\sqrt{6} \\ -1/\sqrt{2} \\ 1/\sqrt{3} \end{bmatrix} \quad
\bm{b}_3 = \begin{bmatrix} -1/\sqrt{6} \\ 1/\sqrt{2} \\ 1/\sqrt{3} \end{bmatrix} \quad
\bm{b}_4 = \begin{bmatrix} \sqrt{2}/\sqrt{3} \\ 0 \\ 1/\sqrt{3} \end{bmatrix} \quad
\bm{b}_5 = \begin{bmatrix} -1/\sqrt{6} \\ -1/\sqrt{2} \\ 1/\sqrt{3} \end{bmatrix} \quad
\bm{b}_6 = \begin{bmatrix} -1/\sqrt{6} \\ 1/\sqrt{2} \\ 1/\sqrt{3} \end{bmatrix}
\end{equation}
\begin{equation}
\bm{K} = k \bm{J}^T \bm{J} =
k \left[
\begin{array}{c|c}
\Sigma_{i = 0}^{6} \hat{\bm{s}}_i \cdot \hat{\bm{s}}_i^T & \Sigma_{i = 0}^{6} \bm{\hat{s}}_i \cdot ({}^A\bm{b}_i \times {}^A\hat{\bm{s}}_i)^T \\
\hline
\Sigma_{i = 0}^{6} ({}^A\bm{b}_i \times {}^A\hat{\bm{s}}_i) \cdot \hat{\bm{s}}_i^T & \Sigma_{i = 0}^{6} ({}^A\bm{b}_i \times {}^A\hat{\bm{s}}_i) \cdot ({}^A\bm{b}_i \times {}^A\hat{\bm{s}}_i)^T\\
\end{array}
\right]
\end{equation}
#+begin_src matlab :exports none :results none
%% Cubic Architecture - Effect of the position of frame {A} and {B}
H = 20e-3; % Height of the Stewart platform [m]
Hc = 100e-3; % Size of the useful part of the cube [m]
FOc = 50e-3; % Center of the cube at the Stewart platform center
%% Frames {A} and {B} at the cube's center
MO_B = 0e-3; % Position {B} with respect to {M} [m]
MHb = 10e-3;
k = 1.4;
stewart_center = initializeStewartPlatform();
stewart_center = initializeFramesPositions(stewart_center, 'H', H, 'MO_B', MO_B);
stewart_center = generateCubicConfiguration(stewart_center, 'Hc', Hc, 'FOc', FOc, 'FHa', 5e-3, 'MHb', MHb);
stewart_center = computeJointsPose(stewart_center);
stewart_center = initializeStrutDynamics(stewart_center, 'k', k);
stewart_center = computeJacobian(stewart_center);
stewart_center = initializeCylindricalPlatforms(stewart_center, 'Fpr', 150e-3, 'Mpr', 150e-3);
displayArchitecture(stewart_center, 'labels', true, 'frames', true);
plotCube(stewart_center, 'Hc', Hc, 'FOc', FOc, 'color', [0,0,0,1], 'link_to_struts', true);
%% Si
si = 1/sqrt(3)*[
[ sqrt(2); 0; ; 1], ...
[-sqrt(2)/2; -sqrt(3/2); 1], ...
[-sqrt(2)/2; sqrt(3/2); 1], ...
[ sqrt(2); 0; ; 1], ...
[-sqrt(2)/2; -sqrt(3/2); 1], ...
[-sqrt(2)/2; sqrt(3/2); 1] ...
];
% Verification
if norm(si - stewart_center.geometry.Bs) > 1e-9
warning('wrong formulas')
end
%% Bi with Hc the "cube height"
% Position of the cube's top points for the six struts (centered cube)
ci = Hc * [
[1/sqrt(2); -sqrt(3)/sqrt(2); 0.5], ...
[1/sqrt(2); -sqrt(3)/sqrt(2); 0.5], ...
[1/sqrt(2); sqrt(3)/sqrt(2); 0.5], ...
[1/sqrt(2); sqrt(3)/sqrt(2); 0.5], ...
[-sqrt(2); 0; 0.5], ...
[-sqrt(2); 0; 0.5] ...
];
% Position of ci with respect to {B}
ci = ci + (- H - MO_B + FOc) * [0;0;1];
% Position of bi with respect to {B}
bi = ci - si * (MHb + FOc + Hc/2 - H) ./ si(3,:);
% Compare from Bi computed from Script
if norm(bi - stewart_center.geometry.Bb) > 1e-9
warning('wrong formulas')
end
%% Stiffness matrix
K = zeros(6,6);
K(1:3, 4:6) = si * cross(bi,si).';
K(4:6, 1:3) = cross(bi,si) * si.';
K(1:3,1:3) = si * si';
K(4:6,4:6) = cross(bi,si) * cross(bi,si).';
K = k*K;
if norm(K - stewart_center.kinematics.K) > 1e-9
warning('wrong formulas')
end
#+end_src
*** Centered cube - joints at cube's vertices => diagonal stiffness matrix
#+begin_src matlab
%% Suppose centered cube : Hc = H, FOc = H/2, MO_B = -H/2
k = 1;
Hc = 200e-3
si = 1/sqrt(3)*[
[ sqrt(2); 0; ; 1], ...
[-sqrt(2)/2; -sqrt(3/2); 1], ...
[-sqrt(2)/2; sqrt(3/2); 1], ...
[ sqrt(2); 0; ; 1], ...
[-sqrt(2)/2; -sqrt(3/2); 1], ...
[-sqrt(2)/2; sqrt(3/2); 1] ...
];
bi = Hc * [
[1/sqrt(2); -sqrt(3)/sqrt(2); 0.5], ...
[1/sqrt(2); -sqrt(3)/sqrt(2); 0.5], ...
[1/sqrt(2); sqrt(3)/sqrt(2); 0.5], ...
[1/sqrt(2); sqrt(3)/sqrt(2); 0.5], ...
[-sqrt(2); 0; 0.5], ...
[-sqrt(2); 0; 0.5] ...
];
K = zeros(6,6);
K(1:3, 4:6) = si * cross(bi,si).';
K(4:6, 1:3) = cross(bi,si) * si.';
K(1:3,1:3) = si * si';
K(4:6,4:6) = cross(bi,si) * cross(bi,si).';
K = k*K
K_formula = diag([2*k, 2*k, 2*k, 1.5*k*Hc^2, 1.5*k*Hc^2, 6*k*Hc^2])
#+end_src
** DONE [#A] Make table for review of Stewart platforms
CLOSED: [2025-03-19 Wed 18:25]
[[file:~/Cloud/work-projects/ID31-NASS/matlab/stewart-simscape/org/bibliography.org::*Built Stewart PLatforms][Built Stewart PLatforms]]
Link to figures.
In figure legend: link to references, mention the university and the application.
** DONE [#C] Create a function to plot the mobility of the Stewart platform
CLOSED: [2025-03-30 Sun 18:31]
Arguments:
- choose to fix the orientation with ${}^{B}R_{A}$
- maximum stroke of each actuator (may be included in the Stewart object)
* Introduction :ignore:
- In the conceptual design phase, the geometry of the Stewart platform was chosen arbitrarily and not optimized
- In the detail design phase, we want to see if the geometry can be optimized to improve the overall performances
- Optimization criteria: mobility, stiffness, dynamical decoupling, more performance / bandwidth
Outline:
- Review of Stewart platform (Section ref:sec:detail_kinematics_stewart_review)
Geometry, Actuators, Sensors, Joints
- Effect of geometry on the Stewart platform characteristics (Section ref:sec:detail_kinematics_geometry)
- Cubic configuration: benefits? (Section ref:sec:detail_kinematics_cubic)
- Obtained geometry for the nano hexapod (Section ref:sec:detail_kinematics_nano_hexapod)
* Review of Stewart platforms
<>
** Introduction :ignore:
- As was explained in the conceptual phase, Stewart platform have the following key elements:
# Section ref:sec:nhexa_stewart_platform
- Two plates connected by six struts
- Each strut is composed of:
- a flexible joint at each end
- an actuator
- one or several sensors
- The exact geometry (i.e. position of joints and orientation of the struts) can be chosen freely depending on the application.
- This results in many different designs found in the literature.
- The focus is here made on Stewart platforms for nano-positioning and vibration control.
Long stroke stewart platforms are not considered here as their design impose other challenges.
Some Stewart platforms found in the literature are listed in Table ref:tab:detail_kinematics_stewart_review
- All presented Stewart platforms are using flexible joints, as it is a prerequisites for nano-positioning capabilities.
- Most of stewart platforms are using voice coil actuators or piezoelectric actuators.
The actuators used for the Stewart platform will be chosen in the next section.
# TODO - Add reference to the section
- Depending on the application, various sensors are integrated in the struts or on the plates.
The choice of sensor for the nano-hexapod will be described in the next section.
# TODO - Add reference to the section
- There are two categories of Stewart platform geometry:
- Cubic architecture (Figure ref:fig:detail_kinematics_stewart_examples_cubic).
Struts are positioned along 6 sides of a cubic (and are therefore orthogonal to each other).
Such specific architecture has some special properties that will be studied in Section ref:sec:detail_kinematics_cubic.
- Non-cubic architecture (Figure ref:fig:detail_kinematics_stewart_examples_non_cubic)
#+name: fig:detail_kinematics_stewart_examples_cubic
#+caption: Some examples of developped Stewart platform with Cubic geometry. (\subref{fig:detail_kinematics_jpl}), (\subref{fig:detail_kinematics_uw_gsp}), (\subref{fig:detail_kinematics_ulb_pz}), (\subref{fig:detail_kinematics_uqp})
#+attr_latex: :options [htbp]
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_jpl}California Institute of Technology - USA}
#+attr_latex: :options {0.48\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.95\linewidth
[[file:figs/detail_kinematics_jpl.jpg]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_uw_gsp}University of Wyoming - USA}
#+attr_latex: :options {0.48\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.95\linewidth
[[file:figs/detail_kinematics_uw_gsp.jpg]]
#+end_subfigure
\bigskip
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_ulb_pz}ULB - Belgium}
#+attr_latex: :options {0.53\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.95\linewidth
[[file:figs/detail_kinematics_ulb_pz.jpg]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_uqp}Naval Postgraduate School - USA}
#+attr_latex: :options {0.43\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.95\linewidth
[[file:figs/detail_kinematics_uqp.jpg]]
#+end_subfigure
#+end_figure
#+name: fig:detail_kinematics_stewart_examples_non_cubic
#+caption: Some examples of developped Stewart platform with non-cubic geometry. (\subref{fig:detail_kinematics_pph}), (\subref{fig:detail_kinematics_zhang11}), (\subref{fig:detail_kinematics_yang19}), (\subref{fig:detail_kinematics_naves})
#+attr_latex: :options [htbp]
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_pph}Naval Postgraduate School - USA}
#+attr_latex: :options {0.48\textwidth}
#+begin_subfigure
#+attr_latex: :height 5cm
[[file:figs/detail_kinematics_pph.jpg]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_zhang11}Beihang University - China}
#+attr_latex: :options {0.48\textwidth}
#+begin_subfigure
#+attr_latex: :height 5cm
[[file:figs/detail_kinematics_zhang11.jpg]]
#+end_subfigure
\bigskip
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_yang19}Nanjing University - China}
#+attr_latex: :options {0.43\textwidth}
#+begin_subfigure
#+attr_latex: :height 5cm
[[file:figs/detail_kinematics_yang19.jpg]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_naves}University of Twente - Netherlands}
#+attr_latex: :options {0.53\textwidth}
#+begin_subfigure
#+attr_latex: :height 5cm
[[file:figs/detail_kinematics_naves.jpg]]
#+end_subfigure
#+end_figure
#+name: tab:detail_kinematics_stewart_review
#+caption: Examples of Stewart platform developed. When not specifically indicated, sensors are included in the struts. All presented Stewart platforms are using flexible joints. The table is ordered by appearance in the literature
#+attr_latex: :environment tabularx :width \linewidth :align llllX
#+attr_latex: :center t :booktabs t :font \scriptsize
| | *Geometry* | *Actuators* | *Sensors* | *Reference* |
|------------------------------------------+--------------+------------------------------+------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| | Cubic | Magnetostrictive | Force, Accelerometers | [[cite:&geng93_six_degree_of_freed_activ;&geng94_six_degree_of_freed_activ;&geng95_intel_contr_system_multip_degree]] |
| Figure ref:fig:detail_kinematics_jpl | Cubic | Voice Coil (0.5 mm) | Force | [[cite:&spanos95_soft_activ_vibrat_isolat;&rahman98_multiax]] |
| | Cubic | Voice Coil (10 mm) | Force, LVDT, Geophones | [[cite:&thayer98_stewar;&thayer02_six_axis_vibrat_isolat_system;&hauge04_sensor_contr_space_based_six]] |
| Figure ref:fig:detail_kinematics_uw_gsp | Cubic | Voice Coil | Force | [[cite:&mcinroy99_dynam;&mcinroy99_precis_fault_toler_point_using_stewar_platf;&mcinroy00_desig_contr_flexur_joint_hexap;&li01_simul_vibrat_isolat_point_contr;&jafari03_orthog_gough_stewar_platf_microm]] |
| | Cubic | Piezoelectric ($25\,\mu m$) | Force | [[cite:&defendini00_techn]] |
| Figure ref:fig:detail_kinematics_ulb_pz | Cubic | APA ($50\,\mu m$) | Force | [[cite:&abu02_stiff_soft_stewar_platf_activ]] |
| Figure ref:fig:detail_kinematics_pph | Non-Cubic | Voice Coil | Accelerometers | [[cite:&chen03_payload_point_activ_vibrat_isolat]] |
| | Cubic | Voice Coil | Force | [[cite:&hanieh03_activ_stewar;&preumont07_six_axis_singl_stage_activ]] |
| Figure ref:fig:detail_kinematics_uqp | Cubic | Piezoelectric ($50\,\mu m$) | Geophone | [[cite:&agrawal04_algor_activ_vibrat_isolat_spacec]] |
| | Non-Cubic | Piezoelectric ($16\,\mu m$) | Eddy Current | [[cite:&furutani04_nanom_cuttin_machin_using_stewar]] |
| | Cubic | Piezoelectric ($120\,\mu m$) | (External) Capacitive | [[cite:&ting06_desig_stewar_nanos_platf;&ting13_compos_contr_desig_stewar_nanos_platf]] |
| | Non-Cubic | Piezoelectric ($160\,\mu m$) | (External) Capacitive | [[cite:&ting07_measur_calib_stewar_microm_system]] |
| Figure ref:fig:detail_kinematics_zhang11 | Non-cubic | Magnetostrictive | Accelerometer | [[cite:&zhang11_six_dof]] |
| | Non-Cubic | Piezoelectric | Strain Gauge | [[cite:&du14_piezo_actuat_high_precis_flexib]] |
| | Cubic | Voice Coil | Accelerometer | [[cite:&chi15_desig_exper_study_vcm_based;&tang18_decen_vibrat_contr_voice_coil;&jiao18_dynam_model_exper_analy_stewar]] |
| | Cubic | Piezoelectric | Force | [[cite:&wang16_inves_activ_vibrat_isolat_stewar]] |
| | Almost cubic | Voice Coil | Force, Accelerometer | [[cite:&beijen18_self_tunin_mimo_distur_feedf;&tjepkema12_activ_ph]] |
| Figure ref:fig:detail_kinematics_yang19 | Almost cubic | Piezoelectric | Force, Strain gauge | [[cite:&yang19_dynam_model_decoup_contr_flexib]] |
| Figure ref:fig:detail_kinematics_naves | Non-Cubic | 3-phase rotary motor | Rotary Encoder | [[cite:&naves20_desig;&naves20_t_flex]] |
Conclusion:
- Various Stewart platform designs:
- geometry, sizes, orientation of struts
- Lot's have a "cubic" architecture that will be discussed in Section ref:sec:detail_kinematics_cubic
- actuator types
- various sensors
- flexible joints (discussed in next chapter)
- The effect of geometry on the properties of the Stewart platform is studied in section ref:sec:detail_kinematics_geometry
- It is determined what is the optimal geometry for the NASS
* Effect of geometry on Stewart platform properties
:PROPERTIES:
:HEADER-ARGS:matlab+: :tangle matlab/detail_kinematics_1_geometry.m
:END:
<>
** Introduction :ignore:
# Section ref:sec:nhexa_stewart_platform (page pageref:sec:nhexa_stewart_platform),
- As was shown during the conceptual phase, the geometry of the Stewart platform influences:
- the stiffness and compliance properties
- the mobility
- the force authority
- the dynamics of the manipulator
- It is therefore important to understand how the geometry impact these properties, and to be able to optimize the geometry for a specific application.
One important tool to study this is the Jacobian matrix which depends on the $\bm{b}_i$ (join position w.r.t top platform) and $\hat{\bm{s}}_i$ (orientation of struts).
The choice of frames ($\{A\}$ and $\{B\}$), independently of the physical Stewart platform geometry, impacts the obtained kinematics and stiffness matrix, as it is defined for forces and motion evaluated at the chosen frame.
** Matlab Init :noexport:ignore:
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
<>
#+end_src
#+begin_src matlab :exports none :results silent :noweb yes
<>
#+end_src
#+begin_src matlab :tangle no :noweb yes
<>
#+end_src
#+begin_src matlab :eval no :noweb yes
<>
#+end_src
#+begin_src matlab :noweb yes
<>
#+end_src
#+begin_src matlab :noweb yes
<>
#+end_src
** Platform Mobility
**** Introduction :ignore:
The mobility of the Stewart platform (or any manipulator) is here defined as the range of motion that it can perform.
It corresponds to the set of possible pose (i.e. combined translation and rotation) of frame {B} with respect to frame {A}.
It should therefore be represented in a six dimensional space.
As was shown during the conceptual phase, for small displacements, the Jacobian matrix can be used to link the strut motion to the motion of frame B with respect to A through equation eqref:eq:detail_kinematics_jacobian.
# Section ref:ssec:nhexa_stewart_platform_jacobian (page pageref:ssec:nhexa_stewart_platform_jacobian).
\begin{equation}\label{eq:detail_kinematics_jacobian}
\begin{bmatrix} \delta l_1 \\ \delta l_2 \\ \delta l_3 \\ \delta l_4 \\ \delta l_5 \\ \delta l_6 \end{bmatrix} = \begin{bmatrix}
{{}^A\hat{\bm{s}}_1}^T & ({}^A\bm{b}_1 \times {}^A\hat{\bm{s}}_1)^T \\
{{}^A\hat{\bm{s}}_2}^T & ({}^A\bm{b}_2 \times {}^A\hat{\bm{s}}_2)^T \\
{{}^A\hat{\bm{s}}_3}^T & ({}^A\bm{b}_3 \times {}^A\hat{\bm{s}}_3)^T \\
{{}^A\hat{\bm{s}}_4}^T & ({}^A\bm{b}_4 \times {}^A\hat{\bm{s}}_4)^T \\
{{}^A\hat{\bm{s}}_5}^T & ({}^A\bm{b}_5 \times {}^A\hat{\bm{s}}_5)^T \\
{{}^A\hat{\bm{s}}_6}^T & ({}^A\bm{b}_6 \times {}^A\hat{\bm{s}}_6)^T
\end{bmatrix} \begin{bmatrix} \delta x \\ \delta y \\ \delta z \\ \delta \theta_x \\ \delta \theta_y \\ \delta \theta_z \end{bmatrix}
\end{equation}
Therefore, the mobility of the Stewart platform (set of $[\delta x\ \delta y\ \delta z\ \delta \theta_x\ \delta \theta_y\ \delta \theta_z]$) depends on:
- the stroke of each strut
- the geometry of the Stewart platform (embodied in the Jacobian matrix)
More specifically:
- the XYZ mobility only depends on the si (orientation of struts)
- the mobility in rotation depends on bi (position of top joints)
As will be shown in Section ref:sec:detail_kinematics_cubic, there are some geometry that gives same stroke in X, Y and Z directions.
As the mobility is of dimension six, it is difficult to represent.
Depending on the applications, only the translation mobility or the rotation mobility may be represented.
**** Mobility in translation
Here, for simplicity, only translations are first considered:
- Let's consider a general Stewart platform geometry shown in Figure ref:fig:detail_kinematics_mobility_trans_arch.
- In the general case: the translational mobility can be represented by a 3D shape with 12 faces (each actuator limits the stroke along its orientation in positive and negative directions).
The faces are therefore perpendicular to the strut direction.
The obtained mobility is shown in Figure ref:fig:detail_kinematics_mobility_trans_result.
- Considering an actuator stroke of $\pm d$, the mobile platform can be translated in any direction with a stroke of $d$
A circle with radius $d$ can be contained in the general shape.
It will touch the shape along six lines defined by the strut axes.
The sphere with radius $d$ is shown in Figure ref:fig:detail_kinematics_mobility_trans_result.
- Therefore, for any (small stroke) Stewart platform with actuator stroke $\pm d$, it is possible to move the top platform in any direction by at least a distance $d$.
Note that no platform angular motion is here considered. When combining angular motion, the linear stroke decreases.
- When considering some symmetry in the system (as typically the case), the shape becomes a Trigonal trapezohedron whose height and width depends on the orientation of the struts.
We only get 6 faces as usually the Stewart platform consists of 3 sets of 2 parallels struts.
#+begin_src matlab :exports none :results none
%% Example of one Stewart platform and associated translational mobility
L_max = 50e-6; % Maximum actuator stroke (+/-) [m]
stewart = initializeStewartPlatform();
stewart = initializeFramesPositions(stewart, 'H', 100e-3, 'MO_B', -50e-3);
stewart = generateGeneralConfiguration(stewart, 'FH', 0, 'FR', 100e-3, 'MH', 0, 'MR', 100e-3, ...
'FTh', [-5, 5, 120-5, 120+5, 240-5, 240+5]*(pi/180), ...
'MTh', [-60+5, 60-5, 60+5, 180-5, 180+5, -60-5]*(pi/180));
stewart = computeJointsPose(stewart);
stewart = initializeStrutDynamics(stewart, 'k', 1);
stewart = computeJacobian(stewart);
stewart = initializeCylindricalPlatforms(stewart, 'Fpr', 110e-3, 'Mpr', 110e-3);
displayArchitecture(stewart, 'labels', false, 'frames', false, 'F_color', [0,0,0], 'M_color', [0,0,0], 'L_color', [0,0,0]);
#+end_src
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/detail_kinematics_mobility_trans_arch.pdf', 'width', 'half', 'height', 'normal');
#+end_src
#+begin_src matlab
thetas = linspace(0, pi, 100);
phis = linspace(0, 2*pi, 100);
rs = zeros(length(thetas), length(phis));
for i = 1:length(thetas)
for j = 1:length(phis)
Tx = sin(thetas(i))*cos(phis(j));
Ty = sin(thetas(i))*sin(phis(j));
Tz = cos(thetas(i));
dL = stewart.kinematics.J*[Tx; Ty; Tz; 0; 0; 0;]; % dL required for 1m displacement in theta/phi direction
rs(i, j) = L_max/max(abs(dL));
end
end
% Sphere with radius equal to actuator stroke
[Xs,Ys,Zs] = sphere;
Xs = 1e6*L_max*Xs;
Ys = 1e6*L_max*Ys;
Zs = 1e6*L_max*Zs;
[phi_grid, theta_grid] = meshgrid(phis, thetas);
X = 1e6 * rs .* sin(theta_grid) .* cos(phi_grid);
Y = 1e6 * rs .* sin(theta_grid) .* sin(phi_grid);
Z = 1e6 * rs .* cos(theta_grid);
figure('Renderer', 'painters');
hold on;
surf(X, Y, Z, 'FaceColor', 'none', 'LineWidth', 0.1, 'EdgeColor', [0, 0, 0]);
surf(Xs, Ys, Zs, 'FaceColor', colors(2,:), 'EdgeColor', 'none');
quiver3(0, 0, 0, 100, 0, 0, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.9);
quiver3(0, 0, 0, 0, 100, 0, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.9);
quiver3(0, 0, 0, 0, 0, 100, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.9);
hold off;
axis equal;
grid off;
axis off;
view(55, 25);
#+end_src
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/detail_kinematics_mobility_trans_result.pdf', 'width', 'normal', 'height', 'tall');
#+end_src
#+name: fig:detail_kinematics_mobility_trans
#+caption: Example of one Stewart platform (\subref{fig:detail_kinematics_mobility_trans_arch}) and associated translational mobility (\subref{fig:detail_kinematics_mobility_trans_result})
#+attr_latex: :options [htbp]
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_mobility_trans_arch}Stewart platform geometry}
#+attr_latex: :options {0.48\textwidth}
#+begin_subfigure
#+attr_latex: :scale 1
[[file:figs/detail_kinematics_mobility_trans_arch.png]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_mobility_trans_result}Translational mobility}
#+attr_latex: :options {0.48\textwidth}
#+begin_subfigure
#+attr_latex: :scale 1
[[file:figs/detail_kinematics_mobility_trans_result.png]]
#+end_subfigure
#+end_figure
To better understand how the geometry of the Stewart platform impacts the translational mobility, two configurations are compared:
- Struts oriented horizontally (Figure ref:fig:detail_kinematics_stewart_mobility_vert_struts) => more stroke in horizontal direction
- Struts oriented vertically (Figure ref:fig:detail_kinematics_stewart_mobility_hori_struts) => more stroke in vertical direction
- Corresponding mobility shown in Figure ref:fig:detail_kinematics_mobility_translation_strut_orientation
#+begin_src matlab :exports none :results none
%% Stewart platform with Vertically oriented struts
L_max = 50e-6; % Maximum actuator stroke (+/-) [m]
stewart_vert = initializeStewartPlatform();
stewart_vert = initializeFramesPositions(stewart_vert, 'H', 40e-3, 'MO_B', -20e-3);
stewart_vert = generateGeneralConfiguration(stewart_vert, 'FH', 0, 'FR', 100e-3, 'MH', 0, 'MR', 100e-3, ...
'FTh', [-25, 25, 120-25, 120+25, 240-25, 240+25]*(pi/180), ...
'MTh', [-60+25, 60-25, 60+25, 180-25, 180+25, -60-25]*(pi/180));
stewart_vert = computeJointsPose(stewart_vert);
stewart_vert = initializeStrutDynamics(stewart_vert, 'k', 1);
stewart_vert = computeJacobian(stewart_vert);
stewart_vert = initializeCylindricalPlatforms(stewart_vert, 'Fpr', 110e-3, 'Mpr', 110e-3);
displayArchitecture(stewart_vert, 'labels', false, 'frames', false, 'F_color', colors(1,:), 'M_color', colors(1,:), 'L_color', colors(1,:));
#+end_src
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/detail_kinematics_stewart_mobility_vert_struts.pdf', 'width', 'half', 'height', 'normal');
#+end_src
#+begin_src matlab :exports none :results none
%% Stewart platform with Horizontally oriented struts
stewart_hori = initializeStewartPlatform();
stewart_hori = initializeFramesPositions(stewart_hori, 'H', 40e-3, 'MO_B', -20e-3);
stewart_hori = generateGeneralConfiguration(stewart_hori, 'FH', 0, 'FR', 100e-3, 'MH', 0, 'MR', 100e-3, ...
'FTh', [-5, 5, 120-5, 120+5, 240-5, 240+5]*(pi/180), ...
'MTh', [-60+5, 60-5, 60+5, 180-5, 180+5, -60-5]*(pi/180));
stewart_hori = computeJointsPose(stewart_hori);
stewart_hori = initializeStrutDynamics(stewart_hori, 'k', 1);
stewart_hori = computeJacobian(stewart_hori);
stewart_hori = initializeCylindricalPlatforms(stewart_hori, 'Fpr', 110e-3, 'Mpr', 110e-3);
displayArchitecture(stewart_hori, 'labels', false, 'frames', false, 'F_color', colors(2,:), 'M_color', colors(2,:), 'L_color', colors(2,:));
#+end_src
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/detail_kinematics_stewart_mobility_hori_struts.pdf', 'width', 'half', 'height', 'normal');
#+end_src
#+begin_src matlab :exports none :results none
%% Translation mobility for two Stewart platform geometry
thetas = linspace(0, pi, 50);
phis = linspace(0, 2*pi, 50);
rs_vert = zeros(length(thetas), length(phis));
rs_hori = zeros(length(thetas), length(phis));
for i = 1:length(thetas)
for j = 1:length(phis)
Tx = sin(thetas(i))*cos(phis(j));
Ty = sin(thetas(i))*sin(phis(j));
Tz = cos(thetas(i));
dL = stewart_vert.kinematics.J*[Tx; Ty; Tz; 0; 0; 0;]; % dL required for 1m displacement in theta/phi direction
rs_vert(i, j) = L_max/max(abs(dL));
dL = stewart_hori.kinematics.J*[Tx; Ty; Tz; 0; 0; 0;]; % dL required for 1m displacement in theta/phi direction
rs_hori(i, j) = L_max/max(abs(dL));
end
end
[phi_grid, theta_grid] = meshgrid(phis, thetas);
X_vert = 1e6 * rs_vert .* sin(theta_grid) .* cos(phi_grid);
Y_vert = 1e6 * rs_vert .* sin(theta_grid) .* sin(phi_grid);
Z_vert = 1e6 * rs_vert .* cos(theta_grid);
X_hori = 1e6 * rs_hori .* sin(theta_grid) .* cos(phi_grid);
Y_hori = 1e6 * rs_hori .* sin(theta_grid) .* sin(phi_grid);
Z_hori = 1e6 * rs_hori .* cos(theta_grid);
[Xs,Ys,Zs] = sphere;
Xs = 1e6*L_max*Xs;
Ys = 1e6*L_max*Ys;
Zs = 1e6*L_max*Zs;
figure;
hold on;
surf(X_vert, Y_vert, Z_vert, 'FaceColor', 'white', 'LineWidth', 0.2, 'EdgeColor', colors(1,:));
surf(X_hori, Y_hori+400, Z_hori, 'FaceColor', 'white', 'LineWidth', 0.2, 'EdgeColor', colors(2,:));
quiver3(0, 0, 0, 200, 0, 0, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.7);
quiver3(0, 0, 0, 0, 200, 0, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.7);
quiver3(0, 0, 0, 0, 0, 200, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.7);
text(200, 0, 0, '$D_x$', 'FontSize', 10, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'top' );
text(0, 200, 0, '$D_y$', 'FontSize', 10, 'HorizontalAlignment', 'right', 'VerticalAlignment', 'bottom');
text(0, 0, 200, '$D_z$', 'FontSize', 10, 'HorizontalAlignment', 'left', 'VerticalAlignment', 'top' );
quiver3(0, 400, 0, 200, 0, 0, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.7);
quiver3(0, 400, 0, 0, 200, 0, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.7);
quiver3(0, 400, 0, 0, 0, 200, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.7);
text(200, 400, 0, '$D_x$', 'FontSize', 10, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'top' );
text(0, 600, 0, '$D_y$', 'FontSize', 10, 'HorizontalAlignment', 'right', 'VerticalAlignment', 'bottom');
text(0, 400, 200, '$D_z$', 'FontSize', 10, 'HorizontalAlignment', 'left', 'VerticalAlignment', 'top' );
hold off;
axis equal;
grid off;
axis off;
view(105, 15);
#+end_src
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/detail_kinematics_mobility_translation_strut_orientation.pdf', 'width', 'full', 'height', 'tall');
#+end_src
#+name: fig:detail_kinematics_stewart_mobility_examples
#+caption: Effect of strut orientation on the obtained mobility in translation. Two Stewart platform geometry are considered: struts oriented vertically (\subref{fig:detail_kinematics_stewart_mobility_vert_struts}) and struts oriented vertically (\subref{fig:detail_kinematics_stewart_mobility_hori_struts}). Obtained mobility for both geometry are shown in (\subref{fig:detail_kinematics_mobility_translation_strut_orientation}).
#+attr_latex: :options [htbp]
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_stewart_mobility_vert_struts}Struts oriented vertically}
#+attr_latex: :options {0.48\textwidth}
#+begin_subfigure
#+attr_latex: :scale 1
[[file:figs/detail_kinematics_stewart_mobility_vert_struts.png]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_stewart_mobility_hori_struts}Struts oriented horizontally}
#+attr_latex: :options {0.48\textwidth}
#+begin_subfigure
#+attr_latex: :scale 1
[[file:figs/detail_kinematics_stewart_mobility_hori_struts.png]]
#+end_subfigure
\bigskip
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_mobility_translation_strut_orientation}Translational mobility of the two configurations}
#+attr_latex: :options {0.95\textwidth}
#+begin_subfigure
#+attr_latex: :scale 1
[[file:figs/detail_kinematics_mobility_translation_strut_orientation.png]]
#+end_subfigure
#+end_figure
**** Mobility in rotation
As shown by equation eqref:eq:detail_kinematics_jacobian, the rotational mobility depends both on the orientation of the struts and on the location of the top joints.
Similarly to the translational case, to increase the rotational mobility in one direction, it is advantageous to have the struts more perpendicular to the rotational direction.
For instance, having the struts more vertical (Figure ref:fig:detail_kinematics_stewart_mobility_vert_struts) gives less rotational stroke along the vertical direction than having the struts oriented more horizontally (Figure ref:fig:detail_kinematics_stewart_mobility_hori_struts).
Two cases are considered with same strut orientation but with different top joints positions:
- struts close to each other (Figure ref:fig:detail_kinematics_stewart_mobility_close_struts)
- struts further apart (Figure ref:fig:detail_kinematics_stewart_mobility_space_struts)
The mobility for pure rotations are compared in Figure ref:fig:detail_kinematics_mobility_angle_strut_distance.
Note that the same strut stroke are considered in both cases to evaluate the mobility.
Having struts further apart decreases the "level arm" and therefore the rotational mobility is reduced.
For rotations and translations, having more mobility also means increasing the effect of actuator noise on the considering degree of freedom.
Somehow, the level arm is increased, so any strut vibration gets amplified.
Therefore, the designed Stewart platform should just have the necessary mobility.
#+begin_src matlab :exports none :results none
%% Stewart platform with struts close to each other
stewart_close = initializeStewartPlatform();
stewart_close = initializeFramesPositions(stewart_close, 'H', 100e-3, 'MO_B', 0);
stewart_close = generateGeneralConfiguration(stewart_close, 'FH', 0, 'FR', 50e-3, 'MH', 0, 'MR', 50e-3, ...
'FTh', [-6, 6, 120-6, 120+6, 240-6, 240+6]*(pi/180), ...
'MTh', [-60+6, 60-6, 60+6, 180-6, 180+6, -60-6]*(pi/180));
stewart_close = computeJointsPose(stewart_close);
stewart_close = initializeStrutDynamics(stewart_close, 'k', 1);
stewart_close = computeJacobian(stewart_close);
stewart_close = initializeCylindricalPlatforms(stewart_close, 'Fpr', 110e-3, 'Mpr', 110e-3);
displayArchitecture(stewart_close, 'labels', false, 'frames', false, 'F_color', colors(1,:), 'M_color', colors(1,:), 'L_color', colors(1,:));
#+end_src
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/detail_kinematics_stewart_mobility_close_struts.pdf', 'width', 'full', 'height', 'short');
#+end_src
#+begin_src matlab :exports none :results none
%% Stewart platform with struts further away from each other
stewart_space = initializeStewartPlatform();
stewart_space = initializeFramesPositions(stewart_space, 'H', 100e-3, 'MO_B', 0);
stewart_space = generateGeneralConfiguration(stewart_space, 'FH', 0, 'FR', 100e-3, 'MH', 0, 'MR', 100e-3, ...
'FTh', [-6, 6, 120-6, 120+6, 240-6, 240+6]*(pi/180), ...
'MTh', [-60+6, 60-6, 60+6, 180-6, 180+6, -60-6]*(pi/180));
stewart_space.platform_F.Fa = stewart_space.platform_M.Mb - (stewart_close.platform_M.Mb - stewart_close.platform_F.Fa);
stewart_space = computeJointsPose(stewart_space);
stewart_space = initializeStrutDynamics(stewart_space, 'k', 1);
stewart_space = computeJacobian(stewart_space);
stewart_space = initializeCylindricalPlatforms(stewart_space, 'Fpr', 110e-3, 'Mpr', 110e-3);
displayArchitecture(stewart_space, 'labels', false, 'frames', false, 'F_color', colors(2,:), 'M_color', colors(2,:), 'L_color', colors(2,:));
#+end_src
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/detail_kinematics_stewart_mobility_space_struts.pdf', 'width', 'full', 'height', 'short');
#+end_src
#+begin_src matlab :exports none :results none
%% Translation mobility for two Stewart platform geometry
thetas = linspace(0, pi, 50);
phis = linspace(0, 2*pi, 50);
rs_close = zeros(length(thetas), length(phis));
rs_space = zeros(length(thetas), length(phis));
for i = 1:length(thetas)
for j = 1:length(phis)
Rx = sin(thetas(i))*cos(phis(j));
Ry = sin(thetas(i))*sin(phis(j));
Rz = cos(thetas(i));
dL = stewart_close.kinematics.J*[0; 0; 0; Rx; Ry; Rz;];
rs_close(i, j) = L_max/max(abs(dL));
dL = stewart_space.kinematics.J*[0; 0; 0; Rx; Ry; Rz;];
rs_space(i, j) = L_max/max(abs(dL));
end
end
[phi_grid, theta_grid] = meshgrid(phis, thetas);
X_close = 1e6 * rs_close .* sin(theta_grid) .* cos(phi_grid);
Y_close = 1e6 * rs_close .* sin(theta_grid) .* sin(phi_grid);
Z_close = 1e6 * rs_close .* cos(theta_grid);
X_space = 1e6 * rs_space .* sin(theta_grid) .* cos(phi_grid);
Y_space = 1e6 * rs_space .* sin(theta_grid) .* sin(phi_grid);
Z_space = 1e6 * rs_space .* cos(theta_grid);
figure;
hold on;
surf(X_close, Y_close, Z_close, 'FaceColor', 'white', 'LineWidth', 0.2, 'EdgeColor', colors(1,:));
surf(X_space, Y_space+6000, Z_space, 'FaceColor', 'white', 'LineWidth', 0.2, 'EdgeColor', colors(2,:));
quiver3(0, 0, 0, 4000, 0, 0, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.7);
quiver3(0, 0, 0, 0, 4000, 0, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.7);
quiver3(0, 0, 0, 0, 0, 4000, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.7);
text(4000, 0, 0, '$R_x$', 'FontSize', 10, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'top' );
text(0, 4000, 0, '$R_y$', 'FontSize', 10, 'HorizontalAlignment', 'right', 'VerticalAlignment', 'bottom');
text(0, 0, 4000, '$R_z$', 'FontSize', 10, 'HorizontalAlignment', 'left', 'VerticalAlignment', 'top' );
quiver3(0, 6000, 0, 4000, 0, 0, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.7);
quiver3(0, 6000, 0, 0, 4000, 0, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.7);
quiver3(0, 6000, 0, 0, 0, 4000, 'k', 'LineWidth', 2, 'MaxHeadSize', 0.7);
text(4000, 6000, 0, '$R_x$', 'FontSize', 10, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'top');
text(0, 10000, 0, '$R_y$', 'FontSize', 10, 'HorizontalAlignment', 'right', 'VerticalAlignment', 'bottom');
text(0, 6000, 4000, '$R_z$', 'FontSize', 10, 'HorizontalAlignment', 'left', 'VerticalAlignment', 'top');
hold off;
axis equal;
grid off;
axis off;
view(105, 15);
#+end_src
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/detail_kinematics_mobility_angle_strut_distance.pdf', 'width', 'full', 'height', 'full');
#+end_src
#+name: fig:detail_kinematics_stewart_mobility_examples
#+caption: Effect of strut position on the obtained mobility in rotation. Two Stewart platform geometry are considered: struts close to each other (\subref{fig:detail_kinematics_stewart_mobility_close_struts}) and struts further appart (\subref{fig:detail_kinematics_stewart_mobility_space_struts}). Obtained mobility for both geometry are shown in (\subref{fig:detail_kinematics_mobility_angle_strut_distance}).
#+attr_latex: :options [htbp]
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_stewart_mobility_close_struts}Struts oriented closeically}
#+attr_latex: :options {0.48\textwidth}
#+begin_subfigure
#+attr_latex: :scale 1
[[file:figs/detail_kinematics_stewart_mobility_close_struts.png]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_stewart_mobility_space_struts}Struts oriented spacezontally}
#+attr_latex: :options {0.48\textwidth}
#+begin_subfigure
#+attr_latex: :scale 1
[[file:figs/detail_kinematics_stewart_mobility_space_struts.png]]
#+end_subfigure
\bigskip
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_mobility_angle_strut_distance}Translational mobility of the two configurations}
#+attr_latex: :options {0.95\textwidth}
#+begin_subfigure
#+attr_latex: :scale 1
[[file:figs/detail_kinematics_mobility_angle_strut_distance.png]]
#+end_subfigure
#+end_figure
**** Combined translations and rotations
It is possible to consider combined translations and rotations.
Displaying such mobility is more complex.
It will be used for the nano-hexapod to verify that the obtained design has the necessary mobility.
For a fixed geometry and a wanted mobility (combined translations and rotations), it is possible to estimate the required minimum actuator stroke.
It will be done in Section ref:sec:detail_kinematics_nano_hexapod to estimate the required actuator stroke for the nano-hexapod geometry.
** Stiffness
**** Introduction :ignore:
Stiffness matrix:
- defines how the nano-hexapod deforms (frame $\{B\}$ with respect to frame $\{A\}$) due to static forces/torques applied on $\{B\}$.
- Depends on the Jacobian matrix (i.e. the geometry) and the strut axial stiffness eqref:eq:detail_kinematics_stiffness_matrix
- Contribution of joints stiffness is here not considered [[cite:&mcinroy00_desig_contr_flexur_joint_hexap;&mcinroy02_model_desig_flexur_joint_stewar]]
\begin{equation}\label{eq:detail_kinematics_stiffness_matrix}
\bm{K} = \bm{J}^T \bm{\mathcal{K}} \bm{J}
\end{equation}
It is assumed that the stiffness of all strut is the same: $\bm{\mathcal{K}} = k \cdot \mathbf{I}_6$.
Obtained stiffness matrix linearly depends on the strut stiffness $k$ eqref:eq:detail_kinematics_stiffness_matrix_simplified.
\begin{equation}\label{eq:detail_kinematics_stiffness_matrix_simplified}
\bm{K} = k \bm{J}^T \bm{J} =
k \left[
\begin{array}{c|c}
\Sigma_{i = 0}^{6} \hat{\bm{s}}_i \cdot \hat{\bm{s}}_i^T & \Sigma_{i = 0}^{6} \bm{\hat{s}}_i \cdot ({}^A\bm{b}_i \times {}^A\hat{\bm{s}}_i)^T \\
\hline
\Sigma_{i = 0}^{6} ({}^A\bm{b}_i \times {}^A\hat{\bm{s}}_i) \cdot \hat{\bm{s}}_i^T & \Sigma_{i = 0}^{6} ({}^A\bm{b}_i \times {}^A\hat{\bm{s}}_i) \cdot ({}^A\bm{b}_i \times {}^A\hat{\bm{s}}_i)^T\\
\end{array}
\right]
\end{equation}
**** Translation Stiffness
XYZ stiffnesses:
- Only depends on the orientation of the struts and not their location: $\hat{\bm{s}}_i \cdot \hat{\bm{s}}_i^T$
- Extreme case: all struts are vertical $s_i = [0,\ 0,\ 1]$ => vertical stiffness of $6 k$, but null stiffness in X and Y directions
- If two struts along X, two struts along Y, and two struts along Z => $\hat{\bm{s}}_i \cdot \hat{\bm{s}}_i^T = 2 \bm{I}_3$
Stiffness is well distributed along directions.
This corresponds to the cubic architecture.
If struts more vertical (Figure ref:fig:detail_kinematics_stewart_mobility_vert_struts):
- increase vertical stiffness
- decrease horizontal stiffness
- increase Rx,Ry stiffness
- decrease Rz stiffness
Opposite conclusions if struts are not horizontal (Figure ref:fig:detail_kinematics_stewart_mobility_hori_struts).
**** Rotational Stiffness
Rotational stiffnesses:
- Same orientation but increased distances (bi) by a factor 2 => rotational stiffness increased by factor 4
Figure ref:fig:detail_kinematics_stewart_mobility_close_struts
Figure ref:fig:detail_kinematics_stewart_mobility_space_struts
Struts further apart:
- no change to XYZ
- increase in rotational stiffness (by the square of the distance)
**** Diagonal Stiffness Matrix
Having the stiffness matrix $\bm{K}$ diagonal can be beneficial for control purposes as it would make the plant in the cartesian frame decoupled at low frequency.
This depends on the geometry and on the chosen {A} frame.
For specific configurations, it is possible to have a diagonal K matrix.
** Dynamical properties
**** In the Cartesian Frame
Dynamical equations (both in the cartesian frame and in the frame of the struts) for the Stewart platform were derived during the conceptual phase with simplifying assumptions (massless struts and perfect joints).
# Section ref:ssec:nhexa_stewart_platform_dynamics (page pageref:ssec:nhexa_stewart_platform_dynamics).
The dynamics depends both on the geometry (Jacobian matrix) but also on the payload being placed on top of the platform.
Under very specific conditions, the equations of motion can be decoupled in the Cartesian space.
These are studied in Section ref:ssec:detail_kinematics_cubic_dynamic.
\begin{equation}\label{eq:nhexa_transfer_function_cart}
\frac{{\mathcal{X}}}{\bm{\mathcal{F}}}(s) = ( \bm{M} s^2 + \bm{J}^{T} \bm{\mathcal{C}} \bm{J} s + \bm{J}^{T} \bm{\mathcal{K}} \bm{J} )^{-1}
\end{equation}
**** In the frame of the Struts
In the frame of the struts, the equations of motion are well decoupled at low frequency.
This is why most of Stewart platforms are controlled in the frame of the struts: bellow the resonance frequency, the system is decoupled and SISO control may be applied for each strut.
\begin{equation}\label{eq:nhexa_transfer_function_struts}
\frac{\bm{\mathcal{L}}}{\bm{f}}(s) = ( \bm{J}^{-T} \bm{M} \bm{J}^{-1} s^2 + \bm{\mathcal{C}} + \bm{\mathcal{K}} )^{-1}
\end{equation}
Coupling between sensors (force sensors, relative position sensor, inertial sensors) in different struts may also be important for decentralized control.
Can the geometry be optimized to have lower coupling between the struts?
This will be studied with the cubic architecture.
**** TODO Dynamic Isotropy
[[cite:&afzali-far16_vibrat_dynam_isotr_hexap_analy_studies]]:
"*Dynamic isotropy*, leading to equal eigenfrequencies, is a powerful optimization measure."
** Conclusion
:PROPERTIES:
:UNNUMBERED: t
:END:
The effects of two changes in the manipulator's geometry, namely the position and orientation of the legs, are summarized in Table ref:tab:detail_kinematics_geometry.
These results could have been easily deduced based on some mechanical principles, but thanks to the kinematic analysis, they can be quantified.
These trade-offs give some guidelines when choosing the Stewart platform geometry.
#+name: tab:detail_kinematics_geometry
#+attr_latex: :environment tabularx :width \linewidth :align lXX
#+attr_latex: :center t :booktabs t :float t
#+caption: Effect of a change in geometry on the manipulator's stiffness, force authority and stroke
| | *legs pointing more vertically* | *legs further apart* |
|-------------------------------+---------------------------------+----------------------|
| Vertical stiffness | $\nearrow$ | $=$ |
| Horizontal stiffness | $\searrow$ | $=$ |
| Vertical rotation stiffness | $\searrow$ | $\nearrow$ |
| Horizontal rotation stiffness | $\nearrow$ | $\nearrow$ |
|-------------------------------+---------------------------------+----------------------|
| Vertical force authority | $\nearrow$ | $=$ |
| Horizontal force authority | $\searrow$ | $=$ |
| Vertical torque authority | $\searrow$ | $\nearrow$ |
| Horizontal torque authority | $\nearrow$ | $\nearrow$ |
|-------------------------------+---------------------------------+----------------------|
| Vertical stroke | $\searrow$ | $=$ |
| Horizontal stroke | $\nearrow$ | $=$ |
| Vertical rotation stroke | $\nearrow$ | $\searrow$ |
| Horizontal rotation stroke | $\searrow$ | $\searrow$ |
* The Cubic Architecture
:PROPERTIES:
:HEADER-ARGS:matlab+: :tangle matlab/detail_kinematics_2_cubic.m
:END:
<>
** Introduction :ignore:
# Cubic configuration file:~/Cloud/work-projects/ID31-NASS/matlab/stewart-simscape/org/cubic-configuration.org
The Cubic configuration for the Stewart platform was first proposed in [[cite:&geng94_six_degree_of_freed_activ]].
This configuration is quite specific in the sense that the active struts are arranged in a mutually orthogonal configuration connecting the corners of a cube Figure ref:fig:detail_kinematics_cubic_schematic.
Cubic configuration:
- The struts are corresponding to 6 of the 8 edges of a cube.
- This way, all struts are perpendicular to each other (except sets of two that are parallel).
#+begin_src latex :file detail_kinematics_cubic_schematic.pdf
\begin{tikzpicture}
\begin{scope}[rotate={45}, shift={(0, 0, -4)}]
% We first define the coordinate of the points of the Cube
\coordinate[] (bot) at (0,0,4);
\coordinate[] (top) at (4,4,0);
\coordinate[] (A1) at (0,0,0);
\coordinate[] (A2) at (4,0,4);
\coordinate[] (A3) at (0,4,4);
\coordinate[] (B1) at (4,0,0);
\coordinate[] (B2) at (4,4,4);
\coordinate[] (B3) at (0,4,0);
% Center of the Cube
\node[] (cubecenter) at ($0.5*(bot) + 0.5*(top)$){$\bullet$};
% \node[above right] at (cubecenter){$C$};
% We draw parts of the cube that corresponds to the Stewart platform
\draw[] (A1)node[]{$\bullet$} -- (B1)node[]{$\bullet$} -- (A2)node[]{$\bullet$} -- (B2)node[]{$\bullet$} -- (A3)node[]{$\bullet$} -- (B3)node[]{$\bullet$} -- (A1);
\draw[opacity=0.5] (bot) -- (A1);
\draw[opacity=0.5] (bot) -- (A2);
\draw[opacity=0.5] (bot) -- (A3);
\draw[opacity=0.5] (top) -- (B1);
\draw[opacity=0.5] (top) -- (B2);
\draw[opacity=0.5] (top) -- (B3);
% ai and bi are computed
\def\lfrom{0.1}
\def\lto{0.9}
\coordinate(a1) at ($(A1) - \lfrom*(A1) + \lfrom*(B1)$);
\coordinate(b1) at ($(A1) - \lto*(A1) + \lto*(B1)$);
\coordinate(a2) at ($(A2) - \lfrom*(A2) + \lfrom*(B1)$);
\coordinate(b2) at ($(A2) - \lto*(A2) + \lto*(B1)$);
\coordinate(a3) at ($(A2) - \lfrom*(A2) + \lfrom*(B2)$);
\coordinate(b3) at ($(A2) - \lto*(A2) + \lto*(B2)$);
\coordinate(a4) at ($(A3) - \lfrom*(A3) + \lfrom*(B2)$);
\coordinate(b4) at ($(A3) - \lto*(A3) + \lto*(B2)$);
\coordinate(a5) at ($(A3) - \lfrom*(A3) + \lfrom*(B3)$);
\coordinate(b5) at ($(A3) - \lto*(A3) + \lto*(B3)$);
\coordinate(a6) at ($(A1) - \lfrom*(A1) + \lfrom*(B3)$);
\coordinate(b6) at ($(A1) - \lto*(A1) + \lto*(B3)$);
% Center of the Stewart Platform
% \node[color=colorblue] at ($0.25*(a1) + 0.25*(a6) + 0.25*(b3) + 0.25*(b4)$){$\bullet$};
% We draw the fixed and mobiles platforms
\path[fill=colorblue, opacity=0.2] (a1) -- (a2) -- (a3) -- (a4) -- (a5) -- (a6) -- cycle;
\path[fill=colorblue, opacity=0.2] (b1) -- (b2) -- (b3) -- (b4) -- (b5) -- (b6) -- cycle;
\draw[color=colorblue, dashed] (a1) -- (a2) -- (a3) -- (a4) -- (a5) -- (a6) -- cycle;
\draw[color=colorblue, dashed] (b1) -- (b2) -- (b3) -- (b4) -- (b5) -- (b6) -- cycle;
% The legs of the hexapod are drawn
\draw[color=colorblue] (a1)node{$\bullet$} -- (b1)node{$\bullet$};
\draw[color=colorblue] (a2)node{$\bullet$} -- (b2)node{$\bullet$};
\draw[color=colorblue] (a3)node{$\bullet$} -- (b3)node{$\bullet$};
\draw[color=colorblue] (a4)node{$\bullet$} -- (b4)node{$\bullet$};
\draw[color=colorblue] (a5)node{$\bullet$} -- (b5)node{$\bullet$};
\draw[color=colorblue] (a6)node{$\bullet$} -- (b6)node{$\bullet$};
\end{scope}
% Height of the Hexapod
\coordinate[] (sizepos) at ($(a2)+(0.2, 0)$);
\coordinate[] (origin) at (0,0,0);
% \draw[<->, dashed] (a2-|sizepos) -- node[midway, right]{$H$} (b2-|sizepos);
% Height offset
% \draw[<->, dashed] (a2-|sizepos) -- node[midway, right]{$H_0$} (origin-|sizepos);
% \draw[<->, dashed] (0.5,2,0) --node[near end, right]{${}^{F}O_{C}$} ++(0,2,0);
% \draw[<->, dashed] (-2,2,0) --node[midway, right]{${}^{F}H_{A}$} ++(0,1,0);
% \draw[<->, dashed] (-2,6,0) --node[midway, right]{${}^{M}H_{B}$} ++(0,-1.5,0);
% Useful part of the cube
% \draw[<->, dashed] ($(A2)+(0.5,0)$) -- node[midway, right]{$H_{C}$} ($(B1)+(0.5,0)$);
\end{tikzpicture}
#+end_src
#+name: fig:detail_kinematics_cubic_schematic
#+caption: Stewart platform Cubic architecture. The struts are aligned with the sides of a cube.
#+RESULTS:
[[file:figs/detail_kinematics_cubic_schematic.png]]
The cubic configuration is attributed a number of properties that made this configuration widely used ([[cite:&preumont07_six_axis_singl_stage_activ;&jafari03_orthog_gough_stewar_platf_microm]]).
From [[cite:&geng94_six_degree_of_freed_activ]]:
1) Uniformity in control capability in all directions
2) Uniformity in stiffness in all directions
3) Minimum cross coupling force effect among actuators
4) Facilitate collocated sensor-actuator control system design
5) Simple kinematics relationships
6) Simple dynamic analysis
7) Simple mechanical design
According to [[cite:&preumont07_six_axis_singl_stage_activ]], it "minimizes the cross-coupling amongst actuators and sensors of different legs" (being orthogonal to each other).
Specific points of interest are:
- uniform mobility, uniform stiffness, and coupling properties
In this section:
- Such properties are studied
- Additional properties interesting for control?
- It is determined if the cubic architecture is interested for the nano-hexapod
** Matlab Init :noexport:ignore:
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
<>
#+end_src
#+begin_src matlab :exports none :results silent :noweb yes
<>
#+end_src
#+begin_src matlab :tangle no :noweb yes
<>
#+end_src
#+begin_src matlab :eval no :noweb yes
<>
#+end_src
#+begin_src matlab :noweb yes
<>
#+end_src
#+begin_src matlab :noweb yes
<>
#+end_src
** The Cubic Architecture
<>
Typical cubic architecture (Figure ref:fig:detail_kinematics_cubic_architecture_examples).
Struts with similar size than the cube's edge (Figure ref:fig:detail_kinematics_cubic_architecture_example).
Similar to Figures ref:fig:detail_kinematics_jpl, ref:fig:detail_kinematics_uw_gsp and ref:fig:detail_kinematics_uqp.
Struts smaller than the cube's edge (Figure ref:fig:detail_kinematics_cubic_architecture_example_small).
Similar to the Stewart platform of Figure ref:fig:detail_kinematics_ulb_pz.
The two stewart platform are having the same properties (stiffness matrix, when evaluated at the cube's center).
#+begin_src matlab :exports none :results none
%% Example of a typical "cubic" architecture
MO_B = -50e-3; % Position {B} with respect to {M} [m]
H = 100e-3; % Height of the Stewart platform [m]
Hc = 100e-3; % Size of the useful part of the cube [m]
FOc = H + MO_B; % Center of the cube with respect to {F}
% here positionned at the frame {B}
stewart = initializeStewartPlatform();
stewart = initializeFramesPositions(stewart, 'H', H, 'MO_B', MO_B);
stewart = generateCubicConfiguration(stewart, 'Hc', Hc, 'FOc', FOc, 'FHa', 5e-3, 'MHb', 5e-3);
stewart = computeJointsPose(stewart);
stewart = initializeStrutDynamics(stewart, 'k', 1);
stewart = initializeJointDynamics(stewart)
stewart = initializeCylindricalPlatforms(stewart, 'Fpr', 150e-3, 'Mpr', 150e-3);
stewart = initializeCylindricalStruts(stewart);
stewart = computeJacobian(stewart);
stewart = initializeStewartPose(stewart)
displayArchitecture(stewart, 'labels', false, 'frames', false);
plotCube(stewart, 'Hc', Hc, 'FOc', FOc, 'color', [0,0,0,0.5], 'link_to_struts', true);
#+end_src
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/detail_kinematics_cubic_architecture_example.pdf', 'width', 'half', 'height', 600);
#+end_src
#+begin_src matlab :exports none :results none
%% Example of a typical "cubic" architecture
MO_B = -20e-3; % Position {B} with respect to {M} [m]
H = 40e-3; % Height of the Stewart platform [m]
Hc = 100e-3; % Size of the useful part of the cube [m]
FOc = H + MO_B; % Center of the cube with respect to {F}
% here positionned at the frame {B}
stewart = initializeStewartPlatform();
stewart = initializeFramesPositions(stewart, 'H', H, 'MO_B', MO_B);
stewart = generateCubicConfiguration(stewart, 'Hc', Hc, 'FOc', FOc, 'FHa', 5e-3, 'MHb', 5e-3);
stewart = computeJointsPose(stewart);
stewart = initializeStrutDynamics(stewart, 'k', 1);
stewart = computeJacobian(stewart);
stewart = initializeCylindricalPlatforms(stewart, 'Fpr', 150e-3, 'Mpr', 150e-3);
displayArchitecture(stewart, 'labels', false, 'frames', false);
plotCube(stewart, 'Hc', Hc, 'FOc', FOc, 'color', [0,0,0,0.5], 'link_to_struts', true);
#+end_src
#+begin_src matlab :tangle no :exports results :results file none
exportFig('figs/detail_kinematics_cubic_architecture_example_small.pdf', 'width', 'half', 'height', 600);
#+end_src
#+name: fig:detail_kinematics_cubic_architecture_examples
#+caption: Caption with reference to sub figure (\subref{fig:detail_kinematics_cubic_architecture_example}) (\subref{fig:detail_kinematics_cubic_architecture_example_small})
#+attr_latex: :options [htbp]
#+begin_figure
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_cubic_architecture_example}sub caption a}
#+attr_latex: :options {0.49\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.95\linewidth
[[file:figs/detail_kinematics_cubic_architecture_example.png]]
#+end_subfigure
#+attr_latex: :caption \subcaption{\label{fig:detail_kinematics_cubic_architecture_example_small}sub caption b}
#+attr_latex: :options {0.49\textwidth}
#+begin_subfigure
#+attr_latex: :width 0.95\linewidth
[[file:figs/detail_kinematics_cubic_architecture_example_small.png]]
#+end_subfigure
#+end_figure
** Static Properties
<>
**** Uniform stiffness
First, we have to understand what is the physical meaning of the Stiffness matrix $\bm{K}$.
The Stiffness matrix links forces $\bm{f}$ and torques $\bm{n}$ applied on the mobile platform at $\{B\}$ to the displacement $\Delta\bm{\mathcal{X}}$ of the mobile platform represented by $\{B\}$ with respect to $\{A\}$:
\[ \bm{\mathcal{F}} = \bm{K} \Delta\bm{\mathcal{X}} \]
with:
- $\bm{\mathcal{F}} = [\bm{f}\ \bm{n}]^{T}$
- $\Delta\bm{\mathcal{X}} = [\delta x, \delta y, \delta z, \delta \theta_{x}, \delta \theta_{y}, \delta \theta_{z}]^{T}$
If the stiffness matrix is inversible, its inverse is the compliance matrix: $\bm{C} = \bm{K}^{-1$ and:
\[ \Delta \bm{\mathcal{X}} = C \bm{\mathcal{F}} \]
Thus, if the stiffness matrix is diagonal, the compliance matrix is also diagonal and a force (resp. torque) $\bm{\mathcal{F}}_i$ applied on the mobile platform at $\{B\}$ will induce a pure translation (resp. rotation) of the mobile platform represented by $\{B\}$ with respect to $\{A\}$.
- [ ] Frames at the center of the cube => diagonal K matrix => static decoupling in the cartesian frame (show the control architecture?)
- [ ] Frames above the top platform => non-diagonal K matrix => coupled at low frequency
- [ ] Uniform stiffness in X,Y,Z, equal to two times the actuator stiffness
Krx = Kry, but not equal to Krz
- [ ] Jacobian matrix? Any special?
The cubic architecture has indeed identical translational stiffnesses.
Therefore, the cubic architecture is special only when considering a frame located at the center of the cube.
This is not very convenient, as in the vast majority of cases, the interesting frame is located about the top platform.
#+begin_src matlab :exports none :results none
%% Cubic Architecture - Effect of the position of frame {A} and {B}
H = 100e-3; % Height of the Stewart platform [m]
Hc = 100e-3; % Size of the useful part of the cube [m]
FOc = H/2; % Center of the cube at the Stewart platform center
%% Frames {A} and {B} at the cube's center
MO_B = -50e-3; % Position {B} with respect to {M} [m]
stewart_center = initializeStewartPlatform();
stewart_center = initializeFramesPositions(stewart_center, 'H', H, 'MO_B', MO_B);
stewart_center = generateCubicConfiguration(stewart_center, 'Hc', Hc, 'FOc', FOc, 'FHa', 5e-3, 'MHb', 5e-3);
stewart_center = computeJointsPose(stewart_center);
stewart_center = initializeStrutDynamics(stewart_center, 'k', 1);
stewart_center = computeJacobian(stewart_center);
stewart_center = initializeCylindricalPlatforms(stewart_center, 'Fpr', 150e-3, 'Mpr', 150e-3);
displayArchitecture(stewart_center, 'labels', false, 'frames', true);
plotCube(stewart_center, 'Hc', Hc, 'FOc', FOc, 'color', [0,0,0,0.5], 'link_to_struts', true);
#+end_src
#+begin_src matlab :exports none :results none
%% Frames {A} and {B} offset from the cube's center
MO_B = 50e-3; % Position {B} with respect to {M} [m]
stewart_offset = initializeStewartPlatform();
stewart_offset = initializeFramesPositions(stewart_offset, 'H', H, 'MO_B', MO_B);
stewart_offset = generateCubicConfiguration(stewart_offset, 'Hc', Hc, 'FOc', FOc, 'FHa', 5e-3, 'MHb', 5e-3);
stewart_offset = computeJointsPose(stewart_offset);
stewart_offset = initializeStrutDynamics(stewart_offset, 'k', 2);
stewart_offset = computeJacobian(stewart_offset);
stewart_offset = initializeCylindricalPlatforms(stewart_offset, 'Fpr', 150e-3, 'Mpr', 150e-3);
displayArchitecture(stewart_offset, 'labels', false, 'frames', true);
plotCube(stewart_offset, 'Hc', Hc, 'FOc', FOc, 'color', [0,0,0,0.5], 'link_to_struts', true);
#+end_src
- [ ] Get the analytical formula for the Stiffness matrix?
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
data2orgtable(stewart_center.kinematics.K, {}, {}, ' %.4f ');
#+end_src
#+RESULTS:
| 2.0 | 0.0 | -0.0 | -0.0 | 0.0 | -0.0 |
|------+------+------+-------+-------+------|
| 0.0 | 2.0 | -0.0 | -0.0 | -0.0 | -0.0 |
| -0.0 | -0.0 | 2.0 | -0.0 | 0.0 | 0.0 |
| -0.0 | -0.0 | -0.0 | 0.015 | -0.0 | 0.0 |
| 0.0 | -0.0 | 0.0 | -0.0 | 0.015 | -0.0 |
| -0.0 | -0.0 | 0.0 | 0.0 | -0.0 | 0.06 |
#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*)
data2orgtable(stewart_offset.kinematics.K, {}, {}, ' %.4f ');
#+end_src
#+RESULTS:
| 2.0 | -0.0 | -0.0 | 0.0 | -0.2 | 0.0 |
|------+------+------+-------+-------+------|
| -0.0 | 2.0 | 0.0 | 0.2 | -0.0 | 0.0 |
| -0.0 | 0.0 | 2.0 | -0.0 | 0.0 | 0.0 |
| 0.0 | 0.2 | -0.0 | 0.035 | -0.0 | 0.0 |
| -0.2 | -0.0 | 0.0 | -0.0 | 0.035 | 0.0 |
| 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.06 |
Note that the cube's center needs not to be at the "center" of the Stewart platform.
This can lead to interesting architectures shown in Section ref:ssec:detail_kinematics_cubic_design.
Here are the conclusion about the Stiffness matrix for the Cubic configuration:
- The cubic configuration permits to have $k_x = k_y = k_z$ and $k_{\theta_x} = k_{\theta_y}$
- The stiffness matrix $K$ is diagonal for the cubic configuration if the Jacobian is estimated at the cube center
**** Uniform Mobility
Uniform mobility in X,Y,Z directions
Show that be obtain a cube.
Cubic configuration: "Vertical cube" with
#+begin_src matlab
%% With cubic configuration
H = 100e-3; % Height of the Stewart platform [m]
Hc = 100e-3; % Size of the useful part of the cube [m]
FOc = 50e-3; % Center of the cube at the Stewart platform center
MO_B = -50e-3; % Position {B} with respect to {M} [m]
MHb = 0;
stewart_cubic = initializeStewartPlatform();
stewart_cubic = initializeFramesPositions(stewart_cubic, 'H', H, 'MO_B', MO_B);
stewart_cubic = generateCubicConfiguration(stewart_cubic, 'Hc', Hc, 'FOc', FOc, 'FHa', 5e-3, 'MHb', MHb);
stewart_cubic = computeJointsPose(stewart_cubic);
stewart_cubic = initializeStrutDynamics(stewart_cubic, 'k', 1);
stewart_cubic = computeJacobian(stewart_cubic);
stewart_cubic = initializeCylindricalPlatforms(stewart_cubic, 'Fpr', 150e-3, 'Mpr', 150e-3);
% Let's now define the actuator stroke.
L_max = 50e-6; % [m]
#+end_src
#+begin_src matlab
thetas = linspace(0, pi, 100);
phis = linspace(0, 2*pi, 200);
rs = zeros(length(thetas), length(phis));
for i = 1:length(thetas)
for j = 1:length(phis)
Tx = sin(thetas(i))*cos(phis(j));
Ty = sin(thetas(i))*sin(phis(j));
Tz = cos(thetas(i));
dL = stewart_cubic.kinematics.J*[Tx; Ty; Tz; 0; 0; 0;]; % dL required for 1m displacement in theta/phi direction
rs(i, j) = L_max/max(abs(dL));
% rs(i, j) = max(abs([dL(dL<0)*L_min; dL(dL>=0)*L_max]));
end
end
% Get circle that fits inside the accessible space
min(min(rs))
max(max(rs))
#+end_src
#+begin_src matlab
[phi_grid, theta_grid] = meshgrid(phis, thetas);
X = 1e6 * rs .* sin(theta_grid) .* cos(phi_grid);
Y = 1e6 * rs .* sin(theta_grid) .* sin(phi_grid);
Z = 1e6 * rs .* cos(theta_grid);
figure;
s = surf(X, Y, Z, 'FaceColor', 'white');
s.EdgeColor = colors(1,:);
axis equal;
grid on;
xlabel('X Translation [$\mu$m]'); ylabel('Y Translation [$\mu$m]'); zlabel('Z Translation [$\mu$m]');
xlim(5e6*[-L_max, L_max]); ylim(5e6*[-L_max, L_max]); zlim(5e6*[-L_max, L_max]);
#+end_src
** Dynamical Decoupling
<>
**** Introduction :ignore:
[[cite:&mcinroy00_desig_contr_flexur_joint_hexap]]
In this section, we study the dynamics of the platform in the cartesian frame.
We here suppose that there is one relative motion sensor in each strut ($\delta\bm{\mathcal{L}}$ is measured) and we would like to control the position of the top platform pose $\delta \bm{\mathcal{X}}$.
Thanks to the Jacobian matrix, we can use the "architecture" shown in Figure ref:fig:detail_kinematics_local_to_cartesian_coordinates to obtain the dynamics of the system from forces/torques applied by the actuators on the top platform to translations/rotations of the top platform.
#+begin_src latex :file detail_kinematics_local_to_cartesian_coordinates.pdf
\begin{tikzpicture}
\node[block] (Jt) at (0, 0) {$\bm{J}^{-T}$};
\node[block, right= of Jt] (G) {$\bm{G}$};
\node[block, right= of G] (J) {$\bm{J}^{-1}$};
\draw[->] ($(Jt.west)+(-0.8, 0)$) -- (Jt.west) node[above left]{$\bm{\mathcal{F}}$};
\draw[->] (Jt.east) -- (G.west) node[above left]{$\bm{\tau}$};
\draw[->] (G.east) -- (J.west) node[above left]{$\delta\bm{\mathcal{L}}$};
\draw[->] (J.east) -- ++(0.8, 0) node[above left]{$\delta\bm{\mathcal{X}}$};
\end{tikzpicture}
#+end_src
#+name: fig:detail_kinematics_local_to_cartesian_coordinates
#+caption: From Strut coordinate to Cartesian coordinate using the Jacobian matrix
#+RESULTS:
[[file:figs/detail_kinematics_local_to_cartesian_coordinates.png]]
We here study the dynamics from $\bm{\mathcal{F}}$ to $\delta\bm{\mathcal{X}}$.
One has to note that when considering the static behavior:
\[ \bm{G}(s = 0) = \begin{bmatrix}
1/k_1 & & 0 \\
& \ddots & 0 \\
0 & & 1/k_6
\end{bmatrix}\]
And thus:
\[ \frac{\delta\bm{\mathcal{X}}}{\bm{\mathcal{F}}}(s = 0) = \bm{J}^{-1} \bm{G}(s = 0) \bm{J}^{-T} = \bm{K}^{-1} = \bm{C} \]
We conclude that the *static* behavior of the platform depends on the stiffness matrix.
For the cubic configuration, we have a diagonal stiffness matrix is the frames $\{A\}$ and $\{B\}$ are coincident with the cube's center.
**** Cube's center at the Center of Mass of the mobile platform
Let's create a Cubic Stewart Platform where the *Center of Mass of the mobile platform is located at the center of the cube*.
We define the size of the Stewart platform and the position of frames $\{A\}$ and $\{B\}$.
#+begin_src matlab
H = 200e-3; % height of the Stewart platform [m]
MO_B = -10e-3; % Position {B} with respect to {M} [m]
#+end_src
Now, we set the cube's parameters such that the center of the cube is coincident with $\{A\}$ and $\{B\}$.
#+begin_src matlab
Hc = 2.5*H; % Size of the useful part of the cube [m]
FOc = H + MO_B; % Center of the cube with respect to {F}
#+end_src
#+begin_src matlab
stewart = initializeStewartPlatform();
stewart = initializeFramesPositions(stewart, 'H', H, 'MO_B', MO_B);
stewart = generateCubicConfiguration(stewart, 'Hc', Hc, 'FOc', FOc, 'FHa', 25e-3, 'MHb', 25e-3);
stewart = computeJointsPose(stewart);
stewart = initializeStrutDynamics(stewart, 'k', 1e6, 'c', 1e1);
stewart = initializeJointDynamics(stewart, 'type_F', 'universal', 'type_M', 'spherical');
stewart = computeJacobian(stewart);
stewart = initializeStewartPose(stewart);
#+end_src
Now we set the geometry and mass of the mobile platform such that its center of mass is coincident with $\{A\}$ and $\{B\}$.
#+begin_src matlab
stewart = initializeCylindricalPlatforms(stewart, 'Fpr', 1.2*max(vecnorm(stewart.platform_F.Fa)), ...
'Mpm', 10, ...
'Mph', 20e-3, ...
'Mpr', 1.2*max(vecnorm(stewart.platform_M.Mb)));
#+end_src
And we set small mass for the struts.
#+begin_src matlab
stewart = initializeCylindricalStruts(stewart, 'Fsm', 1e-3, 'Msm', 1e-3);
stewart = initializeInertialSensor(stewart);
#+end_src
No flexibility below the Stewart platform and no payload.
#+begin_src matlab
ground = initializeGround('type', 'none');
payload = initializePayload('type', 'none');
controller = initializeController('type', 'open-loop');
#+end_src
The obtain geometry is shown in figure [[fig:stewart_cubic_conf_decouple_dynamics]].
#+begin_src matlab :exports none
displayArchitecture(stewart, 'labels', false, 'view', 'all');
#+end_src
#+header: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/stewart_cubic_conf_decouple_dynamics.pdf" :var figsize="full-tall" :post pdf2svg(file=*this*, ext="png")
<>
#+end_src
#+name: fig:stewart_cubic_conf_decouple_dynamics
#+caption: Geometry used for the simulations - The cube's center, the frames $\{A\}$ and $\{B\}$ and the Center of mass of the mobile platform are coincident ([[./figs/stewart_cubic_conf_decouple_dynamics.png][png]], [[./figs/stewart_cubic_conf_decouple_dynamics.pdf][pdf]])
[[file:figs/stewart_cubic_conf_decouple_dynamics.png]]
We now identify the dynamics from forces applied in each strut $\bm{\tau}$ to the displacement of each strut $d \bm{\mathcal{L}}$.
#+begin_src matlab
open('stewart_platform_model.slx')
%% Options for Linearized
options = linearizeOptions;
options.SampleTime = 0;
%% Name of the Simulink File
mdl = 'stewart_platform_model';
%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'openinput'); io_i = io_i + 1; % Actuator Force Inputs [N]
io(io_i) = linio([mdl, '/Stewart Platform'], 1, 'openoutput', [], 'dLm'); io_i = io_i + 1; % Relative Displacement Outputs [m]
%% Run the linearization
G = linearize(mdl, io, options);
G.InputName = {'F1', 'F2', 'F3', 'F4', 'F5', 'F6'};
G.OutputName = {'Dm1', 'Dm2', 'Dm3', 'Dm4', 'Dm5', 'Dm6'};
#+end_src
Now, thanks to the Jacobian (Figure [[fig:local_to_cartesian_coordinates]]), we compute the transfer function from $\bm{\mathcal{F}}$ to $\bm{\mathcal{X}}$.
#+begin_src matlab
Gc = inv(stewart.kinematics.J)*G*inv(stewart.kinematics.J');
Gc = inv(stewart.kinematics.J)*G*stewart.kinematics.J;
Gc.InputName = {'Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz'};
Gc.OutputName = {'Dx', 'Dy', 'Dz', 'Rx', 'Ry', 'Rz'};
#+end_src
The obtain dynamics $\bm{G}_{c}(s) = \bm{J}^{-T} \bm{G}(s) \bm{J}^{-1}$ is shown in Figure [[fig:stewart_cubic_decoupled_dynamics_cartesian]].
#+begin_src matlab :exports none
freqs = logspace(1, 3, 500);
figure;
ax1 = subplot(2, 2, 1);
hold on;
for i = 1:6
for j = i+1:6
plot(freqs, abs(squeeze(freqresp(Gc(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
plot(freqs, abs(squeeze(freqresp(Gc(1, 1), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc(2, 2), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc(3, 3), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
ax3 = subplot(2, 2, 3);
hold on;
for i = 1:6
for j = i+1:6
p4 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
p1 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(1, 1), freqs, 'Hz'))));
p2 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(2, 2), freqs, 'Hz'))));
p3 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(3, 3), freqs, 'Hz'))));
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]);
legend([p1, p2, p3, p4], {'$D_x/F_x$','$D_y/F_y$', '$D_z/F_z$', '$D_i/F_j$'})
ax2 = subplot(2, 2, 2);
hold on;
for i = 1:6
for j = i+1:6
plot(freqs, abs(squeeze(freqresp(Gc(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
plot(freqs, abs(squeeze(freqresp(Gc(4, 4), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc(5, 5), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc(6, 6), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
ax4 = subplot(2, 2, 4);
hold on;
for i = 1:6
for j = i+1:6
p4 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
p1 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(4, 4), freqs, 'Hz'))));
p2 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(5, 5), freqs, 'Hz'))));
p3 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(6, 6), freqs, 'Hz'))));
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]);
legend([p1, p2, p3, p4], {'$R_x/M_x$','$R_y/M_y$', '$R_z/M_z$', '$R_i/M_j$'})
linkaxes([ax1,ax2,ax3,ax4],'x');
#+end_src
#+header: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/stewart_cubic_decoupled_dynamics_cartesian.pdf" :var figsize="full-tall" :post pdf2svg(file=*this*, ext="png")
<>
#+end_src
#+name: fig:stewart_cubic_decoupled_dynamics_cartesian
#+caption: Dynamics from $\bm{\mathcal{F}}$ to $\bm{\mathcal{X}}$ ([[./figs/stewart_cubic_decoupled_dynamics_cartesian.png][png]], [[./figs/stewart_cubic_decoupled_dynamics_cartesian.pdf][pdf]])
[[file:figs/stewart_cubic_decoupled_dynamics_cartesian.png]]
It is interesting to note here that the system shown in Figure [[fig:local_to_cartesian_coordinates_bis]] also yield a decoupled system (explained in section 1.3.3 in cite:li01_simul_fault_vibrat_isolat_point).
#+begin_src latex :file local_to_cartesian_coordinates_bis.pdf
\begin{tikzpicture}
\node[block] (Jt) at (0, 0) {$\bm{J}$};
\node[block, right= of Jt] (G) {$\bm{G}$};
\node[block, right= of G] (J) {$\bm{J}^{-1}$};
\draw[->] ($(Jt.west)+(-0.8, 0)$) -- (Jt.west);
\draw[->] (Jt.east) -- (G.west) node[above left]{$\bm{\tau}$};
\draw[->] (G.east) -- (J.west) node[above left]{$\delta\bm{\mathcal{L}}$};
\draw[->] (J.east) -- ++(0.8, 0) node[above left]{$\delta\bm{\mathcal{X}}$};
\end{tikzpicture}
#+end_src
#+name: fig:local_to_cartesian_coordinates_bis
#+caption: Alternative way to decouple the system
#+RESULTS:
[[file:figs/local_to_cartesian_coordinates_bis.png]]
#+begin_important
The dynamics is well decoupled at all frequencies.
We have the same dynamics for:
- $D_x/F_x$, $D_y/F_y$ and $D_z/F_z$
- $R_x/M_x$ and $D_y/F_y$
The Dynamics from $F_i$ to $D_i$ is just a 1-dof mass-spring-damper system.
This is because the Mass, Damping and Stiffness matrices are all diagonal.
#+end_important
**** Cube's center not coincident with the Mass of the Mobile platform
Let's create a Stewart platform with a cubic architecture where the cube's center is at the center of the Stewart platform.
#+begin_src matlab
H = 200e-3; % height of the Stewart platform [m]
MO_B = -100e-3; % Position {B} with respect to {M} [m]
#+end_src
Now, we set the cube's parameters such that the center of the cube is coincident with $\{A\}$ and $\{B\}$.
#+begin_src matlab
Hc = 2.5*H; % Size of the useful part of the cube [m]
FOc = H + MO_B; % Center of the cube with respect to {F}
#+end_src
#+begin_src matlab
stewart = initializeStewartPlatform();
stewart = initializeFramesPositions(stewart, 'H', H, 'MO_B', MO_B);
stewart = generateCubicConfiguration(stewart, 'Hc', Hc, 'FOc', FOc, 'FHa', 25e-3, 'MHb', 25e-3);
stewart = computeJointsPose(stewart);
stewart = initializeStrutDynamics(stewart, 'K', 1e6*ones(6,1), 'C', 1e1*ones(6,1));
stewart = initializeJointDynamics(stewart, 'type_F', 'universal', 'type_M', 'spherical');
stewart = computeJacobian(stewart);
stewart = initializeStewartPose(stewart);
#+end_src
However, the Center of Mass of the mobile platform is *not* located at the cube's center.
#+begin_src matlab
stewart = initializeCylindricalPlatforms(stewart, 'Fpr', 1.2*max(vecnorm(stewart.platform_F.Fa)), ...
'Mpm', 10, ...
'Mph', 20e-3, ...
'Mpr', 1.2*max(vecnorm(stewart.platform_M.Mb)));
#+end_src
And we set small mass for the struts.
#+begin_src matlab
stewart = initializeCylindricalStruts(stewart, 'Fsm', 1e-3, 'Msm', 1e-3);
stewart = initializeInertialSensor(stewart);
#+end_src
No flexibility below the Stewart platform and no payload.
#+begin_src matlab
ground = initializeGround('type', 'none');
payload = initializePayload('type', 'none');
controller = initializeController('type', 'open-loop');
#+end_src
The obtain geometry is shown in figure [[fig:stewart_cubic_conf_mass_above]].
#+begin_src matlab :exports none
displayArchitecture(stewart, 'labels', false, 'view', 'all');
#+end_src
#+header: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/stewart_cubic_conf_mass_above.pdf" :var figsize="full-tall" :post pdf2svg(file=*this*, ext="png")
<>
#+end_src
#+name: fig:stewart_cubic_conf_mass_above
#+caption: Geometry used for the simulations - The cube's center is coincident with the frames $\{A\}$ and $\{B\}$ but not with the Center of mass of the mobile platform ([[./figs/stewart_cubic_conf_mass_above.png][png]], [[./figs/stewart_cubic_conf_mass_above.pdf][pdf]])
[[file:figs/stewart_cubic_conf_mass_above.png]]
We now identify the dynamics from forces applied in each strut $\bm{\tau}$ to the displacement of each strut $d \bm{\mathcal{L}}$.
#+begin_src matlab
open('stewart_platform_model.slx')
%% Options for Linearized
options = linearizeOptions;
options.SampleTime = 0;
%% Name of the Simulink File
mdl = 'stewart_platform_model';
%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'openinput'); io_i = io_i + 1; % Actuator Force Inputs [N]
io(io_i) = linio([mdl, '/Stewart Platform'], 1, 'openoutput', [], 'dLm'); io_i = io_i + 1; % Relative Displacement Outputs [m]
%% Run the linearization
G = linearize(mdl, io, options);
G.InputName = {'F1', 'F2', 'F3', 'F4', 'F5', 'F6'};
G.OutputName = {'Dm1', 'Dm2', 'Dm3', 'Dm4', 'Dm5', 'Dm6'};
#+end_src
And we use the Jacobian to compute the transfer function from $\bm{\mathcal{F}}$ to $\bm{\mathcal{X}}$.
#+begin_src matlab
Gc = inv(stewart.kinematics.J)*G*inv(stewart.kinematics.J');
Gc.InputName = {'Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz'};
Gc.OutputName = {'Dx', 'Dy', 'Dz', 'Rx', 'Ry', 'Rz'};
#+end_src
The obtain dynamics $\bm{G}_{c}(s) = \bm{J}^{-T} \bm{G}(s) \bm{J}^{-1}$ is shown in Figure [[fig:stewart_conf_coupling_mass_matrix]].
#+begin_src matlab :exports none
freqs = logspace(1, 3, 500);
figure;
ax1 = subplot(2, 2, 1);
hold on;
for i = 1:6
for j = i+1:6
plot(freqs, abs(squeeze(freqresp(Gc(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
plot(freqs, abs(squeeze(freqresp(Gc(1, 1), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc(2, 2), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc(3, 3), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
ax3 = subplot(2, 2, 3);
hold on;
for i = 1:6
for j = i+1:6
p4 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
p1 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(1, 1), freqs, 'Hz'))));
p2 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(2, 2), freqs, 'Hz'))));
p3 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(3, 3), freqs, 'Hz'))));
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]);
legend([p1, p2, p3, p4], {'$D_x/F_x$','$D_y/F_y$', '$D_z/F_z$', '$D_i/F_j$'})
ax2 = subplot(2, 2, 2);
hold on;
for i = 1:6
for j = i+1:6
plot(freqs, abs(squeeze(freqresp(Gc(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
plot(freqs, abs(squeeze(freqresp(Gc(4, 4), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc(5, 5), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gc(6, 6), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
ax4 = subplot(2, 2, 4);
hold on;
for i = 1:6
for j = i+1:6
p4 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
p1 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(4, 4), freqs, 'Hz'))));
p2 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(5, 5), freqs, 'Hz'))));
p3 = plot(freqs, 180/pi*angle(squeeze(freqresp(Gc(6, 6), freqs, 'Hz'))));
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]);
legend([p1, p2, p3, p4], {'$R_x/M_x$','$R_y/M_y$', '$R_z/M_z$', '$R_i/M_j$'})
linkaxes([ax1,ax2,ax3,ax4],'x');
#+end_src
#+header: :tangle no :exports results :results none :noweb yes
#+begin_src matlab :var filepath="figs/stewart_conf_coupling_mass_matrix.pdf" :var figsize="full-tall" :post pdf2svg(file=*this*, ext="png")
<>
#+end_src
#+name: fig:stewart_conf_coupling_mass_matrix
#+caption: Obtained Dynamics from $\bm{\mathcal{F}}$ to $\bm{\mathcal{X}}$ ([[./figs/stewart_conf_coupling_mass_matrix.png][png]], [[./figs/stewart_conf_coupling_mass_matrix.pdf][pdf]])
[[file:figs/stewart_conf_coupling_mass_matrix.png]]
#+begin_important
The system is decoupled at low frequency (the Stiffness matrix being diagonal), but it is *not* decoupled at all frequencies.
This was expected as the mass matrix is not diagonal (the Center of Mass of the mobile platform not being coincident with the frame $\{B\}$).
#+end_important
**** Dynamic isotropy
[[cite:&afzali-far16_vibrat_dynam_isotr_hexap_analy_studies]]:
- proposes an architecture where the CoM can be above the top platform
- [ ] Try to find a stewart platform an a payload for witch all resonances are equal.
Massless struts and plates.
Cylindrical payload tuned to obtained such property.
Show that all modes can be optimally damped?
Compare with Stewart platform with different resonance frequencies. Also need to have parallel stiffness with the struts
- Same resonance frequencies for suspension modes?
Maybe in one case: sphere at the CoM?
Could be nice to show that.
Say that this can be nice for optimal damping for instance (link to paper explaining that)
- Show examples where the dynamics can indeed be decoupled in the cartesian frame (i.e. decoupled K and M matrices)
**** Conclusion
- Better decoupling between the struts? Next section
Some conclusions can be drawn from the above analysis:
- Static Decoupling <=> Diagonal Stiffness matrix <=> {A} and {B} at the cube's center
- Dynamic Decoupling <=> Static Decoupling + CoM of mobile platform coincident with {A} and {B}.
** TODO Decentralized Control
**** Introduction :ignore:
From [[cite:preumont07_six_axis_singl_stage_activ]], the cubic configuration "/minimizes the cross-coupling amongst actuators and sensors of different legs (being orthogonal to each other)/".
This would facilitate the use of decentralized control.
In this section, we wish to study such properties of the cubic architecture.
We will compare the transfer function from sensors to actuators in each strut for a cubic architecture and for a non-cubic architecture (where the struts are not orthogonal with each other).
**** Cubic Architecture
Let's generate a Cubic architecture where the cube's center and the frames $\{A\}$ and $\{B\}$ are coincident.
#+begin_src matlab
H = 200e-3; % height of the Stewart platform [m]
MO_B = -10e-3; % Position {B} with respect to {M} [m]
Hc = 2.5*H; % Size of the useful part of the cube [m]
FOc = H + MO_B; % Center of the cube with respect to {F}
#+end_src
#+begin_src matlab
stewart = initializeStewartPlatform();
stewart = initializeFramesPositions(stewart, 'H', H, 'MO_B', MO_B);
stewart = generateCubicConfiguration(stewart, 'Hc', Hc, 'FOc', FOc, 'FHa', 25e-3, 'MHb', 25e-3);
stewart = computeJointsPose(stewart);
stewart = initializeStrutDynamics(stewart, 'k', 1e6, 'c', 1e1);
stewart = initializeJointDynamics(stewart, 'type_F', 'universal', 'type_M', 'spherical');
stewart = computeJacobian(stewart);
stewart = initializeStewartPose(stewart);
stewart = initializeCylindricalPlatforms(stewart, 'Fpr', 1.2*max(vecnorm(stewart.platform_F.Fa)), ...
'Mpm', 10, ...
'Mph', 20e-3, ...
'Mpr', 1.2*max(vecnorm(stewart.platform_M.Mb)));
stewart = initializeCylindricalStruts(stewart, 'Fsm', 1e-3, 'Msm', 1e-3);
stewart = initializeInertialSensor(stewart);
#+end_src
No flexibility below the Stewart platform and no payload.
#+begin_src matlab
ground = initializeGround('type', 'none');
payload = initializePayload('type', 'none');
controller = initializeController('type', 'open-loop');
#+end_src
#+begin_src matlab
disturbances = initializeDisturbances();
references = initializeReferences(stewart);
#+end_src
#+begin_src matlab :exports none
displayArchitecture(stewart, 'labels', false, 'view', 'all');
#+end_src
And we identify the dynamics from the actuator forces $\tau_{i}$ to the relative motion sensors $\delta \mathcal{L}_{i}$ (Figure [[fig:coupling_struts_relative_sensor_cubic]]) and to the force sensors $\tau_{m,i}$ (Figure [[fig:coupling_struts_force_sensor_cubic]]).
#+begin_src matlab :exports none
open('stewart_platform_model.slx')
%% Options for Linearized
options = linearizeOptions;
options.SampleTime = 0;
%% Name of the Simulink File
mdl = 'stewart_platform_model';
%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'openinput'); io_i = io_i + 1; % Actuator Force Inputs [N]
io(io_i) = linio([mdl, '/Stewart Platform'], 1, 'openoutput', [], 'dLm'); io_i = io_i + 1; % Relative Displacement Outputs [m]
%% Run the linearization
G = linearize(mdl, io, options);
G.InputName = {'F1', 'F2', 'F3', 'F4', 'F5', 'F6'};
G.OutputName = {'Dm1', 'Dm2', 'Dm3', 'Dm4', 'Dm5', 'Dm6'};
#+end_src
#+begin_src matlab :exports none
freqs = logspace(1, 3, 1000);
figure;
ax1 = subplot(2, 1, 1);
hold on;
for i = 1:6
for j = i+1:6
plot(freqs, abs(squeeze(freqresp(G(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
plot(freqs, abs(squeeze(freqresp(G(1, 1), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
ax3 = subplot(2, 1, 2);
hold on;
for i = 1:6
for j = i+1:6
p2 = plot(freqs, 180/pi*angle(squeeze(freqresp(G(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
p1 = plot(freqs, 180/pi*angle(squeeze(freqresp(G(1, 1), freqs, 'Hz'))));
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]);
legend([p1, p2], {'$L_i/\tau_i$', '$L_i/\tau_j$'})
linkaxes([ax1,ax2],'x');
#+end_src
#+begin_src matlab :exports none
%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'openinput'); io_i = io_i + 1; % Actuator Force Inputs [N]
io(io_i) = linio([mdl, '/Stewart Platform'], 1, 'openoutput', [], 'Taum'); io_i = io_i + 1; % Force Sensor Outputs [N]
%% Run the linearization
G = linearize(mdl, io, options);
G.InputName = {'F1', 'F2', 'F3', 'F4', 'F5', 'F6'};
G.OutputName = {'Fm1', 'Fm2', 'Fm3', 'Fm4', 'Fm5', 'Fm6'};
#+end_src
#+begin_src matlab :exports none
freqs = logspace(1, 3, 500);
figure;
ax1 = subplot(2, 1, 1);
hold on;
for i = 1:6
for j = i+1:6
plot(freqs, abs(squeeze(freqresp(G(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
plot(freqs, abs(squeeze(freqresp(G(1, 1), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [N/N]'); set(gca, 'XTickLabel',[]);
ax3 = subplot(2, 1, 2);
hold on;
for i = 1:6
for j = i+1:6
p2 = plot(freqs, 180/pi*angle(squeeze(freqresp(G(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
p1 = plot(freqs, 180/pi*angle(squeeze(freqresp(G(1, 1), freqs, 'Hz'))));
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]);
legend([p1, p2], {'$F_{m,i}/\tau_i$', '$F_{m,i}/\tau_j$'})
linkaxes([ax1,ax2],'x');
#+end_src
**** Non-Cubic Architecture
Now we generate a Stewart platform which is not cubic but with approximately the same size as the previous cubic architecture.
#+begin_src matlab
H = 200e-3; % height of the Stewart platform [m]
MO_B = -10e-3; % Position {B} with respect to {M} [m]
#+end_src
#+begin_src matlab
stewart = initializeStewartPlatform();
stewart = initializeFramesPositions(stewart, 'H', H, 'MO_B', MO_B);
stewart = generateGeneralConfiguration(stewart, 'FR', 250e-3, 'MR', 150e-3);
stewart = computeJointsPose(stewart);
stewart = initializeStrutDynamics(stewart, 'k', 1e6, 'c', 1e1);
stewart = initializeJointDynamics(stewart, 'type_F', 'universal', 'type_M', 'spherical');
stewart = computeJacobian(stewart);
stewart = initializeStewartPose(stewart);
stewart = initializeCylindricalPlatforms(stewart, 'Fpr', 1.2*max(vecnorm(stewart.platform_F.Fa)), ...
'Mpm', 10, ...
'Mph', 20e-3, ...
'Mpr', 1.2*max(vecnorm(stewart.platform_M.Mb)));
stewart = initializeCylindricalStruts(stewart, 'Fsm', 1e-3, 'Msm', 1e-3);
stewart = initializeInertialSensor(stewart);
#+end_src
No flexibility below the Stewart platform and no payload.
#+begin_src matlab
ground = initializeGround('type', 'none');
payload = initializePayload('type', 'none');
controller = initializeController('type', 'open-loop');
#+end_src
#+begin_src matlab :exports none
displayArchitecture(stewart, 'labels', false, 'view', 'all');
#+end_src
And we identify the dynamics from the actuator forces $\tau_{i}$ to the relative motion sensors $\delta \mathcal{L}_{i}$ (Figure [[fig:coupling_struts_relative_sensor_non_cubic]]) and to the force sensors $\tau_{m,i}$ (Figure [[fig:coupling_struts_force_sensor_non_cubic]]).
#+begin_src matlab :exports none
open('stewart_platform_model.slx')
%% Options for Linearized
options = linearizeOptions;
options.SampleTime = 0;
%% Name of the Simulink File
mdl = 'stewart_platform_model';
%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'openinput'); io_i = io_i + 1; % Actuator Force Inputs [N]
io(io_i) = linio([mdl, '/Stewart Platform'], 1, 'openoutput', [], 'dLm'); io_i = io_i + 1; % Relative Displacement Outputs [m]
%% Run the linearization
G = linearize(mdl, io, options);
G.InputName = {'F1', 'F2', 'F3', 'F4', 'F5', 'F6'};
G.OutputName = {'Dm1', 'Dm2', 'Dm3', 'Dm4', 'Dm5', 'Dm6'};
#+end_src
#+begin_src matlab :exports none
freqs = logspace(1, 3, 1000);
figure;
ax1 = subplot(2, 1, 1);
hold on;
for i = 1:6
for j = i+1:6
plot(freqs, abs(squeeze(freqresp(G(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
plot(freqs, abs(squeeze(freqresp(G(1, 1), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [m/N]'); set(gca, 'XTickLabel',[]);
ax3 = subplot(2, 1, 2);
hold on;
for i = 1:6
for j = i+1:6
p2 = plot(freqs, 180/pi*angle(squeeze(freqresp(G(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
p1 = plot(freqs, 180/pi*angle(squeeze(freqresp(G(1, 1), freqs, 'Hz'))));
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]);
legend([p1, p2], {'$L_i/\tau_i$', '$L_i/\tau_j$'})
linkaxes([ax1,ax2],'x');
#+end_src
#+begin_src matlab :exports none
%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Controller'], 1, 'openinput'); io_i = io_i + 1; % Actuator Force Inputs [N]
io(io_i) = linio([mdl, '/Stewart Platform'], 1, 'openoutput', [], 'Taum'); io_i = io_i + 1; % Force Sensor Outputs [N]
%% Run the linearization
G = linearize(mdl, io, options);
G.InputName = {'F1', 'F2', 'F3', 'F4', 'F5', 'F6'};
G.OutputName = {'Fm1', 'Fm2', 'Fm3', 'Fm4', 'Fm5', 'Fm6'};
#+end_src
#+begin_src matlab :exports none
freqs = logspace(1, 3, 500);
figure;
ax1 = subplot(2, 1, 1);
hold on;
for i = 1:6
for j = i+1:6
plot(freqs, abs(squeeze(freqresp(G(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
plot(freqs, abs(squeeze(freqresp(G(1, 1), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude [N/N]'); set(gca, 'XTickLabel',[]);
ax3 = subplot(2, 1, 2);
hold on;
for i = 1:6
for j = i+1:6
p2 = plot(freqs, 180/pi*angle(squeeze(freqresp(G(i, j), freqs, 'Hz'))), 'k-');
end
end
set(gca,'ColorOrderIndex',1);
p1 = plot(freqs, 180/pi*angle(squeeze(freqresp(G(1, 1), freqs, 'Hz'))));
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]);
legend([p1, p2], {'$F_{m,i}/\tau_i$', '$F_{m,i}/\tau_j$'})
linkaxes([ax1,ax2],'x');
#+end_src
**** Conclusion
The Cubic architecture seems to not have any significant effect on the coupling between actuator and sensors of each strut and thus provides no advantages for decentralized control.
** Cubic architecture with Cube's center above the top platform
<>
**** Introduction :ignore:
We saw in section ref:ssec:detail_kinematics_cubic_static that in order to have a diagonal stiffness matrix, the cube's center needs to be located at frames $\{A\}$ and $\{B\}$.
Or, typically $\{A\}$ and $\{B\}$ are located above the top platform where forces are applied and where displacements are expressed.
Say a 100mm tall Stewart platform needs to be designed with the CoM of the payload 20mm above the top platform.
The cube's center therefore needs to be positioned 20mm above the top platform.
The obtained design depends on the considered size of the cube
#+begin_src matlab
%% Cubic configurations with center of the cube above the top platform
H = 100e-3; % height of the Stewart platform [m]
MO_B = 20e-3; % Position {B} with respect to {M} [m]
FOc = H + MO_B; % Center of the cube with respect to {F}
#+end_src
**** Small cube
Similar to [[cite:&furutani04_nanom_cuttin_machin_using_stewar]], even though it is not mentioned that the system has a cubic configuration.
# TODO - Add link to Figure ref:fig:nhexa_stewart_piezo_furutani (page pageref:fig:nhexa_stewart_piezo_furutani)
#+begin_src matlab
%% Small cube
Hc = 2*MO_B; % Size of the useful part of the cube [m]
stewart = initializeStewartPlatform();
stewart = initializeFramesPositions(stewart, 'H', H, 'MO_B', MO_B);
stewart = generateCubicConfiguration(stewart, 'Hc', Hc, 'FOc', FOc, 'FHa', 5e-3, 'MHb', 5e-3);
stewart = computeJointsPose(stewart);
stewart = initializeStrutDynamics(stewart, 'k', 1);
stewart = computeJacobian(stewart);
stewart = initializeCylindricalPlatforms(stewart, 'Fpr', 1.1*max(vecnorm(stewart.platform_F.Fa)), 'Mpr', 1.1*max(vecnorm(stewart.platform_M.Mb)));
#+end_src
#+begin_src matlab :exports none :results none
%% Example of a cubic architecture with cube's center above the top platform - Small cube size
displayArchitecture(stewart, 'labels', false, 'frames', false);
plotCube(stewart, 'Hc', Hc, 'FOc', FOc, 'color', [0,0,0,0.5], 'link_to_struts', true);
scatter3(0, 0, FOc, 200, 'kh');
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/detail_kinematics_cubic_above_small.pdf', 'width', 'wide', 'height', 'normal');
#+end_src
#+name: fig:detail_kinematics_cubic_above_small
#+caption: Example of a cubic architecture with cube's center above the top platform - Small cube size
#+RESULTS:
[[file:figs/detail_kinematics_cubic_above_small.png]]
**** Medium sized cube
Similar to cite:yang19_dynam_model_decoup_contr_flexib (Figure ref:fig:detail_kinematics_yang19)
#+begin_src matlab :exports none :results none
%% Example of a cubic architecture with cube's center above the top platform - Medium cube size
Hc = H + 2*MO_B; % Size of the useful part of the cube [m]
stewart = initializeStewartPlatform();
stewart = initializeFramesPositions(stewart, 'H', H, 'MO_B', MO_B);
stewart = generateCubicConfiguration(stewart, 'Hc', Hc, 'FOc', FOc, 'FHa', 5e-3, 'MHb', 5e-3);
stewart = computeJointsPose(stewart);
stewart = initializeStrutDynamics(stewart, 'k', 1);
stewart = computeJacobian(stewart);
stewart = initializeCylindricalPlatforms(stewart, 'Fpr', 1.1*max(vecnorm(stewart.platform_F.Fa)), 'Mpr', 1.1*max(vecnorm(stewart.platform_M.Mb)));
displayArchitecture(stewart, 'labels', false, 'frames', false);
plotCube(stewart, 'Hc', Hc, 'FOc', FOc, 'color', [0,0,0,0.5], 'link_to_struts', true);
scatter3(0, 0, FOc, 200, 'kh');
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/detail_kinematics_cubic_above_medium.pdf', 'width', 'wide', 'height', 'normal');
#+end_src
#+name: fig:detail_kinematics_cubic_above_medium
#+caption: Example of a cubic architecture with cube's center above the top platform - Medium cube size
#+RESULTS:
[[file:figs/detail_kinematics_cubic_above_medium.png]]
**** Large cube
#+begin_src matlab :exports none :results none
%% Example of a cubic architecture with cube's center above the top platform - Large cube size
Hc = 2*(H + MO_B); % Size of the useful part of the cube [m]
stewart = initializeStewartPlatform();
stewart = initializeFramesPositions(stewart, 'H', H, 'MO_B', MO_B);
stewart = generateCubicConfiguration(stewart, 'Hc', Hc, 'FOc', FOc, 'FHa', 5e-3, 'MHb', 5e-3);
stewart = computeJointsPose(stewart);
stewart = initializeStrutDynamics(stewart, 'k', 1);
stewart = computeJacobian(stewart);
stewart = initializeCylindricalPlatforms(stewart, 'Fpr', 1.1*max(vecnorm(stewart.platform_F.Fa)), 'Mpr', 1.1*max(vecnorm(stewart.platform_M.Mb)));
displayArchitecture(stewart, 'labels', false, 'frames', false);
plotCube(stewart, 'Hc', Hc, 'FOc', FOc, 'color', [0,0,0,0.5], 'link_to_struts', true);
scatter3(0, 0, FOc, 200, 'kh');
#+end_src
#+begin_src matlab :tangle no :exports results :results file replace
exportFig('figs/detail_kinematics_cubic_above_large.pdf', 'width', 'wide', 'height', 'normal');
#+end_src
#+name: fig:detail_kinematics_cubic_above_large
#+caption: Example of a cubic architecture with cube's center above the top platform - Large cube size
#+RESULTS:
[[file:figs/detail_kinematics_cubic_above_large.png]]
**** TODO Required size of the platforms
The minimum size of the platforms depends on the cube's size and the height between the platform and the cube's center.
Let's denote:
- $H$ the height between the cube's center and the considered platform
- $D$ the size of the cube's edges
Let's denote by $a$ and $b$ the points of both ends of one of the cube's edge.
Initially, we have:
\begin{align}
a &= \frac{D}{2} \begin{bmatrix}-1 \\ -1 \\ 1\end{bmatrix} \\
b &= \frac{D}{2} \begin{bmatrix} 1 \\ -1 \\ 1\end{bmatrix}
\end{align}
We rotate the cube around its center (origin of the rotated frame) such that one of its diagonal is vertical.
\[ R = \begin{bmatrix}
\frac{2}{\sqrt{6}} & 0 & \frac{1}{\sqrt{3}} \\
\frac{-1}{\sqrt{6}} & \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{3}} \\
\frac{-1}{\sqrt{6}} & \frac{-1}{\sqrt{2}} & \frac{1}{\sqrt{3}}
\end{bmatrix} \]
After rotation, the points $a$ and $b$ become:
\begin{align}
a &= \frac{D}{2} \begin{bmatrix}-\frac{\sqrt{2}}{\sqrt{3}} \\ -\sqrt{2} \\ -\frac{1}{\sqrt{3}}\end{bmatrix} \\
b &= \frac{D}{2} \begin{bmatrix} \frac{\sqrt{2}}{\sqrt{3}} \\ -\sqrt{2} \\ \frac{1}{\sqrt{3}}\end{bmatrix}
\end{align}
Points $a$ and $b$ define a vector $u = b - a$ that gives the orientation of one of the Stewart platform strut:
\[ u = \frac{D}{\sqrt{3}} \begin{bmatrix} -\sqrt{2} \\ 0 \\ -1\end{bmatrix} \]
Then we want to find the intersection between the line that defines the strut with the plane defined by the height $H$ from the cube's center.
To do so, we first find $g$ such that:
\[ a_z + g u_z = -H \]
We obtain:
\begin{align}
g &= - \frac{H + a_z}{u_z} \\
&= \sqrt{3} \frac{H}{D} - \frac{1}{2}
\end{align}
Then, the intersection point $P$ is given by:
\begin{align}
P &= a + g u \\
&= \begin{bmatrix}
H \sqrt{2} \\
D \frac{1}{\sqrt{2}} \\
H
\end{bmatrix}
\end{align}
Finally, the circle can contains the intersection point has a radius $r$:
\begin{align}
r &= \sqrt{P_x^2 + P_y^2} \\
&= \sqrt{2 H^2 + \frac{1}{2}D^2}
\end{align}
By symmetry, we can show that all the other intersection points will also be on the circle with a radius $r$.
For a small cube:
\[ r \approx \sqrt{2} H \]
**** Conclusion
For each of the configuration, the Stiffness matrix is diagonal with $k_x = k_y = k_y = 2k$ with $k$ is the stiffness of each strut.
However, the rotational stiffnesses are increasing with the cube's size but the required size of the platform is also increasing, so there is a trade-off here.
We found that we can have a diagonal stiffness matrix using the cubic architecture when $\{A\}$ and $\{B\}$ are located above the top platform.
Depending on the cube's size, we obtain 3 different configurations.
** Conclusion
:PROPERTIES:
:UNNUMBERED: t
:END:
* Nano Hexapod :noexport:
:PROPERTIES:
:HEADER-ARGS:matlab+: :tangle matlab/detail_kinematics_3_nano_hexapod.m
:END:
<>
** Introduction :ignore:
For the NASS, the chosen frame $\{A\}$ and $\{B\}$ coincide with the sample's point of interest, which is $150\,mm$ above the top platform.
Requirements:
- The nano-hexapod should fit within a cylinder with radius of $120\,mm$ and with a height of $95\,mm$.
- In terms of mobility: uniform mobility in XYZ directions (100um)
- In terms of stiffness: ??
- In terms of dynamics:
- be able to apply IFF in a decentralized way with good robustness and performances (good damping of modes)
- good decoupling for the HAC
For the NASS, the payloads can have various inertia, with masses ranging from 1 to 50kg.
It is therefore not possible to have one geometry that gives good dynamical properties for all the payloads.
** Matlab Init :noexport:ignore:
#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name)
<>
#+end_src
#+begin_src matlab :exports none :results silent :noweb yes
<>
#+end_src
#+begin_src matlab :tangle no :noweb yes
<>
#+end_src
#+begin_src matlab :eval no :noweb yes
<>
#+end_src
#+begin_src matlab :noweb yes
<>
#+end_src
#+begin_src matlab :noweb yes
<>
#+end_src
** Obtained Geometry
Take both platforms at maximum size.
Make reasonable choice (close to the final choice).
Say that it is good enough to make all the calculations.
The geometry will be slightly refined during the detailed mechanical design for several reason: easy of mount, manufacturability, ...
#+begin_src matlab
%% Obtained Nano Hexapod Design
nano_hexapod = initializeStewartPlatform();
nano_hexapod = initializeFramesPositions(nano_hexapod, ...
'H', 95e-3, ...
'MO_B', 150e-3);
nano_hexapod = generateGeneralConfiguration(nano_hexapod, ...
'FH', 15e-3, ...
'FR', 120e-3, ...
'FTh', [220, 320, 340, 80, 100, 200]*(pi/180), ...
'MH', 15e-3, ...
'MR', 110e-3, ...
'MTh', [255, 285, 15, 45, 135, 165]*(pi/180));
nano_hexapod = computeJointsPose(nano_hexapod);
nano_hexapod = initializeStrutDynamics(nano_hexapod, 'k', 1);
nano_hexapod = computeJacobian(nano_hexapod);
nano_hexapod = initializeCylindricalPlatforms(nano_hexapod, 'Fpr', 130e-3, 'Mpr', 120e-3);
displayArchitecture(nano_hexapod, 'labels', true);
#+end_src
- [ ] Show the obtained geometry and the main parameters.
This geometry will be used for:
- estimate required actuator stroke
- estimate flexible joint stroke
- when performing noise budgeting for the choice of instrumentation
- for control purposes
It is only when the complete mechanical design is finished (Section ...), that the model will be updated.
** Actuator required stroke
The actuator stroke to have the wanted mobility is computed.
Wanted mobility:
- Combined translations in the xyz directions of +/-50um (basically "cube")
- At any point of the cube, be able to do combined Rx and Ry rotations of +/-50urad
- Rz is always at 0
- Say that it is frame B with respect to frame A, but it is motion expressed at the point of interest (at the focus point of the light)
First the minimum actuator stroke to have the wanted mobility is computed.
With the chosen geometry, an actuator stroke of +/-94um is found.
#+begin_src matlab
max_translation = 50e-6;
max_rotation = 50e-6;
Dxs = linspace(-max_translation, max_translation, 3);
Dys = linspace(-max_translation, max_translation, 3);
Dzs = linspace(-max_translation, max_translation, 3);
Rxs = linspace(-max_rotation, max_rotation, 3);
Rys = linspace(-max_rotation, max_rotation, 3);
L_min = 0;
L_max = 0;
for Dx = Dxs
for Dy = Dys
for Dz = Dzs
for Rx = Rxs
for Ry = Rys
ARB = [ cos(Ry) 0 sin(Ry);
0 1 0;
-sin(Ry) 0 cos(Ry)] * ...
[ 1 0 0;
0 cos(Rx) -sin(Rx);
0 sin(Rx) cos(Rx)];
[~, Ls] = inverseKinematics(nano_hexapod, 'AP', [Dx;Dy;Dz], 'ARB', ARB);
if min(Ls) < L_min
L_min = min(Ls);
end
if max(Ls) > L_max
L_max = max(Ls);
end
end
end
end
end
end
sprintf('Actuator stroke should be from %.0f um to %.0f um', 1e6*L_min, 1e6*L_max)
#+end_src
Considering combined rotations and translations, the wanted mobility and the obtained mobility of the Nano hexapod are shown in Figure ...
It can be seen that just wanted mobility (displayed as a cube), just fits inside the obtained mobility.
Here the worst case scenario is considered, meaning that whatever the angular position in Rx and Ry (in the range +/-50urad), the top platform can be positioned anywhere inside the cube.
#+begin_src matlab
%% Compute mobility in translation with combined angular motion
% L_max = 100e-6; % Actuator Stroke (+/-)
% Direction of motion (spherical coordinates)
thetas = linspace(0, pi, 100);
phis = linspace(0, 2*pi, 100);
% Considered Rotations
Rxs = linspace(-max_rotation, max_rotation, 3);
Rys = linspace(-max_rotation, max_rotation, 3);
% Maximum distance that can be reached in the direction of motion
% Considering combined angular motion and limited actuator stroke
rs = zeros(length(thetas), length(phis));
worst_rx_ry = zeros(length(thetas), length(phis), 2);
for i = 1:length(thetas)
for j = 1:length(phis)
% Compute unitary motion in the considered direction
Tx = sin(thetas(i))*cos(phis(j));
Ty = sin(thetas(i))*sin(phis(j));
Tz = cos(thetas(i));
% Start without considering rotations
dL_lin = nano_hexapod.kinematics.J*[Tx; Ty; Tz; 0; 0; 0];
% Strut motion for maximum displacement in the considered direction
dL_lin_max = L_max*dL_lin/max(abs(dL_lin));
% Find rotation that gives worst case stroke
dL_worst = max(abs(dL_lin_max)); % This should be equal to L_max
dL_rot_max = zeros(6,1);
% Perform (small) rotations, and find the (worst) case requiring maximum strut motion
for Rx = Rxs
for Ry = Rys
dL_rot = nano_hexapod.kinematics.J*[0; 0; 0; Rx; Ry; 0];
if max(abs(dL_lin_max + dL_rot)) > dL_worst
dL_worst = max(abs(dL_lin_max + dL_rot));
dL_rot_max = dL_rot;
worst_rx_ry(i,j,:) = [Rx, Ry];
end
end
end
stroke_ratio = min(abs([( L_max - dL_rot_max) ./ dL_lin_max; (-L_max - dL_rot_max) ./ dL_lin_max]));
dL_real = dL_lin_max*stroke_ratio + dL_rot_max;
% % Obtained maximum displacement in the considered direction with angular motion
% rs(i, j) = stroke_ratio*max(abs(dL_lin_max));
rs(i, j) = stroke_ratio*L_max/max(abs(dL_lin));
end
end
min(min(rs))
max(max(rs))
[phi_grid, theta_grid] = meshgrid(phis, thetas);
X = 1e6 * rs .* sin(theta_grid) .* cos(phi_grid);
Y = 1e6 * rs .* sin(theta_grid) .* sin(phi_grid);
Z = 1e6 * rs .* cos(theta_grid);
vertices = 1e6*max_translation*[
-1 -1 -1; % vertex 1
1 -1 -1; % vertex 2
1 1 -1; % vertex 3
-1 1 -1; % vertex 4
-1 -1 1; % vertex 5
1 -1 1; % vertex 6
1 1 1; % vertex 7
-1 1 1 % vertex 8
];
% Define the faces using the vertex indices
faces = [
1 2 3 4; % bottom face
5 6 7 8; % top face
1 2 6 5; % front face
2 3 7 6; % right face
3 4 8 7; % back face
4 1 5 8 % left face
];
figure;
hold on;
s = surf(X, Y, Z, 'FaceColor', 'none');
s.EdgeColor = colors(2, :);
patch('Vertices', vertices, 'Faces', faces, ...
'FaceColor', [0.7 0.7 0.7], ...
'EdgeColor', 'black', ...
'FaceAlpha', 1);
hold off;
axis equal;
grid on;
xlabel('X Translation [$\mu$m]'); ylabel('Y Translation [$\mu$m]'); zlabel('Z Translation [$\mu$m]');
xlim(2e6*[-L_max, L_max]); ylim(2e6*[-L_max, L_max]); zlim(2e6*[-L_max, L_max]);
#+end_src
Therefore, in Section ..., the specification for actuator stroke is +/-100um
** Joint angular stroke
Now that the mobility of the Stewart platform is know, the corresponding flexible joint stroke can be estimated.
- conclude on the required joint angle: 1mrad?
Will be used to design flexible joints.
#+begin_src matlab
%% Estimation of the required flexible joint angular stroke
max_angles = zeros(1,6);
% Compute initial strut orientation
nano_hexapod = computeJointsPose(nano_hexapod, 'AP', zeros(3,1), 'ARB', eye(3));
As = nano_hexapod.geometry.As;
% Only consider translations, but add maximum expected top platform rotation
for i = 1:length(thetas)
for j = 1:length(phis)
% Maximum translations
Tx = rs(i,j)*sin(thetas(i))*cos(phis(j));
Ty = rs(i,j)*sin(thetas(i))*sin(phis(j));
Tz = rs(i,j)*cos(thetas(i));
nano_hexapod = computeJointsPose(nano_hexapod, 'AP', [Tx; Ty; Tz], 'ARB', eye(3));
angles = acos(dot(As, nano_hexapod.geometry.As));
larger_angles = abs(angles) > max_angles;
max_angles(larger_angles) = angles(larger_angles);
end
end
sprintf('Maximum flexible joint angle is %.1f mrad', 1e3*max(max_angles))
#+end_src
* Conclusion
<>
Inertia used for experiments will be very broad => difficult to optimize the dynamics
Specific geometry is not found to have a huge impact on performances.
Practical implementation is important.
Geometry impacts the static and dynamical characteristics of the Stewart platform.
Considering the design constrains, the slight change of geometry will not significantly impact the obtained results.
* Bibliography :ignore:
#+latex: \printbibliography[heading=bibintoc,title={Bibliography}]
* Matlab Functions :noexport:
** =generateCubicConfiguration=: Generate a Cubic Configuration
#+begin_src matlab :tangle matlab/src/generateCubicConfiguration.m :comments none :mkdirp yes :eval no
function [stewart] = generateCubicConfiguration(stewart, args)
% generateCubicConfiguration - Generate a Cubic Configuration
%
% Syntax: [stewart] = generateCubicConfiguration(stewart, args)
%
% Inputs:
% - stewart - A structure with the following fields
% - geometry.H [1x1] - Total height of the platform [m]
% - args - Can have the following fields:
% - Hc [1x1] - Height of the "useful" part of the cube [m]
% - FOc [1x1] - Height of the center of the cube with respect to {F} [m]
% - FHa [1x1] - Height of the plane joining the points ai with respect to the frame {F} [m]
% - MHb [1x1] - Height of the plane joining the points bi with respect to the frame {M} [m]
%
% Outputs:
% - stewart - updated Stewart structure with the added fields:
% - platform_F.Fa [3x6] - Its i'th column is the position vector of joint ai with respect to {F}
% - platform_M.Mb [3x6] - Its i'th column is the position vector of joint bi with respect to {M}
arguments
stewart
args.Hc (1,1) double {mustBeNumeric, mustBePositive} = 60e-3
args.FOc (1,1) double {mustBeNumeric} = 50e-3
args.FHa (1,1) double {mustBeNumeric, mustBeNonnegative} = 15e-3
args.MHb (1,1) double {mustBeNumeric, mustBeNonnegative} = 15e-3
end
assert(isfield(stewart.geometry, 'H'), 'stewart.geometry should have attribute H')
H = stewart.geometry.H;
% We define the useful points of the cube with respect to the Cube's center.
% ${}^{C}C$ are the 6 vertices of the cubes expressed in a frame {C} which is located at the center of the cube and aligned with {F} and {M}.
sx = [ 2; -1; -1];
sy = [ 0; 1; -1];
sz = [ 1; 1; 1];
R = [sx, sy, sz]./vecnorm([sx, sy, sz]);
L = args.Hc*sqrt(3);
Cc = R'*[[0;0;L],[L;0;L],[L;0;0],[L;L;0],[0;L;0],[0;L;L]] - [0;0;1.5*args.Hc];
CCf = [Cc(:,1), Cc(:,3), Cc(:,3), Cc(:,5), Cc(:,5), Cc(:,1)]; % CCf(:,i) corresponds to the bottom cube's vertice corresponding to the i'th leg
CCm = [Cc(:,2), Cc(:,2), Cc(:,4), Cc(:,4), Cc(:,6), Cc(:,6)]; % CCm(:,i) corresponds to the top cube's vertice corresponding to the i'th leg
% We can compute the vector of each leg ${}^{C}\hat{\bm{s}}_{i}$ (unit vector from ${}^{C}C_{f}$ to ${}^{C}C_{m}$).
CSi = (CCm - CCf)./vecnorm(CCm - CCf);
% We now which to compute the position of the joints $a_{i}$ and $b_{i}$.
Fa = CCf + [0; 0; args.FOc] + ((args.FHa-(args.FOc-args.Hc/2))./CSi(3,:)).*CSi;
Mb = CCf + [0; 0; args.FOc-H] + ((H-args.MHb-(args.FOc-args.Hc/2))./CSi(3,:)).*CSi;
stewart.platform_F.Fa = Fa;
stewart.platform_M.Mb = Mb;
#+end_src
** =plotCube=: Plot the Cube
#+begin_src matlab :tangle matlab/src/plotCube.m :comments none :mkdirp yes :eval no
function [] = plotCube(stewart, args)
arguments
stewart
args.Hc (1,1) double {mustBeNumeric, mustBePositive} = 60e-3
args.FOc (1,1) double {mustBeNumeric} = 50e-3
args.color (4,1) double {mustBeNumeric} = [0,0,0,0.5]
args.linewidth (1,1) double {mustBeNumeric, mustBePositive} = 2.5
args.link_to_struts logical {mustBeNumericOrLogical} = false
end
sx = [ 2; -1; -1];
sy = [ 0; 1; -1];
sz = [ 1; 1; 1];
R = [sx, sy, sz]./vecnorm([sx, sy, sz]);
L = args.Hc*sqrt(3);
p_xyz = R'*[[0;0;0],[L;0;0],[L;L;0],[0;L;0],[0;0;L],[L;0;L],[L;L;L],[0;L;L]] - [0;0;1.5*args.Hc];
% Position center of the cube
p_xyz = p_xyz + args.FOc*[0;0;1]*ones(1,8);
edges_order = [1 2 3 4 1];
plot3(p_xyz(1,edges_order), p_xyz(2,edges_order), p_xyz(3,edges_order), '-', 'color', args.color, 'linewidth', args.linewidth);
edges_order = [5 6 7 8 5];
plot3(p_xyz(1,edges_order), p_xyz(2,edges_order), p_xyz(3,edges_order), '-', 'color', args.color, 'linewidth', args.linewidth);
edges_order = [1 5];
plot3(p_xyz(1,edges_order), p_xyz(2,edges_order), p_xyz(3,edges_order), '-', 'color', args.color, 'linewidth', args.linewidth);
edges_order = [2 6];
plot3(p_xyz(1,edges_order), p_xyz(2,edges_order), p_xyz(3,edges_order), '-', 'color', args.color, 'linewidth', args.linewidth);
edges_order = [3 7];
plot3(p_xyz(1,edges_order), p_xyz(2,edges_order), p_xyz(3,edges_order), '-', 'color', args.color, 'linewidth', args.linewidth);
edges_order = [4 8];
plot3(p_xyz(1,edges_order), p_xyz(2,edges_order), p_xyz(3,edges_order), '-', 'color', args.color, 'linewidth', args.linewidth);
if args.link_to_struts
Fb = stewart.platform_M.Mb + stewart.geometry.FO_M;
plot3([Fb(1,1), p_xyz(1,5)],...
[Fb(2,1), p_xyz(2,5)],...
[Fb(3,1), p_xyz(3,5)], '--', 'color', args.color, 'linewidth', args.linewidth);
plot3([Fb(1,2), p_xyz(1,2)],...
[Fb(2,2), p_xyz(2,2)],...
[Fb(3,2), p_xyz(3,2)], '--', 'color', args.color, 'linewidth', args.linewidth);
plot3([Fb(1,3), p_xyz(1,2)],...
[Fb(2,3), p_xyz(2,2)],...
[Fb(3,3), p_xyz(3,2)], '--', 'color', args.color, 'linewidth', args.linewidth);
plot3([Fb(1,4), p_xyz(1,4)],...
[Fb(2,4), p_xyz(2,4)],...
[Fb(3,4), p_xyz(3,4)], '--', 'color', args.color, 'linewidth', args.linewidth);
plot3([Fb(1,5), p_xyz(1,4)],...
[Fb(2,5), p_xyz(2,4)],...
[Fb(3,5), p_xyz(3,4)], '--', 'color', args.color, 'linewidth', args.linewidth);
plot3([Fb(1,6), p_xyz(1,5)],...
[Fb(2,6), p_xyz(2,5)],...
[Fb(3,6), p_xyz(3,5)], '--', 'color', args.color, 'linewidth', args.linewidth);
end
#+end_src
** =computeJacobian=: Compute the Jacobian Matrix
#+begin_src matlab :tangle matlab/src/computeJacobian.m :comments none :mkdirp yes :eval no
function [stewart] = computeJacobian(stewart)
% computeJacobian -
%
% Syntax: [stewart] = computeJacobian(stewart)
%
% Inputs:
% - stewart - With at least the following fields:
% - geometry.As [3x6] - The 6 unit vectors for each strut expressed in {A}
% - geometry.Ab [3x6] - The 6 position of the joints bi expressed in {A}
% - actuators.K [6x1] - Total stiffness of the actuators
%
% Outputs:
% - stewart - With the 3 added field:
% - kinematics.J [6x6] - The Jacobian Matrix
% - kinematics.K [6x6] - The Stiffness Matrix
% - kinematics.C [6x6] - The Compliance Matrix
assert(isfield(stewart.geometry, 'As'), 'stewart.geometry should have attribute As')
As = stewart.geometry.As;
assert(isfield(stewart.geometry, 'Ab'), 'stewart.geometry should have attribute Ab')
Ab = stewart.geometry.Ab;
assert(isfield(stewart.actuators, 'k'), 'stewart.actuators should have attribute k')
Ki = stewart.actuators.k*eye(6);
J = [As' , cross(Ab, As)'];
K = J'*Ki*J;
C = inv(K);
stewart.kinematics.J = J;
stewart.kinematics.K = K;
stewart.kinematics.C = C;
#+end_src
** =inverseKinematics=: Compute Inverse Kinematics
#+begin_src matlab :tangle matlab/src/inverseKinematics.m :comments none :mkdirp yes :eval no
function [Li, dLi] = inverseKinematics(stewart, args)
% inverseKinematics - Compute the needed length of each strut to have the wanted position and orientation of {B} with respect to {A}
%
% Syntax: [stewart] = inverseKinematics(stewart)
%
% Inputs:
% - stewart - A structure with the following fields
% - geometry.Aa [3x6] - The positions ai expressed in {A}
% - geometry.Bb [3x6] - The positions bi expressed in {B}
% - geometry.l [6x1] - Length of each strut
% - args - Can have the following fields:
% - AP [3x1] - The wanted position of {B} with respect to {A}
% - ARB [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A}
%
% Outputs:
% - Li [6x1] - The 6 needed length of the struts in [m] to have the wanted pose of {B} w.r.t. {A}
% - dLi [6x1] - The 6 needed displacement of the struts from the initial position in [m] to have the wanted pose of {B} w.r.t. {A}
arguments
stewart
args.AP (3,1) double {mustBeNumeric} = zeros(3,1)
args.ARB (3,3) double {mustBeNumeric} = eye(3)
end
assert(isfield(stewart.geometry, 'Aa'), 'stewart.geometry should have attribute Aa')
Aa = stewart.geometry.Aa;
assert(isfield(stewart.geometry, 'Bb'), 'stewart.geometry should have attribute Bb')
Bb = stewart.geometry.Bb;
assert(isfield(stewart.geometry, 'l'), 'stewart.geometry should have attribute l')
l = stewart.geometry.l;
Li = sqrt(args.AP'*args.AP + diag(Bb'*Bb) + diag(Aa'*Aa) - (2*args.AP'*Aa)' + (2*args.AP'*(args.ARB*Bb))' - diag(2*(args.ARB*Bb)'*Aa));
dLi = Li-l;
#+end_src
** =forwardKinematicsApprox=: Compute the Approximate Forward Kinematics
#+begin_src matlab :tangle matlab/src/forwardKinematicsApprox.m :comments none :mkdirp yes :eval no
function [P, R] = forwardKinematicsApprox(stewart, args)
% forwardKinematicsApprox - Computed the approximate pose of {B} with respect to {A} from the length of each strut and using
% the Jacobian Matrix
%
% Syntax: [P, R] = forwardKinematicsApprox(stewart, args)
%
% Inputs:
% - stewart - A structure with the following fields
% - kinematics.J [6x6] - The Jacobian Matrix
% - args - Can have the following fields:
% - dL [6x1] - Displacement of each strut [m]
%
% Outputs:
% - P [3x1] - The estimated position of {B} with respect to {A}
% - R [3x3] - The estimated rotation matrix that gives the orientation of {B} with respect to {A}
arguments
stewart
args.dL (6,1) double {mustBeNumeric} = zeros(6,1)
end
assert(isfield(stewart.kinematics, 'J'), 'stewart.kinematics should have attribute J')
J = stewart.kinematics.J;
X = J\args.dL;
P = X(1:3);
theta = norm(X(4:6));
s = X(4:6)/theta;
R = [s(1)^2*(1-cos(theta)) + cos(theta) , s(1)*s(2)*(1-cos(theta)) - s(3)*sin(theta), s(1)*s(3)*(1-cos(theta)) + s(2)*sin(theta);
s(2)*s(1)*(1-cos(theta)) + s(3)*sin(theta), s(2)^2*(1-cos(theta)) + cos(theta), s(2)*s(3)*(1-cos(theta)) - s(1)*sin(theta);
s(3)*s(1)*(1-cos(theta)) - s(2)*sin(theta), s(3)*s(2)*(1-cos(theta)) + s(1)*sin(theta), s(3)^2*(1-cos(theta)) + cos(theta)];
#+end_src
** =initializeStewartPlatform=: Initialize the Stewart Platform structure
#+begin_src matlab :tangle matlab/src/initializeStewartPlatform.m :comments none :mkdirp yes :eval no
function [stewart] = initializeStewartPlatform()
% initializeStewartPlatform - Initialize the stewart structure
%
% Syntax: [stewart] = initializeStewartPlatform(args)
%
% Outputs:
% - stewart - A structure with the following sub-structures:
% - platform_F -
% - platform_M -
% - joints_F -
% - joints_M -
% - struts_F -
% - struts_M -
% - actuators -
% - geometry -
% - properties -
stewart = struct();
stewart.platform_F = struct();
stewart.platform_M = struct();
stewart.joints_F = struct();
stewart.joints_M = struct();
stewart.struts_F = struct();
stewart.struts_M = struct();
stewart.actuators = struct();
stewart.sensors = struct();
stewart.sensors.inertial = struct();
stewart.sensors.force = struct();
stewart.sensors.relative = struct();
stewart.geometry = struct();
stewart.kinematics = struct();
#+end_src
** =initializeFramesPositions=: Initialize the positions of frames {A}, {B}, {F} and {M}
#+begin_src matlab :tangle matlab/src/initializeFramesPositions.m :comments none :mkdirp yes :eval no
function [stewart] = initializeFramesPositions(stewart, args)
% initializeFramesPositions - Initialize the positions of frames {A}, {B}, {F} and {M}
%
% Syntax: [stewart] = initializeFramesPositions(stewart, args)
%
% Inputs:
% - args - Can have the following fields:
% - H [1x1] - Total Height of the Stewart Platform (height from {F} to {M}) [m]
% - MO_B [1x1] - Height of the frame {B} with respect to {M} [m]
%
% Outputs:
% - stewart - A structure with the following fields:
% - geometry.H [1x1] - Total Height of the Stewart Platform [m]
% - geometry.FO_M [3x1] - Position of {M} with respect to {F} [m]
% - platform_M.MO_B [3x1] - Position of {B} with respect to {M} [m]
% - platform_F.FO_A [3x1] - Position of {A} with respect to {F} [m]
arguments
stewart
args.H (1,1) double {mustBeNumeric, mustBePositive} = 90e-3
args.MO_B (1,1) double {mustBeNumeric} = 50e-3
end
H = args.H; % Total Height of the Stewart Platform [m]
FO_M = [0; 0; H]; % Position of {M} with respect to {F} [m]
MO_B = [0; 0; args.MO_B]; % Position of {B} with respect to {M} [m]
FO_A = MO_B + FO_M; % Position of {A} with respect to {F} [m]
stewart.geometry.H = H;
stewart.geometry.FO_M = FO_M;
stewart.platform_M.MO_B = MO_B;
stewart.platform_F.FO_A = FO_A;
#+end_src
** =generateGeneralConfiguration=: Generate a Very General Configuration
#+begin_src matlab :tangle matlab/src/generateGeneralConfiguration.m :comments none :mkdirp yes :eval no
function [stewart] = generateGeneralConfiguration(stewart, args)
% generateGeneralConfiguration - Generate a Very General Configuration
%
% Syntax: [stewart] = generateGeneralConfiguration(stewart, args)
%
% Inputs:
% - args - Can have the following fields:
% - FH [1x1] - Height of the position of the fixed joints with respect to the frame {F} [m]
% - FR [1x1] - Radius of the position of the fixed joints in the X-Y [m]
% - FTh [6x1] - Angles of the fixed joints in the X-Y plane with respect to the X axis [rad]
% - MH [1x1] - Height of the position of the mobile joints with respect to the frame {M} [m]
% - FR [1x1] - Radius of the position of the mobile joints in the X-Y [m]
% - MTh [6x1] - Angles of the mobile joints in the X-Y plane with respect to the X axis [rad]
%
% Outputs:
% - stewart - updated Stewart structure with the added fields:
% - platform_F.Fa [3x6] - Its i'th column is the position vector of joint ai with respect to {F}
% - platform_M.Mb [3x6] - Its i'th column is the position vector of joint bi with respect to {M}
arguments
stewart
args.FH (1,1) double {mustBeNumeric, mustBeNonnegative} = 15e-3
args.FR (1,1) double {mustBeNumeric, mustBePositive} = 115e-3;
args.FTh (6,1) double {mustBeNumeric} = [-10, 10, 120-10, 120+10, 240-10, 240+10]*(pi/180);
args.MH (1,1) double {mustBeNumeric, mustBeNonnegative} = 15e-3
args.MR (1,1) double {mustBeNumeric, mustBePositive} = 90e-3;
args.MTh (6,1) double {mustBeNumeric} = [-60+10, 60-10, 60+10, 180-10, 180+10, -60-10]*(pi/180);
end
Fa = zeros(3,6);
Mb = zeros(3,6);
for i = 1:6
Fa(:,i) = [args.FR*cos(args.FTh(i)); args.FR*sin(args.FTh(i)); args.FH];
Mb(:,i) = [args.MR*cos(args.MTh(i)); args.MR*sin(args.MTh(i)); -args.MH];
end
stewart.platform_F.Fa = Fa;
stewart.platform_M.Mb = Mb;
#+end_src
** =computeJointsPose=: Compute the Pose of the Joints
#+begin_src matlab :tangle matlab/src/computeJointsPose.m :comments none :mkdirp yes :eval no
function [stewart] = computeJointsPose(stewart, args)
% computeJointsPose -
%
% Syntax: [stewart] = computeJointsPose(stewart, args)
%
% Inputs:
% - stewart - A structure with the following fields
% - platform_F.Fa [3x6] - Its i'th column is the position vector of joint ai with respect to {F}
% - platform_M.Mb [3x6] - Its i'th column is the position vector of joint bi with respect to {M}
% - platform_F.FO_A [3x1] - Position of {A} with respect to {F}
% - platform_M.MO_B [3x1] - Position of {B} with respect to {M}
% - geometry.FO_M [3x1] - Position of {M} with respect to {F}
% - args - Can have the following fields:
% - AP [3x1] - The wanted position of {B} with respect to {A}
% - ARB [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A}
%
% Outputs:
% - stewart - A structure with the following added fields
% - geometry.Aa [3x6] - The i'th column is the position of ai with respect to {A}
% - geometry.Ab [3x6] - The i'th column is the position of bi with respect to {A}
% - geometry.Ba [3x6] - The i'th column is the position of ai with respect to {B}
% - geometry.Bb [3x6] - The i'th column is the position of bi with respect to {B}
% - geometry.l [6x1] - The i'th element is the initial length of strut i
% - geometry.As [3x6] - The i'th column is the unit vector of strut i expressed in {A}
% - geometry.Bs [3x6] - The i'th column is the unit vector of strut i expressed in {B}
% - struts_F.l [6x1] - Length of the Fixed part of the i'th strut
% - struts_M.l [6x1] - Length of the Mobile part of the i'th strut
% - platform_F.FRa [3x3x6] - The i'th 3x3 array is the rotation matrix to orientate the bottom of the i'th strut from {F}
% - platform_M.MRb [3x3x6] - The i'th 3x3 array is the rotation matrix to orientate the top of the i'th strut from {M}
arguments
stewart
args.AP (3,1) double {mustBeNumeric} = zeros(3,1)
args.ARB (3,3) double {mustBeNumeric} = eye(3)
end
assert(isfield(stewart.platform_F, 'Fa'), 'stewart.platform_F should have attribute Fa')
Fa = stewart.platform_F.Fa;
assert(isfield(stewart.platform_M, 'Mb'), 'stewart.platform_M should have attribute Mb')
Mb = stewart.platform_M.Mb;
assert(isfield(stewart.platform_F, 'FO_A'), 'stewart.platform_F should have attribute FO_A')
FO_A = stewart.platform_F.FO_A;
assert(isfield(stewart.platform_M, 'MO_B'), 'stewart.platform_M should have attribute MO_B')
MO_B = stewart.platform_M.MO_B;
assert(isfield(stewart.geometry, 'FO_M'), 'stewart.geometry should have attribute FO_M')
FO_M = stewart.geometry.FO_M;
Aa = Fa - repmat(FO_A, [1, 6]);
Bb = Mb - repmat(MO_B, [1, 6]);
Ab = Bb - repmat(-MO_B-FO_M+FO_A, [1, 6]);
Ba = Aa - repmat( MO_B+FO_M-FO_A, [1, 6]);
Ab = args.ARB *Bb - repmat(-args.AP, [1, 6]);
Ba = args.ARB'*Aa - repmat( args.AP, [1, 6]);
As = (Ab - Aa)./vecnorm(Ab - Aa); % As_i is the i'th vector of As
l = vecnorm(Ab - Aa)';
Bs = (Bb - Ba)./vecnorm(Bb - Ba);
FRa = zeros(3,3,6);
MRb = zeros(3,3,6);
for i = 1:6
FRa(:,:,i) = [cross([0;1;0], As(:,i)) , cross(As(:,i), cross([0;1;0], As(:,i))) , As(:,i)];
FRa(:,:,i) = FRa(:,:,i)./vecnorm(FRa(:,:,i));
MRb(:,:,i) = [cross([0;1;0], Bs(:,i)) , cross(Bs(:,i), cross([0;1;0], Bs(:,i))) , Bs(:,i)];
MRb(:,:,i) = MRb(:,:,i)./vecnorm(MRb(:,:,i));
end
stewart.geometry.Aa = Aa;
stewart.geometry.Ab = Ab;
stewart.geometry.Ba = Ba;
stewart.geometry.Bb = Bb;
stewart.geometry.As = As;
stewart.geometry.Bs = Bs;
stewart.geometry.l = l;
stewart.struts_F.l = l/2;
stewart.struts_M.l = l/2;
stewart.platform_F.FRa = FRa;
stewart.platform_M.MRb = MRb;
#+end_src
** =initializeStewartPose=: Determine the initial stroke in each leg to have the wanted pose
#+begin_src matlab :tangle matlab/src/initializeStewartPose.m :comments none :mkdirp yes :eval no
function [stewart] = initializeStewartPose(stewart, args)
% initializeStewartPose - Determine the initial stroke in each leg to have the wanted pose
% It uses the inverse kinematic
%
% Syntax: [stewart] = initializeStewartPose(stewart, args)
%
% Inputs:
% - stewart - A structure with the following fields
% - Aa [3x6] - The positions ai expressed in {A}
% - Bb [3x6] - The positions bi expressed in {B}
% - args - Can have the following fields:
% - AP [3x1] - The wanted position of {B} with respect to {A}
% - ARB [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A}
%
% Outputs:
% - stewart - updated Stewart structure with the added fields:
% - actuators.Leq [6x1] - The 6 needed displacement of the struts from the initial position in [m] to have the wanted pose of {B} w.r.t. {A}
arguments
stewart
args.AP (3,1) double {mustBeNumeric} = zeros(3,1)
args.ARB (3,3) double {mustBeNumeric} = eye(3)
end
[Li, dLi] = inverseKinematics(stewart, 'AP', args.AP, 'ARB', args.ARB);
stewart.actuators.Leq = dLi;
#+end_src
** =initializeCylindricalPlatforms=: Initialize the geometry of the Fixed and Mobile Platforms
#+begin_src matlab :tangle matlab/src/initializeCylindricalPlatforms.m :comments none :mkdirp yes :eval no
function [stewart] = initializeCylindricalPlatforms(stewart, args)
% initializeCylindricalPlatforms - Initialize the geometry of the Fixed and Mobile Platforms
%
% Syntax: [stewart] = initializeCylindricalPlatforms(args)
%
% Inputs:
% - args - Structure with the following fields:
% - Fpm [1x1] - Fixed Platform Mass [kg]
% - Fph [1x1] - Fixed Platform Height [m]
% - Fpr [1x1] - Fixed Platform Radius [m]
% - Mpm [1x1] - Mobile Platform Mass [kg]
% - Mph [1x1] - Mobile Platform Height [m]
% - Mpr [1x1] - Mobile Platform Radius [m]
%
% Outputs:
% - stewart - updated Stewart structure with the added fields:
% - platform_F [struct] - structure with the following fields:
% - type = 1
% - M [1x1] - Fixed Platform Mass [kg]
% - I [3x3] - Fixed Platform Inertia matrix [kg*m^2]
% - H [1x1] - Fixed Platform Height [m]
% - R [1x1] - Fixed Platform Radius [m]
% - platform_M [struct] - structure with the following fields:
% - M [1x1] - Mobile Platform Mass [kg]
% - I [3x3] - Mobile Platform Inertia matrix [kg*m^2]
% - H [1x1] - Mobile Platform Height [m]
% - R [1x1] - Mobile Platform Radius [m]
arguments
stewart
args.Fpm (1,1) double {mustBeNumeric, mustBePositive} = 1
args.Fph (1,1) double {mustBeNumeric, mustBePositive} = 10e-3
args.Fpr (1,1) double {mustBeNumeric, mustBePositive} = 125e-3
args.Mpm (1,1) double {mustBeNumeric, mustBePositive} = 1
args.Mph (1,1) double {mustBeNumeric, mustBePositive} = 10e-3
args.Mpr (1,1) double {mustBeNumeric, mustBePositive} = 100e-3
end
I_F = diag([1/12*args.Fpm * (3*args.Fpr^2 + args.Fph^2), ...
1/12*args.Fpm * (3*args.Fpr^2 + args.Fph^2), ...
1/2 *args.Fpm * args.Fpr^2]);
I_M = diag([1/12*args.Mpm * (3*args.Mpr^2 + args.Mph^2), ...
1/12*args.Mpm * (3*args.Mpr^2 + args.Mph^2), ...
1/2 *args.Mpm * args.Mpr^2]);
stewart.platform_F.type = 1;
stewart.platform_F.I = I_F;
stewart.platform_F.M = args.Fpm;
stewart.platform_F.R = args.Fpr;
stewart.platform_F.H = args.Fph;
stewart.platform_M.type = 1;
stewart.platform_M.I = I_M;
stewart.platform_M.M = args.Mpm;
stewart.platform_M.R = args.Mpr;
stewart.platform_M.H = args.Mph;
#+end_src
** =initializeStrutDynamics=: Add Stiffness and Damping properties of each strut
#+begin_src matlab :tangle matlab/src/initializeStrutDynamics.m :comments none :mkdirp yes :eval no
function [stewart] = initializeStrutDynamics(stewart, args)
% initializeStrutDynamics - Add Stiffness and Damping properties of each strut
%
% Syntax: [stewart] = initializeStrutDynamics(args)
%
% Inputs:
% - args - Structure with the following fields:
% - K [6x1] - Stiffness of each strut [N/m]
% - C [6x1] - Damping of each strut [N/(m/s)]
%
% Outputs:
% - stewart - updated Stewart structure with the added fields:
% - actuators.type = 1
% - actuators.K [6x1] - Stiffness of each strut [N/m]
% - actuators.C [6x1] - Damping of each strut [N/(m/s)]
arguments
stewart
args.type char {mustBeMember(args.type,{'1dof', '2dof', 'flexible'})} = '1dof'
args.k (1,1) double {mustBeNumeric, mustBeNonnegative} = 20e6
args.kp (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.ke (1,1) double {mustBeNumeric, mustBeNonnegative} = 5e6
args.ka (1,1) double {mustBeNumeric, mustBeNonnegative} = 60e6
args.c (1,1) double {mustBeNumeric, mustBeNonnegative} = 2e1
args.cp (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.ce (1,1) double {mustBeNumeric, mustBeNonnegative} = 1e6
args.ca (1,1) double {mustBeNumeric, mustBeNonnegative} = 10
args.F_gain (1,1) double {mustBeNumeric} = 1
args.me (1,1) double {mustBeNumeric} = 0.01
args.ma (1,1) double {mustBeNumeric} = 0.01
end
if strcmp(args.type, '1dof')
stewart.actuators.type = 1;
elseif strcmp(args.type, '2dof')
stewart.actuators.type = 2;
elseif strcmp(args.type, 'flexible')
stewart.actuators.type = 3;
end
stewart.actuators.k = args.k;
stewart.actuators.c = args.c;
% Parallel stiffness
stewart.actuators.kp = args.kp;
stewart.actuators.cp = args.cp;
stewart.actuators.ka = args.ka;
stewart.actuators.ca = args.ca;
stewart.actuators.ke = args.ke;
stewart.actuators.ce = args.ce;
stewart.actuators.F_gain = args.F_gain;
stewart.actuators.ma = args.ma;
stewart.actuators.me = args.me;
end
#+end_src
** =displayArchitecture=: 3D plot of the Stewart platform architecture
#+begin_src matlab :tangle matlab/src/displayArchitecture.m :comments none :mkdirp yes :eval no
function [] = displayArchitecture(stewart, args)
% displayArchitecture - 3D plot of the Stewart platform architecture
%
% Syntax: [] = displayArchitecture(args)
%
% Inputs:
% - stewart
% - args - Structure with the following fields:
% - AP [3x1] - The wanted position of {B} with respect to {A}
% - ARB [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A}
% - ARB [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A}
% - F_color [color] - Color used for the Fixed elements
% - M_color [color] - Color used for the Mobile elements
% - L_color [color] - Color used for the Legs elements
% - frames [true/false] - Display the Frames
% - legs [true/false] - Display the Legs
% - joints [true/false] - Display the Joints
% - labels [true/false] - Display the Labels
% - platforms [true/false] - Display the Platforms
% - views ['all', 'xy', 'yz', 'xz', 'default'] -
%
% Outputs:
arguments
stewart
args.AP (3,1) double {mustBeNumeric} = zeros(3,1)
args.ARB (3,3) double {mustBeNumeric} = eye(3)
args.F_color = [0 0.4470 0.7410]
args.M_color = [0.8500 0.3250 0.0980]
args.L_color = [0 0 0]
args.frames logical {mustBeNumericOrLogical} = true
args.legs logical {mustBeNumericOrLogical} = true
args.joints logical {mustBeNumericOrLogical} = true
args.labels logical {mustBeNumericOrLogical} = true
args.platforms logical {mustBeNumericOrLogical} = true
args.views char {mustBeMember(args.views,{'all', 'xy', 'xz', 'yz', 'default'})} = 'default'
end
assert(isfield(stewart.platform_F, 'FO_A'), 'stewart.platform_F should have attribute FO_A')
FO_A = stewart.platform_F.FO_A;
assert(isfield(stewart.platform_M, 'MO_B'), 'stewart.platform_M should have attribute MO_B')
MO_B = stewart.platform_M.MO_B;
assert(isfield(stewart.geometry, 'H'), 'stewart.geometry should have attribute H')
H = stewart.geometry.H;
assert(isfield(stewart.platform_F, 'Fa'), 'stewart.platform_F should have attribute Fa')
Fa = stewart.platform_F.Fa;
assert(isfield(stewart.platform_M, 'Mb'), 'stewart.platform_M should have attribute Mb')
Mb = stewart.platform_M.Mb;
% The reference frame of the 3d plot corresponds to the frame $\{F\}$.
if ~strcmp(args.views, 'all')
figure;
else
f = figure('visible', 'off');
end
hold on;
% We first compute homogeneous matrices that will be useful to position elements on the figure where the reference frame is $\{F\}$.
FTa = [eye(3), FO_A; ...
zeros(1,3), 1];
ATb = [args.ARB, args.AP; ...
zeros(1,3), 1];
BTm = [eye(3), -MO_B; ...
zeros(1,3), 1];
FTm = FTa*ATb*BTm;
% Let's define a parameter that define the length of the unit vectors used to display the frames.
d_unit_vector = H/4;
% Let's define a parameter used to position the labels with respect to the center of the element.
d_label = H/20;
% Let's first plot the frame $\{F\}$.
Ff = [0, 0, 0];
if args.frames
quiver3(Ff(1)*ones(1,3), Ff(2)*ones(1,3), Ff(3)*ones(1,3), ...
[d_unit_vector 0 0], [0 d_unit_vector 0], [0 0 d_unit_vector], '-', 'Color', args.F_color)
if args.labels
text(Ff(1) + d_label, ...
Ff(2) + d_label, ...
Ff(3) + d_label, '$\{F\}$', 'Color', args.F_color);
end
end
% Now plot the frame $\{A\}$ fixed to the Base.
if args.frames
quiver3(FO_A(1)*ones(1,3), FO_A(2)*ones(1,3), FO_A(3)*ones(1,3), ...
[d_unit_vector 0 0], [0 d_unit_vector 0], [0 0 d_unit_vector], '-', 'Color', args.F_color)
if args.labels
text(FO_A(1) + d_label, ...
FO_A(2) + d_label, ...
FO_A(3) + d_label, '$\{A\}$', 'Color', args.F_color);
end
end
% Let's then plot the circle corresponding to the shape of the Fixed base.
if args.platforms && stewart.platform_F.type == 1
theta = [0:0.1:2*pi+0.1]; % Angles [rad]
v = null([0; 0; 1]'); % Two vectors that are perpendicular to the circle normal
center = [0; 0; 0]; % Center of the circle
radius = stewart.platform_F.R; % Radius of the circle [m]
points = center*ones(1, length(theta)) + radius*(v(:,1)*cos(theta) + v(:,2)*sin(theta));
plot3(points(1,:), ...
points(2,:), ...
points(3,:), '-', 'Color', args.F_color);
end
% Let's now plot the position and labels of the Fixed Joints
if args.joints
scatter3(Fa(1,:), ...
Fa(2,:), ...
Fa(3,:), 'MarkerEdgeColor', args.F_color);
if args.labels
for i = 1:size(Fa,2)
text(Fa(1,i) + d_label, ...
Fa(2,i), ...
Fa(3,i), sprintf('$a_{%i}$', i), 'Color', args.F_color);
end
end
end
% Plot the frame $\{M\}$.
Fm = FTm*[0; 0; 0; 1]; % Get the position of frame {M} w.r.t. {F}
if args.frames
FM_uv = FTm*[d_unit_vector*eye(3); zeros(1,3)]; % Rotated Unit vectors
quiver3(Fm(1)*ones(1,3), Fm(2)*ones(1,3), Fm(3)*ones(1,3), ...
FM_uv(1,1:3), FM_uv(2,1:3), FM_uv(3,1:3), '-', 'Color', args.M_color)
if args.labels
text(Fm(1) + d_label, ...
Fm(2) + d_label, ...
Fm(3) + d_label, '$\{M\}$', 'Color', args.M_color);
end
end
% Plot the frame $\{B\}$.
FB = FO_A + args.AP;
if args.frames
FB_uv = FTm*[d_unit_vector*eye(3); zeros(1,3)]; % Rotated Unit vectors
quiver3(FB(1)*ones(1,3), FB(2)*ones(1,3), FB(3)*ones(1,3), ...
FB_uv(1,1:3), FB_uv(2,1:3), FB_uv(3,1:3), '-', 'Color', args.M_color)
if args.labels
text(FB(1) - d_label, ...
FB(2) + d_label, ...
FB(3) + d_label, '$\{B\}$', 'Color', args.M_color);
end
end
% Let's then plot the circle corresponding to the shape of the Mobile platform.
if args.platforms && stewart.platform_M.type == 1
theta = [0:0.1:2*pi+0.1]; % Angles [rad]
v = null((FTm(1:3,1:3)*[0;0;1])'); % Two vectors that are perpendicular to the circle normal
center = Fm(1:3); % Center of the circle
radius = stewart.platform_M.R; % Radius of the circle [m]
points = center*ones(1, length(theta)) + radius*(v(:,1)*cos(theta) + v(:,2)*sin(theta));
plot3(points(1,:), ...
points(2,:), ...
points(3,:), '-', 'Color', args.M_color);
end
% Plot the position and labels of the rotation joints fixed to the mobile platform.
if args.joints
Fb = FTm*[Mb;ones(1,6)];
scatter3(Fb(1,:), ...
Fb(2,:), ...
Fb(3,:), 'MarkerEdgeColor', args.M_color);
if args.labels
for i = 1:size(Fb,2)
text(Fb(1,i) + d_label, ...
Fb(2,i), ...
Fb(3,i), sprintf('$b_{%i}$', i), 'Color', args.M_color);
end
end
end
% Plot the legs connecting the joints of the fixed base to the joints of the mobile platform.
if args.legs
for i = 1:6
plot3([Fa(1,i), Fb(1,i)], ...
[Fa(2,i), Fb(2,i)], ...
[Fa(3,i), Fb(3,i)], '-', 'Color', args.L_color);
if args.labels
text((Fa(1,i)+Fb(1,i))/2 + d_label, ...
(Fa(2,i)+Fb(2,i))/2, ...
(Fa(3,i)+Fb(3,i))/2, sprintf('$%i$', i), 'Color', args.L_color);
end
end
end
switch args.views
case 'default'
view([1 -0.6 0.4]);
case 'xy'
view([0 0 1]);
case 'xz'
view([0 -1 0]);
case 'yz'
view([1 0 0]);
end
axis equal;
axis off;
if strcmp(args.views, 'all')
hAx = findobj('type', 'axes');
figure;
s1 = subplot(2,2,1);
copyobj(get(hAx(1), 'Children'), s1);
view([0 0 1]);
axis equal;
axis off;
title('Top')
s2 = subplot(2,2,2);
copyobj(get(hAx(1), 'Children'), s2);
view([1 -0.6 0.4]);
axis equal;
axis off;
s3 = subplot(2,2,3);
copyobj(get(hAx(1), 'Children'), s3);
view([1 0 0]);
axis equal;
axis off;
title('Front')
s4 = subplot(2,2,4);
copyobj(get(hAx(1), 'Children'), s4);
view([0 -1 0]);
axis equal;
axis off;
title('Side')
close(f);
end
#+end_src
** =describeStewartPlatform=: Display some text describing the current defined Stewart Platform
#+begin_src matlab :tangle matlab/src/describeStewartPlatform.m :comments none :mkdirp yes :eval no
function [] = describeStewartPlatform(stewart)
% describeStewartPlatform - Display some text describing the current defined Stewart Platform
%
% Syntax: [] = describeStewartPlatform(args)
%
% Inputs:
% - stewart
%
% Outputs:
arguments
stewart
end
fprintf('GEOMETRY:\n')
fprintf('- The height between the fixed based and the top platform is %.3g [mm].\n', 1e3*stewart.geometry.H)
if stewart.platform_M.MO_B(3) > 0
fprintf('- Frame {A} is located %.3g [mm] above the top platform.\n', 1e3*stewart.platform_M.MO_B(3))
else
fprintf('- Frame {A} is located %.3g [mm] below the top platform.\n', - 1e3*stewart.platform_M.MO_B(3))
end
fprintf('- The initial length of the struts are:\n')
fprintf('\t %.3g, %.3g, %.3g, %.3g, %.3g, %.3g [mm]\n', 1e3*stewart.geometry.l)
fprintf('\n')
fprintf('ACTUATORS:\n')
if stewart.actuators.type == 1
fprintf('- The actuators are classical.\n')
fprintf('- The Stiffness and Damping of each actuators is:\n')
fprintf('\t k = %.0e [N/m] \t c = %.0e [N/(m/s)]\n', stewart.actuators.k, stewart.actuators.c)
elseif stewart.actuators.type == 2
fprintf('- The actuators are mechanicaly amplified.\n')
end
fprintf('\n')
fprintf('JOINTS:\n')
switch stewart.joints_F.type
case 1
fprintf('- The joints on the fixed based are universal joints\n')
case 2
fprintf('- The joints on the fixed based are spherical joints\n')
case 3
fprintf('- The joints on the fixed based are perfect universal joints\n')
case 4
fprintf('- The joints on the fixed based are perfect spherical joints\n')
end
switch stewart.joints_M.type
case 1
fprintf('- The joints on the mobile based are universal joints\n')
case 2
fprintf('- The joints on the mobile based are spherical joints\n')
case 3
fprintf('- The joints on the mobile based are perfect universal joints\n')
case 4
fprintf('- The joints on the mobile based are perfect spherical joints\n')
end
fprintf('- The position of the joints on the fixed based with respect to {F} are (in [mm]):\n')
fprintf('\t % .3g \t % .3g \t % .3g\n', 1e3*stewart.platform_F.Fa)
fprintf('- The position of the joints on the mobile based with respect to {M} are (in [mm]):\n')
fprintf('\t % .3g \t % .3g \t % .3g\n', 1e3*stewart.platform_M.Mb)
fprintf('\n')
fprintf('KINEMATICS:\n')
if isfield(stewart.kinematics, 'K')
fprintf('- The Stiffness matrix K is (in [N/m]):\n')
fprintf('\t % .0e \t % .0e \t % .0e \t % .0e \t % .0e \t % .0e\n', stewart.kinematics.K)
end
if isfield(stewart.kinematics, 'C')
fprintf('- The Damping matrix C is (in [m/N]):\n')
fprintf('\t % .0e \t % .0e \t % .0e \t % .0e \t % .0e \t % .0e\n', stewart.kinematics.C)
end
#+end_src
** =initializeCylindricalStruts=: Define the inertia of cylindrical struts
#+begin_src matlab :tangle matlab/src/initializeCylindricalStruts.m :comments none :mkdirp yes :eval no
function [stewart] = initializeCylindricalStruts(stewart, args)
% initializeCylindricalStruts - Define the mass and moment of inertia of cylindrical struts
%
% Syntax: [stewart] = initializeCylindricalStruts(args)
%
% Inputs:
% - args - Structure with the following fields:
% - Fsm [1x1] - Mass of the Fixed part of the struts [kg]
% - Fsh [1x1] - Height of cylinder for the Fixed part of the struts [m]
% - Fsr [1x1] - Radius of cylinder for the Fixed part of the struts [m]
% - Msm [1x1] - Mass of the Mobile part of the struts [kg]
% - Msh [1x1] - Height of cylinder for the Mobile part of the struts [m]
% - Msr [1x1] - Radius of cylinder for the Mobile part of the struts [m]
%
% Outputs:
% - stewart - updated Stewart structure with the added fields:
% - struts_F [struct] - structure with the following fields:
% - M [6x1] - Mass of the Fixed part of the struts [kg]
% - I [3x3x6] - Moment of Inertia for the Fixed part of the struts [kg*m^2]
% - H [6x1] - Height of cylinder for the Fixed part of the struts [m]
% - R [6x1] - Radius of cylinder for the Fixed part of the struts [m]
% - struts_M [struct] - structure with the following fields:
% - M [6x1] - Mass of the Mobile part of the struts [kg]
% - I [3x3x6] - Moment of Inertia for the Mobile part of the struts [kg*m^2]
% - H [6x1] - Height of cylinder for the Mobile part of the struts [m]
% - R [6x1] - Radius of cylinder for the Mobile part of the struts [m]
arguments
stewart
args.Fsm (1,1) double {mustBeNumeric, mustBePositive} = 0.1
args.Fsh (1,1) double {mustBeNumeric, mustBePositive} = 50e-3
args.Fsr (1,1) double {mustBeNumeric, mustBePositive} = 5e-3
args.Msm (1,1) double {mustBeNumeric, mustBePositive} = 0.1
args.Msh (1,1) double {mustBeNumeric, mustBePositive} = 50e-3
args.Msr (1,1) double {mustBeNumeric, mustBePositive} = 5e-3
end
stewart.struts_M.type = 1;
stewart.struts_M.M = args.Msm;
stewart.struts_M.R = args.Msr;
stewart.struts_M.H = args.Msh;
stewart.struts_F.type = 1;
stewart.struts_F.M = args.Fsm;
stewart.struts_F.R = args.Fsr;
stewart.struts_F.H = args.Fsh;
end
#+end_src
** =initializeJointDynamics=: Add Stiffness and Damping properties for spherical joints
#+begin_src matlab :tangle matlab/src/initializeJointDynamics.m :comments none :mkdirp yes :eval no
function [stewart] = initializeJointDynamics(stewart, args)
% initializeJointDynamics - Add Stiffness and Damping properties for the spherical joints
%
% Syntax: [stewart] = initializeJointDynamics(args)
%
% Inputs:
% - args - Structure with the following fields:
% - type_F - 'universal', 'spherical', 'universal_p', 'spherical_p'
% - type_M - 'universal', 'spherical', 'universal_p', 'spherical_p'
% - Kf_M [6x1] - Bending (Rx, Ry) Stiffness for each top joints [(N.m)/rad]
% - Kt_M [6x1] - Torsion (Rz) Stiffness for each top joints [(N.m)/rad]
% - Cf_M [6x1] - Bending (Rx, Ry) Damping of each top joint [(N.m)/(rad/s)]
% - Ct_M [6x1] - Torsion (Rz) Damping of each top joint [(N.m)/(rad/s)]
% - Kf_F [6x1] - Bending (Rx, Ry) Stiffness for each bottom joints [(N.m)/rad]
% - Kt_F [6x1] - Torsion (Rz) Stiffness for each bottom joints [(N.m)/rad]
% - Cf_F [6x1] - Bending (Rx, Ry) Damping of each bottom joint [(N.m)/(rad/s)]
% - Cf_F [6x1] - Torsion (Rz) Damping of each bottom joint [(N.m)/(rad/s)]
%
% Outputs:
% - stewart - updated Stewart structure with the added fields:
% - stewart.joints_F and stewart.joints_M:
% - type - 1 (universal), 2 (spherical), 3 (universal perfect), 4 (spherical perfect)
% - Kx, Ky, Kz [6x1] - Translation (Tx, Ty, Tz) Stiffness [N/m]
% - Kf [6x1] - Flexion (Rx, Ry) Stiffness [(N.m)/rad]
% - Kt [6x1] - Torsion (Rz) Stiffness [(N.m)/rad]
% - Cx, Cy, Cz [6x1] - Translation (Rx, Ry) Damping [N/(m/s)]
% - Cf [6x1] - Flexion (Rx, Ry) Damping [(N.m)/(rad/s)]
% - Cb [6x1] - Torsion (Rz) Damping [(N.m)/(rad/s)]
arguments
stewart
args.type_F char {mustBeMember(args.type_F,{'2dof', '3dof', '4dof', '6dof', 'flexible'})} = '2dof'
args.type_M char {mustBeMember(args.type_M,{'2dof', '3dof', '4dof', '6dof', 'flexible'})} = '3dof'
args.Kf_M (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Cf_M (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Kt_M (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Ct_M (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Kf_F (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Cf_F (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Kt_F (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Ct_F (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Ka_F (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Ca_F (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Kr_F (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Cr_F (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Ka_M (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Ca_M (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Kr_M (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.Cr_M (1,1) double {mustBeNumeric, mustBeNonnegative} = 0
args.K_M double {mustBeNumeric} = zeros(6,6)
args.M_M double {mustBeNumeric} = zeros(6,6)
args.n_xyz_M double {mustBeNumeric} = zeros(2,3)
args.xi_M double {mustBeNumeric} = 0.1
args.step_file_M char {} = ''
args.K_F double {mustBeNumeric} = zeros(6,6)
args.M_F double {mustBeNumeric} = zeros(6,6)
args.n_xyz_F double {mustBeNumeric} = zeros(2,3)
args.xi_F double {mustBeNumeric} = 0.1
args.step_file_F char {} = ''
end
switch args.type_F
case '2dof'
stewart.joints_F.type = 1;
case '3dof'
stewart.joints_F.type = 2;
case '4dof'
stewart.joints_F.type = 3;
case '6dof'
stewart.joints_F.type = 4;
case 'flexible'
stewart.joints_F.type = 5;
otherwise
error("joints_F are not correctly defined")
end
switch args.type_M
case '2dof'
stewart.joints_M.type = 1;
case '3dof'
stewart.joints_M.type = 2;
case '4dof'
stewart.joints_M.type = 3;
case '6dof'
stewart.joints_M.type = 4;
case 'flexible'
stewart.joints_M.type = 5;
otherwise
error("joints_M are not correctly defined")
end
stewart.joints_M.Ka = args.Ka_M;
stewart.joints_M.Kr = args.Kr_M;
stewart.joints_F.Ka = args.Ka_F;
stewart.joints_F.Kr = args.Kr_F;
stewart.joints_M.Ca = args.Ca_M;
stewart.joints_M.Cr = args.Cr_M;
stewart.joints_F.Ca = args.Ca_F;
stewart.joints_F.Cr = args.Cr_F;
stewart.joints_M.Kf = args.Kf_M;
stewart.joints_M.Kt = args.Kt_M;
stewart.joints_F.Kf = args.Kf_F;
stewart.joints_F.Kt = args.Kt_F;
stewart.joints_M.Cf = args.Cf_M;
stewart.joints_M.Ct = args.Ct_M;
stewart.joints_F.Cf = args.Cf_F;
stewart.joints_F.Ct = args.Ct_F;
stewart.joints_F.M = args.M_F;
stewart.joints_F.K = args.K_F;
stewart.joints_F.n_xyz = args.n_xyz_F;
stewart.joints_F.xi = args.xi_F;
stewart.joints_F.xi = args.xi_F;
stewart.joints_F.step_file = args.step_file_F;
stewart.joints_M.M = args.M_M;
stewart.joints_M.K = args.K_M;
stewart.joints_M.n_xyz = args.n_xyz_M;
stewart.joints_M.xi = args.xi_M;
stewart.joints_M.step_file = args.step_file_M;
end
#+end_src
* Helping Functions :noexport:
** Initialize Path
#+NAME: m-init-path
#+BEGIN_SRC matlab
%% Path for functions, data and scripts
addpath('./matlab/mat/'); % Path for data
addpath('./matlab/src/'); % Path for functions
addpath('./matlab/subsystems/'); % Path for Subsystems Simulink files
addpath('./matlab/'); % Path for scripts
#+END_SRC
#+NAME: m-init-path-tangle
#+BEGIN_SRC matlab
%% Path for functions, data and scripts
addpath('./mat/'); % Path for data
addpath('./src/'); % Path for functions
addpath('./subsystems/'); % Path for Subsystems Simulink files
#+END_SRC
** Initialize Simscape Model
#+NAME: m-init-simscape
#+begin_src matlab
% Simulink Model name
mdl = 'nano_hexapod_model';
#+end_src
** Initialize other elements
#+NAME: m-init-other
#+BEGIN_SRC matlab
%% Colors for the figures
colors = colororder;
#+END_SRC