diff --git a/figs/test_nhexa_center_part_hexapod_mounting.jpg b/figs/test_nhexa_center_part_hexapod_mounting.jpg index 65fb347..d9667db 100644 Binary files a/figs/test_nhexa_center_part_hexapod_mounting.jpg and b/figs/test_nhexa_center_part_hexapod_mounting.jpg differ diff --git a/figs/test_nhexa_mount_encoder_heads.jpg b/figs/test_nhexa_mount_encoder_heads.jpg new file mode 100644 index 0000000..99ba6a0 Binary files /dev/null and b/figs/test_nhexa_mount_encoder_heads.jpg differ diff --git a/figs/test_nhexa_mount_encoder_rulers.jpg b/figs/test_nhexa_mount_encoder_rulers.jpg new file mode 100644 index 0000000..613e4f3 Binary files /dev/null and b/figs/test_nhexa_mount_encoder_rulers.jpg differ diff --git a/figs/test_nhexa_mounted_hexapod.jpg b/figs/test_nhexa_mounted_hexapod.jpg new file mode 100644 index 0000000..a7c4c6d Binary files /dev/null and b/figs/test_nhexa_mounted_hexapod.jpg differ diff --git a/figs/test_nhexa_mounting_tool_hexapod_top_view.pdf b/figs/test_nhexa_mounting_tool_hexapod_top_view.pdf new file mode 100644 index 0000000..ccbe906 Binary files /dev/null and b/figs/test_nhexa_mounting_tool_hexapod_top_view.pdf differ diff --git a/figs/test_nhexa_mounting_tool_hexapod_top_view.png b/figs/test_nhexa_mounting_tool_hexapod_top_view.png new file mode 100644 index 0000000..c9360d2 Binary files /dev/null and b/figs/test_nhexa_mounting_tool_hexapod_top_view.png differ diff --git a/figs/test_nhexa_mounting_tool_hexapod_top_view.svg b/figs/test_nhexa_mounting_tool_hexapod_top_view.svg new file mode 100644 index 0000000..005bc42 Binary files /dev/null and b/figs/test_nhexa_mounting_tool_hexapod_top_view.svg differ diff --git a/figs/test_nhexa_plates_tolerances.jpg b/figs/test_nhexa_plates_tolerances.jpg new file mode 100644 index 0000000..0f8044f Binary files /dev/null and b/figs/test_nhexa_plates_tolerances.jpg differ diff --git a/figs/test_nhexa_table_springs.jpg b/figs/test_nhexa_table_springs.jpg new file mode 100644 index 0000000..530235f Binary files /dev/null and b/figs/test_nhexa_table_springs.jpg differ diff --git a/test-bench-nano-hexapod.org b/test-bench-nano-hexapod.org index 4cac7a1..07b91a8 100644 --- a/test-bench-nano-hexapod.org +++ b/test-bench-nano-hexapod.org @@ -131,7 +131,28 @@ Maybe the rest is not so interesting here as it will be presented again in the n - High Authority Controller HAC - Decoupling Strategy -** TODO [#A] Update the default APA parameters to have good match +** TODO [#C] Add nice pictures + +[[file:~/Cloud/pictures/work/nano-hexapod/vibration-table]] + +** TODO [#B] Proper analysis of the identified dynamics + +- [ ] Top plate flexible modes (2 modes) +- [ ] Modes of the encoder supports +- [ ] ... + +** TODO [#B] Make nice subfigures for identified modes +SCHEDULED: <2024-10-26 Sat> + +Maybe try to do similar thing as for the micro station: [[file:~/Cloud/work-projects/ID31-NASS/phd-thesis-chapters/A3-micro-station-modal-analysis/mode_shapes-gif-to-jpg/gen_mode_1.sh]] + +- [ ] Table: 6 rigid body modes + 3 flexible modes + [[file:figs/modal-analysis-table]] +- [ ] Nano hexapod: 6 rigid body modes + 2 flexible modes + [[file:figs/modal-analysis-hexapod]] + +** DONE [#A] Update the default APA parameters to have good match +CLOSED: [2024-10-26 Sat 15:25] initializeNanoHexapodFinal @@ -175,9 +196,13 @@ end #+end_src -** TODO [#A] Check why the model has more damping now +** DONE [#A] Check why the model has more damping now +CLOSED: [2024-10-26 Sat 15:26] -** TODO [#A] Determine how to manage the Simscape model of the hexapod +- Probably because damping on the FJ bench was overestimated (the damping linked to the suspended mass was maybe underestimated) + +** DONE [#A] Determine how to manage the Simscape model of the hexapod +CLOSED: [2024-10-26 Sat 15:26] - git submodule? - Maybe just copy paste the directory as it will not change a lot now @@ -3555,932 +3580,141 @@ set(gca, 'XScale', 'lin'); set(gca, 'YScale', 'lin'); xlabel('Real'); ylabel('Imag'); xlim([-10, 1]); ylim([-4, 2]); #+end_src -* Introduction :ignore: -This document is dedicated to the experimental study of the nano-hexapod shown in Figure ref:fig:test_nhexa_picture_bench_granite_nano_hexapod. +** Other Backups +*** Nano-Hexapod Compliance - Effect of IFF +<> -#+name: fig:test_nhexa_picture_bench_granite_nano_hexapod -#+caption: Nano-Hexapod -#+attr_latex: :width \linewidth -[[file:figs/test_nhexa_IMG_20210608_152917.jpg]] +In this section, we wish to estimate the effectiveness of the IFF strategy regarding the compliance. -#+name: fig:test_nhexa_picture_bench_granite_overview -#+caption: Nano-Hexapod and the control electronics -#+attr_latex: :width \linewidth -[[file:figs/test_nhexa_IMG_20210608_154722.jpg]] - -In Figure ref:fig:test_nhexa_nano_hexapod_signals is shown a block diagram of the experimental setup. -When possible, the notations are consistent with this diagram and summarized in Table ref:tab:list_signals. - -#+begin_src latex :file nano_hexapod_signals.pdf -\definecolor{instrumentation}{rgb}{0, 0.447, 0.741} -\definecolor{mechanics}{rgb}{0.8500, 0.325, 0.098} - -\begin{tikzpicture} - % Blocs - \node[block={4.0cm}{3.0cm}, fill=mechanics!20!white] (nano_hexapod) {Mechanics}; - \coordinate[] (inputF) at (nano_hexapod.west); - \coordinate[] (outputL) at ($(nano_hexapod.south east)!0.8!(nano_hexapod.north east)$); - \coordinate[] (outputF) at ($(nano_hexapod.south east)!0.2!(nano_hexapod.north east)$); - - \node[block, left= 0.8 of inputF, fill=instrumentation!20!white, align=center] (F_stack) {\tiny Actuator \\ \tiny stacks}; - \node[block, left= 0.8 of F_stack, fill=instrumentation!20!white] (PD200) {PD200}; - \node[DAC, left= 0.8 of PD200, fill=instrumentation!20!white] (F_DAC) {DAC}; - \node[block, right=0.8 of outputF, fill=instrumentation!20!white, align=center] (Fm_stack){\tiny Sensor \\ \tiny stack}; - \node[ADC, right=0.8 of Fm_stack,fill=instrumentation!20!white] (Fm_ADC) {ADC}; - \node[block, right=0.8 of outputL, fill=instrumentation!20!white] (encoder) {\tiny Encoder}; - - % Connections and labels - \draw[->] ($(F_DAC.west)+(-0.8,0)$) node[above right]{$\bm{u}$} node[below right]{$[V]$} -- node[sloped]{$/$} (F_DAC.west); - \draw[->] (F_DAC.east) -- node[midway, above]{$\tilde{\bm{u}}$}node[midway, below]{$[V]$} (PD200.west); - \draw[->] (PD200.east) -- node[midway, above]{$\bm{u}_a$}node[midway, below]{$[V]$} (F_stack.west); - \draw[->] (F_stack.east) -- (inputF) node[above left]{$\bm{\tau}$}node[below left]{$[N]$}; - - \draw[->] (outputF) -- (Fm_stack.west) node[above left]{$\bm{\epsilon}$} node[below left]{$[m]$}; - \draw[->] (Fm_stack.east) -- node[midway, above]{$\tilde{\bm{\tau}}_m$}node[midway, below]{$[V]$} (Fm_ADC.west); - \draw[->] (Fm_ADC.east) -- node[sloped]{$/$} ++(0.8, 0)coordinate(end) node[above left]{$\bm{\tau}_m$}node[below left]{$[V]$}; - - \draw[->] (outputL) -- (encoder.west) node[above left]{$d\bm{\mathcal{L}}$} node[below left]{$[m]$}; - \draw[->] (encoder.east) -- node[sloped]{$/$} (encoder-|end) node[above left]{$d\bm{\mathcal{L}}_m$}node[below left]{$[m]$}; - - % Nano-Hexapod - \begin{scope}[on background layer] - \node[fit={(F_stack.west|-nano_hexapod.south) (Fm_stack.east|-nano_hexapod.north)}, fill=black!20!white, draw, inner sep=2pt] (system) {}; - \node[above] at (system.north) {Nano-Hexapod}; - \end{scope} -\end{tikzpicture} -#+end_src - -#+name: fig:test_nhexa_nano_hexapod_signals -#+caption: Block diagram of the system with named signals -#+attr_latex: :scale 1 -[[file:figs/test_nhexa_nano_hexapod_signals.png]] - -#+name: tab:list_signals -#+caption: List of signals -#+attr_latex: :environment tabularx :width \linewidth :align Xllll -#+attr_latex: :center t :booktabs t -| | *Unit* | *Matlab* | *Vector* | *Elements* | -|------------------------------------+-----------+-----------+-----------------------+----------------------| -| Control Input (wanted DAC voltage) | =[V]= | =u= | $\bm{u}$ | $u_i$ | -| DAC Output Voltage | =[V]= | =u= | $\tilde{\bm{u}}$ | $\tilde{u}_i$ | -| PD200 Output Voltage | =[V]= | =ua= | $\bm{u}_a$ | $u_{a,i}$ | -| Actuator applied force | =[N]= | =tau= | $\bm{\tau}$ | $\tau_i$ | -|------------------------------------+-----------+-----------+-----------------------+----------------------| -| Strut motion | =[m]= | =dL= | $d\bm{\mathcal{L}}$ | $d\mathcal{L}_i$ | -| Encoder measured displacement | =[m]= | =dLm= | $d\bm{\mathcal{L}}_m$ | $d\mathcal{L}_{m,i}$ | -|------------------------------------+-----------+-----------+-----------------------+----------------------| -| Force Sensor strain | =[m]= | =epsilon= | $\bm{\epsilon}$ | $\epsilon_i$ | -| Force Sensor Generated Voltage | =[V]= | =taum= | $\tilde{\bm{\tau}}_m$ | $\tilde{\tau}_{m,i}$ | -| Measured Generated Voltage | =[V]= | =taum= | $\bm{\tau}_m$ | $\tau_{m,i}$ | -|------------------------------------+-----------+-----------+-----------------------+----------------------| -| Motion of the top platform | =[m,rad]= | =dX= | $d\bm{\mathcal{X}}$ | $d\mathcal{X}_i$ | -| Metrology measured displacement | =[m,rad]= | =dXm= | $d\bm{\mathcal{X}}_m$ | $d\mathcal{X}_{m,i}$ | - -This document is divided in the following sections: -- Section ref:sec:test_nhexa_mounting: mounting of the nano-hexapod -- Section ref:sec:test_nhexa_encoders_plates: the same is done when the encoders are fixed to the plates. -- Section ref:sec:test_nhexa_decentralized_hac_iff: a decentralized HAC-LAC strategy is studied and implemented. - -* Mounting Procedure -<> - -** Mounting Goals - -#+name: fig:test_nhexa_nano_hexapod_elements -#+caption: Received top and bottom nano-hexapod's plates -#+attr_latex: :width \linewidth -[[file:figs/test_nhexa_nano_hexapod_elements.png]] - -#+name: fig:test_nhexa_fixation_flexible_joints -#+caption: Fixation of the flexible points to the nano-hexapod plates -#+begin_figure -#+attr_latex: :caption \subcaption{\label{fig:test_nhexa_fixation_flexible_joints}Flexible Joint Clamping} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :width 0.99\linewidth -[[file:figs/test_nhexa_fixation_flexible_joints.png]] -#+end_subfigure -#+attr_latex: :caption \subcaption{\label{fig:test_nhexa_location_bot_flex}Bottom Positioning} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :width 0.99\linewidth -[[file:figs/test_nhexa_location_bot_flex.png]] -#+end_subfigure -#+attr_latex: :caption \subcaption{\label{fig:test_nhexa_location_top_flexible_joints}Top positioning} -#+attr_latex: :options {0.33\textwidth} -#+begin_subfigure -#+attr_latex: :width 0.99\linewidth -[[file:figs/test_nhexa_location_top_flexible_joints.png]] -#+end_subfigure -#+end_figure - -#+name: fig:test_nhexa_specifications_flexible_joints -#+caption:Reference surfaces of the flexible joint interface with the plates -#+attr_latex: :width 0.3\linewidth -[[file:figs/test_nhexa_specifications_flexible_joints.png]] - -** Mounting Bench - - -#+name: fig:test_nhexa_mounting_hexapod_cut -#+caption: Received top and bottom nano-hexapod's plates -#+attr_latex: :width \linewidth -[[file:figs/test_nhexa_mounting_hexapod_cut.png]] - -#+name: fig:test_nhexa_center_part_hexapod_mounting -#+caption: Received top and bottom nano-hexapod's plates -#+attr_latex: :width \linewidth -[[file:figs/test_nhexa_center_part_hexapod_mounting.jpg]] - -** Mounting Procedure - -1. Fix the bottom plate with the cylindrical tool -2. Put the top plate on the granite -3. Put the cylindrical tool and bottom plate on top of the top plate (Figure ref:fig:test_nhexa_mounting_tool_hexapod_bot_view). - This position the bottom plate with respect to the top plate in X, Y, Z, Rx, Ry -4. Put the pin to position/fix the Rz. - Now the two plates should be position and clamped together -5. Fix the 6 struts -6. Remove the pin and the tool -7. Put the nano-hexapod in place - -** Nano-Hexapod Mounting -<> - -*** Introduction :ignore: - - -*** Plates - -#+name: fig:test_nhexa_nano_hexapod_plates -#+caption: Received top and bottom nano-hexapod's plates -#+attr_latex: :width \linewidth -[[file:figs/test_nhexa_nano_hexapod_plates.jpg]] - -#+name: fig:test_nhexa_plates_tolerences -#+caption: Bottom plate on the measurement granite (FARO arm). Zoom on the main feature of the plate -#+attr_latex: :width \linewidth -[[file:figs/test_nhexa_plates_tolerences.jpg]] - -*** Mounting Tool - -A mounting tool is used to position the top and bottom platforms. -Then the struts can be mounted one by one. -When all the struts are mounted, the "mounting tool" is disassembled and the nano-hexapod is considered to be mounted. - -The main goal of this "mounting tool" is to position the "V" shapes of both plates such that they are coaxial. - -The straightness is the diameter of the smallest cylinder containing all points of the axis. - -#+name: tab:measured_straightness -#+caption: Measured straightness between the two "V" for the six struts. These measurements are performed two times for each strut. -#+attr_latex: :environment tabularx :width 0.5\linewidth :align Xcc -#+attr_latex: :center t :booktabs t -| Strut nb | *Meas 1* | *Meas 2* | -|----------+----------+----------| -| 1 | 7um | 3um | -| 2 | 11um | 11um | -| 3 | 15um | 14um | -| 4 | 6um | 6um | -| 5 | 7um | 5um | -| 6 | 6um | 7um | - -Using the FARO arm, the coaxiality of the "V" shapes have been measured to better than $15\,\mu m$! -This means that the two cylinders corresponding to the flexible joints are both within a perfect cylinder with a diameter of $15\,\mu m$. -This is probably better than that, but we reached the limit of the FARO arm's precision. - -#+name: fig:test_nhexa_mounting_tool_hexapod_bot_view -#+caption: Bottom and top plates mounted together with the special tool -#+attr_latex: :width \linewidth -[[file:figs/test_nhexa_mounting_tool_hexapod_bot_view.jpg]] - -#+name: fig:test_nhexa_mounting_tool_hexapod_top_view -#+caption: Bottom and top plates mounted together with the special tool (top view) -#+attr_latex: :width \linewidth -[[file:figs/test_nhexa_mounting_tool_hexapod_top_view.jpg]] - -*** Mounted Hexapod - -#+name: fig:test_nhexa_nano_hexapod_mounted -#+caption: Mounted Nano-Hexapod -#+attr_latex: :width \linewidth -[[file:figs/test_nhexa_nano_hexapod_mounted.jpg]] - -* Suspended Table -** Introduction - -This document is divided as follows: -- Section ref:sec:experimental_setup: the experimental setup and all the instrumentation are described -- Section ref:sec:meas_transformation: the mathematics used to compute the 6DoF motion of a solid body from several inertial sensor is derived -- Section ref:sec:simscape_model: a Simscape model of the vibration table is developed -- Section ref:sec:table_dynamics: the table dynamics is identified and compared with the Simscape model - -** Experimental Setup -<> -*** Introduction :ignore: -*** CAD Model - -#+name: fig:vibration-table-cad-view -#+caption: CAD View of the vibration table -#+attr_latex: :width 0.8\linewidth -[[file:figs/vibration-table-cad-view.png]] - -*** Instrumentation - -#+begin_note -Here are the documentation of the equipment used for this vibration table: -- Modal Shaker: Watson and Gearing -- Inertial Shaker: [[file:doc/inertial_shakers.pdf][IS20]] -- Viscoelastic supports: [[file:doc/810002_doc.pdf][810002]] -- Spring supports: [[file:doc/9129fcb6ec46bb52925bb16155a850f3be01c479.pdf][MV803-12CC]] -- Optical Table: [[https://www.thorlabs.com/thorproduct.cfm?partnumber=B4545A][B4545A]] -- Triaxial Accelerometer: [[https://www.pcb.com/products?model=356b18][356B18]] -- OROS -#+end_note - -*** Suspended table - -- Dimensions :: 450 mm x 450 mm x 60 mm -- Mass :: 21.30 kg - -#+name: fig:compliance_optical_table -#+caption: Compliance of the B4545A optical table -#+attr_latex: :width 0.8\linewidth -[[file:figs/B4545A_Compliance_inLb-780.png]] - -If we include including the bottom interface plate: -- Total mass: 30.7 kg -- CoM: 42mm below Center of optical table -- Ix = 0.54, Iy = 0.54, Iz = 1.07 (with respect to CoM) - -*** Inertial Sensors - -| Equipment | -|----------------------------------| -| (2x) 1D accelerometer [[https://www.pcbpiezotronics.fr/produit/accelerometre/393b05/][PCB 393B05]] | -| (4x) 3D accelerometer [[https://www.pcbpiezotronics.fr/produit/accelerometres/356b18/][PCB 356B18]] | - -** Compute the 6DoF solid body motion from several inertial sensors -:PROPERTIES: -:header-args:matlab+: :tangle matlab/meas_transformation.m -:END: -<> -*** Introduction :ignore: -Let's consider a solid body with several accelerometers attached to it (Figure ref:fig:local_to_global_coordinates). - -#+begin_src latex :file local_to_global_coordinates.pdf :post pdf2svg(file=*this*, ext="png") :exports results -\newcommand\irregularcircle[2]{% radius, irregularity - \pgfextra {\pgfmathsetmacro\len{(#1)+rand*(#2)}} - +(0:\len pt) - \foreach \a in {10,20,...,350}{ - \pgfextra {\pgfmathsetmacro\len{(#1)+rand*(#2)}} - -- +(\a:\len pt) - } -- cycle -} -\begin{tikzpicture} - \draw[rounded corners=1mm, fill=blue!30!white] (0, 0) \irregularcircle{3cm}{1mm}; - - \node[] (origin) at (0, 0) {$\bullet$}; - \begin{scope}[shift={(origin)}] - \def\axissize{0.8cm} - \draw[->] (0, 0) -- ++(\axissize, 0) node[above left]{$x$}; - \draw[->] (0, 0) -- ++(0, \axissize) node[below right]{$y$}; - \draw[fill, color=black] (0, 0) circle (0.05*\axissize); - \node[draw, circle, inner sep=0pt, minimum size=0.4*\axissize, label=left:$z$] (yaxis) at (0, 0){}; - \node[below right] at (0, 0){$\{O\}$}; - \end{scope} - - \coordinate[] (p1) at (-1.5, -1.5); - \coordinate[] (p2) at (-1.5, -1.5); - \coordinate[] (p3) at ( 1.5, -1.5); - \coordinate[] (p4) at ( 1.5, -1.5); - \coordinate[] (p5) at ( 1.5, 1.5); - \coordinate[] (p6) at ( 1.5, 1.5); - - \draw[->] (p1)node[]{$\bullet$} -- ++(0, 1)node[right]{$a_1$}; - \node[draw, circle, inner sep=0pt, minimum size=0.3cm, label=left:$a_2$] at (p2){}; - \draw[fill, color=black] (p2) circle (0.05); - \draw[->] (p3)node[]{$\bullet$} -- ++(1, 0)node[right]{$a_3$}; - \node[draw, circle, inner sep=0pt, minimum size=0.3cm, label=left:$a_4$] at (p4){}; - \draw[fill, color=black] (p4) circle (0.05); - \draw[->] (p5)node[]{$\bullet$} -- ++(1, 0)node[right]{$a_5$}; - \node[draw, circle, inner sep=0pt, minimum size=0.3cm, label=left:$a_6$] at (p6){}; - \draw[fill, color=black] (p6) circle (0.04); -\end{tikzpicture} -#+end_src - -#+name: fig:local_to_global_coordinates -#+caption: Schematic of the measured motions of a solid body -#+RESULTS: -[[file:figs/local_to_global_coordinates.png]] - -The goal of this section is to see how to compute the acceleration/angular acceleration of the solid body from the accelerations $\vec{a}_i$ measured by the accelerometers. - -The acceleration/angular acceleration of the solid body is defined as the vector ${}^O\vec{x}$: -\begin{equation} -{}^O\vec{x} = \begin{bmatrix} - \dot{v}_x \\ \dot{v}_y \\ \dot{v}_z \\ \dot{\omega}_x \\ \dot{\omega}_y \\ \dot{\omega}_z -\end{bmatrix} -\end{equation} - -As we want to measure 6dof, we suppose that we have 6 uniaxial acceleremoters (we could use more, but 6 is enough). -The measurement of the individual vectors is defined as the vector $\vec{a}$: -\begin{equation} -\vec{a} = \begin{bmatrix} - a_1 \\ a_2 \\ a_3 \\ a_4 \\ a_5 \\ a_6 -\end{bmatrix} -\end{equation} - -From the positions and orientations of the acceleremoters (defined in Section ref:sec:accelerometer_pos), it is quite straightforward to compute the accelerations measured by the sensors from the acceleration/angular acceleration of the solid body (Section [[sec:transformation_motion_to_acc]]). -From this, we can easily build a transformation matrix $M$, such that: -\begin{equation} -\vec{a} = M \cdot {}^O\vec{x} -\end{equation} - -If the matrix is invertible, we can just take the inverse in order to obtain the transformation matrix giving the 6dof acceleration of the solid body from the accelerometer measurements (Section ref:sec:transformation_acc_to_motion): -\begin{equation} -{}^O\vec{x} = M^{-1} \cdot \vec{a} -\end{equation} - -If it is not invertible, then it means that it is not possible to compute all 6dof of the solid body from the measurements. -The solution is then to change the location/orientation of some of the accelerometers. - -*** 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 -addpath('matlab/') -#+end_src - -*** Define accelerometers positions/orientations -<> -Let's first define the position and orientation of all measured accelerations with respect to a defined frame $\{O\}$. +The top plate is excited vertically using the instrumented hammer two times: +1. no control loop is used +2. decentralized IFF is used +The data are loaded. #+begin_src matlab -Opm = [-0.1875, -0.1875, -0.245; - -0.1875, -0.1875, -0.245; - 0.1875, -0.1875, -0.245; - 0.1875, -0.1875, -0.245; - 0.1875, 0.1875, -0.245; - 0.1875, 0.1875, -0.245]'; +frf_ol = load('Measurement_Z_axis.mat'); % Open-Loop +frf_iff = load('Measurement_Z_axis_damped.mat'); % IFF #+end_src -There are summarized in Table ref:tab:accelerometers_table_positions. - -#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) -data2orgtable(Opm, {'x', 'y', 'z'}, {'$a_1$', '$a_2$', '$a_3$', '$a_4$', '$a_5$', '$a_6$'}, ' %.3f '); -#+end_src - -#+name: tab:accelerometers_table_positions -#+caption: Positions of the accelerometers fixed to the vibration table with respect to $\{O\}$ -#+attr_latex: :environment tabularx :width 0.55\linewidth :align Xcccccc -#+attr_latex: :center t :booktabs t :float t -#+RESULTS: -| | $a_1$ | $a_2$ | $a_3$ | $a_4$ | $a_5$ | $a_6$ | -|---+--------+--------+--------+--------+--------+--------| -| x | -0.188 | -0.188 | 0.188 | 0.188 | 0.188 | 0.188 | -| y | -0.188 | -0.188 | -0.188 | -0.188 | 0.188 | 0.188 | -| z | -0.245 | -0.245 | -0.245 | -0.245 | -0.245 | -0.245 | - -We then define the direction of the measured accelerations (unit vectors): +The mean vertical motion of the top platform is computed by averaging all 5 vertical accelerometers. #+begin_src matlab -Osm = [0, 1, 0; - 0, 0, 1; - 1, 0, 0; - 0, 0, 1; - 1, 0, 0; - 0, 1, 0]'; +%% Multiply by 10 (gain in m/s^2/V) and divide by 5 (number of accelerometers) +d_frf_ol = 10/5*(frf_ol.FFT1_H1_4_1_RMS_Y_Mod + frf_ol.FFT1_H1_7_1_RMS_Y_Mod + frf_ol.FFT1_H1_10_1_RMS_Y_Mod + frf_ol.FFT1_H1_13_1_RMS_Y_Mod + frf_ol.FFT1_H1_16_1_RMS_Y_Mod)./(2*pi*frf_ol.FFT1_H1_16_1_RMS_X_Val).^2; +d_frf_iff = 10/5*(frf_iff.FFT1_H1_4_1_RMS_Y_Mod + frf_iff.FFT1_H1_7_1_RMS_Y_Mod + frf_iff.FFT1_H1_10_1_RMS_Y_Mod + frf_iff.FFT1_H1_13_1_RMS_Y_Mod + frf_iff.FFT1_H1_16_1_RMS_Y_Mod)./(2*pi*frf_iff.FFT1_H1_16_1_RMS_X_Val).^2; #+end_src -They are summarized in Table ref:tab:accelerometers_table_orientations. - -#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) -data2orgtable(Osm, {'x', 'y', 'z'}, {'$\hat{s}_1$', '$\hat{s}_2$', '$\hat{s}_3$', '$\hat{s}_4$', '$\hat{s}_5$', '$\hat{s}_6$'}, ' %.0f '); +The vertical compliance (magnitude of the transfer function from a vertical force applied on the top plate to the vertical motion of the top plate) is shown in Figure ref:fig:test_nhexa_compliance_vertical_comp_iff. +#+begin_src matlab :exports none +%% Comparison of the vertical compliances (OL and IFF) +figure; +hold on; +plot(frf_ol.FFT1_H1_16_1_RMS_X_Val, d_frf_ol, 'DisplayName', 'OL'); +plot(frf_iff.FFT1_H1_16_1_RMS_X_Val, d_frf_iff, 'DisplayName', 'IFF'); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('Vertical Compliance [$m/N$]'); +xlim([20, 2e3]); ylim([2e-9, 2e-5]); +legend('location', 'northeast'); #+end_src -#+name: tab:accelerometers_table_orientations -#+caption: Orientations of the accelerometers fixed to the vibration table expressed in $\{O\}$ -#+attr_latex: :environment tabularx :width 0.35\linewidth :align Xcccccc -#+attr_latex: :center t :booktabs t :float t +#+begin_src matlab :tangle no :exports results :results file replace +exportFig('figs/compliance_vertical_comp_iff.pdf', 'width', 'wide', 'height', 'normal'); +#+end_src + +#+name: fig:test_nhexa_compliance_vertical_comp_iff +#+caption: Measured vertical compliance with and without IFF #+RESULTS: -| | $\hat{s}_1$ | $\hat{s}_2$ | $\hat{s}_3$ | $\hat{s}_4$ | $\hat{s}_5$ | $\hat{s}_6$ | -|---+-------------+-------------+-------------+-------------+-------------+-------------| -| x | 0 | 0 | 1 | 0 | 1 | 0 | -| y | 1 | 0 | 0 | 0 | 0 | 0 | -| z | 0 | 1 | 0 | 1 | 0 | 1 | +[[file:figs/test_nhexa_compliance_vertical_comp_iff.png]] -*** Transformation matrix from motion of the solid body to accelerometer measurements -<> - -Let's try to estimate the x-y-z acceleration of any point of the solid body from the acceleration/angular acceleration of the solid body expressed in $\{O\}$. -For any point $p_i$ of the solid body (corresponding to an accelerometer), we can write: -\begin{equation} -\begin{bmatrix} -a_{i,x} \\ a_{i,y} \\ a_{i,z} -\end{bmatrix} = \begin{bmatrix} -\dot{v}_x \\ \dot{v}_y \\ \dot{v}_z -\end{bmatrix} + p_i \times \begin{bmatrix} -\dot{\omega}_x \\ \dot{\omega}_y \\ \dot{\omega}_z -\end{bmatrix} -\end{equation} - -We can write the cross product as a matrix product using the skew-symmetric transformation: -\begin{equation} -\begin{bmatrix} -a_{i,x} \\ a_{i,y} \\ a_{i,z} -\end{bmatrix} = \begin{bmatrix} -\dot{v}_x \\ \dot{v}_y \\ \dot{v}_z -\end{bmatrix} + \underbrace{\begin{bmatrix} - 0 & p_{i,z} & -p_{i,y} \\ - -p_{i,z} & 0 & p_{i,x} \\ - p_{i,y} & -p_{i,x} & 0 -\end{bmatrix}}_{P_{i,[\times]}} \cdot \begin{bmatrix} -\dot{\omega}_x \\ \dot{\omega}_y \\ \dot{\omega}_z -\end{bmatrix} -\end{equation} - -If we now want to know the (scalar) acceleration $a_i$ of the point $p_i$ in the direction of the accelerometer direction $\hat{s}_i$, we can just project the 3d acceleration on $\hat{s}_i$: -\begin{equation} -a_i = \hat{s}_i^T \cdot \begin{bmatrix} -a_{i,x} \\ a_{i,y} \\ a_{i,z} -\end{bmatrix} = \hat{s}_i^T \cdot \begin{bmatrix} -\dot{v}_x \\ \dot{v}_y \\ \dot{v}_z -\end{bmatrix} + \left( \hat{s}_i^T \cdot P_{i,[\times]} \right) \cdot \begin{bmatrix} -\dot{\omega}_x \\ \dot{\omega}_y \\ \dot{\omega}_z -\end{bmatrix} -\end{equation} - -Which is equivalent as a simple vector multiplication: -\begin{equation} -a_i = \begin{bmatrix} -\hat{s}_i^T & \hat{s}_i^T \cdot P_{i,[\times]} -\end{bmatrix} -\begin{bmatrix} -\dot{v}_x \\ \dot{v}_y \\ \dot{v}_z \\ \dot{\omega}_x \\ \dot{\omega}_y \\ \dot{\omega}_z -\end{bmatrix} = \begin{bmatrix} -\hat{s}_i^T & \hat{s}_i^T \cdot P_{i,[\times]} -\end{bmatrix} {}^O\vec{x} -\end{equation} - -And finally we can combine the 6 (line) vectors for the 6 accelerometers to write that in a matrix form. -We obtain Eq. eqref:eq:M_matrix. #+begin_important -The transformation from solid body acceleration ${}^O\vec{x}$ from sensor measured acceleration $\vec{a}$ is: -\begin{equation} \label{eq:M_matrix} -\vec{a} = \underbrace{\begin{bmatrix} -\hat{s}_1^T & \hat{s}_1^T \cdot P_{1,[\times]} \\ -\vdots & \vdots \\ -\hat{s}_6^T & \hat{s}_6^T \cdot P_{6,[\times]} -\end{bmatrix}}_{M} {}^O\vec{x} -\end{equation} +From Figure ref:fig:test_nhexa_compliance_vertical_comp_iff, it is clear that the IFF control strategy is very effective in damping the suspensions modes of the nano-hexapod. +It also has the effect of (slightly) degrading the vertical compliance at low frequency. -with $\hat{s}_i$ the unit vector representing the measured direction of the i'th accelerometer expressed in frame $\{O\}$ and $P_{i,[\times]}$ the skew-symmetric matrix representing the cross product of the position of the i'th accelerometer expressed in frame $\{O\}$. +It also seems some damping can be added to the modes at around 205Hz which are flexible modes of the struts. #+end_important -Let's define such matrix using matlab: +*** Comparison with the Simscape Model +<> + +Let's initialize the Simscape model such that it corresponds to the experiment. #+begin_src matlab -M = zeros(length(Opm), 6); +%% Nano-Hexapod is fixed on a rigid granite +support.type = 0; -for i = 1:length(Opm) - Ri = [0, Opm(3,i), -Opm(2,i); - -Opm(3,i), 0, Opm(1,i); - Opm(2,i), -Opm(1,i), 0]; - M(i, 1:3) = Osm(:,i)'; - M(i, 4:6) = Osm(:,i)'*Ri; -end -#+end_src +%% No Payload on top of the Nano-Hexapod +payload.type = 0; -The obtained matrix is shown in Table ref:tab:effect_motion_on_meas. - -#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) -data2orgtable(M, {'$a_1$', '$a_2$', '$a_3$', '$a_4$', '$a_5$', '$a_6$'}, {'$\dot{x}_x$', '$\dot{x}_y$', '$\dot{x}_z$', '$\dot{\omega}_x$', '$\dot{\omega}_y$', '$\dot{\omega}_z$'}, ' %.2f '); -#+end_src - -#+name: tab:effect_motion_on_meas -#+caption: Effect of a displacement/rotation on the 6 measurements -#+attr_latex: :environment tabularx :width 0.45\linewidth :align Xcccccc -#+attr_latex: :center t :booktabs t :float t -#+RESULTS: -| | $\dot{x}_x$ | $\dot{x}_y$ | $\dot{x}_z$ | $\dot{\omega}_x$ | $\dot{\omega}_y$ | $\dot{\omega}_z$ | -|-------+-------------+-------------+-------------+------------------+------------------+------------------| -| $a_1$ | 0.0 | 1.0 | 0.0 | 0.24 | 0.0 | -0.19 | -| $a_2$ | 0.0 | 0.0 | 1.0 | -0.19 | 0.19 | 0.0 | -| $a_3$ | 1.0 | 0.0 | 0.0 | 0.0 | -0.24 | 0.19 | -| $a_4$ | 0.0 | 0.0 | 1.0 | -0.19 | -0.19 | 0.0 | -| $a_5$ | 1.0 | 0.0 | 0.0 | 0.0 | -0.24 | -0.19 | -| $a_6$ | 0.0 | 0.0 | 1.0 | 0.19 | -0.19 | 0.0 | - -*** Compute the transformation matrix from accelerometer measurement to motion of the solid body -<> - -In order to compute the motion of the solid body ${}^O\vec{x}$ with respect to frame $\{O\}$ from the accelerometer measurements $\vec{a}$, we have to inverse the transformation matrix $M$. -\begin{equation} -{}^O\vec{x} = M^{-1} \vec{a} -\end{equation} - -We therefore need the determinant of $M$ to be non zero: -#+begin_src matlab :results value replace :exports both :tangle no -det(M) -#+end_src - -The obtained inverse of the matrix is shown in Table ref:tab:compute_motion_from_meas. - -#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) -data2orgtable(inv(M), {'$\dot{x}_x$', '$\dot{x}_y$', '$\dot{x}_z$', '$\dot{\omega}_x$', '$\dot{\omega}_y$', '$\dot{\omega}_z$'}, {'$a_1$', '$a_2$', '$a_3$', '$a_4$', '$a_5$', '$a_6$'}, ' %.1f '); -#+end_src - -#+name: tab:compute_motion_from_meas -#+caption: Compute the displacement/rotation from the 6 measurements -#+attr_latex: :environment tabularx :width 0.45\linewidth :align Xcccccc -#+attr_latex: :center t :booktabs t :float t -#+RESULTS: -| | $a_1$ | $a_2$ | $a_3$ | $a_4$ | $a_5$ | $a_6$ | -|------------------+-------+-------+-------+-------+-------+-------| -| $\dot{x}_x$ | 0.0 | 0.7 | 0.5 | -0.7 | 0.5 | 0.0 | -| $\dot{x}_y$ | 1.0 | 0.0 | 0.5 | 0.7 | -0.5 | -0.7 | -| $\dot{x}_z$ | 0.0 | 0.5 | 0.0 | 0.0 | 0.0 | 0.5 | -| $\dot{\omega}_x$ | 0.0 | 0.0 | 0.0 | -2.7 | 0.0 | 2.7 | -| $\dot{\omega}_y$ | 0.0 | 2.7 | 0.0 | -2.7 | 0.0 | 0.0 | -| $\dot{\omega}_z$ | 0.0 | 0.0 | 2.7 | 0.0 | -2.7 | 0.0 | - -** Simscape Model -:PROPERTIES: -:header-args:matlab+: :tangle matlab/simscape_model.m -:END: -<> -*** Introduction :ignore: -In this section, the Simscape model of the vibration table is described. - -#+name: fig:simscape_vibration_table -#+caption: 3D representation of the simscape model -#+attr_latex: :width 0.8\linewidth -[[file:figs/simscape_vibration_table.png]] - -*** 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 -addpath('matlab/') -#+end_src - -#+begin_src matlab -% Run meas_transformation.m script in order to get the tranformation (jacobian) matrix -run('meas_transformation.m') -#+end_src - -#+begin_src matlab -% Open the Simulink File -open('vibration_table') -#+end_src - -*** Simscape Sub-systems -<> - -Parameters for sub-components of the simscape model are defined below. - -**** Springs -<> - -The 4 springs supporting the suspended optical table are modelled with "bushing joints" having stiffness and damping in the x-y-z directions: - -#+begin_src matlab -spring.kx = 1e4; % X- Stiffness [N/m] -spring.cx = 1e1; % X- Damping [N/(m/s)] - -spring.ky = 1e4; % Y- Stiffness [N/m] -spring.cy = 1e1; % Y- Damping [N/(m/s)] - -spring.kz = 1e4; % Z- Stiffness [N/m] -spring.cz = 1e1; % Z- Damping [N/(m/s)] - -spring.z0 = 32e-3; % Equilibrium z-length [m] -#+end_src - -And we can increase the "equilibrium position" of the vertical springs to take into account the gravity forces and start closer to equilibrium: -#+begin_src matlab -spring.dl = (30.5918/4)*9.80665/spring.kz; -#+end_src - -**** Inertial Shaker (IS20) -<> - -The inertial shaker is defined as two solid bodies: -- the "housing" that is fixed to the element that we want to excite -- the "inertial mass" that is suspended inside the housing - -The inertial mass is guided inside the housing and an actuator (coil and magnet) can be used to apply a force between the inertial mass and the support. -The "reacting" force on the support is then used as an excitation. - -#+name: tab:is20_characteristics -#+caption: Summary of the IS20 datasheet -#+attr_latex: :environment tabularx :width 0.4\linewidth :align lX -#+attr_latex: :center t :booktabs t :float t -| Characteristic | Value | -|-----------------+------------| -| Output Force | 20 N | -| Frequency Range | 10-3000 Hz | -| Moving Mass | 0.1 kg | -| Total Mass | 0.3 kg | - -From the datasheet in Table ref:tab:is20_characteristics, we can estimate the parameters of the physical shaker. - -These parameters are defined below -#+begin_src matlab -shaker.w0 = 2*pi*10; % Resonance frequency of moving mass [rad/s] -shaker.m = 0.1; % Moving mass [m] -shaker.m_tot = 0.3; % Total mass [m] -shaker.k = shaker.m*shaker.w0^2; % Spring constant [N/m] -shaker.c = 0.2*sqrt(shaker.k*shaker.m); % Damping [N/(m/s)] -#+end_src - -**** 3D accelerometer (356B18) -<> - -An accelerometer consists of 2 solids: -- a "housing" rigidly fixed to the measured body -- an "inertial mass" suspended inside the housing by springs and guided in the measured direction - -The relative motion between the housing and the inertial mass gives a measurement of the acceleration of the measured body (up to the suspension mode of the inertial mass). - -#+name: tab:356b18_characteristics -#+caption: Summary of the 356B18 datasheet -#+attr_latex: :environment tabularx :width 0.5\linewidth :align lX -#+attr_latex: :center t :booktabs t :float t -| Characteristic | Value | -|---------------------+---------------------| -| Sensitivity | 0.102 V/(m/s2) | -| Frequency Range | 0.5 to 3000 Hz | -| Resonance Frequency | > 20 kHz | -| Resolution | 0.0005 m/s2 rms | -| Weight | 0.025 kg | -| Size | 20.3x26.1x20.3 [mm] | - -Here are defined the parameters for the triaxial accelerometer: -#+begin_src matlab -acc_3d.m = 0.005; % Inertial mass [kg] -acc_3d.m_tot = 0.025; % Total mass [m] - -acc_3d.w0 = 2*pi*20e3; % Resonance frequency [rad/s] - -acc_3d.kx = acc_3d.m*acc_3d.w0^2; % Spring constant [N/m] -acc_3d.ky = acc_3d.m*acc_3d.w0^2; % Spring constant [N/m] -acc_3d.kz = acc_3d.m*acc_3d.w0^2; % Spring constant [N/m] - -acc_3d.cx = 1e2; % Damping [N/(m/s)] -acc_3d.cy = 1e2; % Damping [N/(m/s)] -acc_3d.cz = 1e2; % Damping [N/(m/s)] -#+end_src - -DC gain between support acceleration and inertial mass displacement is $-m/k$: -#+begin_src matlab -acc_3d.g_x = 1/(-acc_3d.m/acc_3d.kx); % [m/s^2/m] -acc_3d.g_y = 1/(-acc_3d.m/acc_3d.ky); % [m/s^2/m] -acc_3d.g_z = 1/(-acc_3d.m/acc_3d.kz); % [m/s^2/m] -#+end_src - -We also define the sensitivity in order to have the outputs in volts. -#+begin_src matlab -acc_3d.gV_x = 0.102; % [V/(m/s^2)] -acc_3d.gV_y = 0.102; % [V/(m/s^2)] -acc_3d.gV_z = 0.102; % [V/(m/s^2)] -#+end_src - -The problem with using such model for accelerometers is that this adds states to the identified models (2x3 states for each triaxial accelerometer). -These states represents the dynamics of the suspended inertial mass. -In the frequency band of interest (few Hz up to ~1 kHz), the dynamics of the inertial mass can be ignore (its resonance is way above 1kHz). -Therefore, we might as well use idealized "transform sensors" blocks as they will give the same result up to ~20kHz while allowing to reduce the number of identified states. - -The accelerometer model can be chosen by setting the =type= property: -#+begin_src matlab -acc_3d.type = 2; % 1: inertial mass, 2: perfect -#+end_src - -*** Identification -<> - -**** Number of states -Let's first use perfect 3d accelerometers: -#+begin_src matlab -acc_3d.type = 2; % 1: inertial mass, 2: perfect -#+end_src - -And identify the dynamics from the shaker force to the measured accelerations: -#+begin_src matlab -%% Name of the Simulink File -mdl = 'vibration_table'; - -%% Input/Output definition -clear io; io_i = 1; -io(io_i) = linio([mdl, '/F'], 1, 'openinput'); io_i = io_i + 1; -io(io_i) = linio([mdl, '/acc'], 1, 'openoutput'); io_i = io_i + 1; - -%% Run the linearization -Gp = linearize(mdl, io); -Gp.InputName = {'F'}; -Gp.OutputName = {'a1', 'a2', 'a3', 'a4', 'a5', 'a6'}; -#+end_src - -#+begin_src matlab :results output replace :exports results :tangle no -size(Gp) -#+end_src - -#+RESULTS: -: size(Gp) -: State-space model with 6 outputs, 1 inputs, and 12 states. - -We indeed have the 12 states corresponding to the 6 DoF of the suspended optical table. - -Let's now consider the inertial masses for the triaxial accelerometers: -#+begin_src matlab -acc_3d.type = 1; % 1: inertial mass, 2: perfect -#+end_src - -#+begin_src matlab -%% Name of the Simulink File -mdl = 'vibration_table'; - -%% Input/Output definition -clear io; io_i = 1; -io(io_i) = linio([mdl, '/F'], 1, 'openinput'); io_i = io_i + 1; -io(io_i) = linio([mdl, '/acc'], 1, 'openoutput'); io_i = io_i + 1; - -%% Run the linearization -Ga = linearize(mdl, io); -Ga.InputName = {'F'}; -Ga.OutputName = {'a1', 'a2', 'a3', 'a4', 'a5', 'a6'}; -#+end_src - -#+begin_src matlab :results output replace :exports results :tangle no -size(Ga) -#+end_src - -#+RESULTS: -: size(Ga) -: State-space model with 6 outputs, 1 inputs, and 30 states. - -And we can see that 18 states have been added. -This corresponds to 6 states for each triaxial accelerometers. - -**** Resonance frequencies and mode shapes -Let's now identify the resonance frequency and mode shapes associated with the suspension modes of the optical table. - -#+begin_src matlab -acc_3d.type = 2; % 1: inertial mass, 2: perfect - -%% Name of the Simulink File -mdl = 'vibration_table'; - -%% Input/Output definition -clear io; io_i = 1; -io(io_i) = linio([mdl, '/F'], 1, 'openinput'); io_i = io_i + 1; -io(io_i) = linio([mdl, '/a1,a2'], 1, 'openoutput'); io_i = io_i + 1; - -%% Run the linearization -G = linearize(mdl, io); -G.InputName = {'F'}; -G.OutputName = {'ax'}; -#+end_src - -Compute the resonance frequencies -#+begin_src matlab -ws = eig(G.A); -ws = ws(imag(ws) > 0); -#+end_src - -And the associated response of the optical table -#+begin_src matlab -x_mod = zeros(6, 6); - -for i = 1:length(ws) - xi = evalfr(G, ws(i)); - x_mod(:,i) = xi./norm(xi); -end -#+end_src - -The results are shown in Table ref:tab:mode_shapes. -The motion associated to the mode shapes are just indicative. - -#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) -data2orgtable([flip(imag(ws)/2/pi)'; flip(abs(x_mod),2)], {'$\omega_0$ [Hz]', 'x', 'y', 'z', 'Rx', 'Ry', 'Rz'}, {}, ' %.1f '); -#+end_src - -#+name: tab:mode_shapes -#+caption: Resonance frequency and approximation of the mode shapes -#+attr_latex: :environment tabularx :width 0.4\linewidth :align Xcccccc -#+attr_latex: :center t :booktabs t :float t -#+RESULTS: -| $\omega_0$ [Hz] | 5.6 | 5.6 | 5.7 | 8.2 | 8.2 | 8.2 | -|-----------------+-----+-----+-----+-----+-----+-----| -| x | 0.1 | 0.7 | 0.0 | 0.0 | 0.2 | 0.0 | -| y | 0.7 | 0.1 | 0.0 | 0.0 | 0.0 | 0.2 | -| z | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | -| Rx | 0.7 | 0.1 | 0.0 | 0.0 | 0.1 | 1.0 | -| Ry | 0.1 | 0.7 | 0.0 | 0.0 | 1.0 | 0.1 | -| Rz | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | - -*** Verify transformation -#+begin_src matlab -%% Options for Linearized -options = linearizeOptions; -options.SampleTime = 0; - -%% Name of the Simulink File -mdl = 'vibration_table'; - -%% Input/Output definition -clear io; io_i = 1; -io(io_i) = linio([mdl, '/F'], 1, 'openinput'); io_i = io_i + 1; -io(io_i) = linio([mdl, '/acc'], 1, 'openoutput'); io_i = io_i + 1; -io(io_i) = linio([mdl, '/acc_O'], 1, 'openoutput'); io_i = io_i + 1; - -%% Run the linearization -G = linearize(mdl, io, 0.0, options); -G.InputName = {'F'}; -G.OutputName = {'a1', 'a2', 'a3', 'a4', 'a5', 'a6', ... - 'Dx', 'Dy', 'Dz', 'Rx', 'Ry', 'Rz'}; -#+end_src - -#+begin_src matlab -G_acc = inv(M)*G(1:6, 1); -G_id = G(7:12, 1); -#+end_src - -#+begin_src matlab -bodeFig({G_acc(1), G_id(1)}) -bodeFig({G_acc(2), G_id(2)}) -bodeFig({G_acc(3), G_id(3)}) -bodeFig({G_acc(4), G_id(4)}) -bodeFig({G_acc(5), G_id(5)}) -bodeFig({G_acc(6), G_id(6)}) -#+end_src - -** Nano-Hexapod -:PROPERTIES: -:header-args:matlab+: :tangle matlab/nano_hexapod.m -:END: -<> -*** Introduction :ignore: - -A configuration is added to be able to put the nano-hexapod on top of the vibration table as shown in Figure ref:fig:simscape_vibration_table. - -#+name: fig:simscape_vibration_table -#+caption: 3D representation of the simscape model with the nano-hexapod -#+attr_latex: :width 0.8\linewidth -[[file:figs/vibration_table_nano_hexapod_simscape.png]] - -The nano-hexapod's simscape model is taken from another [[https://git.tdehaeze.xyz/tdehaeze/nass-simscape][git repository]]. - -*** 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 -addpath('matlab/') -addpath('matlab/nass-simscape/matlab/nano_hexapod/') -addpath('matlab/nass-simscape/STEPS/nano_hexapod/') -addpath('matlab/nass-simscape/STEPS/png/') -addpath('matlab/nass-simscape/src/') -addpath('matlab/nass-simscape/mat/') -#+end_src - -#+begin_src matlab :eval no -addpath('nass-simscape/matlab/nano_hexapod/') -addpath('nass-simscape/STEPS/nano_hexapod/') -addpath('nass-simscape/STEPS/png/') -addpath('nass-simscape/src/') -addpath('nass-simscape/mat/') -#+end_src - -#+begin_src matlab -% Open the Simulink File -open('vibration_table') -#+end_src - -*** Nano-Hexapod -#+begin_src matlab +%% Initialize Nano-Hexapod in Open Loop n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... 'flex_top_type', '4dof', ... - 'motion_sensor_type', 'plates', ... - 'actuator_type', 'flexible'); + 'motion_sensor_type', 'struts', ... + 'actuator_type', '2dof'); + #+end_src +And let's compare the measured vertical compliance with the vertical compliance as estimated from the Simscape model. + +The transfer function from a vertical external force to the absolute motion of the top platform is identified (with and without IFF) using the Simscape model. +#+begin_src matlab :exports none +%% Identify the IFF Plant (transfer function from u to taum) +clear io; io_i = 1; +io(io_i) = linio([mdl, '/Fz_ext'], 1, 'openinput'); io_i = io_i + 1; % External - Vertical force +io(io_i) = linio([mdl, '/Z_top_plat'], 1, 'openoutput'); io_i = io_i + 1; % Absolute vertical motion of top platform +#+end_src + +#+begin_src matlab :exports none +%% Perform the identifications +G_compl_z_ol = linearize(mdl, io, 0.0, options); +#+end_src + +#+begin_src matlab :exports none +%% Initialize Nano-Hexapod with IFF +Kiff = 400*(1/(s + 2*pi*40))*... % Low pass filter (provides integral action above 40Hz) + (s/(s + 2*pi*30))*... % High pass filter to limit low frequency gain + (1/(1 + s/2/pi/500))*... % Low pass filter to be more robust to high frequency resonances + eye(6); % Diagonal 6x6 controller + +%% Initialize the Nano-Hexapod with IFF +n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... + 'flex_top_type', '4dof', ... + 'motion_sensor_type', 'struts', ... + 'actuator_type', '2dof', ... + 'controller_type', 'iff'); + +%% Perform the identification +G_compl_z_iff = linearize(mdl, io, 0.0, options); +#+end_src + +The comparison is done in Figure ref:fig:test_nhexa_compliance_vertical_comp_model_iff. +Again, the model is quite accurate in predicting the (closed-loop) behavior of the system. + +#+begin_src matlab :exports none +%% Comparison of the measured compliance and the one obtained from the model +freqs = 2*logspace(1,3,1000); + +figure; +hold on; +plot(frf_ol.FFT1_H1_16_1_RMS_X_Val, d_frf_ol, '-', 'DisplayName', 'OL - Meas.'); +plot(frf_iff.FFT1_H1_16_1_RMS_X_Val, d_frf_iff, '-', 'DisplayName', 'IFF - Meas.'); +set(gca,'ColorOrderIndex',1) +plot(freqs, abs(squeeze(freqresp(G_compl_z_ol, freqs, 'Hz'))), '--', 'DisplayName', 'OL - Model') +plot(freqs, abs(squeeze(freqresp(G_compl_z_iff, freqs, 'Hz'))), '--', 'DisplayName', 'IFF - Model') +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('Vertical Compliance [$m/N$]'); +xlim([20, 2e3]); ylim([2e-9, 2e-5]); +legend('location', 'northeast', 'FontSize', 8); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file replace +exportFig('figs/compliance_vertical_comp_model_iff.pdf', 'width', 'wide', 'height', 'normal'); +#+end_src + +#+name: fig:test_nhexa_compliance_vertical_comp_model_iff +#+caption: Measured vertical compliance with and without IFF +#+RESULTS: +[[file:figs/test_nhexa_compliance_vertical_comp_model_iff.png]] + *** Computation of the transmissibility from accelerometer data **** Introduction :ignore: @@ -4679,22 +3913,252 @@ ylim([1e-4, 1e2]); xlim([freqs(1), freqs(end)]); #+end_src -** Identification of the table's dynamics -<> -*** Matlab Init :noexport:ignore: -#+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) -<> +*** Rigidification of the added payloads +- [ ] figure + +#+begin_src matlab +%% Load Identification Data +meas_added_mass = {}; + +for i_strut = 1:6 + meas_added_mass(i_strut) = {load(sprintf('frf_data_exc_strut_%i_spindle_1m_solid.mat', i_strut), 't', 'Va', 'Vs', 'de')}; +end #+end_src -#+begin_src matlab :exports none :results silent :noweb yes -<> +Finally the $6 \times 6$ transfer function matrices from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ and from $\bm{u}$ to $\bm{\tau}_m$ are identified: +#+begin_src matlab +%% DVF Plant (transfer function from u to dLm) + +G_dL = zeros(length(f), 6, 6); +for i_strut = 1:6 + G_dL(:,:,i_strut) = tfestimate(meas_added_mass{i_strut}.Va, meas_added_mass{i_strut}.de, win, Noverlap, Nfft, 1/Ts); +end + +%% IFF Plant (transfer function from u to taum) +G_tau = zeros(length(f), 6, 6); +for i_strut = 1:6 + G_tau(:,:,i_strut) = tfestimate(meas_added_mass{i_strut}.Va, meas_added_mass{i_strut}.Vs, win, Noverlap, Nfft, 1/Ts); +end #+end_src -#+begin_src matlab :tangle no -addpath('matlab/') +#+begin_src matlab :exports none +%% Bode plot for the transfer function from u to dLm - Several payloads +figure; +tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); + +ax1 = nexttile([2,1]); +hold on; +% Diagonal terms +for i = 1:6 + plot(frf_ol.f, abs(frf_ol.G_dL{1}(:,i, i)), 'color', colors(1,:)); + plot(f, abs(G_dL(:,i, i)), 'color', colors(2,:)); +end +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('Amplitude [m/V]'); +ylim([1e-8, 1e-3]); +xlim([20, 2e3]); #+end_src -*** Mode Shapes +#+begin_src matlab :exports none +%% Bode plot for the transfer function from u to dLm +figure; +tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); + +ax1 = nexttile([2,1]); +hold on; +for i = 1:6 + plot(frf_ol.f, abs(frf_ol.G_dL(:,i, i)), 'color', colors(1,:)); + plot(f, abs(G_dL(:,i, i)), 'color', colors(2,:)); +end +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('Amplitude [m/V]'); +ylim([1e-8, 1e-3]); +xlim([10, 1e3]); +#+end_src + + +* Introduction :ignore: + +In the previous section, all the struts were mounted and individually characterized. +Now the nano-hexapod is assembled using a mounting procedure described in Section ref:sec:test_nhexa_mounting. + +In order to identify the dynamics of the nano-hexapod, a special suspended table is developed which consists of a stiff "optical breadboard" suspended on top of four soft springs. +The Nano-Hexapod is then fixed on top of the suspended table, such that its dynamics is not affected by complex dynamics except from the suspension modes of the table that can be well characterized and modelled (Section ref:sec:test_nhexa_table). + +The obtained nano-hexapod dynamics is analyzed in Section ref:sec:test_nhexa_dynamics, and compared with the Simscape model in Section ref:sec:test_nhexa_model. + +* Nano-Hexapod Assembly Procedure +<> +The assembly of the nano-hexapod is quite critical to both avoid additional stress in the flexible joints (that would result in a loss of stroke) and for the precise determination of the Jacobian matrix. +The goal is to fix the six struts to the two nano-hexapod plates (shown in Figure ref:fig:test_nhexa_nano_hexapod_plates) while the two plates are parallel, aligned vertically, and such that all the flexible joints do not experience any stress. +Do to so, a precisely machined mounting tool (Figure ref:fig:test_nhexa_center_part_hexapod_mounting) is used to position the two nano-hexapod plates during the assembly procedure. + +#+name: fig:test_nhexa_received_parts +#+caption: Received Nano-Hexapod plates (\subref{fig:test_nhexa_nano_hexapod_plates}) and mounting tool used to position the two plates during assembly (\subref{fig:test_nhexa_center_part_hexapod_mounting}) +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:test_nhexa_nano_hexapod_plates}Received top and bottom plates} +#+attr_latex: :options {0.59\textwidth} +#+begin_subfigure +#+attr_org: :width 800px +#+attr_latex: :height 4cm +[[file:figs/test_nhexa_nano_hexapod_plates.jpg]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_nhexa_center_part_hexapod_mounting}Mounting tool} +#+attr_latex: :options {0.39\textwidth} +#+begin_subfigure +#+attr_org: :width 800px +#+attr_latex: :height 4cm +[[file:figs/test_nhexa_center_part_hexapod_mounting.jpg]] +#+end_subfigure +#+end_figure + +The mechanical tolerances of the received plates are checked using a FARO arm[fn:1] (Figure ref:fig:test_nhexa_plates_tolerances) and are found to comply with the requirements[fn:2]. +The same is done for the mounting tool[fn:3] +The two plates are then fixed to the mounting tool as shown in Figure ref:fig:test_nhexa_mounting_tool_hexapod_top_view. +The main goal of this "mounting tool" is to position the flexible joint interfaces (the "V" shapes) of both plates such that a cylinder can rest on the 4 flat interfaces at the same time. + +#+name: fig:test_nhexa_dimensional_check +#+caption: A Faro arm is used to dimensionally check the received parts (\subref{fig:test_nhexa_plates_tolerances}) and after mounting the two plates with the mounting part (\subref{fig:test_nhexa_mounting_tool_hexapod_top_view}) +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:test_nhexa_plates_tolerances}Dimensional check of the bottom plate} +#+attr_latex: :options {0.49\textwidth} +#+begin_subfigure +#+attr_org: :width 800px +#+attr_latex: :width 0.95\linewidth +[[file:figs/test_nhexa_plates_tolerances.jpg]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_nhexa_mounting_tool_hexapod_top_view}Wanted coaxiality between interfaces} +#+attr_latex: :options {0.49\textwidth} +#+begin_subfigure +#+attr_org: :width 800px +#+attr_latex: :width 0.95\linewidth +[[file:figs/test_nhexa_mounting_tool_hexapod_top_view.png]] +#+end_subfigure +#+end_figure + +The quality of the positioning can be estimated by measuring the "straightness" of the top and bottom "V" interfaces. +This corresponds to the diameter of the smallest cylinder that contains all points of the measured axis. +This is again done using the FARO arm, and the results for all the six struts are summarized in Table ref:tab:measured_straightness. +The straightness is found to be better than $15\,\mu m$ for all the struts[fn:4], which is sufficiently good to not induce significant stress of the flexible joint during the assembly. + +#+name: tab:measured_straightness +#+caption: Measured straightness between the two "V" for the six struts. These measurements are performed two times for each strut. +#+attr_latex: :environment tabularx :width 0.35\linewidth :align Xcc +#+attr_latex: :center t :booktabs t +| *Strut* | *Meas 1* | *Meas 2* | +|---------+--------------+--------------| +| 1 | $7\,\mu m$ | $3\, \mu m$ | +| 2 | $11\, \mu m$ | $11\, \mu m$ | +| 3 | $15\, \mu m$ | $14\, \mu m$ | +| 4 | $6\, \mu m$ | $6\, \mu m$ | +| 5 | $7\, \mu m$ | $5\, \mu m$ | +| 6 | $6\, \mu m$ | $7\, \mu m$ | + +The encoder rulers and heads are then fixed to the top and bottom plates respectively (Figure ref:fig:test_nhexa_mount_encoder). +The encoder heads are then aligned to maximize the received contrast. + +# 1. Fix the bottom plate with the cylindrical tool +# 2. Put the top plate on the granite +# 3. Put the cylindrical tool and bottom plate on top of the top plate (Figure ref:fig:test_nhexa_mounting_tool_hexapod_bot_view). +# This position the bottom plate with respect to the top plate in X, Y, Z, Rx, Ry +# 4. Put the pin to position/fix the Rz. +# Now the two plates should be position and clamped together +# 5. Verify the coaxiality between the flexible joint interfaces +# 6. Fix the 6 encoder heads and rulers +# 7. Fix the 6 struts +# 8. Remove the pin and the mounting spacer + +#+name: fig:test_nhexa_mount_encoder +#+caption: Mounting of the encoders to the Nano-hexapod. The rulers are fixed to the top plate (\subref{fig:test_nhexa_mount_encoder_rulers}) while the encoders heads are fixed to the botom plate (\subref{fig:test_nhexa_mount_encoder_heads}) +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:test_nhexa_mount_encoder_rulers}Encoder rulers} +#+attr_latex: :options {0.49\textwidth} +#+begin_subfigure +#+attr_org: :width 800px +#+attr_latex: :width 0.95\linewidth +[[file:figs/test_nhexa_mount_encoder_rulers.jpg]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:test_nhexa_mount_encoder_heads}Encoder heads} +#+attr_latex: :options {0.49\textwidth} +#+begin_subfigure +#+attr_org: :width 800px +#+attr_latex: :width 0.95\linewidth +[[file:figs/test_nhexa_mount_encoder_heads.jpg]] +#+end_subfigure +#+end_figure + +The six struts are then fixed to the bottom and top plates one by one. +First the top flexible joint is fixed such that its flat reference surface is in contact with the top plate. +This is to precisely known the position of the flexible joint with respect to the top plate. +Then the bottom flexible joint is fixed. +After all six struts are mounted, the mounting tool (Figure ref:fig:test_nhexa_center_part_hexapod_mounting) can be disassembled, and the fully mounted nano-hexapod as shown in Figure ref:fig:test_nhexa_nano_hexapod_mounted is obtained. + +#+name: fig:test_nhexa_nano_hexapod_mounted +#+caption: Mounted Nano-Hexapod +#+attr_org: :width 800px +#+attr_latex: :width \linewidth +[[file:figs/test_nhexa_mounted_hexapod.jpg]] + +* Suspended Table +:PROPERTIES: +:header-args:matlab+: :tangle matlab/scripts/test_nhexa_table.m +:END: +<> +** Introduction + +# In EPDM: ID00/test_bench/table_dyn + +This document is divided as follows: +- Section ref:ssec:test_nhexa_table_setup: the experimental setup and all the instrumentation are described +- Section ref:ssec:test_nhexa_table_identification: the table dynamics is identified +- Section ref:ssec:test_nhexa_table_model: a Simscape model of the vibration table is developed and tuned from the measurements + +** Experimental Setup +<> +*** Introduction :ignore: + +- [ ] Redo the CAD view + +#+name: fig:vibration-table-cad-view +#+caption: CAD View of the vibration table +#+attr_latex: :width 0.8\linewidth +[[file:figs/vibration-table-cad-view.png]] + +*** Suspended table + +- Dimensions :: 450 mm x 450 mm x 60 mm +- Mass :: 21.3 kg (bot=7.8, top=7.6, mid=5.9kg) +- Interface plate :: 3.2kg + +#+name: fig:compliance_optical_table +#+caption: Compliance of the B4545A optical table +#+attr_latex: :width 0.8\linewidth +[[file:figs/test_nhexa_compliance_table.png]] + +If we include including the bottom interface plate: +- Total mass: 24.5 kg +- CoM: 42mm below Center of optical table +- Ix = 0.54, Iy = 0.54, Iz = 1.07 (with respect to CoM) + +*** Springs + +Helical compression spring +make of steel wire (52SiCrNi5) with rectangular cross section +SZ8005 20 x 044 from Steinel +L0 = 44mm +Spring rate = 17.8 N/mm + +[[file:figs/test_nhexa_table_springs.jpg]] + +** Identification of the table's response +<> + +(4x) 3D accelerometer [[https://www.pcbpiezotronics.fr/produit/accelerometres/356b18/][PCB 356B18]] #+name: tab:list_modes #+caption: List of the identified modes @@ -4710,10 +4174,10 @@ addpath('matlab/') | 6 | 8.9 | Tilt | | 7 | 700 | Flexible Mode | -#+name: fig:mode_shapes_rigid_table +#+name: fig:test_nhexa_mode_shapes_rigid_table #+caption: Mode shapes of the 6 suspension modes (from 1Hz to 9Hz) #+attr_latex: :width \linewidth -[[file:figs/mode_shapes_rigid_table.gif]] +[[file:figs/test_nhexa_mode_shapes_rigid_table.png]] #+name: fig:ModeShapeHF1_crop #+caption: First flexible mode of the table at 700Hz @@ -4721,55 +4185,20 @@ addpath('matlab/') [[file:figs/ModeShapeHF1_crop.gif]] -* Nano-Hexapod Dynamics -<> - -** Introduction :ignore: -In this section, the encoders are fixed to the plates rather than to the struts as shown in Figure ref:fig:test_nhexa_enc_fixed_to_struts. - -#+name: fig:test_nhexa_enc_fixed_to_struts -#+caption: Nano-Hexapod with encoders fixed to the struts -#+attr_latex: :width \linewidth -[[file:figs/test_nhexa_IMG_20210625_083801.jpg]] - -It is structured as follow: -- Section ref:sec:test_nhexa_enc_plates_plant_id: The dynamics of the nano-hexapod is identified. -- Section ref:sec:test_nhexa_enc_plates_comp_simscape: The identified dynamics is compared with the Simscape model. -- Section ref:sec:test_nhexa_enc_plates_iff: The Integral Force Feedback (IFF) control strategy is applied and the dynamics of the damped nano-hexapod is identified and compare with the Simscape model. - -** Modal Analysis :noexport: +** Simscape Model of the suspended table :PROPERTIES: -:header-args:matlab+: :tangle matlab/scripts/enc_struts_compliance_iff.m +:header-args:matlab+: :tangle matlab/simscape_model.m :END: -<> - -- [ ] *This test was made using encoder fixed to the struts, is it relevant to put it here?* - +<> *** Introduction :ignore: -Several 3-axis accelerometers are fixed on the top platform of the nano-hexapod as shown in Figure ref:fig:test_nhexa_compliance_vertical_comp_iff. +In this section, the Simscape model of the vibration table is described. -#+name: fig:test_nhexa_accelerometers_nano_hexapod -#+caption: Location of the accelerometers on top of the nano-hexapod -#+attr_latex: :width \linewidth -[[file:figs/test_nhexa_accelerometers_nano_hexapod.jpg]] - -The top platform is then excited using an instrumented hammer as shown in Figure ref:fig:test_nhexa_hammer_excitation_compliance_meas. - -#+name: fig:test_nhexa_hammer_excitation_compliance_meas -#+caption: Example of an excitation using an instrumented hammer -#+attr_latex: :width \linewidth -[[file:figs/test_nhexa_hammer_excitation_compliance_meas.jpg]] - -From this experiment, the resonance frequencies and the associated mode shapes can be computed (Section ref:sec:test_nhexa_modal_analysis_mode_shapes). -Then, in Section ref:sec:test_nhexa_compliance_effect_iff, the vertical compliance of the nano-hexapod is experimentally estimated. -Finally, in Section ref:sec:test_nhexa_compliance_effect_iff_comp_model, the measured compliance is compare with the estimated one from the Simscape model. +#+name: fig:simscape_vibration_table +#+caption: 3D representation of the simscape model +#+attr_latex: :width 0.8\linewidth +[[file:figs/simscape_vibration_table.png]] *** Matlab Init :noexport:ignore: -#+begin_src matlab -%% enc_struts_compliance_iff.m -% Compare measured compliance and estimated compliance from the Simscape model -#+end_src - #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> #+end_src @@ -4794,6 +4223,277 @@ Finally, in Section ref:sec:test_nhexa_compliance_effect_iff_comp_model, the mea <> #+end_src +*** Simscape Sub-systems +<> + +Parameters for sub-components of the simscape model are defined below. + +**** Springs +<> + +The 4 springs supporting the suspended optical table are modelled with "bushing joints" having stiffness and damping in the x-y-z directions: + +#+begin_src matlab +%% This parameters are defined in the Mask of the suspended table +% spring.kx = 0.5e3; % X- Stiffness [N/m] +% spring.cx = 15; % X- Damping [N/(m/s)] + +% spring.ky = 0.5e3; % Y- Stiffness [N/m] +% spring.cy = 15; % Y- Damping [N/(m/s)] + +% spring.kz = 1e3; % Z- Stiffness [N/m] +% spring.cz = 50; % Z- Damping [N/(m/s)] + +% spring.z0 = 32e-3; % Equilibrium z-length [m] +#+end_src + +**** Inertial Shaker (IS20) +<> + +The inertial shaker is defined as two solid bodies: +- the "housing" that is fixed to the element that we want to excite +- the "inertial mass" that is suspended inside the housing + +The inertial mass is guided inside the housing and an actuator (coil and magnet) can be used to apply a force between the inertial mass and the support. +The "reacting" force on the support is then used as an excitation. + +#+name: tab:is20_characteristics +#+caption: Summary of the IS20 datasheet +#+attr_latex: :environment tabularx :width 0.4\linewidth :align lX +#+attr_latex: :center t :booktabs t :float t +| Characteristic | Value | +|-----------------+------------| +| Output Force | 20 N | +| Frequency Range | 10-3000 Hz | +| Moving Mass | 0.1 kg | +| Total Mass | 0.3 kg | + +From the datasheet in Table ref:tab:is20_characteristics, we can estimate the parameters of the physical shaker. + +These parameters are defined below +**** 3D accelerometer (356B18) +<> + +An accelerometer consists of 2 solids: +- a "housing" rigidly fixed to the measured body +- an "inertial mass" suspended inside the housing by springs and guided in the measured direction + +The relative motion between the housing and the inertial mass gives a measurement of the acceleration of the measured body (up to the suspension mode of the inertial mass). + +#+name: tab:356b18_characteristics +#+caption: Summary of the 356B18 datasheet +#+attr_latex: :environment tabularx :width 0.5\linewidth :align lX +#+attr_latex: :center t :booktabs t :float t +| Characteristic | Value | +|---------------------+---------------------| +| Sensitivity | 0.102 V/(m/s2) | +| Frequency Range | 0.5 to 3000 Hz | +| Resonance Frequency | > 20 kHz | +| Resolution | 0.0005 m/s2 rms | +| Weight | 0.025 kg | +| Size | 20.3x26.1x20.3 [mm] | + +*** Identification +<> +Let's now identify the resonance frequency and mode shapes associated with the suspension modes of the optical table. + +#+begin_src matlab +%% Configure Simscape Model +table_type = 'Suspended'; % On top of vibration table +device_type = 'None'; % No device on the vibration table +payload_num = 0; % No Payload + +%% Input/Output definition +clear io; io_i = 1; +io(io_i) = linio([mdl, '/F'], 1, 'openinput'); io_i = io_i + 1; +io(io_i) = linio([mdl, '/F_v'], 1, 'openoutput'); io_i = io_i + 1; + +%% Run the linearization +G = linearize(mdl, io); +G.InputName = {'Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz'}; +G.OutputName = {'Vdx', 'Vdy', 'Vdz', 'Vrx', 'Vry', 'Vrz'}; +#+end_src + +#+begin_src matlab +freqs = logspace(0, 2, 1000); +figure; +hold on; +plot(freqs, abs(squeeze(freqresp(G(1,1), freqs, 'Hz'))), 'DisplayName', '$x$'); +plot(freqs, abs(squeeze(freqresp(G(2,2), freqs, 'Hz'))), 'DisplayName', '$y$'); +plot(freqs, abs(squeeze(freqresp(G(3,3), freqs, 'Hz'))), 'DisplayName', '$z$'); +plot(freqs, abs(squeeze(freqresp(G(4,4), freqs, 'Hz'))), 'DisplayName', '$R_x$'); +plot(freqs, abs(squeeze(freqresp(G(5,5), freqs, 'Hz'))), 'DisplayName', '$R_y$'); +plot(freqs, abs(squeeze(freqresp(G(6,6), freqs, 'Hz'))), 'DisplayName', '$R_z$'); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('Amplitude [$m/s/N$]'); +legend('location', 'northeast'); +#+end_src + +#+begin_src matlab :results output replace :exports results :tangle no +size(G) +#+end_src + +#+RESULTS: +: size(G) +: State-space model with 6 outputs, 6 inputs, and 12 states. + +Compute the resonance frequencies +#+begin_src matlab +ws = eig(G.A); +ws = ws(imag(ws) > 0); +#+end_src + +#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) +data2orgtable([sort(imag(ws))'/2/pi; 1.3, 1.3, 1.95, 6.85, 8.9, 9.5], {'Simscape', 'Experimental'}, {'x', 'y', 'Rz', 'Dz', 'Rx', 'Ry'}, ' %.2f '); +#+end_src + +#+RESULTS: +| | x | y | Rz | Dz | Rx | Ry | +|--------------+------+------+------+------+------+------| +| Simscape | 1.28 | 1.28 | 1.82 | 6.78 | 9.47 | 9.47 | +| Experimental | 1.3 | 1.3 | 1.95 | 6.85 | 8.9 | 9.5 | + + +And the associated response of the optical table +#+begin_src matlab +x_mod = zeros(6, 6); % 6 modes, 6 outputs + +for i = 1:length(ws) + xi = evalfr(G(1,:), ws(i)); + x_mod(:,i) = xi./norm(xi); +end +#+end_src + +The results are shown in Table ref:tab:mode_shapes. +The motion associated to the mode shapes are just indicative. + +#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) +data2orgtable([flip(imag(ws)/2/pi)'; flip(abs(x_mod),2)], {'$\omega_0$ [Hz]', 'x', 'y', 'z', 'Rx', 'Ry', 'Rz'}, {}, ' %.1f '); +#+end_src + +#+name: tab:mode_shapes +#+caption: Resonance frequency and approximation of the mode shapes +#+attr_latex: :environment tabularx :width 0.4\linewidth :align Xcccccc +#+attr_latex: :center t :booktabs t :float t +#+RESULTS: +| $\omega_0$ [Hz] | 8.2 | 8.2 | 8.2 | 5.8 | 5.6 | 5.6 | +|-----------------+-----+-----+-----+-----+-----+-----| +| x | 0.0 | 0.0 | 0.0 | 0.0 | 0.1 | 0.5 | +| y | 0.0 | 0.0 | 0.0 | 0.0 | 0.5 | 0.0 | +| z | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | +| Rx | 1.0 | 0.0 | 0.0 | 0.0 | 0.8 | 0.0 | +| Ry | 0.0 | 1.0 | 0.0 | 0.0 | 0.2 | 0.9 | +| Rz | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | + +* Nano-Hexapod Dynamics +<> + +** Introduction :ignore: + +In Figure ref:fig:test_nhexa_nano_hexapod_signals is shown a block diagram of the experimental setup. +When possible, the notations are consistent with this diagram and summarized in Table ref:tab:list_signals. + +#+begin_src latex :file nano_hexapod_signals.pdf +\definecolor{instrumentation}{rgb}{0, 0.447, 0.741} +\definecolor{mechanics}{rgb}{0.8500, 0.325, 0.098} + +\begin{tikzpicture} + % Blocs + \node[block={4.0cm}{3.0cm}, fill=mechanics!20!white] (nano_hexapod) {Mechanics}; + \coordinate[] (inputF) at (nano_hexapod.west); + \coordinate[] (outputL) at ($(nano_hexapod.south east)!0.8!(nano_hexapod.north east)$); + \coordinate[] (outputF) at ($(nano_hexapod.south east)!0.2!(nano_hexapod.north east)$); + + \node[block, left= 0.8 of inputF, fill=instrumentation!20!white, align=center] (F_stack) {\tiny Actuator \\ \tiny stacks}; + \node[block, left= 0.8 of F_stack, fill=instrumentation!20!white] (PD200) {PD200}; + \node[DAC, left= 0.8 of PD200, fill=instrumentation!20!white] (F_DAC) {DAC}; + \node[block, right=0.8 of outputF, fill=instrumentation!20!white, align=center] (Fm_stack){\tiny Sensor \\ \tiny stack}; + \node[ADC, right=0.8 of Fm_stack,fill=instrumentation!20!white] (Fm_ADC) {ADC}; + \node[block, right=0.8 of outputL, fill=instrumentation!20!white] (encoder) {\tiny Encoder}; + + % Connections and labels + \draw[->] ($(F_DAC.west)+(-0.8,0)$) node[above right]{$\bm{u}$} node[below right]{$[V]$} -- node[sloped]{$/$} (F_DAC.west); + \draw[->] (F_DAC.east) -- node[midway, above]{$\tilde{\bm{u}}$}node[midway, below]{$[V]$} (PD200.west); + \draw[->] (PD200.east) -- node[midway, above]{$\bm{u}_a$}node[midway, below]{$[V]$} (F_stack.west); + \draw[->] (F_stack.east) -- (inputF) node[above left]{$\bm{\tau}$}node[below left]{$[N]$}; + + \draw[->] (outputF) -- (Fm_stack.west) node[above left]{$\bm{\epsilon}$} node[below left]{$[m]$}; + \draw[->] (Fm_stack.east) -- node[midway, above]{$\tilde{\bm{\tau}}_m$}node[midway, below]{$[V]$} (Fm_ADC.west); + \draw[->] (Fm_ADC.east) -- node[sloped]{$/$} ++(0.8, 0)coordinate(end) node[above left]{$\bm{\tau}_m$}node[below left]{$[V]$}; + + \draw[->] (outputL) -- (encoder.west) node[above left]{$d\bm{\mathcal{L}}$} node[below left]{$[m]$}; + \draw[->] (encoder.east) -- node[sloped]{$/$} (encoder-|end) node[above left]{$d\bm{\mathcal{L}}_m$}node[below left]{$[m]$}; + + % Nano-Hexapod + \begin{scope}[on background layer] + \node[fit={(F_stack.west|-nano_hexapod.south) (Fm_stack.east|-nano_hexapod.north)}, fill=black!20!white, draw, inner sep=2pt] (system) {}; + \node[above] at (system.north) {Nano-Hexapod}; + \end{scope} +\end{tikzpicture} +#+end_src + +#+name: fig:test_nhexa_nano_hexapod_signals +#+caption: Block diagram of the system with named signals +#+attr_latex: :scale 1 +[[file:figs/test_nhexa_nano_hexapod_signals.png]] + +#+name: tab:list_signals +#+caption: List of signals +#+attr_latex: :environment tabularx :width \linewidth :align Xllll +#+attr_latex: :center t :booktabs t +| | *Unit* | *Matlab* | *Vector* | *Elements* | +|------------------------------------+-----------+-----------+-----------------------+----------------------| +| Control Input (wanted DAC voltage) | =[V]= | =u= | $\bm{u}$ | $u_i$ | +| DAC Output Voltage | =[V]= | =u= | $\tilde{\bm{u}}$ | $\tilde{u}_i$ | +| PD200 Output Voltage | =[V]= | =ua= | $\bm{u}_a$ | $u_{a,i}$ | +| Actuator applied force | =[N]= | =tau= | $\bm{\tau}$ | $\tau_i$ | +|------------------------------------+-----------+-----------+-----------------------+----------------------| +| Strut motion | =[m]= | =dL= | $d\bm{\mathcal{L}}$ | $d\mathcal{L}_i$ | +| Encoder measured displacement | =[m]= | =dLm= | $d\bm{\mathcal{L}}_m$ | $d\mathcal{L}_{m,i}$ | +|------------------------------------+-----------+-----------+-----------------------+----------------------| +| Force Sensor strain | =[m]= | =epsilon= | $\bm{\epsilon}$ | $\epsilon_i$ | +| Force Sensor Generated Voltage | =[V]= | =taum= | $\tilde{\bm{\tau}}_m$ | $\tilde{\tau}_{m,i}$ | +| Measured Generated Voltage | =[V]= | =taum= | $\bm{\tau}_m$ | $\tau_{m,i}$ | +|------------------------------------+-----------+-----------+-----------------------+----------------------| +| Motion of the top platform | =[m,rad]= | =dX= | $d\bm{\mathcal{X}}$ | $d\mathcal{X}_i$ | +| Metrology measured displacement | =[m,rad]= | =dXm= | $d\bm{\mathcal{X}}_m$ | $d\mathcal{X}_{m,i}$ | + +#+name: fig:test_nhexa_enc_fixed_to_struts +#+caption: Nano-Hexapod with encoders fixed to the struts +#+attr_latex: :width \linewidth +[[file:figs/test_nhexa_IMG_20210625_083801.jpg]] + +It is structured as follow: +- Section ref:sec:test_nhexa_enc_plates_plant_id: The dynamics of the nano-hexapod is identified. +- Section ref:sec:test_nhexa_enc_plates_comp_simscape: The identified dynamics is compared with the Simscape model. + +** Modal Analysis :noexport: +<> + +This could just be used to show that experimental measure of the flexible mode of the top plate has been done: +- [ ] *This test was made using encoder fixed to the struts, is it relevant to put it here?* +- [ ] Also compare with the FEM + +*** Introduction :ignore: +Several 3-axis accelerometers are fixed on the top platform of the nano-hexapod as shown in Figure ref:fig:test_nhexa_compliance_vertical_comp_iff. + +#+name: fig:test_nhexa_accelerometers_nano_hexapod +#+caption: Location of the accelerometers on top of the nano-hexapod +#+attr_latex: :width \linewidth +[[file:figs/test_nhexa_accelerometers_nano_hexapod.jpg]] + +The top platform is then excited using an instrumented hammer as shown in Figure ref:fig:test_nhexa_hammer_excitation_compliance_meas. + +#+name: fig:test_nhexa_hammer_excitation_compliance_meas +#+caption: Example of an excitation using an instrumented hammer +#+attr_latex: :width \linewidth +[[file:figs/test_nhexa_hammer_excitation_compliance_meas.jpg]] + +From this experiment, the resonance frequencies and the associated mode shapes can be computed (Section ref:sec:test_nhexa_modal_analysis_mode_shapes). +Then, in Section ref:sec:test_nhexa_compliance_effect_iff, the vertical compliance of the nano-hexapod is experimentally estimated. +Finally, in Section ref:sec:test_nhexa_compliance_effect_iff_comp_model, the measured compliance is compare with the estimated one from the Simscape model. + *** Obtained Mode Shapes <> @@ -4827,139 +4527,12 @@ The obtained modes are summarized in Table ref:tab:description_modes. | 6 | 180 | Suspension Mode: Z-rotation | | 7 | 692 | (flexible) Membrane mode of the top platform | -*** Nano-Hexapod Compliance - Effect of IFF -<> +*** FEM -In this section, we wish to estimate the effectiveness of the IFF strategy regarding the compliance. - -The top plate is excited vertically using the instrumented hammer two times: -1. no control loop is used -2. decentralized IFF is used - -The data are loaded. -#+begin_src matlab -frf_ol = load('Measurement_Z_axis.mat'); % Open-Loop -frf_iff = load('Measurement_Z_axis_damped.mat'); % IFF -#+end_src - -The mean vertical motion of the top platform is computed by averaging all 5 vertical accelerometers. -#+begin_src matlab -%% Multiply by 10 (gain in m/s^2/V) and divide by 5 (number of accelerometers) -d_frf_ol = 10/5*(frf_ol.FFT1_H1_4_1_RMS_Y_Mod + frf_ol.FFT1_H1_7_1_RMS_Y_Mod + frf_ol.FFT1_H1_10_1_RMS_Y_Mod + frf_ol.FFT1_H1_13_1_RMS_Y_Mod + frf_ol.FFT1_H1_16_1_RMS_Y_Mod)./(2*pi*frf_ol.FFT1_H1_16_1_RMS_X_Val).^2; -d_frf_iff = 10/5*(frf_iff.FFT1_H1_4_1_RMS_Y_Mod + frf_iff.FFT1_H1_7_1_RMS_Y_Mod + frf_iff.FFT1_H1_10_1_RMS_Y_Mod + frf_iff.FFT1_H1_13_1_RMS_Y_Mod + frf_iff.FFT1_H1_16_1_RMS_Y_Mod)./(2*pi*frf_iff.FFT1_H1_16_1_RMS_X_Val).^2; -#+end_src - -The vertical compliance (magnitude of the transfer function from a vertical force applied on the top plate to the vertical motion of the top plate) is shown in Figure ref:fig:test_nhexa_compliance_vertical_comp_iff. -#+begin_src matlab :exports none -%% Comparison of the vertical compliances (OL and IFF) -figure; -hold on; -plot(frf_ol.FFT1_H1_16_1_RMS_X_Val, d_frf_ol, 'DisplayName', 'OL'); -plot(frf_iff.FFT1_H1_16_1_RMS_X_Val, d_frf_iff, 'DisplayName', 'IFF'); -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -xlabel('Frequency [Hz]'); ylabel('Vertical Compliance [$m/N$]'); -xlim([20, 2e3]); ylim([2e-9, 2e-5]); -legend('location', 'northeast'); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/compliance_vertical_comp_iff.pdf', 'width', 'wide', 'height', 'normal'); -#+end_src - -#+name: fig:test_nhexa_compliance_vertical_comp_iff -#+caption: Measured vertical compliance with and without IFF -#+RESULTS: -[[file:figs/test_nhexa_compliance_vertical_comp_iff.png]] - -#+begin_important -From Figure ref:fig:test_nhexa_compliance_vertical_comp_iff, it is clear that the IFF control strategy is very effective in damping the suspensions modes of the nano-hexapod. -It also has the effect of (slightly) degrading the vertical compliance at low frequency. - -It also seems some damping can be added to the modes at around 205Hz which are flexible modes of the struts. -#+end_important - -*** Comparison with the Simscape Model -<> - -Let's initialize the Simscape model such that it corresponds to the experiment. -#+begin_src matlab -%% Nano-Hexapod is fixed on a rigid granite -support.type = 0; - -%% No Payload on top of the Nano-Hexapod -payload.type = 0; - -%% Initialize Nano-Hexapod in Open Loop -n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... - 'flex_top_type', '4dof', ... - 'motion_sensor_type', 'struts', ... - 'actuator_type', '2dof'); - -#+end_src - -And let's compare the measured vertical compliance with the vertical compliance as estimated from the Simscape model. - -The transfer function from a vertical external force to the absolute motion of the top platform is identified (with and without IFF) using the Simscape model. -#+begin_src matlab :exports none -%% Identify the IFF Plant (transfer function from u to taum) -clear io; io_i = 1; -io(io_i) = linio([mdl, '/Fz_ext'], 1, 'openinput'); io_i = io_i + 1; % External - Vertical force -io(io_i) = linio([mdl, '/Z_top_plat'], 1, 'openoutput'); io_i = io_i + 1; % Absolute vertical motion of top platform -#+end_src - -#+begin_src matlab :exports none -%% Perform the identifications -G_compl_z_ol = linearize(mdl, io, 0.0, options); -#+end_src - -#+begin_src matlab :exports none -%% Initialize Nano-Hexapod with IFF -Kiff = 400*(1/(s + 2*pi*40))*... % Low pass filter (provides integral action above 40Hz) - (s/(s + 2*pi*30))*... % High pass filter to limit low frequency gain - (1/(1 + s/2/pi/500))*... % Low pass filter to be more robust to high frequency resonances - eye(6); % Diagonal 6x6 controller - -%% Initialize the Nano-Hexapod with IFF -n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... - 'flex_top_type', '4dof', ... - 'motion_sensor_type', 'struts', ... - 'actuator_type', '2dof', ... - 'controller_type', 'iff'); - -%% Perform the identification -G_compl_z_iff = linearize(mdl, io, 0.0, options); -#+end_src - -The comparison is done in Figure ref:fig:test_nhexa_compliance_vertical_comp_model_iff. -Again, the model is quite accurate in predicting the (closed-loop) behavior of the system. - -#+begin_src matlab :exports none -%% Comparison of the measured compliance and the one obtained from the model -freqs = 2*logspace(1,3,1000); - -figure; -hold on; -plot(frf_ol.FFT1_H1_16_1_RMS_X_Val, d_frf_ol, '-', 'DisplayName', 'OL - Meas.'); -plot(frf_iff.FFT1_H1_16_1_RMS_X_Val, d_frf_iff, '-', 'DisplayName', 'IFF - Meas.'); -set(gca,'ColorOrderIndex',1) -plot(freqs, abs(squeeze(freqresp(G_compl_z_ol, freqs, 'Hz'))), '--', 'DisplayName', 'OL - Model') -plot(freqs, abs(squeeze(freqresp(G_compl_z_iff, freqs, 'Hz'))), '--', 'DisplayName', 'IFF - Model') -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -xlabel('Frequency [Hz]'); ylabel('Vertical Compliance [$m/N$]'); -xlim([20, 2e3]); ylim([2e-9, 2e-5]); -legend('location', 'northeast', 'FontSize', 8); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/compliance_vertical_comp_model_iff.pdf', 'width', 'wide', 'height', 'normal'); -#+end_src - -#+name: fig:test_nhexa_compliance_vertical_comp_model_iff -#+caption: Measured vertical compliance with and without IFF -#+RESULTS: -[[file:figs/test_nhexa_compliance_vertical_comp_model_iff.png]] +- [[file:/home/thomas/Cloud/work-projects/ID31-NASS/nass-fem/Assembly 20201020/Modal t=0.50mm]] +- [[file:/home/thomas/Cloud/work-projects/ID31-NASS/nass-fem/GitLab_nass-fem/dynamic-modal/assy-hexapod-20201022/t_0.25mm]] +- [[file:/home/thomas/Cloud/work-projects/ID31-NASS/nass-fem/GitLab_nass-fem/dynamic-modal/assy-hexapod-20201022/t_0.5mm]] +- [[file:/home/thomas/Cloud/work-projects/ID31-NASS/nass-fem/GitLab_nass-fem/plateau-superelement]] ** Identification of the dynamics :PROPERTIES: @@ -5009,7 +4582,7 @@ For each excitation, the 6 force sensors and 6 encoders are measured and saved. meas_data = {}; for i = 1:6 - meas_data(i) = {load(sprintf('frf_exc_strut_%i_enc_plates_noise.mat', i), 't', 'Va', 'Vs', 'de')}; + meas_data(i) = {load(sprintf('frf_data_exc_strut_%i_realigned_vib_table_0m.mat', i), 't', 'Va', 'Vs', 'de')}; end #+end_src @@ -5088,7 +4661,7 @@ exportFig('figs/enc_plates_dvf_frf.pdf', 'width', 'wide', 'height', 'tall'); #+name: fig:test_nhexa_enc_plates_dvf_frf #+caption: Measured FRF for the transfer function from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ #+RESULTS: -[[file:figs/test_nhexa_enc_plates_dvf_frf.png]] +[[file:figs/enc_plates_dvf_frf.png]] #+begin_important From Figure ref:fig:test_nhexa_enc_plates_dvf_frf, we can draw few conclusions on the transfer functions from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ when the encoders are fixed to the plates: @@ -5160,7 +4733,7 @@ exportFig('figs/enc_plates_iff_frf.pdf', 'width', 'wide', 'height', 'tall'); #+name: fig:test_nhexa_enc_plates_iff_frf #+caption: Measured FRF for the IFF plant #+RESULTS: -[[file:figs/test_nhexa_enc_plates_iff_frf.png]] +[[file:figs/enc_plates_iff_frf.png]] #+begin_important It is shown in Figure ref:fig:test_nhexa_enc_plates_iff_comp_simscape_all that: @@ -5172,13 +4745,368 @@ It is shown in Figure ref:fig:test_nhexa_enc_plates_iff_comp_simscape_all that: *** Save Identified Plants The identified dynamics is saved for further use. #+begin_src matlab :exports none :tangle no -save('matlab/data_frf/identified_plants_enc_plates.mat', 'f', 'Ts', 'G_tau', 'G_dL') +save('matlab/mat/data_frf/identified_plants_enc_plates.mat', 'f', 'Ts', 'G_tau', 'G_dL') #+end_src #+begin_src matlab :eval no -save('data_frf/identified_plants_enc_plates.mat', 'f', 'Ts', 'G_tau', 'G_dL') +save('data_frf/mat/identified_plants_enc_plates.mat', 'f', 'Ts', 'G_tau', 'G_dL') #+end_src +** Effect of Payload mass on the Dynamics +:PROPERTIES: +:header-args:matlab+: :tangle matlab/scripts/id_frf_enc_plates_effect_payload.m +:END: +<> +*** Introduction :ignore: +In this section, the encoders are fixed to the plates, and we identify the dynamics for several payloads. +The added payload are half cylinders, and three layers can be added for a total of around 40kg (Figure ref:fig:test_nhexa_picture_added_3_masses). + +#+name: fig:test_nhexa_picture_added_3_masses +#+caption: Picture of the nano-hexapod with added mass +#+attr_latex: :width \linewidth +[[file:figs/test_nhexa_picture_added_3_masses.jpg]] + +First the dynamics from $\bm{u}$ to $d\mathcal{L}_m$ and $\bm{\tau}_m$ is identified. +Then, the Integral Force Feedback controller is developed and applied as shown in Figure ref:fig:test_nhexa_nano_hexapod_signals_iff. +Finally, the dynamics from $\bm{u}^\prime$ to $d\mathcal{L}_m$ is identified and the added damping can be estimated. + +#+begin_src latex :file nano_hexapod_signals_iff.pdf +\definecolor{instrumentation}{rgb}{0, 0.447, 0.741} +\definecolor{mechanics}{rgb}{0.8500, 0.325, 0.098} +\definecolor{control}{rgb}{0.4660, 0.6740, 0.1880} + +\begin{tikzpicture} + % Blocs + \node[block={4.0cm}{3.0cm}, fill=mechanics!20!white] (nano_hexapod) {Mechanics}; + \coordinate[] (inputF) at (nano_hexapod.west); + \coordinate[] (outputL) at ($(nano_hexapod.south east)!0.8!(nano_hexapod.north east)$); + \coordinate[] (outputF) at ($(nano_hexapod.south east)!0.2!(nano_hexapod.north east)$); + + \node[block, left= 0.8 of inputF, fill=instrumentation!20!white, align=center] (F_stack) {\tiny Actuator \\ \tiny stacks}; + \node[block, left= 0.8 of F_stack, fill=instrumentation!20!white] (PD200) {PD200}; + \node[DAC, left= 0.8 of PD200, fill=instrumentation!20!white] (F_DAC) {DAC}; + \node[block, right=0.8 of outputF, fill=instrumentation!20!white, align=center] (Fm_stack){\tiny Sensor \\ \tiny stack}; + \node[ADC, right=0.8 of Fm_stack,fill=instrumentation!20!white] (Fm_ADC) {ADC}; + \node[block, right=0.8 of outputL, fill=instrumentation!20!white] (encoder) {\tiny Encoder}; + \node[addb, left= 0.8 of F_DAC, fill=control!20!white] (add_iff) {}; + \node[block, below=0.8 of add_iff, fill=control!20!white] (Kiff) {\tiny $K_{\text{IFF}}(s)$}; + + % Connections and labels + \draw[->] (add_iff.east) node[above right]{$\bm{u}$} node[below right]{$[V]$} -- node[sloped]{$/$} (F_DAC.west); + \draw[->] (F_DAC.east) -- node[midway, above]{$\tilde{\bm{u}}$}node[midway, below]{$[V]$} (PD200.west); + \draw[->] (PD200.east) -- node[midway, above]{$\bm{u}_a$}node[midway, below]{$[V]$} (F_stack.west); + \draw[->] (F_stack.east) -- (inputF) node[above left]{$\bm{\tau}$}node[below left]{$[N]$}; + + \draw[->] (outputF) -- (Fm_stack.west) node[above left]{$\bm{\epsilon}$} node[below left]{$[m]$}; + \draw[->] (Fm_stack.east) -- node[midway, above]{$\tilde{\bm{\tau}}_m$}node[midway, below]{$[V]$} (Fm_ADC.west); + \draw[->] (Fm_ADC.east) -- node[sloped]{$/$} ++(0.8, 0)coordinate(end) node[above left]{$\bm{\tau}_m$}node[below left]{$[V]$}; + + \draw[->] (outputL) -- (encoder.west) node[above left]{$d\bm{\mathcal{L}}$} node[below left]{$[m]$}; + \draw[->] (encoder.east) -- node[sloped]{$/$} (encoder-|end) node[above left]{$d\bm{\mathcal{L}}_m$}node[below left]{$[m]$}; + + \draw[->] ($(Fm_ADC.east)+(0.14,0)$) node[branch]{} -- node[sloped]{$/$} ++(0, -1.8) -| (Kiff.south); + \draw[->] (Kiff.north) -- node[sloped]{$/$} (add_iff.south); + \draw[->] ($(add_iff.west)+(-0.8,0)$) node[above right]{$\bm{u}^\prime$} node[below right]{$[V]$} -- node[sloped]{$/$} (add_iff.west); + + % Nano-Hexapod + \begin{scope}[on background layer] + \node[fit={(F_stack.west|-nano_hexapod.south) (Fm_stack.east|-nano_hexapod.north)}, fill=black!20!white, draw, inner sep=2pt] (system) {}; + \node[above] at (system.north) {Nano-Hexapod}; + \end{scope} +\end{tikzpicture} +#+end_src + +#+name: fig:test_nhexa_nano_hexapod_signals_iff +#+caption: Block Diagram of the experimental setup and model +#+RESULTS: +[[file:figs/test_nhexa_nano_hexapod_signals_iff.png]] + +*** Matlab Init :noexport:ignore: +#+begin_src matlab +%% id_frf_enc_plates_effect_payload.m +% Identification of the nano-hexapod dynamics from u to dL and to taum for several payloads +% Encoders are fixed to the plates +#+end_src + +#+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 + +*** Measured Frequency Response Functions +The following data are loaded: +- =Va=: the excitation voltage (corresponding to $u_i$) +- =Vs=: the generated voltage by the 6 force sensors (corresponding to $\bm{\tau}_m$) +- =de=: the measured motion by the 6 encoders (corresponding to $d\bm{\mathcal{L}}_m$) +#+begin_src matlab +%% Load Identification Data +meas_added_mass = {}; + +for i_mass = i_masses + for i_strut = 1:6 + meas_added_mass(i_strut, i_mass+1) = {load(sprintf('frf_data_exc_strut_%i_realigned_vib_table_%im.mat', i_strut, i_mass), 't', 'Va', 'Vs', 'de')}; + end +end +#+end_src + +The window =win= and the frequency vector =f= are defined. +#+begin_src matlab :exports none +%% Setup useful variables +Ts = 1e-4; % Sampling Time [s] +Nfft = floor(1/Ts); % Number of points for the FFT computation +win = hanning(Nfft); % Hanning window +Noverlap = floor(Nfft/2); % Overlap between frequency analysis + +% And we get the frequency vector +[~, f] = tfestimate(meas_added_mass{1,1}.Va, meas_added_mass{1,1}.de, win, Noverlap, Nfft, 1/Ts); +#+end_src + +Finally the $6 \times 6$ transfer function matrices from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ and from $\bm{u}$ to $\bm{\tau}_m$ are identified: +#+begin_src matlab +%% DVF Plant (transfer function from u to dLm) +G_dL = {}; + +for i_mass = i_masses + G_dL(i_mass+1) = {zeros(length(f), 6, 6)}; + for i_strut = 1:6 + G_dL{i_mass+1}(:,:,i_strut) = tfestimate(meas_added_mass{i_strut, i_mass+1}.Va, meas_added_mass{i_strut, i_mass+1}.de, win, Noverlap, Nfft, 1/Ts); + end +end + +%% IFF Plant (transfer function from u to taum) +G_tau = {}; + +for i_mass = i_masses + G_tau(i_mass+1) = {zeros(length(f), 6, 6)}; + for i_strut = 1:6 + G_tau{i_mass+1}(:,:,i_strut) = tfestimate(meas_added_mass{i_strut, i_mass+1}.Va, meas_added_mass{i_strut, i_mass+1}.Vs, win, Noverlap, Nfft, 1/Ts); + end +end +#+end_src + +The identified dynamics are then saved for further use. +#+begin_src matlab :exports none :tangle no +save('matlab/mat/data_frf/frf_vib_table_m.mat', 'f', 'Ts', 'G_tau', 'G_dL') +#+end_src + +#+begin_src matlab :eval no +save('data_frf/mat/frf_vib_table_m.mat', 'f', 'Ts', 'G_tau', 'G_dL') +#+end_src + +#+begin_src matlab :exports none +frf_ol = load('frf_vib_table_m.mat', 'f', 'Ts', 'G_tau', 'G_dL'); +#+end_src + +*** Transfer function from Actuators to Encoders +The transfer functions from $\bm{u}$ to $d\bm{\mathcal{L}}_{m}$ are shown in Figure ref:fig:test_nhexa_comp_plant_payloads_dvf. + +#+begin_src matlab :exports none +%% Bode plot for the transfer function from u to dLm - Several payloads +figure; +tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); + +ax1 = nexttile([2,1]); +hold on; +for i_mass = i_masses + % Diagonal terms + plot(frf_ol.f, abs(frf_ol.G_dL{i_mass+1}(:,1, 1)), 'color', colors(i_mass+1,:), ... + 'DisplayName', sprintf('$d\\mathcal{L}_{m,i}/u_i$ - %i', i_mass)); + for i = 2:6 + plot(frf_ol.f, abs(frf_ol.G_dL{i_mass+1}(:,i, i)), 'color', colors(i_mass+1,:), ... + 'HandleVisibility', 'off'); + end + % Off-Diagonal terms + for i = 1:5 + for j = i+1:6 + plot(frf_ol.f, abs(frf_ol.G_dL{i_mass+1}(:,i,j)), 'color', [colors(i_mass+1,:), 0.2], ... + 'HandleVisibility', 'off'); + end + end +end +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude [m/V]'); set(gca, 'XTickLabel',[]); +ylim([1e-8, 1e-3]); +legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2); + +ax2 = nexttile; +hold on; +for i_mass = i_masses + for i =1:6 + plot(frf_ol.f, 180/pi*angle(frf_ol.G_dL{i_mass+1}(:,i, i)), 'color', colors(i_mass+1,:)); + end +end +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); +xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); +hold off; +yticks(-360:90:360); +ylim([-90, 180]) + +linkaxes([ax1,ax2],'x'); +xlim([20, 2e3]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file replace +exportFig('figs/comp_plant_payloads_dvf.pdf', 'width', 'wide', 'height', 'tall'); +#+end_src + +#+name: fig:test_nhexa_comp_plant_payloads_dvf +#+caption: Measured Frequency Response Functions from $u_i$ to $d\mathcal{L}_{m,i}$ for all 4 payload conditions. Diagonal terms are solid lines, and shaded lines are off-diagonal terms. +#+RESULTS: +[[file:figs/test_nhexa_comp_plant_payloads_dvf.png]] + + +#+begin_important +From Figure ref:fig:test_nhexa_comp_plant_payloads_dvf, we can observe few things: +- The obtained dynamics is changing a lot between the case without mass and when there is at least one added mass. +- Between 1, 2 and 3 added masses, the dynamics is not much different, and it would be easier to design a controller only for these cases. +- The flexible modes of the top plate is first decreased a lot when the first mass is added (from 700Hz to 400Hz). + This is due to the fact that the added mass is composed of two half cylinders which are not fixed together. + Therefore is adds a lot of mass to the top plate without adding a lot of rigidity in one direction. + When more than 1 mass layer is added, the half cylinders are added with some angles such that rigidity are added in all directions (see Figure ref:fig:test_nhexa_picture_added_3_masses). + In that case, the frequency of these flexible modes are increased. + In practice, the payload should be one solid body, and we should not see a massive decrease of the frequency of this flexible mode. +- Flexible modes of the top plate are becoming less problematic as masses are added. +- First flexible mode of the strut at 230Hz is not much decreased when mass is added. + However, its apparent amplitude is much decreased. +#+end_important + +*** Transfer function from Actuators to Force Sensors +The transfer functions from $\bm{u}$ to $\bm{\tau}_{m}$ are shown in Figure ref:fig:test_nhexa_comp_plant_payloads_iff. + +#+begin_src matlab :exports none +%% Bode plot for the transfer function from u to dLm +figure; +tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); + +ax1 = nexttile([2,1]); +hold on; +for i_mass = i_masses + % Diagonal terms + plot(frf_ol.f, abs(frf_ol.G_tau{i_mass+1}(:,1, 1)), 'color', colors(i_mass+1,:), ... + 'DisplayName', sprintf('$\\tau_{m,i}/u_i$ - %i', i_mass)); + for i = 2:6 + plot(frf_ol.f, abs(frf_ol.G_tau{i_mass+1}(:,i, i)), 'color', colors(i_mass+1,:), ... + 'HandleVisibility', 'off'); + end + % Off-Diagonal terms + for i = 1:5 + for j = i+1:6 + plot(frf_ol.f, abs(frf_ol.G_tau{i_mass+1}(:,i,j)), 'color', [colors(i_mass+1,:), 0.2], ... + 'HandleVisibility', 'off'); + end + end +end +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude [V/V]'); set(gca, 'XTickLabel',[]); +ylim([1e-2, 1e2]); +legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 3); + +ax2 = nexttile; +hold on; +for i_mass = i_masses + for i =1:6 + plot(frf_ol.f, 180/pi*angle(frf_ol.G_tau{i_mass+1}(:,i, i)), 'color', colors(i_mass+1,:)); + end +end +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); +xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); +hold off; +yticks(-360:90:360); + +linkaxes([ax1,ax2],'x'); +xlim([20, 2e3]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file replace +exportFig('figs/comp_plant_payloads_iff.pdf', 'width', 'wide', 'height', 'tall'); +#+end_src + +#+name: fig:test_nhexa_comp_plant_payloads_iff +#+caption: Measured Frequency Response Functions from $u_i$ to $\tau_{m,i}$ for all 4 payload conditions. Diagonal terms are solid lines, and shaded lines are off-diagonal terms. +#+RESULTS: +[[file:figs/test_nhexa_comp_plant_payloads_iff.png]] + +#+begin_important +From Figure ref:fig:test_nhexa_comp_plant_payloads_iff, we can see that for all added payloads, the transfer function from $\bm{u}$ to $\bm{\tau}_{m}$ always has alternating poles and zeros. +#+end_important + +*** Coupling of the transfer function from Actuator to Encoders +The RGA-number, which is a measure of the interaction in the system, is computed for the transfer function matrix from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ for all the payloads. +The obtained numbers are compared in Figure ref:fig:test_nhexa_rga_num_ol_masses. + +#+begin_src matlab :exports none +%% Decentralized RGA - Undamped Plant +RGA_num = zeros(length(frf_ol.f), length(i_masses)); +for i_mass = i_masses + for i = 1:length(frf_ol.f) + RGA_num(i, i_mass+1) = sum(sum(abs(eye(6) - squeeze(frf_ol.G_dL{i_mass+1}(i,:,:)).*inv(squeeze(frf_ol.G_dL{i_mass+1}(i,:,:))).'))); + end +end +#+end_src + +#+begin_src matlab :exports none +%% RGA for Decentralized plant +figure; +hold on; +for i_mass = i_masses + plot(frf_ol.f, RGA_num(:,i_mass+1), '-', 'color', colors(i_mass+1,:), ... + 'DisplayName', sprintf('RGA-num - %i mass', i_mass)); +end +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('RGA Number'); +xlim([10, 1e3]); ylim([1e-2, 1e2]); +legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file replace +exportFig('figs/rga_num_ol_masses.pdf', 'width', 'wide', 'height', 'normal'); +#+end_src + +#+name: fig:test_nhexa_rga_num_ol_masses +#+caption: RGA-number for the open-loop transfer function from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ +#+RESULTS: +[[file:figs/test_nhexa_rga_num_ol_masses.png]] + +#+begin_important +From Figure ref:fig:test_nhexa_rga_num_ol_masses, it is clear that the coupling is quite large starting from the first suspension mode of the nano-hexapod. +Therefore, is the payload's mass is increase, the coupling in the system start to become unacceptably large at lower frequencies. +#+end_important + +** Conclusion +#+begin_important +In this section, the dynamics of the nano-hexapod with the encoders fixed to the plates is studied. + +It has been found that: +- The measured dynamics is in agreement with the dynamics of the simscape model, up to the flexible modes of the top plate. + See figures ref:fig:test_nhexa_enc_plates_iff_comp_simscape and ref:fig:test_nhexa_enc_plates_iff_comp_offdiag_simscape for the transfer function to the force sensors and Figures ref:fig:test_nhexa_enc_plates_dvf_comp_simscape and ref:fig:test_nhexa_enc_plates_dvf_comp_offdiag_simscape for the transfer functions to the encoders +- The Integral Force Feedback strategy is very effective in damping the suspension modes of the nano-hexapod (Figure ref:fig:test_nhexa_enc_plant_plates_effect_iff). +- The transfer function from $\bm{u}^\prime$ to $d\bm{\mathcal{L}}_m$ show nice dynamical properties and is a much better candidate for the high-authority-control than when the encoders were fixed to the struts. + At least up to the flexible modes of the top plate, the diagonal elements of the transfer function matrix have alternating poles and zeros, and the phase is moving smoothly. + Only the flexible modes of the top plates seems to be problematic for control. +#+end_important + +* Comparison with the Nano-Hexapod model? +<> ** Comparison with the Simscape Model :PROPERTIES: :header-args:matlab+: :tangle matlab/scripts/frf_enc_plates_comp_simscape.m @@ -5187,6 +5115,13 @@ save('data_frf/identified_plants_enc_plates.mat', 'f', 'Ts', 'G_tau', 'G_dL') *** Introduction :ignore: In this section, the measured dynamics done in Section ref:sec:test_nhexa_enc_plates_plant_id is compared with the dynamics estimated from the Simscape model. +A configuration is added to be able to put the nano-hexapod on top of the vibration table as shown in Figure ref:fig:simscape_vibration_table. + +#+name: fig:simscape_vibration_table +#+caption: 3D representation of the simscape model with the nano-hexapod +#+attr_latex: :width 0.8\linewidth +[[file:figs/vibration_table_nano_hexapod_simscape.png]] + *** Matlab Init :noexport:ignore: #+begin_src matlab %% frf_enc_plates_comp_simscape.m @@ -5226,44 +5161,61 @@ frf_ol = load('identified_plants_enc_plates.mat', 'f', 'Ts', 'G_tau', 'G_dL'); *** Identification with the Simscape Model The nano-hexapod is initialized with the APA taken as 2dof models. #+begin_src matlab -%% Initialize Nano-Hexapod +%% Initialize Simscape Model +table_type = 'Suspended'; % On top of vibration table +device_type = 'Hexapod'; % On top of vibration table +payload_num = 0; % No Payload + n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... 'flex_top_type', '4dof', ... 'motion_sensor_type', 'plates', ... 'actuator_type', '2dof'); - -support.type = 1; % On top of vibration table -payload.type = 0; % No Payload -#+end_src - -Then the transfer function from $\bm{u}$ to $\bm{\tau}_m$ is identified using the Simscape model. -#+begin_src matlab -%% Identify the transfer function from u to taum -clear io; io_i = 1; -io(io_i) = linio([mdl, '/du'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs -io(io_i) = linio([mdl, '/Fm'], 1, 'openoutput'); io_i = io_i + 1; % Force Sensors - -G_tau = exp(-s*frf_ol.Ts)*linearize(mdl, io, 0.0, options); #+end_src Now, the dynamics from the DAC voltage $\bm{u}$ to the encoders $d\bm{\mathcal{L}}_m$ is estimated using the Simscape model. #+begin_src matlab %% Identify the DVtransfer function from u to dLm clear io; io_i = 1; -io(io_i) = linio([mdl, '/du'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs +io(io_i) = linio([mdl, '/u'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs io(io_i) = linio([mdl, '/dL'], 1, 'openoutput'); io_i = io_i + 1; % Encoders G_dL = exp(-s*frf_ol.Ts)*linearize(mdl, io, 0.0, options); #+end_src +#+begin_src matlab :exports none +%% Comparison of the plants (encoder output) when tuning the misalignment +freqs = 2*logspace(1, 3, 1000); + +i_input = 1; + +figure; +hold on; +plot(frf_ol.f, abs(frf_ol.G_dL(:, 1, i_input))); +plot(freqs, abs(squeeze(freqresp(G_dL(1, i_input), freqs, 'Hz')))); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +set(gca, 'XTickLabel',[]); ylabel('Amplitude [m/V]'); +xlim([40, 4e2]); ylim([1e-8, 1e-2]); +#+end_src + +Then the transfer function from $\bm{u}$ to $\bm{\tau}_m$ is identified using the Simscape model. +#+begin_src matlab +%% Identify the transfer function from u to taum +clear io; io_i = 1; +io(io_i) = linio([mdl, '/u'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs +io(io_i) = linio([mdl, '/Fm'], 1, 'openoutput'); io_i = io_i + 1; % Force Sensors + +G_tau = exp(-s*frf_ol.Ts)*linearize(mdl, io, 0.0, options); +#+end_src + The identified dynamics is saved for further use. #+begin_src matlab :exports none :tangle no %% Save Identified Plants -save('matlab/data_frf/simscape_plants_enc_plates.mat', 'G_tau', 'G_dL'); +save('matlab/mat/data_frf/simscape_plants_enc_plates.mat', 'G_tau', 'G_dL'); #+end_src #+begin_src matlab :eval no -save('data_frf/simscape_plants_enc_plates.mat', 'G_tau', 'G_dL'); +save('mat/data_frf/simscape_plants_enc_plates.mat', 'G_tau', 'G_dL'); #+end_src #+begin_src matlab :exports none @@ -5630,424 +5582,6 @@ The Simscape model is quite accurate for the transfer function matrices from $\b The Simscape model can therefore be used to develop the control strategies. #+end_important -** Effect of Payload mass on the Dynamics -:PROPERTIES: -:header-args:matlab+: :tangle matlab/scripts/id_frf_enc_plates_effect_payload.m -:END: -<> -*** Introduction :ignore: -In this section, the encoders are fixed to the plates, and we identify the dynamics for several payloads. -The added payload are half cylinders, and three layers can be added for a total of around 40kg (Figure ref:fig:test_nhexa_picture_added_3_masses). - -#+name: fig:test_nhexa_picture_added_3_masses -#+caption: Picture of the nano-hexapod with added mass -#+attr_latex: :width \linewidth -[[file:figs/test_nhexa_picture_added_3_masses.jpg]] - -First the dynamics from $\bm{u}$ to $d\mathcal{L}_m$ and $\bm{\tau}_m$ is identified. -Then, the Integral Force Feedback controller is developed and applied as shown in Figure ref:fig:test_nhexa_nano_hexapod_signals_iff. -Finally, the dynamics from $\bm{u}^\prime$ to $d\mathcal{L}_m$ is identified and the added damping can be estimated. - -#+begin_src latex :file nano_hexapod_signals_iff.pdf -\definecolor{instrumentation}{rgb}{0, 0.447, 0.741} -\definecolor{mechanics}{rgb}{0.8500, 0.325, 0.098} -\definecolor{control}{rgb}{0.4660, 0.6740, 0.1880} - -\begin{tikzpicture} - % Blocs - \node[block={4.0cm}{3.0cm}, fill=mechanics!20!white] (nano_hexapod) {Mechanics}; - \coordinate[] (inputF) at (nano_hexapod.west); - \coordinate[] (outputL) at ($(nano_hexapod.south east)!0.8!(nano_hexapod.north east)$); - \coordinate[] (outputF) at ($(nano_hexapod.south east)!0.2!(nano_hexapod.north east)$); - - \node[block, left= 0.8 of inputF, fill=instrumentation!20!white, align=center] (F_stack) {\tiny Actuator \\ \tiny stacks}; - \node[block, left= 0.8 of F_stack, fill=instrumentation!20!white] (PD200) {PD200}; - \node[DAC, left= 0.8 of PD200, fill=instrumentation!20!white] (F_DAC) {DAC}; - \node[block, right=0.8 of outputF, fill=instrumentation!20!white, align=center] (Fm_stack){\tiny Sensor \\ \tiny stack}; - \node[ADC, right=0.8 of Fm_stack,fill=instrumentation!20!white] (Fm_ADC) {ADC}; - \node[block, right=0.8 of outputL, fill=instrumentation!20!white] (encoder) {\tiny Encoder}; - \node[addb, left= 0.8 of F_DAC, fill=control!20!white] (add_iff) {}; - \node[block, below=0.8 of add_iff, fill=control!20!white] (Kiff) {\tiny $K_{\text{IFF}}(s)$}; - - % Connections and labels - \draw[->] (add_iff.east) node[above right]{$\bm{u}$} node[below right]{$[V]$} -- node[sloped]{$/$} (F_DAC.west); - \draw[->] (F_DAC.east) -- node[midway, above]{$\tilde{\bm{u}}$}node[midway, below]{$[V]$} (PD200.west); - \draw[->] (PD200.east) -- node[midway, above]{$\bm{u}_a$}node[midway, below]{$[V]$} (F_stack.west); - \draw[->] (F_stack.east) -- (inputF) node[above left]{$\bm{\tau}$}node[below left]{$[N]$}; - - \draw[->] (outputF) -- (Fm_stack.west) node[above left]{$\bm{\epsilon}$} node[below left]{$[m]$}; - \draw[->] (Fm_stack.east) -- node[midway, above]{$\tilde{\bm{\tau}}_m$}node[midway, below]{$[V]$} (Fm_ADC.west); - \draw[->] (Fm_ADC.east) -- node[sloped]{$/$} ++(0.8, 0)coordinate(end) node[above left]{$\bm{\tau}_m$}node[below left]{$[V]$}; - - \draw[->] (outputL) -- (encoder.west) node[above left]{$d\bm{\mathcal{L}}$} node[below left]{$[m]$}; - \draw[->] (encoder.east) -- node[sloped]{$/$} (encoder-|end) node[above left]{$d\bm{\mathcal{L}}_m$}node[below left]{$[m]$}; - - \draw[->] ($(Fm_ADC.east)+(0.14,0)$) node[branch]{} -- node[sloped]{$/$} ++(0, -1.8) -| (Kiff.south); - \draw[->] (Kiff.north) -- node[sloped]{$/$} (add_iff.south); - \draw[->] ($(add_iff.west)+(-0.8,0)$) node[above right]{$\bm{u}^\prime$} node[below right]{$[V]$} -- node[sloped]{$/$} (add_iff.west); - - % Nano-Hexapod - \begin{scope}[on background layer] - \node[fit={(F_stack.west|-nano_hexapod.south) (Fm_stack.east|-nano_hexapod.north)}, fill=black!20!white, draw, inner sep=2pt] (system) {}; - \node[above] at (system.north) {Nano-Hexapod}; - \end{scope} -\end{tikzpicture} -#+end_src - -#+name: fig:test_nhexa_nano_hexapod_signals_iff -#+caption: Block Diagram of the experimental setup and model -#+RESULTS: -[[file:figs/test_nhexa_nano_hexapod_signals_iff.png]] - -*** Matlab Init :noexport:ignore: -#+begin_src matlab -%% id_frf_enc_plates_effect_payload.m -% Identification of the nano-hexapod dynamics from u to dL and to taum for several payloads -% Encoders are fixed to the plates -#+end_src - -#+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 - -*** Measured Frequency Response Functions -The following data are loaded: -- =Va=: the excitation voltage (corresponding to $u_i$) -- =Vs=: the generated voltage by the 6 force sensors (corresponding to $\bm{\tau}_m$) -- =de=: the measured motion by the 6 encoders (corresponding to $d\bm{\mathcal{L}}_m$) -#+begin_src matlab -%% Load Identification Data -meas_added_mass = {}; - -for i_mass = i_masses - for i_strut = 1:6 - meas_added_mass(i_strut, i_mass+1) = {load(sprintf('frf_data_exc_strut_%i_realigned_vib_table_%im.mat', i_strut, i_mass), 't', 'Va', 'Vs', 'de')}; - end -end -#+end_src - -The window =win= and the frequency vector =f= are defined. -#+begin_src matlab -% Sampling Time [s] -Ts = (meas_added_mass{1,1}.t(end) - (meas_added_mass{1,1}.t(1)))/(length(meas_added_mass{1,1}.t)-1); - -% Hannning Windows -win = hanning(ceil(1/Ts)); - -% And we get the frequency vector -[~, f] = tfestimate(meas_added_mass{1,1}.Va, meas_added_mass{1,1}.de, win, Noverlap, Nfft, 1/Ts); -#+end_src - -Finally the $6 \times 6$ transfer function matrices from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ and from $\bm{u}$ to $\bm{\tau}_m$ are identified: -#+begin_src matlab -%% DVF Plant (transfer function from u to dLm) -G_dL = {}; - -for i_mass = i_masses - G_dL(i_mass+1) = {zeros(length(f), 6, 6)}; - for i_strut = 1:6 - G_dL{i_mass+1}(:,:,i_strut) = tfestimate(meas_added_mass{i_strut, i_mass+1}.Va, meas_added_mass{i_strut, i_mass+1}.de, win, Noverlap, Nfft, 1/Ts); - end -end - -%% IFF Plant (transfer function from u to taum) -G_tau = {}; - -for i_mass = i_masses - G_tau(i_mass+1) = {zeros(length(f), 6, 6)}; - for i_strut = 1:6 - G_tau{i_mass+1}(:,:,i_strut) = tfestimate(meas_added_mass{i_strut, i_mass+1}.Va, meas_added_mass{i_strut, i_mass+1}.Vs, win, Noverlap, Nfft, 1/Ts); - end -end -#+end_src - -The identified dynamics are then saved for further use. -#+begin_src matlab :exports none :tangle no -save('matlab/data_frf/frf_vib_table_m.mat', 'f', 'Ts', 'G_tau', 'G_dL') -#+end_src - -#+begin_src matlab :eval no -save('data_frf/frf_vib_table_m.mat', 'f', 'Ts', 'G_tau', 'G_dL') -#+end_src - -#+begin_src matlab :exports none -frf_ol = load('frf_vib_table_m.mat', 'f', 'Ts', 'G_tau', 'G_dL'); -#+end_src - -*** Rigidification of the added payloads -- [ ] figure - -#+begin_src matlab -%% Load Identification Data -meas_added_mass = {}; - -for i_strut = 1:6 - meas_added_mass(i_strut) = {load(sprintf('frf_data_exc_strut_%i_spindle_1m_solid.mat', i_strut), 't', 'Va', 'Vs', 'de')}; -end -#+end_src - -The window =win= and the frequency vector =f= are defined. -#+begin_src matlab -% Sampling Time [s] -Ts = (meas_added_mass{1}.t(end) - (meas_added_mass{1}.t(1)))/(length(meas_added_mass{1}.t)-1); - -% Hannning Windows -win = hanning(ceil(1/Ts)); - -% And we get the frequency vector -[~, f] = tfestimate(meas_added_mass{1}.Va, meas_added_mass{1}.de, win, Noverlap, Nfft, 1/Ts); -#+end_src - -Finally the $6 \times 6$ transfer function matrices from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ and from $\bm{u}$ to $\bm{\tau}_m$ are identified: -#+begin_src matlab -%% DVF Plant (transfer function from u to dLm) - -G_dL = zeros(length(f), 6, 6); -for i_strut = 1:6 - G_dL(:,:,i_strut) = tfestimate(meas_added_mass{i_strut}.Va, meas_added_mass{i_strut}.de, win, Noverlap, Nfft, 1/Ts); -end - -%% IFF Plant (transfer function from u to taum) -G_tau = zeros(length(f), 6, 6); -for i_strut = 1:6 - G_tau(:,:,i_strut) = tfestimate(meas_added_mass{i_strut}.Va, meas_added_mass{i_strut}.Vs, win, Noverlap, Nfft, 1/Ts); -end -#+end_src - -#+begin_src matlab :exports none -%% Bode plot for the transfer function from u to dLm - Several payloads -figure; -tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); - -ax1 = nexttile([2,1]); -hold on; -% Diagonal terms -for i = 1:6 - plot(frf_ol.f, abs(frf_ol.G_dL{2}(:,i, i)), 'color', colors(1,:)); - plot(f, abs(G_dL(:,i, i)), 'color', colors(2,:)); -end -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -xlabel('Frequency [Hz]'); ylabel('Amplitude [m/V]'); -ylim([1e-8, 1e-3]); -xlim([20, 2e3]); -#+end_src - -#+begin_src matlab :exports none -%% Bode plot for the transfer function from u to dLm -figure; -tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); - -ax1 = nexttile([2,1]); -hold on; -for i = 1:6 - plot(frf_ol.f, abs(frf_ol.G_dL(:,i, i)), 'color', colors(1,:)); - plot(f, abs(G_dL(:,i, i)), 'color', colors(2,:)); -end -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -xlabel('Frequency [Hz]'); ylabel('Amplitude [m/V]'); -ylim([1e-8, 1e-3]); -xlim([10, 1e3]); -#+end_src - - -*** Transfer function from Actuators to Encoders -The transfer functions from $\bm{u}$ to $d\bm{\mathcal{L}}_{m}$ are shown in Figure ref:fig:test_nhexa_comp_plant_payloads_dvf. - -#+begin_src matlab :exports none -%% Bode plot for the transfer function from u to dLm - Several payloads -figure; -tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); - -ax1 = nexttile([2,1]); -hold on; -for i_mass = i_masses - % Diagonal terms - plot(frf_ol.f, abs(frf_ol.G_dL{i_mass+1}(:,1, 1)), 'color', colors(i_mass+1,:), ... - 'DisplayName', sprintf('$d\\mathcal{L}_{m,i}/u_i$ - %i', i_mass)); - for i = 2:6 - plot(frf_ol.f, abs(frf_ol.G_dL{i_mass+1}(:,i, i)), 'color', colors(i_mass+1,:), ... - 'HandleVisibility', 'off'); - end - % Off-Diagonal terms - for i = 1:5 - for j = i+1:6 - plot(frf_ol.f, abs(frf_ol.G_dL{i_mass+1}(:,i,j)), 'color', [colors(i_mass+1,:), 0.2], ... - 'HandleVisibility', 'off'); - end - end -end -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/V]'); set(gca, 'XTickLabel',[]); -ylim([1e-8, 1e-3]); -legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2); - -ax2 = nexttile; -hold on; -for i_mass = i_masses - for i =1:6 - plot(frf_ol.f, 180/pi*angle(frf_ol.G_dL{i_mass+1}(:,i, i)), 'color', colors(i_mass+1,:)); - end -end -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); -xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); -hold off; -yticks(-360:90:360); -ylim([-90, 180]) - -linkaxes([ax1,ax2],'x'); -xlim([20, 2e3]); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/comp_plant_payloads_dvf.pdf', 'width', 'wide', 'height', 'tall'); -#+end_src - -#+name: fig:test_nhexa_comp_plant_payloads_dvf -#+caption: Measured Frequency Response Functions from $u_i$ to $d\mathcal{L}_{m,i}$ for all 4 payload conditions. Diagonal terms are solid lines, and shaded lines are off-diagonal terms. -#+RESULTS: -[[file:figs/test_nhexa_comp_plant_payloads_dvf.png]] - - -#+begin_important -From Figure ref:fig:test_nhexa_comp_plant_payloads_dvf, we can observe few things: -- The obtained dynamics is changing a lot between the case without mass and when there is at least one added mass. -- Between 1, 2 and 3 added masses, the dynamics is not much different, and it would be easier to design a controller only for these cases. -- The flexible modes of the top plate is first decreased a lot when the first mass is added (from 700Hz to 400Hz). - This is due to the fact that the added mass is composed of two half cylinders which are not fixed together. - Therefore is adds a lot of mass to the top plate without adding a lot of rigidity in one direction. - When more than 1 mass layer is added, the half cylinders are added with some angles such that rigidity are added in all directions (see Figure ref:fig:test_nhexa_picture_added_3_masses). - In that case, the frequency of these flexible modes are increased. - In practice, the payload should be one solid body, and we should not see a massive decrease of the frequency of this flexible mode. -- Flexible modes of the top plate are becoming less problematic as masses are added. -- First flexible mode of the strut at 230Hz is not much decreased when mass is added. - However, its apparent amplitude is much decreased. -#+end_important - -*** Transfer function from Actuators to Force Sensors -The transfer functions from $\bm{u}$ to $\bm{\tau}_{m}$ are shown in Figure ref:fig:test_nhexa_comp_plant_payloads_iff. - -#+begin_src matlab :exports none -%% Bode plot for the transfer function from u to dLm -figure; -tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); - -ax1 = nexttile([2,1]); -hold on; -for i_mass = i_masses - % Diagonal terms - plot(frf_ol.f, abs(frf_ol.G_tau{i_mass+1}(:,1, 1)), 'color', colors(i_mass+1,:), ... - 'DisplayName', sprintf('$\\tau_{m,i}/u_i$ - %i', i_mass)); - for i = 2:6 - plot(frf_ol.f, abs(frf_ol.G_tau{i_mass+1}(:,i, i)), 'color', colors(i_mass+1,:), ... - 'HandleVisibility', 'off'); - end - % Off-Diagonal terms - for i = 1:5 - for j = i+1:6 - plot(frf_ol.f, abs(frf_ol.G_tau{i_mass+1}(:,i,j)), 'color', [colors(i_mass+1,:), 0.2], ... - 'HandleVisibility', 'off'); - end - end -end -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [V/V]'); set(gca, 'XTickLabel',[]); -ylim([1e-2, 1e2]); -legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 3); - -ax2 = nexttile; -hold on; -for i_mass = i_masses - for i =1:6 - plot(frf_ol.f, 180/pi*angle(frf_ol.G_tau{i_mass+1}(:,i, i)), 'color', colors(i_mass+1,:)); - end -end -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); -xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); -hold off; -yticks(-360:90:360); - -linkaxes([ax1,ax2],'x'); -xlim([20, 2e3]); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/comp_plant_payloads_iff.pdf', 'width', 'wide', 'height', 'tall'); -#+end_src - -#+name: fig:test_nhexa_comp_plant_payloads_iff -#+caption: Measured Frequency Response Functions from $u_i$ to $\tau_{m,i}$ for all 4 payload conditions. Diagonal terms are solid lines, and shaded lines are off-diagonal terms. -#+RESULTS: -[[file:figs/test_nhexa_comp_plant_payloads_iff.png]] - -#+begin_important -From Figure ref:fig:test_nhexa_comp_plant_payloads_iff, we can see that for all added payloads, the transfer function from $\bm{u}$ to $\bm{\tau}_{m}$ always has alternating poles and zeros. -#+end_important - -*** Coupling of the transfer function from Actuator to Encoders -The RGA-number, which is a measure of the interaction in the system, is computed for the transfer function matrix from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ for all the payloads. -The obtained numbers are compared in Figure ref:fig:test_nhexa_rga_num_ol_masses. - -#+begin_src matlab :exports none -%% Decentralized RGA - Undamped Plant -RGA_num = zeros(length(frf_ol.f), length(i_masses)); -for i_mass = i_masses - for i = 1:length(frf_ol.f) - RGA_num(i, i_mass+1) = sum(sum(abs(eye(6) - squeeze(frf_ol.G_dL{i_mass+1}(i,:,:)).*inv(squeeze(frf_ol.G_dL{i_mass+1}(i,:,:))).'))); - end -end -#+end_src - -#+begin_src matlab :exports none -%% RGA for Decentralized plant -figure; -hold on; -for i_mass = i_masses - plot(frf_ol.f, RGA_num(:,i_mass+1), '-', 'color', colors(i_mass+1,:), ... - 'DisplayName', sprintf('RGA-num - %i mass', i_mass)); -end -hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -xlabel('Frequency [Hz]'); ylabel('RGA Number'); -xlim([10, 1e3]); ylim([1e-2, 1e2]); -legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2); -#+end_src - -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/rga_num_ol_masses.pdf', 'width', 'wide', 'height', 'normal'); -#+end_src - -#+name: fig:test_nhexa_rga_num_ol_masses -#+caption: RGA-number for the open-loop transfer function from $\bm{u}$ to $d\bm{\mathcal{L}}_m$ -#+RESULTS: -[[file:figs/test_nhexa_rga_num_ol_masses.png]] - -#+begin_important -From Figure ref:fig:test_nhexa_rga_num_ol_masses, it is clear that the coupling is quite large starting from the first suspension mode of the nano-hexapod. -Therefore, is the payload's mass is increase, the coupling in the system start to become unacceptably large at lower frequencies. -#+end_important - ** Comparison with the Simscape model :PROPERTIES: :header-args:matlab+: :tangle matlab/scripts/id_frf_enc_plates_effect_payload_comp_simscape.m @@ -6095,19 +5629,21 @@ frf_ol_m = load('frf_vib_table_m.mat', 'f', 'Ts', 'G_tau', 'G_dL'); Let's initialize the simscape model with the nano-hexapod fixed on top of the vibration table. #+begin_src matlab %% Initialize Nano-Hexapod +table_type = 'Suspended'; % On top of vibration table +device_type = 'Hexapod'; % On top of vibration table +payload_num = 0; % No Payload + n_hexapod = initializeNanoHexapodFinal('flex_bot_type', '4dof', ... 'flex_top_type', '4dof', ... 'motion_sensor_type', 'plates', ... 'actuator_type', '2dof'); - -support.type = 1; % On top of vibration table #+end_src First perform the identification for the transfer functions from $\bm{u}$ to $d\bm{\mathcal{L}}_m$: #+begin_src matlab %% Identify the DVF Plant (transfer function from u to dLm) clear io; io_i = 1; -io(io_i) = linio([mdl, '/du'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs +io(io_i) = linio([mdl, '/u'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs io(io_i) = linio([mdl, '/dL'], 1, 'openoutput'); io_i = io_i + 1; % Encoders %% Identification for all the added payloads @@ -6115,15 +5651,15 @@ G_dL = {}; for i = i_masses fprintf('i = %i\n', i) - payload.type = i; % Change the payload on the nano-hexapod - G_dL(i+1) = {exp(-s*frf_ol.Ts)*linearize(mdl, io, 0.0, options)}; + payload_num = i; % Change the payload on the nano-hexapod + G_dL(i+1) = {exp(-s*frf_ol_m.Ts)*linearize(mdl, io, 0.0, options)}; end #+end_src #+begin_src matlab %% Identify the IFF Plant (transfer function from u to taum) clear io; io_i = 1; -io(io_i) = linio([mdl, '/du'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs +io(io_i) = linio([mdl, '/u'], 1, 'openinput'); io_i = io_i + 1; % Actuator Inputs io(io_i) = linio([mdl, '/Fm'], 1, 'openoutput'); io_i = io_i + 1; % Force Sensors %% Identification for all the added payloads @@ -6131,18 +5667,18 @@ G_tau = {}; for i = 0:3 fprintf('i = %i\n', i) - payload.type = i; % Change the payload on the nano-hexapod - G_tau(i+1) = {exp(-s*frf_ol.Ts)*linearize(mdl, io, 0.0, options)}; + payload_num = i; % Change the payload on the nano-hexapod + G_tau(i+1) = {exp(-s*frf_ol_m.Ts)*linearize(mdl, io, 0.0, options)}; end #+end_src The identified dynamics are then saved for further use. #+begin_src matlab :exports none :tangle no -save('matlab/data_frf/sim_vib_table_m.mat', 'G_tau', 'G_dL') +save('matlab/mat/data_frf/sim_vib_table_m.mat', 'G_tau', 'G_dL') #+end_src #+begin_src matlab :eval no -save('data_frf/sim_vib_table_m.mat', 'G_tau', 'G_dL') +save('./mat/data_frf/sim_vib_table_m.mat', 'G_tau', 'G_dL') #+end_src #+begin_src matlab :exports none @@ -6206,7 +5742,7 @@ exportFig('figs/comp_masses_model_exp_dvf.pdf', 'width', 'wide', 'height', 'tall #+name: fig:test_nhexa_comp_masses_model_exp_dvf #+caption: Comparison of the transfer functions from $u_i$ to $d\mathcal{L}_{m,i}$ - measured FRF and identification from the Simscape model #+RESULTS: -[[file:figs/test_nhexa_comp_masses_model_exp_dvf.png]] +[[file:figs/comp_masses_model_exp_dvf.png]] #+begin_src matlab :exports none :tangle no ax1.YLim = [1e-6, 5e-4]; @@ -6296,19 +5832,6 @@ exportFig('figs/comp_masses_model_exp_iff_zoom.pdf', 'width', 'wide', 'height', #+RESULTS: [[file:figs/test_nhexa_comp_masses_model_exp_iff_zoom.png]] -** Conclusion -#+begin_important -In this section, the dynamics of the nano-hexapod with the encoders fixed to the plates is studied. - -It has been found that: -- The measured dynamics is in agreement with the dynamics of the simscape model, up to the flexible modes of the top plate. - See figures ref:fig:test_nhexa_enc_plates_iff_comp_simscape and ref:fig:test_nhexa_enc_plates_iff_comp_offdiag_simscape for the transfer function to the force sensors and Figures ref:fig:test_nhexa_enc_plates_dvf_comp_simscape and ref:fig:test_nhexa_enc_plates_dvf_comp_offdiag_simscape for the transfer functions to the encoders -- The Integral Force Feedback strategy is very effective in damping the suspension modes of the nano-hexapod (Figure ref:fig:test_nhexa_enc_plant_plates_effect_iff). -- The transfer function from $\bm{u}^\prime$ to $d\bm{\mathcal{L}}_m$ show nice dynamical properties and is a much better candidate for the high-authority-control than when the encoders were fixed to the struts. - At least up to the flexible modes of the top plate, the diagonal elements of the transfer function matrix have alternating poles and zeros, and the phase is moving smoothly. - Only the flexible modes of the top plates seems to be problematic for control. -#+end_important - * Bibliography :ignore: #+latex: \printbibliography[heading=bibintoc,title={Bibliography}] @@ -6319,453 +5842,42 @@ It has been found that: # #+latex: \printglossary[type=\glossarytype] # #+latex: \printglossary -* Matlab Functions :noexport: -** =generateXYZTrajectory= -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/generateXYZTrajectory.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: -<> - -*** Function description :ignore: - -Function description: - -#+begin_src matlab -n -function [ref] = generateXYZTrajectory(args) -% generateXYZTrajectory - -% -% Syntax: [ref] = generateXYZTrajectory(args) -% -% Inputs: -% - args -% -% Outputs: -% - ref - Reference Signal -#+end_src - -*** Optional Parameters :ignore: - -Optional Parameters: - -#+begin_src matlab +n -arguments - args.points double {mustBeNumeric} = zeros(2, 3) % [m] - - args.ti (1,1) double {mustBeNumeric, mustBeNonnegative} = 1 % Time to go to first point and after last point [s] - args.tw (1,1) double {mustBeNumeric, mustBeNonnegative} = 0.5 % Time wait between each point [s] - args.tm (1,1) double {mustBeNumeric, mustBeNonnegative} = 1 % Motion time between points [s] - - args.Ts (1,1) double {mustBeNumeric, mustBePositive} = 1e-3 % Sampling Time [s] -end -#+end_src - -*** Initialize Time Vectors :ignore: - -Initialize Time Vectors: - -#+begin_src matlab +n -time_i = 0:args.Ts:args.ti; -time_w = 0:args.Ts:args.tw; -time_m = 0:args.Ts:args.tm; -#+end_src - -*** XYZ Trajectory :ignore: - -Generation of the XYZ Trajectory: - -#+begin_src matlab +n -% Go to initial position -xyz = (args.points(1,:))'*(time_i/args.ti); - -% Wait -xyz = [xyz, xyz(:,end).*ones(size(time_w))]; - -% Scans -for i = 2:size(args.points, 1) - % Go to next point - xyz = [xyz, xyz(:,end) + (args.points(i,:)' - xyz(:,end))*(time_m/args.tm)]; - % Wait a litle bit - xyz = [xyz, xyz(:,end).*ones(size(time_w))]; -end - -% End motion -xyz = [xyz, xyz(:,end) - xyz(:,end)*(time_i/args.ti)]; -#+end_src - -*** Reference Signal :ignore: - -Save the trajectory as a standard structure: - -#+begin_src matlab +n -t = 0:args.Ts:args.Ts*(length(xyz) - 1); - -ref = zeros(length(xyz), 7); - -ref(:, 1) = t; -ref(:, 2:4) = xyz'; -#+end_src - -** =generateYZScanTrajectory= -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/generateYZScanTrajectory.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: -<> - -*** Function description :ignore: - -Function description - -#+begin_src matlab -function [ref] = generateYZScanTrajectory(args) -% generateYZScanTrajectory - -% -% Syntax: [ref] = generateYZScanTrajectory(args) -% -% Inputs: -% - args -% -% Outputs: -% - ref - Reference Signal -#+end_src - -*** Optional Parameters :ignore: - -Optional Parameters - -#+begin_src matlab -arguments - args.y_tot (1,1) double {mustBeNumeric, mustBePositive} = 10e-6 % [m] - args.z_tot (1,1) double {mustBeNumeric, mustBePositive} = 10e-6 % [m] - - args.n (1,1) double {mustBeInteger, mustBePositive} = 10 % [-] - - args.Ts (1,1) double {mustBeNumeric, mustBePositive} = 1e-4 % [s] - - args.ti (1,1) double {mustBeNumeric, mustBeNonnegative} = 1 % [s] - args.tw (1,1) double {mustBeNumeric, mustBeNonnegative} = 1 % [s] - args.ty (1,1) double {mustBeNumeric, mustBeNonnegative} = 1 % [s] - args.tz (1,1) double {mustBeNumeric, mustBeNonnegative} = 1 % [s] -end -#+end_src - -*** Initialize Time Vectors :ignore: - -Initialize Time Vectors - -#+begin_src matlab -time_i = 0:args.Ts:args.ti; -time_w = 0:args.Ts:args.tw; -time_y = 0:args.Ts:args.ty; -time_z = 0:args.Ts:args.tz; -#+end_src - -*** Y and Z vectors :ignore: - -Y and Z vectors - -#+begin_src matlab -% Go to initial position -y = (time_i/args.ti)*(args.y_tot/2); - -% Wait -y = [y, y(end)*ones(size(time_w))]; - -% Scans -for i = 1:args.n - if mod(i,2) == 0 - y = [y, -(args.y_tot/2) + (time_y/args.ty)*args.y_tot]; - else - y = [y, (args.y_tot/2) - (time_y/args.ty)*args.y_tot]; - end - - if i < args.n - y = [y, y(end)*ones(size(time_z))]; - end -end - -% Wait a litle bit -y = [y, y(end)*ones(size(time_w))]; - -% End motion -y = [y, y(end) - y(end)*time_i/args.ti]; -#+end_src - -#+begin_src matlab -% Go to initial position -z = (time_i/args.ti)*(args.z_tot/2); - -% Wait -z = [z, z(end)*ones(size(time_w))]; - -% Scans -for i = 1:args.n - z = [z, z(end)*ones(size(time_y))]; - - if i < args.n - z = [z, z(end) - (time_z/args.tz)*args.z_tot/(args.n-1)]; - end -end - -% Wait a litle bit -z = [z, z(end)*ones(size(time_w))]; - -% End motion -z = [z, z(end) - z(end)*time_i/args.ti]; -#+end_src - -*** Reference Signal :ignore: - -Reference Signal - -#+begin_src matlab -t = 0:args.Ts:args.Ts*(length(y) - 1); - -ref = zeros(length(y), 7); - -ref(:, 1) = t; -ref(:, 3) = y; -ref(:, 4) = z; -#+end_src - -** =generateSpiralAngleTrajectory= -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/generateSpiralAngleTrajectory.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: -<> - -*** Function description :ignore: - -Function description - -#+begin_src matlab -function [ref] = generateSpiralAngleTrajectory(args) -% generateSpiralAngleTrajectory - -% -% Syntax: [ref] = generateSpiralAngleTrajectory(args) -% -% Inputs: -% - args -% -% Outputs: -% - ref - Reference Signal -#+end_src - -*** Optional Parameters :ignore: - -Optional Parameters - -#+begin_src matlab -arguments - args.R_tot (1,1) double {mustBeNumeric, mustBePositive} = 10e-6 % [rad] - args.n_turn (1,1) double {mustBeInteger, mustBePositive} = 5 % [-] - args.Ts (1,1) double {mustBeNumeric, mustBePositive} = 1e-3 % [s] - args.t_turn (1,1) double {mustBeNumeric, mustBePositive} = 1 % [s] - args.t_end (1,1) double {mustBeNumeric, mustBePositive} = 1 % [s] -end -#+end_src - -*** Initialize Time Vectors :ignore: - -Initialize Time Vectors - -#+begin_src matlab -time_s = 0:args.Ts:args.n_turn*args.t_turn; -time_e = 0:args.Ts:args.t_end; -#+end_src - -*** Rx and Ry vectors :ignore: - -Rx and Ry vectors - -#+begin_src matlab -Rx = sin(2*pi*time_s/args.t_turn).*(args.R_tot*time_s/(args.n_turn*args.t_turn)); -Ry = cos(2*pi*time_s/args.t_turn).*(args.R_tot*time_s/(args.n_turn*args.t_turn)); -#+end_src - -#+begin_src matlab -Rx = [Rx, 0*time_e]; -Ry = [Ry, Ry(end) - Ry(end)*time_e/args.t_end]; -#+end_src - -*** Reference Signal :ignore: - -Reference Signal - -#+begin_src matlab -t = 0:args.Ts:args.Ts*(length(Rx) - 1); - -ref = zeros(length(Rx), 7); - -ref(:, 1) = t; -ref(:, 5) = Rx; -ref(:, 6) = Ry; -#+end_src - -** =getTransformationMatrixAcc= -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/getTransformationMatrixAcc.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: -<> - -*** Function description :ignore: - -Function description: - -#+begin_src matlab -function [M] = getTransformationMatrixAcc(Opm, Osm) -% getTransformationMatrixAcc - -% -% Syntax: [M] = getTransformationMatrixAcc(Opm, Osm) -% -% Inputs: -% - Opm - Nx3 (N = number of accelerometer measurements) X,Y,Z position of accelerometers -% - Opm - Nx3 (N = number of accelerometer measurements) Unit vectors representing the accelerometer orientation -% -% Outputs: -% - M - Transformation Matrix -#+end_src - -*** Transformation matrix from motion of the solid body to accelerometer measurements :ignore: - -Let's try to estimate the x-y-z acceleration of any point of the solid body from the acceleration/angular acceleration of the solid body expressed in $\{O\}$. -For any point $p_i$ of the solid body (corresponding to an accelerometer), we can write: -\begin{equation} -\begin{bmatrix} -a_{i,x} \\ a_{i,y} \\ a_{i,z} -\end{bmatrix} = \begin{bmatrix} -\dot{v}_x \\ \dot{v}_y \\ \dot{v}_z -\end{bmatrix} + p_i \times \begin{bmatrix} -\dot{\omega}_x \\ \dot{\omega}_y \\ \dot{\omega}_z -\end{bmatrix} -\end{equation} - -We can write the cross product as a matrix product using the skew-symmetric transformation: -\begin{equation} -\begin{bmatrix} -a_{i,x} \\ a_{i,y} \\ a_{i,z} -\end{bmatrix} = \begin{bmatrix} -\dot{v}_x \\ \dot{v}_y \\ \dot{v}_z -\end{bmatrix} + \underbrace{\begin{bmatrix} - 0 & p_{i,z} & -p_{i,y} \\ - -p_{i,z} & 0 & p_{i,x} \\ - p_{i,y} & -p_{i,x} & 0 -\end{bmatrix}}_{P_{i,[\times]}} \cdot \begin{bmatrix} -\dot{\omega}_x \\ \dot{\omega}_y \\ \dot{\omega}_z -\end{bmatrix} -\end{equation} - -If we now want to know the (scalar) acceleration $a_i$ of the point $p_i$ in the direction of the accelerometer direction $\hat{s}_i$, we can just project the 3d acceleration on $\hat{s}_i$: -\begin{equation} -a_i = \hat{s}_i^T \cdot \begin{bmatrix} -a_{i,x} \\ a_{i,y} \\ a_{i,z} -\end{bmatrix} = \hat{s}_i^T \cdot \begin{bmatrix} -\dot{v}_x \\ \dot{v}_y \\ \dot{v}_z -\end{bmatrix} + \left( \hat{s}_i^T \cdot P_{i,[\times]} \right) \cdot \begin{bmatrix} -\dot{\omega}_x \\ \dot{\omega}_y \\ \dot{\omega}_z -\end{bmatrix} -\end{equation} - -Which is equivalent as a simple vector multiplication: -\begin{equation} -a_i = \begin{bmatrix} -\hat{s}_i^T & \hat{s}_i^T \cdot P_{i,[\times]} -\end{bmatrix} -\begin{bmatrix} -\dot{v}_x \\ \dot{v}_y \\ \dot{v}_z \\ \dot{\omega}_x \\ \dot{\omega}_y \\ \dot{\omega}_z -\end{bmatrix} = \begin{bmatrix} -\hat{s}_i^T & \hat{s}_i^T \cdot P_{i,[\times]} -\end{bmatrix} {}^O\vec{x} -\end{equation} - -And finally we can combine the 6 (line) vectors for the 6 accelerometers to write that in a matrix form. -We obtain Eq. eqref:eq:M_matrix. -#+begin_important -The transformation from solid body acceleration ${}^O\vec{x}$ from sensor measured acceleration $\vec{a}$ is: -\begin{equation} \label{eq:M_matrix} -\vec{a} = \underbrace{\begin{bmatrix} -\hat{s}_1^T & \hat{s}_1^T \cdot P_{1,[\times]} \\ -\vdots & \vdots \\ -\hat{s}_6^T & \hat{s}_6^T \cdot P_{6,[\times]} -\end{bmatrix}}_{M} {}^O\vec{x} -\end{equation} - -with $\hat{s}_i$ the unit vector representing the measured direction of the i'th accelerometer expressed in frame $\{O\}$ and $P_{i,[\times]}$ the skew-symmetric matrix representing the cross product of the position of the i'th accelerometer expressed in frame $\{O\}$. -#+end_important - -Let's define such matrix using matlab: -#+begin_src matlab -M = zeros(length(Opm), 6); - -for i = 1:length(Opm) - Ri = [0, Opm(3,i), -Opm(2,i); - -Opm(3,i), 0, Opm(1,i); - Opm(2,i), -Opm(1,i), 0]; - M(i, 1:3) = Osm(:,i)'; - M(i, 4:6) = Osm(:,i)'*Ri; -end -#+end_src - -#+begin_src matlab -end -#+end_src - * Helping Functions :noexport: ** Initialize Path #+NAME: m-init-path #+BEGIN_SRC matlab -%% Path for functions, data and scripts -addpath('./matlab/data_frf/'); % Path for Computed FRF -addpath('./matlab/data_sim/'); % Path for Simulation -addpath('./matlab/data_meas/'); % Path for Measurements -addpath('./matlab/src/'); % Path for functions addpath('./matlab/'); % Path for scripts -%% Simscape Model - Nano Hexapod -addpath('./matlab/nass-simscape/matlab/nano_hexapod/') -addpath('./matlab/nass-simscape/STEPS/nano_hexapod/') -addpath('./matlab/nass-simscape/STEPS/png/') -addpath('./matlab/nass-simscape/src/') -addpath('./matlab/nass-simscape/mat/') - -%% Simscape Model - Vibration Table -addpath('./matlab/vibration-table/matlab/') -addpath('./matlab/vibration-table/STEPS/') +%% Path for functions, data and scripts +addpath('./matlab/mat/data_frf/'); % Path for Computed FRF +addpath('./matlab/mat/data_sim/'); % Path for Simulation +addpath('./matlab/mat/data_meas/'); % Path for Measurements +addpath('./matlab/src/'); % Path for functions +addpath('./matlab/STEPS/'); % Path for STEPS +addpath('./matlab/subsystems/'); % Path for Subsystems Simulink files #+END_SRC #+NAME: m-init-path-tangle #+BEGIN_SRC matlab %% Path for functions, data and scripts -addpath('./data_frf/'); % Path for Computed FRF -addpath('./data_sim/'); % Path for Simulation -addpath('./data_meas/'); % Path for Measurements +addpath('./mat/data_frf/'); % Path for Computed FRF +addpath('./mat/data_sim/'); % Path for Simulation +addpath('./mat/data_meas/'); % Path for Measurements addpath('./src/'); % Path for functions - -%% Simscape Model - Nano Hexapod -addpath('./nass-simscape/matlab/nano_hexapod/') -addpath('./nass-simscape/STEPS/nano_hexapod/') -addpath('./nass-simscape/STEPS/png/') -addpath('./nass-simscape/src/') -addpath('./nass-simscape/mat/') - -%% Simscape Model - Vibration Table -addpath('./vibration-table/matlab/') -addpath('./vibration-table/STEPS/') +addpath('./STEPS/'); % Path for STEPS +addpath('./subsystems/'); % Path for Subsystems Simulink files #+END_SRC ** Initialize Simscape Model #+NAME: m-init-simscape #+begin_src matlab %% Initialize Parameters for Simscape model -support.type = 1; % On top of vibration table -payload.type = 0; % No Payload -Rx = zeros(1, 7); % Default reference path +table_type = 'Rigid'; % On top of vibration table +device_type = 'None'; % On top of vibration table +payload_num = 0; % No Payload %% Open Simulink Model -mdl = 'nano_hexapod_simscape'; +mdl = 'test_bench_nano_hexapod'; options = linearizeOptions; options.SampleTime = 0; @@ -6787,3 +5899,7 @@ freqs = 2*logspace(1, 3, 1000); #+END_SRC * Footnotes +[fn:4]As the accuracy of the FARO arm is $\pm 13\,\mu m$, the true straightness is probably better than the values indicated. The limitation of the instrument is here reached. +[fn:3]The height dimension is better than $40\,\mu m$. The diameter fit of 182g6 and 24g6 with the two plates is verified. +[fn:2]Location of all the interface surfaces with the flexible joints are checked. The fits (182H7 and 24H8) with the interface element are checked. +[fn:1]Faro Arm Platinum 4ft, specified accuracy of $\pm 13\mu m$ diff --git a/test-bench-nano-hexapod.pdf b/test-bench-nano-hexapod.pdf index 998ea35..da29cf3 100644 Binary files a/test-bench-nano-hexapod.pdf and b/test-bench-nano-hexapod.pdf differ