#+TITLE: Test Bench - Nano-Hexapod Struts :DRAWER: #+LANGUAGE: en #+EMAIL: dehaeze.thomas@gmail.com #+AUTHOR: Dehaeze Thomas #+HTML_LINK_HOME: ../index.html #+HTML_LINK_UP: ../index.html #+HTML_HEAD: #+HTML_HEAD: #+BIND: org-latex-image-default-option "scale=1" #+BIND: org-latex-image-default-width "" #+LaTeX_CLASS: scrreprt #+LaTeX_CLASS_OPTIONS: [a4paper, 10pt, DIV=12, parskip=full, bibliography=totoc] #+LaTeX_HEADER_EXTRA: \input{preamble.tex} #+LATEX_HEADER_EXTRA: \bibliography{test-bench-struts.bib} #+BIND: org-latex-bib-compiler "biber" #+PROPERTY: header-args:matlab :session *MATLAB* #+PROPERTY: header-args:matlab+ :comments org #+PROPERTY: header-args:matlab+ :exports none #+PROPERTY: header-args:matlab+ :results none #+PROPERTY: header-args:matlab+ :eval no-export #+PROPERTY: header-args:matlab+ :noweb yes #+PROPERTY: header-args:matlab+ :mkdirp yes #+PROPERTY: header-args:matlab+ :output-dir figs #+PROPERTY: header-args:matlab+ :tangle no #+PROPERTY: header-args:latex :headers '("\\usepackage{tikz}" "\\usepackage{import}" "\\import{$HOME/Cloud/tikz/org/}{config.tex}") #+PROPERTY: header-args:latex+ :imagemagick t :fit yes #+PROPERTY: header-args:latex+ :iminoptions -scale 100% -density 150 #+PROPERTY: header-args:latex+ :imoutoptions -quality 100 #+PROPERTY: header-args:latex+ :results file raw replace #+PROPERTY: header-args:latex+ :buffer no #+PROPERTY: header-args:latex+ :tangle no #+PROPERTY: header-args:latex+ :eval no-export #+PROPERTY: header-args:latex+ :exports results #+PROPERTY: header-args:latex+ :mkdirp yes #+PROPERTY: header-args:latex+ :output-dir figs #+PROPERTY: header-args:latex+ :post pdf2svg(file=*this*, ext="png") :END: #+begin_export html

This report is also available as a pdf.


#+end_export #+latex: \clearpage * Build :noexport: #+NAME: startblock #+BEGIN_SRC emacs-lisp :results none :tangle no (add-to-list 'org-latex-classes '("scrreprt" "\\documentclass{scrreprt}" ("\\chapter{%s}" . "\\chapter*{%s}") ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}") ("\\paragraph{%s}" . "\\paragraph*{%s}") )) ;; Remove automatic org heading labels (defun my-latex-filter-removeOrgAutoLabels (text backend info) "Org-mode automatically generates labels for headings despite explicit use of `#+LABEL`. This filter forcibly removes all automatically generated org-labels in headings." (when (org-export-derived-backend-p backend 'latex) (replace-regexp-in-string "\\\\label{sec:org[a-f0-9]+}\n" "" text))) (add-to-list 'org-export-filter-headline-functions 'my-latex-filter-removeOrgAutoLabels) ;; Use no package by default (setq org-latex-packages-alist nil) (setq org-latex-default-packages-alist nil) ;; Do not include the subtitle inside the title (setq org-latex-subtitle-separate t) (setq org-latex-subtitle-format "\\subtitle{%s}") (setq org-export-before-parsing-hook '(org-ref-glossary-before-parsing org-ref-acronyms-before-parsing)) #+END_SRC * Notes :noexport: Prefix for figures/section/tables =test_struts= To integrate: - [X] [[file:~/Cloud/work-projects/ID31-NASS/matlab/test-bench-strut-mounting/test-bench-strut-mounting.org][test-bench-strut-mounting]] - [X] [[file:~/Cloud/work-projects/ID31-NASS/matlab/test-bench-apa300ml/test-bench-apa300ml.org][test-bench-apa300ml]] - [X] Dynamical measurements (Section 5) - [X] Simscape model (Section 6) - [X] Check what are the used Matlab functions - [X] check [[file:~/Cloud/work-projects/ID31-NASS/matlab/test-bench-apa300ml/test-bench-apa300ml.org::*Compare with the FEM/Simscape Model][Compare with the FEM/Simscape Model]] *no, it is only for the APA and not the strut* - [X] Check [[file:~/Cloud/work-projects/ID31-NASS/matlab/test-bench-apa300ml/test-bench-apa300ml.org::*New Measurements - IFF Root Locus][New Measurements - IFF Root Locus]] *no, it is only for the APA and not the strut* ** TODO [#C] Add schematic of the test bench with signals here: [[*Introduction][Introduction]] - $u$ - $d_e$ - $d_a$ ** TODO [#B] Rework mounting procedure section - [X] Use smaller images, maybe one subfigure for all the steps - [ ] Add some notes to the figure ref:fig:test_struts_mounting_bench_first_concept - [ ] Explain clearly the mounting goals (coaxiality, etc.) - [ ] Speak about the "pin" that is used to align the APA with respect to the flexible joints (initially not used) ** DONE [#B] Rework flexible mode measurements CLOSED: [2024-03-25 Mon 16:35] - [X] Use smaller images, one subfigure for all measurements ** DONE [#B] Make the simscape model work CLOSED: [2024-03-25 Mon 15:09] * Introduction :ignore: In this document, a test-bench is used to characterize the struts of the nano-hexapod. Each strut includes (Figure ref:fig:test_struts_picture_strut): - 2 flexible joints at each ends. These flexible joints have been characterized in a separate test bench (see ...). - 1 Amplified Piezoelectric Actuator (APA300ML) (described in Section ...). Two stacks are used as an actuator and one stack as a (force) sensor. - 1 encoder (Renishaw Vionic) that has been characterized in a separate test bench (see ...). #+name: fig:test_struts_picture_strut #+caption: One strut including two flexible joints, an amplified piezoelectric actuator and an encoder #+attr_latex: :width 0.8\linewidth [[file:figs/test_struts_picture_strut.jpg]] Then the struts are mounted (procedure described in Section ref:sec:test_struts_mounting), and are fixed to the same measurement bench. The goals are to: - Section ref:sec:test_struts_dynamical_meas: Identify the dynamics from the generated DAC voltage to: - the sensors stack generated voltage - the measured displacement by the encoder - the measured displacement by the interferometer (representing encoders that would be fixed to the nano-hexapod's plates instead of the struts) - Section ref:sec:test_struts_simscape: Compare the measurements with the Simscape model of the struts and tune the models The final goal of the work presented in this document is to have an accurate Simscape model of the struts that can then be included in the Simscape model of the nano-hexapod. #+name: tab:test_struts_section_matlab_code #+caption: Report sections and corresponding Matlab files #+attr_latex: :environment tabularx :width 0.6\linewidth :align lX #+attr_latex: :center t :booktabs t | *Sections* | *Matlab File* | |--------------------------------------------+----------------------------------| | Section ref:sec:test_struts_flexible_modes | =test_struts_1_flexible_modes.m= | | Section ref:sec:test_struts_dynamical_meas | =test_struts_2_dynamical_meas.m= | | Section ref:sec:test_struts_simscape | =test_struts_3_simscape_model.m= | * Mounting Procedure <> ** Introduction :ignore: ** Mounting Bench A mounting bench is used to greatly simply the mounting of the struts as well as ensuring the correct strut length and coaxiality of the flexible joint's interfaces. This is very important in order to not loose any stroke when the struts will be mounted on the nano-hexapod. A CAD view of the mounting bench is shown in Figure ref:fig:test_struts_mounting_bench_first_concept. Faro arm[fn:1] #+name: fig:test_struts_mounting_bench_first_concept #+caption: CAD view of the mounting bench #+attr_latex: :width 0.6\linewidth [[file:figs/test_struts_mounting_bench_first_concept.png]] The main part of the bench is here to ensure both the correct strut length and strut coaxiality as shown in Figure ref:fig:test_struts_mounting_step_0. #+name: fig:test_struts_mounting_base_part #+caption: Caption..., add foot note with Faro arm #+attr_latex: :options [htbp] #+begin_figure #+attr_latex: :caption \subcaption{\label{fig:test_struts_mounting_step_0}Useful features of the main mounting element} #+attr_latex: :options {0.56\textwidth} #+begin_subfigure #+attr_latex: :height 4.5cm [[file:figs/test_struts_mounting_step_0.jpg]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_check_dimensions_bench}Dimensional check} #+attr_latex: :options {0.43\textwidth} #+begin_subfigure #+attr_latex: :height 4.5cm [[file:figs/test_struts_check_dimensions_bench.jpg]] #+end_subfigure #+end_figure The tight tolerances of this element has been verified as shown in Figure ref:fig:test_struts_check_dimensions_bench and were found to comply with the requirements. The flexible joints are rigidly fixed to cylindrical tools shown in Figures ref:fig:test_struts_cylindrical_mounting_part_top and ref:fig:test_struts_cylindrical_mounting_part_bot which are then mounted on the mounting tool shown in Figure ref:fig:test_struts_mounting_step_0. This cylindrical tool is here to protect the flexible joints when tightening the screws and therefore applying large torque. ** Mounting Procedure - [ ] Better explain the mounting procedure - [ ] Speak about the "locating" pins that are used to aligned the APA with the two flexible joints The mounting procedure is as follows: 1. Screw flexible joints inside the cylindrical interface element shown in Figure ref:fig:test_struts_cylindrical_mounting 2. Fix the two interface elements. One of the two should be clamped, the other one should have its axial rotation free. Visually align the clamped one horizontally. (Figure ref:fig:test_struts_mounting_step_1) 3. Put cylindrical washers, APA and interface pieces on top of the flexible joints (Figure ref:fig:test_struts_mounting_step_2) 4. Put the 4 screws just in contact such that everything is correctly positioned and such that the "free" flexible joint is correctly oriented 5. Put the 8 lateral screws in contact 6. Tighten the 4 screws to fix the APA on the two flexible joints (using a torque screwdriver) 7. Remove the 4 laterals screws 8. (optional) Put the APA horizontally and fix the encoder and align it to maximize the contrast (Figure ref:fig:test_struts_mounting_step_3) 9. Disassemble to have an properly mounted strut (Figure ref:fig:test_struts_mounting_step_4) for which the coaxiality between the two flexible joint's interfaces is good #+name: fig:test_struts_cylindrical_mounting #+caption: Preparation of the flexible joints by fixing them in their cylindrical interface #+attr_latex: :options [htbp] #+begin_figure #+attr_latex: :caption \subcaption{\label{fig:test_struts_cylindrical_mounting_part_top}Cylindral Interface (Top)} #+attr_latex: :options {0.33\textwidth} #+begin_subfigure #+attr_latex: :height 4.5cm [[file:figs/test_struts_cylindrical_mounting_part_top.jpg]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_cylindrical_mounting_part_bot}Cylindrlcal Interface (Bottom)} #+attr_latex: :options {0.33\textwidth} #+begin_subfigure #+attr_latex: :height 4.5cm [[file:figs/test_struts_cylindrical_mounting_part_bot.jpg]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_mounting_joints}Mounted flexible joints} #+attr_latex: :options {0.33\textwidth} #+begin_subfigure #+attr_latex: :height 4.5cm [[file:figs/test_struts_mounting_joints.jpg]] #+end_subfigure #+end_figure #+name: fig:test_struts_mounting_steps #+caption: Steps for mounting the struts. #+attr_latex: :options [htbp] #+begin_figure #+attr_latex: :caption \subcaption{\label{fig:test_struts_mounting_step_1}Step 1} #+attr_latex: :options {0.5\textwidth} #+begin_subfigure #+attr_latex: :width 0.95\linewidth [[file:figs/test_struts_mounting_step_1.jpg]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_mounting_step_2}Step 2} #+attr_latex: :options {0.5\textwidth} #+begin_subfigure #+attr_latex: :width 0.95\linewidth [[file:figs/test_struts_mounting_step_2.jpg]] #+end_subfigure \bigskip #+attr_latex: :caption \subcaption{\label{fig:test_struts_mounting_step_3}Step 3} #+attr_latex: :options {0.5\textwidth} #+begin_subfigure #+attr_latex: :width 0.95\linewidth [[file:figs/test_struts_mounting_step_3.jpg]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_mounting_step_4}Step 4} #+attr_latex: :options {0.5\textwidth} #+begin_subfigure #+attr_latex: :width 0.95\linewidth [[file:figs/test_struts_mounting_step_4.jpg]] #+end_subfigure #+end_figure * Measurement of flexible modes :PROPERTIES: :header-args:matlab+: :tangle matlab/test_struts_1_flexible_modes.m :END: <> ** Introduction From a Finite Element Model of the struts, it have been found that three main resonances are foreseen to be problematic for the control of the APA300ML (Figure ref:fig:test_struts_mode_shapes): an "X-bending" mode at 189Hz, a "Y-bending" mode at 285Hz and a "Z-torsion" mode at 400Hz. #+name: fig:test_struts_mode_shapes #+caption: Spurious resonances of the struts estimated from a Finite Element Model #+attr_latex: :options [htbp] #+begin_figure #+attr_latex: :caption \subcaption{\label{fig:test_struts_mode_shapes_1}X-bending mode (189Hz)} #+attr_latex: :options {0.33\textwidth} #+begin_subfigure #+attr_latex: :width 0.9\linewidth [[file:figs/test_struts_mode_shapes_1.png]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_mode_shapes_2}Y-bending mode (285Hz)} #+attr_latex: :options {0.33\textwidth} #+begin_subfigure #+attr_latex: :width 0.9\linewidth [[file:figs/test_struts_mode_shapes_2.png]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_mode_shapes_3}Z-torsion mode (400Hz)} #+attr_latex: :options {0.33\textwidth} #+begin_subfigure #+attr_latex: :width 0.9\linewidth [[file:figs/test_struts_mode_shapes_3.png]] #+end_subfigure #+end_figure ** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> #+end_src #+begin_src matlab :exports none :results silent :noweb yes <> #+end_src #+begin_src matlab :tangle no :noweb yes <> #+end_src #+begin_src matlab :eval no :noweb yes <> #+end_src #+begin_src matlab :noweb yes <> #+end_src ** Measurement Setup A Laser vibrometer is measuring the difference of motion between two beam path (red points in Figure ref:fig:test_struts_meas_modes). The strut is excited with an instrumented hammer and the transfer function from the hammer to the measured rotation is computed. The "X-bending" mode is measured as shown in Figure ref:fig:test_struts_meas_x_bending. The "Y-bending" mode is measured as shown in Figure ref:fig:test_struts_meas_y_bending. Finally, the "Z-torsion" is measured as shown in Figure ref:fig:test_struts_meas_z_torsion. This is done with and without the encoder fixed to the strut. #+name: fig:test_struts_meas_modes #+caption: Measurement of strut flexible modes #+attr_latex: :options [htbp] #+begin_figure #+attr_latex: :caption \subcaption{\label{fig:test_struts_meas_x_bending}X-bending mode} #+attr_latex: :options {0.33\textwidth} #+begin_subfigure #+attr_latex: :width 0.9\linewidth [[file:figs/test_struts_meas_x_bending.jpg]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_meas_y_bending}Y-bending mode} #+attr_latex: :options {0.33\textwidth} #+begin_subfigure #+attr_latex: :width 0.9\linewidth [[file:figs/test_struts_meas_y_bending.jpg]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_meas_z_torsion}Z-torsion mode} #+attr_latex: :options {0.33\textwidth} #+begin_subfigure #+attr_latex: :width 0.9\linewidth [[file:figs/test_struts_meas_z_torsion.jpg]] #+end_subfigure #+end_figure ** Measured results The obtained frequency response functions are shown in Figure ref:fig:test_struts_spur_res_frf. #+begin_src matlab :exports none %% Load Data (without the encoder) bending_X = load('strut_spur_res_x_bending.mat'); bending_Y = load('strut_spur_res_y_bending.mat'); torsion_Z = load('strut_spur_res_z_torsion.mat'); %% Load Data (with the encoder) bending_X_enc = load('strut_spur_res_x_bending_enc.mat'); bending_Y_enc = load('strut_spur_res_y_bending_enc.mat'); torsion_Z_enc = load('strut_spur_res_z_torsion_enc.mat'); #+end_src #+begin_src matlab :exports none %% Plot the responses (without the encoder) figure; hold on; plot(bending_X.FFT1_AvSpc_1_RMS_X_Val, bending_X.FFT1_AvSpc_1_RMS_Y_Val, ... 'DisplayName', 'X-Bending') plot(bending_Y.FFT1_AvSpc_1_RMS_X_Val, bending_Y.FFT1_AvSpc_1_RMS_Y_Val, ... 'DisplayName', 'Y-Bending') plot(torsion_Z.FFT1_AvSpc_1_RMS_X_Val, torsion_Z.FFT1_AvSpc_1_RMS_Y_Val, ... 'DisplayName', 'Z-torsion'); text(226, 1.5e-4,{'226Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center') text(310, 6e-5,{'337Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center') text(398, 1.5e-4,{'398Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center') hold off; set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log'); xlabel('Frequency [Hz]'); ylabel('Amplitude'); xlim([50, 8e2]); ylim([5e-7, 3e-4]) legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); #+end_src #+begin_src matlab :tangle no :exports results :results file none exportFig('figs/test_struts_spur_res_frf_no_enc.pdf', 'width', 'half', 'height', 'normal'); #+end_src #+begin_src matlab :exports none %% Plot the responses (with the encoder) figure; hold on; plot(bending_X_enc.FFT1_AvSpc_1_RMS_X_Val, bending_X_enc.FFT1_AvSpc_1_RMS_Y_Val, ... 'DisplayName', 'X-Bending') plot(bending_Y_enc.FFT1_AvSpc_1_RMS_X_Val, bending_Y_enc.FFT1_AvSpc_1_RMS_Y_Val, ... 'DisplayName', 'Y-Bending') plot(torsion_Z_enc.FFT1_AvSpc_1_RMS_X_Val, torsion_Z_enc.FFT1_AvSpc_1_RMS_Y_Val, ... 'DisplayName', 'Z-torsion'); text(198, 4e-5,{'198Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center') text(293, 6e-5,{'293Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center') text(381, 1e-4,{'381Hz'}, 'VerticalAlignment', 'bottom','HorizontalAlignment','center') hold off; set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log'); xlabel('Frequency [Hz]'); ylabel('Amplitude'); xlim([50, 8e2]); ylim([5e-7, 3e-4]) legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); #+end_src #+begin_src matlab :tangle no :exports results :results file none exportFig('figs/test_struts_spur_res_frf_enc.pdf', 'width', 'half', 'height', 'normal'); #+end_src #+name: fig:test_struts_spur_res_frf #+caption: Measured frequency response functions without the encoder ref:fig:test_struts_spur_res_frf and with the encoder ref:fig:test_struts_spur_res_frf_enc #+attr_latex: :options [htbp] #+begin_figure #+attr_latex: :caption \subcaption{\label{fig:test_struts_spur_res_frf_no_enc}without encoder} #+attr_latex: :options {0.49\textwidth} #+begin_subfigure #+attr_latex: :width 0.95\linewidth [[file:figs/test_struts_spur_res_frf_no_enc.png]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_spur_res_frf_enc}with the encoder} #+attr_latex: :options {0.49\textwidth} #+begin_subfigure #+attr_latex: :width 0.95\linewidth [[file:figs/test_struts_spur_res_frf_enc.png]] #+end_subfigure #+end_figure ** Conclusion :ignore: Table ref:tab:test_struts_spur_mode_freqs summarizes the measured resonance frequencies as well as the computed ones using the Finite Element Model. It is shown that: - the resonance frequencies of the 3 modes are only slightly increasing when the encoder is removed - the computed resonance frequencies from the FEM are very close to the measured one when the encoder is fixed to the strut #+name: tab:test_struts_spur_mode_freqs #+caption: Measured frequency of the strut spurious modes #+attr_latex: :environment tabularx :width 0.7\linewidth :align Xccc #+attr_latex: :center t :booktabs t :float t | *Mode* | *Struts (FEM)* | *Struts (exp)* | *Plates (exp)* | |-----------+----------------+----------------+----------------| | X-Bending | 189Hz | 198Hz | 226Hz | | Y-Bending | 285Hz | 293Hz | 337Hz | | Z-Torsion | 400Hz | 381Hz | 398Hz | * Dynamical measurements :PROPERTIES: :header-args:matlab+: :tangle matlab/test_struts_2_dynamical_meas.m :END: <> ** Introduction :ignore: The bench is shown in Figure ref:fig:test_struts_bench_leg. #+name: fig:test_struts_bench_leg #+caption: Experimental setup used to measured the dynamics of the struts. #+attr_latex: :options [htbp] #+begin_figure #+attr_latex: :caption \subcaption{\label{fig:test_struts_bench_leg_overview}Overview Picture} #+attr_latex: :options {0.32\textwidth} #+begin_subfigure #+attr_latex: :height 214px [[file:figs/test_struts_bench_leg_overview.jpg]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_bench_schematic}Schematic} #+attr_latex: :options {0.68\textwidth} #+begin_subfigure #+attr_latex: :scale 1 [[file:figs/test_struts_bench_schematic.png]] #+end_subfigure #+end_figure First, the effect of the encoder on the measured dynamics is studied in Section ref:ssec:test_struts_effect_encoder. Then, the dynamics seen by the encoder and by the interferometers are compared in Section ref:ssec:test_struts_comp_enc_int. Finally, all the measured struts are compared in terms of dynamics in Section ref:ssec:test_struts_comp_all_struts. ** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> #+end_src #+begin_src matlab :exports none :results silent :noweb yes <> #+end_src #+begin_src matlab :tangle no :noweb yes <> #+end_src #+begin_src matlab :eval no :noweb yes <> #+end_src #+begin_src matlab :noweb yes <> #+end_src ** Effect of the Encoder on the measured dynamics <> #+begin_src matlab %% Parameters for Frequency Analysis 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 %% Measure FRF for Strut 1 - No encoder % Load Data leg_sweep = load('frf_data_leg_1_sweep.mat', 'u', 'Vs', 'de', 'da'); leg_noise_hf = load('frf_data_leg_1_noise_hf.mat', 'u', 'Vs', 'de', 'da'); % We get the frequency vector that will be the same for all the frequency domain analysis. [~, f] = tfestimate(leg_sweep.u, leg_sweep.de, win, Noverlap, Nfft, 1/Ts); i_lf = f <= 350; % Indices used for the low frequency i_hf = f > 350; % Indices used for the high frequency % Compute FRF function from u to da (interferometer) [frf_sweep, ~] = tfestimate(leg_sweep.u, leg_sweep.da, win, Noverlap, Nfft, 1/Ts); [frf_noise_hf, ~] = tfestimate(leg_noise_hf.u, leg_noise_hf.da, win, Noverlap, Nfft, 1/Ts); int_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; % Combine the FRF % Compute FRF function from u to Vs (force sensor) [frf_sweep, ~] = tfestimate(leg_sweep.u, leg_sweep.Vs, win, Noverlap, Nfft, 1/Ts); [frf_noise_hf, ~] = tfestimate(leg_noise_hf.u, leg_noise_hf.Vs, win, Noverlap, Nfft, 1/Ts); iff_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; % Combine the FRF %% Measure FRF for Strut 1 - With encoder % Load Data leg_enc_sweep = load('frf_data_leg_coder_1_noise.mat', 'u', 'Vs', 'de', 'da'); leg_enc_noise_hf = load('frf_data_leg_coder_1_noise_hf.mat', 'u', 'Vs', 'de', 'da'); % Compute FRF function from u to da (interferometer) [frf_sweep, ~] = tfestimate(leg_enc_sweep.u, leg_enc_sweep.da, win, Noverlap, Nfft, 1/Ts); [frf_noise_hf, ~] = tfestimate(leg_enc_noise_hf.u, leg_enc_noise_hf.da, win, Noverlap, Nfft, 1/Ts); int_with_enc_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; % Combine the FRF % Compute FRF function from u to Vs (force sensor) [frf_sweep, ~] = tfestimate(leg_enc_sweep.u, leg_enc_sweep.Vs, win, Noverlap, Nfft, 1/Ts); [frf_noise_hf, ~] = tfestimate(leg_enc_noise_hf.u, leg_enc_noise_hf.Vs, win, Noverlap, Nfft, 1/Ts); iff_with_enc_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; % Combine the FRF % Compute FRF function from u to de (encoder) [frf_sweep, ~] = tfestimate(leg_enc_sweep.u, leg_enc_sweep.de, win, Noverlap, Nfft, 1/Ts); [frf_noise_hf, ~] = tfestimate(leg_enc_noise_hf.u, leg_enc_noise_hf.de, win, Noverlap, Nfft, 1/Ts); enc_frf = [frf_sweep(i_lf); frf_noise_hf(i_hf)]; % Combine the FRF #+end_src Measurements are performed either when no encoder is fixed to the strut (Figure ref:fig:test_struts_bench_leg_front) or when one encoder is fixed to the strut (Figure ref:fig:test_struts_bench_leg_coder). #+name: fig:test_struts_bench_leg_with_without_enc #+caption: Struts fixed to the test bench with clamped flexible joints. The coder can be fixed to the struts (\subref{fig:test_struts_bench_leg_coder}) or removed (\subref{fig:test_struts_bench_leg_front}) #+attr_latex: :options [htbp] #+begin_figure #+attr_latex: :caption \subcaption{\label{fig:test_struts_bench_leg_coder}Strut with encoder} #+attr_latex: :options {0.5\textwidth} #+begin_subfigure #+attr_latex: :height 6cm [[file:figs/test_struts_bench_leg_coder.jpg]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_bench_leg_front}Strut without encoder} #+attr_latex: :options {0.5\textwidth} #+begin_subfigure #+attr_latex: :height 6cm [[file:figs/test_struts_bench_leg_front.jpg]] #+end_subfigure #+end_figure Figure ref:fig:test_struts_effect_encoder_int Same goes for the transfer function from excitation voltage $u$ to the axial motion of the strut $d_a$ as measured by the interferometer (). The transfer function from the excitation voltage $u$ to the generated voltage $V_s$ by the sensor stack is not influence by the fixation of the encoder (Figure ref:fig:test_struts_effect_encoder_iff). This means that the IFF control strategy should be as effective whether or not the encoders are fixed to the struts. #+begin_src matlab :exports none %% Plot the FRF from u to da with and without the encoder figure; tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(int_with_enc_frf), '-', 'DisplayName', 'With encoder'); plot(f, abs(int_frf), '-', 'DisplayName', 'Without encoder'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_a/u$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-7, 1e-3]); legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); ax2 = nexttile; hold on; plot(f, 180/pi*angle(int_with_enc_frf), '-'); plot(f, 180/pi*angle(int_frf), '-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file none exportFig('figs/test_struts_effect_encoder_int.pdf', 'width', 'half', 'height', 'tall'); #+end_src #+begin_src matlab :exports none %% Compare the IFF plant with and without the encoders figure; tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(iff_with_enc_frf), 'DisplayName', 'With Encoder'); plot(f, abs(iff_frf), 'DisplayName', 'Without Encoder'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $V_s/u$ [V/V]'); set(gca, 'XTickLabel',[]); hold off; legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); ylim([1e-2, 1e2]); ax2 = nexttile; hold on; plot(f, 180/pi*angle(iff_with_enc_frf)); plot(f, 180/pi*angle(iff_frf)); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file none exportFig('figs/test_struts_effect_encoder_iff.pdf', 'width', 'half', 'height', 'tall'); #+end_src #+name: fig:test_struts_effect_encoder #+caption: Effect of having the encoder fixed to the struts on the measured dynamics from $u$ to $d_a$ (\subref{fig:test_struts_effect_encoder_int}) and from $u$ to $V_s$ (\subref{fig:test_struts_effect_encoder_iff}) #+attr_latex: :options [htbp] #+begin_figure #+attr_latex: :caption \subcaption{\label{fig:test_struts_effect_encoder_int}$u$ to $d_a$} #+attr_latex: :options {0.49\textwidth} #+begin_subfigure #+attr_latex: :width 0.95\linewidth [[file:figs/test_struts_effect_encoder_int.png]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_effect_encoder_iff}$u$ to $V_s$} #+attr_latex: :options {0.49\textwidth} #+begin_subfigure #+attr_latex: :width 0.95\linewidth [[file:figs/test_struts_effect_encoder_iff.png]] #+end_subfigure #+end_figure ** Comparison of the encoder and interferometer <> The dynamics as measured by the encoder and by the interferometers are compared in Figure ref:fig:test_struts_comp_enc_int. The dynamics from the excitation voltage $u$ to the measured displacement by the encoder $d_e$ presents much more complicated behavior than the transfer function to the displacement as measured by the Interferometer (compared in Figure ref:fig:test_struts_comp_enc_int). It will be further investigated why the two dynamics as so different and what are causing all these resonances. As shown in Figure ref:fig:test_struts_comp_enc_int, we can clearly see three spurious resonances at 197Hz, 290Hz and 376Hz. These resonances correspond to parasitic resonances of the strut itself that was estimated using a finite element model of the strut (Figure ref:fig:test_struts_mode_shapes): - Mode in X-bending at 189Hz - Mode in Y-bending at 285Hz - Mode in Z-torsion at 400Hz The good news is that these resonances are not seen on the interferometer (they are therefore not impacting the axial motion of the strut). But these resonances are making the use of encoder fixed to the strut difficult. #+begin_src matlab :exports none figure; tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(enc_frf), 'DisplayName', 'Encoder'); plot(f, abs(int_with_enc_frf), 'DisplayName', 'Interferometer'); text(93, 4e-4, {'93Hz'}, 'VerticalAlignment','bottom','HorizontalAlignment','center') text(200, 1.3e-4,{'197Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center') text(300, 4e-6, {'290Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center') text(400, 1.4e-6,{'376Hz'},'VerticalAlignment','bottom','HorizontalAlignment','center') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d/u$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); ylim([1e-8, 1e-3]); ax2 = nexttile; hold on; plot(f, 180/pi*angle(enc_frf)); plot(f, 180/pi*angle(int_with_enc_frf)); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/test_struts_comp_enc_int.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:test_struts_comp_enc_int #+caption: Comparison of the transfer functions from excitation voltage $u$ to either the encoder $d_e$ or the interferometer $d_a$ #+RESULTS: [[file:figs/test_struts_comp_enc_int.png]] ** Comparison of all the Struts <> #+begin_src matlab %% Numbers of the measured legs strut_nums = [1 2 3 4 5]; %% Load the measurement data % First identification (low frequency noise) leg_noise = {}; for i = 1:length(strut_nums) leg_noise(i) = {load(sprintf('frf_data_leg_coder_%i_noise.mat', strut_nums(i)), 'u', 'Vs', 'de', 'da')}; end % Second identification (high frequency noise) leg_noise_hf = {}; for i = 1:length(strut_nums) leg_noise_hf(i) = {load(sprintf('frf_data_leg_coder_%i_noise_hf.mat', strut_nums(i)), 'u', 'Vs', 'de', 'da')}; end %% Compute FRF - From u to de (encoder) enc_frf = zeros(length(f), length(strut_nums)); for i = 1:length(strut_nums) [frf_lf, ~] = tfestimate(leg_noise{i}.u, detrend(leg_noise{i}.de, 0), win, Noverlap, Nfft, 1/Ts); [frf_hf, ~] = tfestimate(leg_noise_hf{i}.u, detrend(leg_noise_hf{i}.de, 0), win, Noverlap, Nfft, 1/Ts); enc_frf(:, i) = [frf_lf(i_lf); frf_hf(i_hf)]; end %% Compute FRF - From u to da (interferometer) int_frf = zeros(length(f), length(strut_nums)); for i = 1:length(strut_nums) [frf_lf, ~] = tfestimate(leg_noise{i}.u, leg_noise{i}.da, win, Noverlap, Nfft, 1/Ts); [frf_hf, ~] = tfestimate(leg_noise_hf{i}.u, leg_noise_hf{i}.da, win, Noverlap, Nfft, 1/Ts); int_frf(:, i) = [frf_lf(i_lf); frf_hf(i_hf)]; end %% Compute FRF - From u to Vs (force sensor) iff_frf = zeros(length(f), length(strut_nums)); for i = 1:length(strut_nums) [frf_lf, ~] = tfestimate(leg_noise{i}.u, leg_noise{i}.Vs, win, Noverlap, Nfft, 1/Ts); [frf_hf, ~] = tfestimate(leg_noise_hf{i}.u, leg_noise_hf{i}.Vs, win, Noverlap, Nfft, 1/Ts); iff_frf(:, i) = [frf_lf(i_lf); frf_hf(i_hf)]; end #+end_src Then, the transfer function from the DAC output voltage $u$ to the measured displacement by the Attocube is computed for all the struts and shown in Figure ref:fig:test_struts_comp_interf_plants. All the struts are giving very similar FRF. #+begin_src matlab :exports none %% Plot the FRF from u to de (interferometer) figure; tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(strut_nums) plot(f, abs(int_frf(:, i)), ... 'DisplayName', sprintf('Leg %i', strut_nums(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_a/u$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2); ylim([1e-9, 1e-3]); ax2 = nexttile; hold on; for i = 1:length(strut_nums) plot(f, 180/pi*angle(int_frf(:, i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file none exportFig('figs/test_struts_comp_interf_plants.pdf', 'width', 'half', 'height', 'tall'); #+end_src #+begin_src matlab :exports none %% Plot the FRF from u to Vs figure; tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(strut_nums) plot(f, abs(iff_frf(:, i)), ... 'DisplayName', sprintf('Leg %i', strut_nums(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $V_s/u$ [V/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-2, 1e2]); legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 2); ax2 = nexttile; hold on; for i = 1:length(strut_nums) plot(f, 180/pi*angle(iff_frf(:, i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file none exportFig('figs/test_struts_comp_iff_plants.pdf', 'width', 'half', 'height', 'tall'); #+end_src #+name: fig:test_struts_comp_plants #+caption: Comparison of the measured plants #+attr_latex: :options [htbp] #+begin_figure #+attr_latex: :caption \subcaption{\label{fig:test_struts_comp_interf_plants}$u$ to $d_a$} #+attr_latex: :options {0.49\textwidth} #+begin_subfigure #+attr_latex: :width \linewidth [[file:figs/test_struts_comp_interf_plants.png]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_comp_iff_plants}$u$ to $V_s$} #+attr_latex: :options {0.49\textwidth} #+begin_subfigure #+attr_latex: :width \linewidth [[file:figs/test_struts_comp_iff_plants.png]] #+end_subfigure #+end_figure There is a very large variability of the dynamics as measured by the encoder as shown in Figure ref:fig:test_struts_comp_enc_plants. Even-though the same peaks are seen for all of the struts (95Hz, 200Hz, 300Hz, 400Hz), the amplitude of the peaks are not the same. Moreover, the location or even the presence of complex conjugate zeros is changing from one strut to the other. All of this will be studied in Section ref:sec:test_struts_simscape using the Simscape model. #+begin_src matlab :exports none %% Bode plot of the FRF from u to de figure; tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(strut_nums) plot(f, abs(enc_frf(:, i)), ... 'DisplayName', sprintf('Leg %i', strut_nums(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 2); ylim([1e-8, 1e-3]); ax2 = nexttile; hold on; for i = 1:length(strut_nums) plot(f, 180/pi*angle(enc_frf(:, i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/test_struts_comp_enc_plants.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:test_struts_comp_enc_plants #+caption: Estimated frequency response functions from $u$ to the encoder $d_e$ for all the mounted struts #+RESULTS: [[file:figs/test_struts_comp_enc_plants.png]] ** Conclusion :ignore: #+begin_important All the struts are giving very consistent behavior from the excitation voltage $u$ to the force sensor generated voltage $V_s$ and to the interferometer measured displacement $d_a$. However, the dynamics from $u$ to the encoder measurement $d_e$ is much more complex and variable from one strut to the other most likely due to poor alignment of the APA with respect to the flexible joints. #+end_important #+begin_src matlab :tangle no :exports none %% Save the estimated FRF for further analysis save('./matlab/mat/meas_struts_frf.mat', 'f', 'enc_frf', 'int_frf', 'iff_frf', 'strut_nums'); #+end_src #+begin_src matlab :eval no %% Save the estimated FRF for further analysis save('./mat/meas_struts_frf.mat', 'f', 'enc_frf', 'int_frf', 'iff_frf', 'strut_nums'); #+end_src * Strut Model :PROPERTIES: :header-args:matlab+: :tangle matlab/test_struts_3_simscape_model.m :END: <> ** Introduction :ignore: However, now the full strut is put instead of only the APA (see Figure ref:fig:test_struts_simscape_model). #+name: fig:test_struts_simscape_model #+caption: Screenshot of the Simscape model of the strut fixed to the bench #+attr_latex: :width 0.5\linewidth [[file:figs/test_struts_simscape_model.png]] This Simscape model is used to: - compare the measured FRF with the modelled FRF - help the correct understanding/interpretation of the results - tune the model of the struts (APA, flexible joints, encoder) This study is structured as follow: - Section ref:ssec:test_struts_comp_model: the measured FRF are compared with the Simscape model. - Section ref:ssec:test_struts_effect_misalignment: the flexible APA model is used, and the effect of a misalignment of the APA and flexible joints is studied. It is found that the misalignment has a large impact on the dynamics from $u$ to $d_e$. - Section ref:ssec:test_struts_effect_joint_stiffness: the effect of the flexible joint's stiffness on the dynamics is studied. It is found that the axial stiffness of the joints has a large impact on the location of the zeros on the transfer function from $V_s$ to $d_e$. ** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> #+end_src #+begin_src matlab :exports none :results silent :noweb yes <> #+end_src #+begin_src matlab :tangle no :noweb yes <> #+end_src #+begin_src matlab :eval no :noweb yes <> #+end_src #+begin_src matlab :tangle no :noweb yes <> #+end_src #+begin_src matlab :eval no :noweb yes <> #+end_src #+begin_src matlab :noweb yes <> #+end_src #+begin_src matlab :exports none %% Input/Output definition of the Model clear io; io_i = 1; io(io_i) = linio([mdl, '/u'], 1, 'openinput'); io_i = io_i + 1; % DAC Voltage io(io_i) = linio([mdl, '/Vs'], 1, 'openoutput'); io_i = io_i + 1; % Sensor Voltage io(io_i) = linio([mdl, '/de'], 1, 'openoutput'); io_i = io_i + 1; % Encoder io(io_i) = linio([mdl, '/da'], 1, 'openoutput'); io_i = io_i + 1; % Interferometer #+end_src #+begin_src matlab %% Frequency vector [Hz] freqs = logspace(1, log10(2000), 1000); #+end_src ** Model dynamics <> #+begin_src matlab %% Load measured FRF for comparison load('meas_struts_frf.mat', 'f', 'enc_frf', 'int_frf', 'iff_frf', 'strut_nums'); %% Initialize strut with 2DoF model for the APA300ML and identify the dynamics n_hexapod = struct(); n_hexapod.flex_bot = initializeBotFlexibleJoint('type', '4dof'); n_hexapod.flex_top = initializeTopFlexibleJoint('type', '4dof'); n_hexapod.actuator = initializeAPA('type', '2dof'); c_granite = 0; % Do not take into account damping added by the air bearing % Run the linearization Gs_2dof = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts); Gs_2dof.InputName = {'u'}; Gs_2dof.OutputName = {'Vs', 'de', 'da'}; %% Initialize strut with "flexible" model for the APA300ML and identify the dynamics n_hexapod = struct(); n_hexapod.flex_bot = initializeBotFlexibleJoint('type', '4dof'); n_hexapod.flex_top = initializeTopFlexibleJoint('type', '4dof'); n_hexapod.actuator = initializeAPA('type', 'flexible'); c_granite = 100; % Do not take into account damping added by the air bearing % Run the linearization Gs_flex = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts); Gs_flex.InputName = {'u'}; Gs_flex.OutputName = {'Vs', 'de', 'da'}; #+end_src Two models of the APA300ML are used here for comparison: - a simple two degrees of freedom model - a model using a super element extracted from a finite element model These two models of the APA300ML were tuned to best match measured frequency response functions of the APA alone. The flexible joints are here modelled with the 4DoF model (axial stiffness, two bending stiffnesses and one torsion stiffness). These two models are compared with the measured frequency responses in Figure ref:fig:test_struts_comp_frf_flexible_model. The model dynamics from DAC voltage $u$ to the axial motion of the strut $d_a$ (Figure ref:fig:test_struts_comp_frf_flexible_model_int) and from DAC voltage $u$ to the force sensor voltage $V_s$ (Figure ref:fig:test_struts_comp_frf_flexible_model_iff) are well matching the experimental identification. However, the transfer function from $u$ to encoder displacement $d_e$ are not well matching for both models. For the 2DoF model, this is normal as the resonances affecting the dynamics are not modelled at all (the APA300ML is modelled as infinitely rigid in all directions except the translation along it's actuation axis). For the flexible model, it will be shown in the next section that by adding some misalignment betwen the flexible joints and the APA300ML, this model can better represent the observed dynamics. #+begin_src matlab :exports none %% Compare the FRF and identified dynamics from u to Vs and da figure; tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1a = nexttile([2,1]); hold on; plot(f, abs(int_frf(:, 1)), 'color', [0,0,0,0.2], ... 'DisplayName', 'FRF'); for i = 2:length(strut_nums) plot(f, abs(int_frf(:, i)), 'color', [0,0,0,0.2], ... 'HandleVisibility', 'off'); end plot(freqs, abs(squeeze(freqresp(Gs_2dof('da', 'u'), freqs, 'Hz'))), '-', ... 'color', colors(1,:), 'DisplayName', '2DoF Model') plot(freqs, abs(squeeze(freqresp(Gs_flex('da', 'u'), freqs, 'Hz'))), '-', ... 'color', colors(2,:), 'DisplayName', 'Flex. Model') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_a/u$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; ax2a = nexttile; hold on; for i = 1:length(strut_nums) plot(f, 180/pi*angle(int_frf(:, i)), 'color', [0,0,0,0.2]); end plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_2dof('da', 'u'), freqs, 'Hz'))), '-', 'color', colors(1,:)) plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_flex('da', 'u'), freqs, 'Hz'))), '-', 'color', colors(2,:)) hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1a,ax2a],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file none exportFig('figs/test_struts_comp_frf_flexible_model_int.pdf', 'width', 400, 'height', 'tall'); #+end_src #+begin_src matlab :exports none %% Compare the FRF and identified dynamics from u to Vs and da figure; tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1a = nexttile([2,1]); hold on; plot(f, abs(enc_frf(:, 1)), 'color', [0,0,0,0.2], ... 'DisplayName', 'FRF'); for i = 2:length(strut_nums) plot(f, abs(enc_frf(:, i)), 'color', [0,0,0,0.2], ... 'HandleVisibility', 'off'); end plot(freqs, abs(squeeze(freqresp(Gs_2dof('de', 'u'), freqs, 'Hz'))), '-', ... 'color', colors(1,:), 'DisplayName', '2DoF Model') plot(freqs, abs(squeeze(freqresp(Gs_flex('de', 'u'), freqs, 'Hz'))), '-', ... 'color', colors(2,:), 'DisplayName', 'Flex. Model') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; ax2a = nexttile; hold on; for i = 1:length(strut_nums) plot(f, 180/pi*angle(enc_frf(:, i)), 'color', [0,0,0,0.2]); end plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_2dof('de', 'u'), freqs, 'Hz'))), '-', 'color', colors(1,:)) plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_flex('de', 'u'), freqs, 'Hz'))), '-', 'color', colors(2,:)) hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1a,ax2a],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file none exportFig('figs/test_struts_comp_frf_flexible_model_enc.pdf', 'width', 400, 'height', 'tall'); #+end_src #+begin_src matlab :exports none %% Compare the FRF and identified dynamics from u to Vs and da figure; tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1a = nexttile([2,1]); hold on; plot(f, abs(iff_frf(:, i)), 'color', [0,0,0,0.2], ... 'DisplayName', 'FRF'); for i = 1:length(strut_nums) plot(f, abs(iff_frf(:, i)), 'color', [0,0,0,0.2], ... 'HandleVisibility', 'off'); end plot(freqs, abs(squeeze(freqresp(Gs_2dof('Vs', 'u'), freqs, 'Hz'))), '-', ... 'color', colors(1,:), 'DisplayName', '2DoF Model') plot(freqs, abs(squeeze(freqresp(Gs_flex('Vs', 'u'), freqs, 'Hz'))), '-', ... 'color', colors(2,:), 'DisplayName', 'Flex. Model') hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $V_s/u$ [V/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-2, 1e2]); leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; ax2a = nexttile; hold on; for i = 1:length(strut_nums) plot(f, 180/pi*angle(iff_frf(:, i)), 'color', [0,0,0,0.2]); end set(gca,'ColorOrderIndex',1); plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_2dof('Vs', 'u'), freqs, 'Hz'))), '-', 'color', colors(1,:)) plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_flex('Vs', 'u'), freqs, 'Hz'))), '-', 'color', colors(2,:)) hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1a,ax2a],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file none exportFig('figs/test_struts_comp_frf_flexible_model_iff.pdf', 'width', 400, 'height', 'tall'); #+end_src #+name: fig:test_struts_comp_frf_flexible_model #+caption: Comparison of the measured dynamics and of the Simscape dynamics using the "flexible" APA300ML model (Super-Element extracted from a Finite Element Model). #+attr_latex: :options [htbp] #+begin_figure #+attr_latex: :caption \subcaption{\label{fig:test_struts_comp_frf_flexible_model_int}$u$ to $d_a$} #+attr_latex: :options {0.33\textwidth} #+begin_subfigure #+attr_latex: :width 0.9\linewidth [[file:figs/test_struts_comp_frf_flexible_model_int.png]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_comp_frf_flexible_model_enc}$u$ to $d_e$} #+attr_latex: :options {0.33\textwidth} #+begin_subfigure #+attr_latex: :width 0.9\linewidth [[file:figs/test_struts_comp_frf_flexible_model_enc.png]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_comp_frf_flexible_model_iff}$u$ to $V_s$} #+attr_latex: :options {0.33\textwidth} #+begin_subfigure #+attr_latex: :width 0.9\linewidth [[file:figs/test_struts_comp_frf_flexible_model_iff.png]] #+end_subfigure #+end_figure ** Effect of strut misalignment <> As was shown in Figure ref:fig:test_struts_comp_enc_plants, the identified dynamics from DAC voltage $u$ to encoder measured displacement $d_e$ are very different from one strut to the other. In this section, it is investigated whether poor alignment of the strut (flexible joints with respect to the APA) can explain such dynamics. For instance, consider Figure ref:fig:test_struts_misalign_schematic where there is a misalignment in the $y$ direction between the two flexible joints (well aligned thanks to the mounting procedure in Section ref:sec:test_struts_mounting) and the APA300ML. In such case, the "x-bending" mode at 200Hz (see Figure ref:fig:test_struts_meas_x_bending) can be expected to be more excited, and thus the dynamics from the actuator to the encoder should be affected at frequencies around 200Hz. #+name: fig:test_struts_misalign_schematic #+caption: Mis-alignement between the joints and the APA #+attr_latex: :width 0.8\linewidth [[file:figs/test_struts_misalign_schematic.png]] To verify this assumption, the dynamics from output DAC voltage $u$ to the measured displacement by the encoder $d_e$ is computed using the Simscape model with flexible APA for several misalignment in the $y$ direction. Obtained dynamics are shown in Figure ref:fig:test_struts_effect_misalignment_y. The alignment of the APA with the flexible joints as a *huge* influence on the dynamics from actuator voltage to measured displacement by the encoder. The misalignment in the $y$ direction mostly influences: - the presence of the flexible mode at 200Hz (see mode shape in Figure ref:fig:test_struts_mode_shapes_1) - the location of the complex conjugate zero between the first two resonances: - if $d_y < 0$: there is no zero between the two resonances and possibly not even between the second and third ones - if $d_y > 0$: there is a complex conjugate zero between the first two resonances - the location of the high frequency complex conjugate zeros at 500Hz (secondary effect, as the axial stiffness of the joint also has large effect on the position of this zero) The same can be done for a misalignment in the $x$ direction. The obtained dynamics are shown in Figure ref:fig:test_struts_effect_misalignment_x where it is shown that misalignment in the $x$ direction mostly influences the presence of the flexible mode at 300Hz (see mode shape in Figure ref:fig:test_struts_mode_shapes_2). Comparing the experimental frequency response functions for all the APA in Figure ref:fig:test_struts_comp_enc_plants with the model dynamics for several $y$ misalignments in Figure ref:fig:test_struts_effect_misalignment_y indicates a clear similarity. This similarity suggests that the identified differences in dynamics are caused by the misalignment. #+begin_src matlab %% Effect of a misalignment in Y-Direction % Considered misalignment in the Y direction dy_aligns = [-0.5, -0.1, 0.1, 0.5]*1e-3; % [m] % Transfer functions from u to de for all the misalignment in y direction Gs_dy_align = {zeros(length(dy_aligns), 1)}; for i = 1:length(dy_aligns) n_hexapod.actuator = initializeAPA('type', 'flexible', 'd_align_bot', [0; dy_aligns(i); 0], 'd_align_top', [0; dy_aligns(i); 0]); G = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts); G.InputName = {'u'}; G.OutputName = {'Vs', 'de', 'da'}; Gs_dy_align(i) = {G}; end %% Effect of a misalignment in X-Direction % Considered misalignment in the X direction dx_aligns = [-0.1, -0.05, 0.05, 0.1]*1e-3; % [m] % Transfer functions from u to de for all the misalignment in x direction Gs_dx_align = {zeros(length(dx_aligns), 1)}; for i = 1:length(dx_aligns) n_hexapod.actuator = initializeAPA('type', 'flexible', 'd_align_bot', [dx_aligns(i); 0; 0], 'd_align_top', [dx_aligns(i); 0; 0]); G = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts); G.InputName = {'u'}; G.OutputName = {'Vs', 'de', 'da'}; Gs_dx_align(i) = {G}; end #+end_src #+begin_src matlab :exports none %% Transfer function from Vs to de - effect of x-misalignment figure; tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(dy_aligns) plot(freqs, abs(squeeze(freqresp(Gs_dy_align{i}('de', 'u'), freqs, 'Hz'))), ... 'DisplayName', sprintf('$d_y = %.1f$ [mm]', 1e3*dy_aligns(i))); end plot(freqs, abs(squeeze(freqresp(Gs_flex('de', 'u'), freqs, 'Hz'))), 'k-', ... 'DisplayName', 'aligned'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; ax2 = nexttile; hold on; for i = 1:length(dy_aligns) plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_dy_align{i}('de', 'u'), freqs, 'Hz')))); end plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_flex('de', 'u'), freqs, 'Hz'))), 'k-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file none exportFig('figs/test_struts_effect_misalignment_y.pdf', 'width', 'half', 'height', 'tall'); #+end_src #+begin_src matlab :exports none %% Transfer function from Vs to de - effect of x-misalignment figure; tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(dx_aligns) plot(freqs, abs(squeeze(freqresp(Gs_dx_align{i}('de', 'u'), freqs, 'Hz'))), ... 'DisplayName', sprintf('$d_x = %.1f$ [mm]', 1e3*dx_aligns(i))); end plot(freqs, abs(squeeze(freqresp(Gs_flex('de', 'u'), freqs, 'Hz'))), 'k-', ... 'DisplayName', 'aligned'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; ax2 = nexttile; hold on; for i = 1:length(dx_aligns) plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_dx_align{i}('de', 'u'), freqs, 'Hz')))); end plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_flex('de', 'u'), freqs, 'Hz'))), 'k-'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file none exportFig('figs/test_struts_effect_misalignment_x.pdf', 'width', 'half', 'height', 'tall'); #+end_src #+name: fig:test_struts_effect_misalignment #+caption: Effect of a misalignment between the flexible joints and the APA300ML in the $y$ direction (\subref{fig:test_struts_effect_misalignment_y}) and in the $x$ direction (\subref{fig:test_struts_effect_misalignment_x}) #+attr_latex: :options [htbp] #+begin_figure #+attr_latex: :caption \subcaption{\label{fig:test_struts_effect_misalignment_y}Misalignment along $y$} #+attr_latex: :options {0.49\textwidth} #+begin_subfigure #+attr_latex: :width 0.95\linewidth [[file:figs/test_struts_effect_misalignment_y.png]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_effect_misalignment_x}Misalignment along $x$} #+attr_latex: :options {0.49\textwidth} #+begin_subfigure #+attr_latex: :width 0.95\linewidth [[file:figs/test_struts_effect_misalignment_x.png]] #+end_subfigure #+end_figure ** Measured strut misalignment <> During the first mounting of the struts presented in Section ref:sec:test_struts_mounting, the positioning pins used to position the APA with respect to the flexible joints in the $y$ directions were not used (not received at the time). Therefore, large $y$ misalignments may be expected. In order to estimate the misalignments between the two flexible joints and the APA: - the struts are fixed horizontally to the mounting bench as shown in Figure ref:fig:test_struts_mounting_step_3 but without the encoder - using a length gauge[fn:2], the height difference from the flexible joints surface and the APA shell surface is measured both for the top and bottom joints and on both sides - as the thickness of the flexible joint is $21\,mm$ and the thickness of the APA shell is $20\,mm$, $0.5\,mm$ of height different should be measured is the two are perfectly aligned Large variations in the $y$ misalignment are found from one strut to the other (results are summarized in Table ref:tab:test_struts_meas_y_misalignment). To check the validity of the measurement, it can be verified that sum of the measured thickness difference on each side is $1\,mm$ (equal to the thickness difference between the flexible joint and the APA). This thickness differences for all the struts were found to be between $0.94\,mm$ and $1.00\,mm$ which indicate low errors as compared to the misalignments found in Table ref:tab:test_struts_meas_y_misalignment. #+begin_src matlab %% Measurement of the y misalignment between the APA and the flexible joints % Mesured struts strut_nums = [1, 2, 3, 4, 5]; % Measured height differences in [mm] % R ("red" side), B ("black" side) % R Top B Top R Bot B Bot strut_align = [[-0.40, -0.60, -0.16, -0.82] % Strut 1 [-0.67, -0.30, -0.34, -0.63] % Strut 2 [-0.07, -0.88, -0.16, -0.79] % Strut 3 [-0.48, -0.46, 0.07, -1.00] % Strut 4 [-0.33, -0.64, -0.48, -0.52]]; % Strut 5 % Verification that the thickness difference between the APA shell and the flexible joints is 1mm thichness_diff_top = strut_align(:,1) + strut_align(:,2); % [mm] thichness_diff_bot = strut_align(:,1) + strut_align(:,2); % [mm] % Estimation of the dy misalignment dy_bot = (strut_align(:,1) - strut_align(:,2))/2; % [mm] dy_top = (strut_align(:,3) - strut_align(:,4))/2; % [mm] #+end_src #+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) data2orgtable([dy_bot, dy_top] , {'1', '2', '3', '4', '5'}, {'*Strut*', '*Bot*', '*Top*'}, ' %.2f '); #+end_src #+name: tab:test_struts_meas_y_misalignment #+caption: Measured $y$ misalignment at the top and bottom of the APA. Measurements are in $mm$ #+attr_latex: :environment tabularx :width 0.25\linewidth :align ccc #+attr_latex: :center t :booktabs t #+RESULTS: | *Strut* | *Bot* | *Top* | |---------+-------+-------| | 1 | 0.1 | 0.33 | | 2 | -0.19 | 0.14 | | 3 | 0.41 | 0.32 | | 4 | -0.01 | 0.54 | | 5 | 0.15 | 0.02 | By using the measured $y$ misalignment in the Simscape model with the flexible APA model, the measured dynamics from $u$ to $d_e$ can be approached as shown in Figure ref:fig:test_struts_comp_dy_tuned_model_frf_enc. Even better match in the dynamics can be obtained by fine tuning both the $x$ and $y$ misalignments (yellow curves in Figure ref:fig:test_struts_comp_dy_tuned_model_frf_enc). This confirms that the misalignment between the APA and the strut axis (determined by the two flexible joints) is critical and is inducing large variations in the dynamics from DAC voltage $u$ to encoder measured displacement $d_e$. If encoders are to be used when fixed on the struts, it is therefore very important to properly align the APA and the flexible joints when mounting the struts. In the next section, the struts are re-assembled with a "positioning pin" to better align the APA with the flexible joints. With a better alignment, the amplitude of the spurious resonances are expected to decrease as was shown in Figure ref:fig:test_struts_effect_misalignment_y. #+begin_src matlab %% Idenfity the dynamics from u to de - misalignement estimated from measurement Gs_y_align = {zeros(size(strut_align,1), 1)}; % Measured dy alignment strut_align = 1e-3*[[-0.60, -0.82, -0.40, -0.16] [-0.30, -0.63, -0.67, -0.34] [-0.88, -0.79, -0.07, -0.16] [-0.48, 0.07, -0.46, -1.00] [-0.33, -0.48, -0.64, -0.52] [-0.34, -0.42, -0.63, -0.57]]; for i = 1:size(strut_align,1) n_hexapod.actuator = initializeAPA('type', 'flexible', ... 'd_align_bot', [0; strut_align(i, 2) - strut_align(i, 4); 0], ... 'd_align_top', [0; strut_align(i, 1) - strut_align(i, 3); 0]); G = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts); G.InputName = {'u'}; G.OutputName = {'Vs', 'de', 'da'}; Gs_y_align(i) = {G}; end %% Idenfity the dynamics from u to de - misalignement tuned to have the best match d_aligns = [[-0.05, -0.3, 0]; [ 0, 0.5, 0]; [-0.1, -0.3, 0]; [ 0, 0.3, 0]; [-0.05, 0.05, 0]]'*1e-3; % Idenfity the transfer function from actuator to encoder for all cases Gs_xy_align = {zeros(size(d_aligns,2), 1)}; for i = 1:5 n_hexapod.actuator = initializeAPA('type', 'flexible', 'd_align_top', d_aligns(:,i), 'd_align_bot', d_aligns(:,i)); G = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts); G.InputName = {'u'}; G.OutputName = {'Vs', 'de', 'da'}; Gs_xy_align(i) = {G}; end #+end_src #+begin_src matlab :exports none %% Comparison of the plants (encoder output) when tuning the misalignment figure; tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile(); hold on; plot(f, abs(enc_frf(:, 1)), 'DisplayName', 'Measurement'); plot(freqs, abs(squeeze(freqresp(Gs_y_align{1}('de', 'u'), freqs, 'Hz'))), ... 'DisplayName', '$d_y$ from meas'); plot(freqs, abs(squeeze(freqresp(Gs_xy_align{1}('de', 'u'), freqs, 'Hz'))), ... 'DisplayName', 'Tuned $d_x$, $d_y$'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); ylabel('Amplitude [m/V]'); leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; title('Strut 1'); xticks([1e1, 1e2, 1e3]); ax2 = nexttile(); hold on; plot(f, abs(enc_frf(:, 2)), 'DisplayName', 'Measurement'); plot(freqs, abs(squeeze(freqresp(Gs_y_align{2}('de', 'u'), freqs, 'Hz'))), ... 'DisplayName', '$d_y$ from meas'); plot(freqs, abs(squeeze(freqresp(Gs_xy_align{2}('de', 'u'), freqs, 'Hz'))), ... 'DisplayName', 'Tuned $d_x$, $d_y$'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]); leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; title('Strut 2'); xticks([1e1, 1e2, 1e3]); ax3 = nexttile(); hold on; plot(f, abs(enc_frf(:, 3)), 'DisplayName', 'Measuremnet'); plot(freqs, abs(squeeze(freqresp(Gs_y_align{3}('de', 'u'), freqs, 'Hz'))), ... 'DisplayName', '$d_y$ from meas'); plot(freqs, abs(squeeze(freqresp(Gs_xy_align{3}('de', 'u'), freqs, 'Hz'))), ... 'DisplayName', 'Tuned $d_x$, $d_y$'); hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]); leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; title('Strut 3'); xticks([1e1, 1e2, 1e3]); linkaxes([ax1,ax2,ax3],'xy'); xlim([10, 2e3]); ylim([1e-8, 1e-3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/test_struts_comp_dy_tuned_model_frf_enc.pdf', 'width', 'full', 'height', 'normal'); #+end_src #+name: fig:test_struts_comp_dy_tuned_model_frf_enc #+caption: Comparison of the frequency response functions from DAC voltage $u$ to measured displacement $d_e$ by the encoders for three struts. In blue the measured dynamics, in red the dynamics extracted from the model with the $y$ misalignment estimated from measurements, in yellow the dynamics extracted from the model when both the $x$ and $y$ misalignments are tuned #+RESULTS: [[file:figs/test_struts_comp_dy_tuned_model_frf_enc.png]] ** Proper struts alignment <> After the positioning pins had been received, the struts were mounted again with the positioning pins. This should make the APA better aligned with the two flexible joints. This alignment is then estimated using a length gauge as in the previous sections. Measured $y$ alignments are summarized in Table ref:tab:test_struts_meas_y_misalignment_with_pin and are found to be bellow $55\mu m$ for all the struts which is much better than better (see Table ref:tab:test_struts_meas_y_misalignment). #+begin_src matlab %% Measurement of the y misalignment between the APA and the flexible joints after strut better alignment % Numbers of the measured legs strut_align_nums = [1 2 3 4 5 6]; % Measured height differences in [mm] % R ("red" side), B ("black" side) % R Top B Top R Bot B Bot strut_align = [[-0.54, -0.50, -0.50, -0.52] % strut 1 [-0.44, -0.55, -0.49, -0.49] % strut 2 [-0.48, -0.50, -0.50, -0.46] % strut 3 [-0.45, -0.51, -0.51, -0.45] % strut 4 [-0.50, -0.50, -0.50, -0.50] % strut 5 [-0.50, -0.49, -0.43, -0.54]]; % strut 6 % Verification that the thickness difference between the APA shell and the flexible joints is 1mm thichness_diff_top = strut_align(:,1) + strut_align(:,2); % [mm] thichness_diff_bot = strut_align(:,1) + strut_align(:,2); % [mm] % Estimation of the dy misalignment dy_bot = (strut_align(:,1) - strut_align(:,2))/2; % [mm] dy_top = (strut_align(:,3) - strut_align(:,4))/2; % [mm] #+end_src #+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) data2orgtable([dy_bot, dy_top] , {'1', '2', '3', '4', '5', '6'}, {'*Strut*', '*Bot*', '*Top*'}, ' %.3f '); #+end_src #+name: tab:test_struts_meas_y_misalignment_with_pin #+caption: Measured $y$ misalignment at the top and bottom of the APA after realigning the struts using a positioning pin. Measurements are in $mm$. #+attr_latex: :environment tabularx :width 0.25\linewidth :align ccc #+attr_latex: :center t :booktabs t #+RESULTS: | *Strut* | *Bot* | *Top* | |---------+--------+-------| | 1 | -0.02 | 0.01 | | 2 | 0.055 | 0.0 | | 3 | 0.01 | -0.02 | | 4 | 0.03 | -0.03 | | 5 | 0.0 | 0.0 | | 6 | -0.005 | 0.055 | The dynamics of the re-aligned struts are then measured using the same test bench (Figure ref:fig:test_struts_bench_leg). The comparison of the initial strut dynamics and the dynamics of the re-aligned struts (i.e. with the positioning pin) is made in Figure ref:fig:test_struts_comp_enc_frf_realign. Even though the struts are now much better aligned, not much improvement can be observed. The dynamics of the six aligned struts are quite different from one another. Having the encoders fixed to the struts may prove to be difficult to use. Therefore, the encoders may be fixed to the nano-hexapod plates instead. #+begin_src matlab %% New dynamical identified with re-aligned struts % Load the identification data leg_noise = {}; for i = 1:length(strut_align_nums) leg_noise(i) = {load(sprintf('frf_struts_align_%i_noise.mat', strut_align_nums(i)), 'u', 'Vs', 'de')}; end % Parameters for Frequency Analysis 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 % Only used to have the frequency vector "f" [~, f] = tfestimate(leg_noise{1}.u, leg_noise{1}.de, win, Noverlap, Nfft, 1/Ts); % Transfer function from u to de (encoder) enc_frf_aligned = zeros(length(f), length(strut_align_nums)); for i = 1:length(strut_align_nums) enc_frf_aligned(:, i) = tfestimate(leg_noise{i}.u, leg_noise{i}.de, win, Noverlap, Nfft, 1/Ts); end #+end_src #+begin_src matlab :exports none %% Bode plot of the FRF from u to de figure; tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; plot(f, abs(enc_frf(:, 1)), 'color', [colors(1,:), 0.5], ... 'DisplayName', 'Initial alignment'); for i = 1:length(strut_nums) plot(f, abs(enc_frf(:, i)), 'color', [colors(1,:), 0.5], ... 'HandleVisibility', 'off'); end plot(f, abs(enc_frf_aligned(:, 1)), 'color', [colors(2,:), 0.5], ... 'DisplayName', 'With positioning pin'); for i = 1:length(strut_align_nums) plot(f, abs(enc_frf_aligned(:, i)), 'color', [colors(2,:), 0.5], ... 'HandleVisibility', 'off'); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); ylim([1e-8, 1e-3]); ax2 = nexttile; hold on; for i = 1:length(strut_nums) plot(f, 180/pi*angle(enc_frf(:, i)), 'color', [colors(1,:), 0.5]); end for i = 1:length(strut_align_nums) plot(f, 180/pi*angle(enc_frf_aligned(:, i)), 'color', [colors(2,:), 0.5]); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([10, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file replace exportFig('figs/test_struts_comp_enc_frf_realign.pdf', 'width', 'wide', 'height', 'tall'); #+end_src #+name: fig:test_struts_comp_enc_frf_realign #+caption: #+RESULTS: [[file:figs/test_struts_comp_enc_frf_realign.png]] ** Effect of the flexible joint <> As the struts are composed of one APA and two flexible joints, it is expected that the flexible joint characteristics will change the dynamic behavior of the struts. Using the Simscape model, the effect of the flexible joint's characteristics on the dynamics as measured on the test bench are studied. The studied dynamics is between $u$ and the encoder displacement $d_e$. Let's initialize an APA which is a little bit misaligned. #+begin_src matlab % APA Initialization n_hexapod.actuator = initializeAPA('type', 'flexible', 'd_align_bot', [0.1e-3; 0.5e-3; 0], 'd_align_top', [0.1e-3; 0.5e-3; 0]); %% Study the effect of the bending stiffness of the Flexible joints % Tested bending stiffnesses [Nm/rad] kRs = [3, 4, 5, 6, 7]; % Idenfity the transfer function from actuator to encoder for all bending stiffnesses Gs_kRs = {zeros(length(kRs), 1)}; for i = 1:length(kRs) n_hexapod.flex_bot = initializeBotFlexibleJoint(... 'type', '4dof', ... 'kRx', kRs(i), ... 'kRy', kRs(i)); n_hexapod.flex_top = initializeTopFlexibleJoint(... 'type', '4dof', ... 'kRx', kRs(i), ... 'kRy', kRs(i)); G = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts); G.InputName = {'u'}; G.OutputName = {'Vs', 'de', 'da'}; Gs_kRs(i) = {G}; end %% Study the effect of the axial stiffness of the Flexible joints % Tested axial stiffnesses [N/m] kzs = [5e7 7.5e7 1e8 2.5e8]; % Idenfity the transfer function from actuator to encoder for all bending stiffnesses Gs_kzs = {zeros(length(kzs), 1)}; for i = 1:length(kzs) n_hexapod.flex_bot = initializeBotFlexibleJoint(... 'type', '4dof', ... 'kz', kzs(i)); n_hexapod.flex_top = initializeTopFlexibleJoint(... 'type', '4dof', ... 'kz', kzs(i)); G = exp(-s*1e-4)*linearize(mdl, io, 0.0, opts); G.InputName = {'u'}; G.OutputName = {'Vs', 'de', 'da'}; Gs_kzs(i) = {G}; end #+end_src #+begin_src matlab :exports none %% Plot the obtained transfer functions for all the bending stiffnesses figure; tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(kRs) plot(freqs, abs(squeeze(freqresp(Gs_kRs{i}('de', 'u'), freqs, 'Hz'))), ... 'DisplayName', sprintf('$k_R = %.0f$ [Nm/rad]', kRs(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); ax2 = nexttile; hold on; for i = 1:length(kRs) plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_kRs{i}('de', 'u'), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([20, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file none exportFig('figs/test_struts_effect_flex_bending_stiffness_enc.pdf', 'width', 'half', 'height', 'tall'); #+end_src #+begin_src matlab :exports none %% Plot the obtained transfer functions for all the axial stiffnesses figure; tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None'); ax1 = nexttile([2,1]); hold on; for i = 1:length(kzs) plot(freqs, abs(squeeze(freqresp(Gs_kzs{i}('de', 'u'), freqs, 'Hz'))), ... 'DisplayName', sprintf('$k_z = %.1e$ [N/m]', kzs(i))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); ylabel('Amplitude $d_e/u$ [m/V]'); set(gca, 'XTickLabel',[]); hold off; ylim([1e-8, 1e-3]); legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); ax2 = nexttile; hold on; for i = 1:length(kzs) plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_kzs{i}('de', 'u'), freqs, 'Hz')))); end hold off; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin'); xlabel('Frequency [Hz]'); ylabel('Phase [deg]'); hold off; yticks(-360:90:360); ylim([-180, 180]); linkaxes([ax1,ax2],'x'); xlim([20, 2e3]); #+end_src #+begin_src matlab :tangle no :exports results :results file none exportFig('figs/test_struts_effect_flex_axial_stiffness_enc.pdf', 'width', 'half', 'height', 'tall'); #+end_src #+name: fig:test_struts_effect_flex_stiffness_enc #+caption: Effect of the flexible joints' bending (\subref{fig:test_struts_effect_flex_bending_stiffness_enc}) and axial (\subref{fig:test_struts_effect_flex_axial_stiffness_enc}) stiffnesses on the strut dynamics from $u$ to $d_e$ #+attr_latex: :options [htbp] #+begin_figure #+attr_latex: :caption \subcaption{\label{fig:test_struts_effect_flex_bending_stiffness_enc}Effect of bending stiffness} #+attr_latex: :options {0.49\textwidth} #+begin_subfigure #+attr_latex: :width 0.95\linewidth [[file:figs/test_struts_effect_flex_bending_stiffness_enc.png]] #+end_subfigure #+attr_latex: :caption \subcaption{\label{fig:test_struts_effect_flex_axial_stiffness_enc}Effect of axial stiffness} #+attr_latex: :options {0.49\textwidth} #+begin_subfigure #+attr_latex: :width 0.95\linewidth [[file:figs/test_struts_effect_flex_axial_stiffness_enc.png]] #+end_subfigure #+end_figure The bending stiffness of the joints has little impact on the transfer function from $u$ to $d_e$. The axial stiffness of the flexible joint has a large impact on the frequency of the complex conjugate zero. Using the measured FRF on the test-bench, if is therefore possible to estimate the axial stiffness of the flexible joints from the location of the zero. This method gives nice match between the measured FRF and the one extracted from the simscape model, however it could give not so accurate values of the joint's axial stiffness as other factors are also influencing the location of the zero. Using this method, an axial stiffness of $70 N/\mu m$ is found to give good results (and is reasonable based on the finite element models). ** Conclusion :ignore: * Conclusion <> * Bibliography :ignore: #+latex: \printbibliography[heading=bibintoc,title={Bibliography}] * Helping Functions :noexport: ** Initialize Path #+NAME: m-init-path #+BEGIN_SRC matlab %% Path for functions, data and scripts addpath('./matlab/mat/'); % Path for data addpath('./matlab/src/'); % Path for functions addpath('./matlab/'); % Path for scripts #+END_SRC #+NAME: m-init-path-tangle #+BEGIN_SRC matlab %% Path for functions, data and scripts addpath('./mat/'); % Path for data addpath('./src/'); % Path for functions #+END_SRC ** Initialize Simscape #+NAME: m-init-path-simscape #+BEGIN_SRC matlab addpath('./matlab/STEPS/'); % Path for Simscape Model %% Linearization options opts = linearizeOptions; opts.SampleTime = 0; %% Open Simscape Model mdl = 'test_struts_simscape'; % Name of the Simulink File open(mdl); % Open Simscape Model #+END_SRC #+NAME: m-init-path-simscape-tangle #+BEGIN_SRC matlab addpath('./STEPS/'); % Path for Simscape Model %% Linearization options opts = linearizeOptions; opts.SampleTime = 0; %% Open Simscape Model mdl = 'test_struts_simscape'; % Name of the Simulink File open(mdl); % Open Simscape Model #+END_SRC ** Initialize other elements #+NAME: m-init-other #+BEGIN_SRC matlab %% Colors for the figures colors = colororder; #+END_SRC ** =initializeBotFlexibleJoint= - Initialize Flexible Joint :PROPERTIES: :header-args:matlab: :tangle matlab/src/initializeBotFlexibleJoint.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: <> *** Function description :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab function [flex_bot] = initializeBotFlexibleJoint(args) % initializeBotFlexibleJoint - % % Syntax: [flex_bot] = initializeBotFlexibleJoint(args) % % Inputs: % - args - % % Outputs: % - flex_bot - #+end_src *** Optional Parameters :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab arguments args.type char {mustBeMember(args.type,{'2dof', '3dof', '4dof'})} = '2dof' args.kRx (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*5 args.kRy (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*5 args.kRz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*260 args.kz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*7e7 args.cRx (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001 args.cRy (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001 args.cRz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001 args.cz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001 end #+end_src *** Initialize the structure :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab flex_bot = struct(); #+end_src *** Set the Joint's type :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab switch args.type case '2dof' flex_bot.type = 1; case '3dof' flex_bot.type = 2; case '4dof' flex_bot.type = 3; end #+end_src *** Set parameters :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab flex_bot.kRx = args.kRx; flex_bot.kRy = args.kRy; flex_bot.kRz = args.kRz; flex_bot.kz = args.kz; #+end_src #+begin_src matlab flex_bot.cRx = args.cRx; flex_bot.cRy = args.cRy; flex_bot.cRz = args.cRz; flex_bot.cz = args.cz; #+end_src ** =initializeTopFlexibleJoint= - Initialize Flexible Joint :PROPERTIES: :header-args:matlab: :tangle matlab/src/initializeTopFlexibleJoint.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: <> *** Function description :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab function [flex_top] = initializeTopFlexibleJoint(args) % initializeTopFlexibleJoint - % % Syntax: [flex_top] = initializeTopFlexibleJoint(args) % % Inputs: % - args - % % Outputs: % - flex_top - #+end_src *** Optional Parameters :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab arguments args.type char {mustBeMember(args.type,{'2dof', '3dof', '4dof'})} = '2dof' args.kRx (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*5 args.kRy (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*5 args.kRz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*260 args.kz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*7e7 args.cRx (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001 args.cRy (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001 args.cRz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001 args.cz (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*0.001 end #+end_src *** Initialize the structure :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab flex_top = struct(); #+end_src *** Set the Joint's type :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab switch args.type case '2dof' flex_top.type = 1; case '3dof' flex_top.type = 2; case '4dof' flex_top.type = 3; end #+end_src *** Set parameters :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab flex_top.kRx = args.kRx; flex_top.kRy = args.kRy; flex_top.kRz = args.kRz; flex_top.kz = args.kz; #+end_src #+begin_src matlab flex_top.cRx = args.cRx; flex_top.cRy = args.cRy; flex_top.cRz = args.cRz; flex_top.cz = args.cz; #+end_src ** =initializeAPA= - Initialize APA :PROPERTIES: :header-args:matlab+: :tangle matlab/src/initializeAPA.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: <> *** Function description :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab function [actuator] = initializeAPA(args) % initializeAPA - % % Syntax: [actuator] = initializeAPA(args) % % Inputs: % - args - % % Outputs: % - actuator - #+end_src *** Optional Parameters :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab arguments args.type char {mustBeMember(args.type,{'2dof', 'flexible frame', 'flexible'})} = '2dof' % Actuator and Sensor constants args.Ga (1,1) double {mustBeNumeric} = 0 args.Gs (1,1) double {mustBeNumeric} = 0 % For 2DoF args.k (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*380000 args.ke (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*4952605 args.ka (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*2476302 args.c (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*20 args.ce (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*200 args.ca (6,1) double {mustBeNumeric, mustBePositive} = ones(6,1)*100 args.Leq (6,1) double {mustBeNumeric} = ones(6,1)*0.056 % Force Flexible APA args.xi (1,1) double {mustBeNumeric, mustBePositive} = 0.01 args.d_align_bot (3,1) double {mustBeNumeric} = zeros(3,1) % [m] args.d_align_top (3,1) double {mustBeNumeric} = zeros(3,1) % [m] % For Flexible Frame args.ks (1,1) double {mustBeNumeric, mustBePositive} = 235e6 args.cs (1,1) double {mustBeNumeric, mustBePositive} = 1e1 end #+end_src *** Initialize Structure :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab actuator = struct(); #+end_src *** Type :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab switch args.type case '2dof' actuator.type = 1; case 'flexible frame' actuator.type = 2; case 'flexible' actuator.type = 3; end #+end_src *** Actuator/Sensor Constants :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab if args.Ga == 0 switch args.type case '2dof' actuator.Ga = -2.5796; case 'flexible frame' actuator.Ga = 1; % TODO case 'flexible' actuator.Ga = 23.2; end else actuator.Ga = args.Ga; % Actuator gain [N/V] end #+end_src #+begin_src matlab if args.Gs == 0 switch args.type case '2dof' actuator.Gs = 466664; case 'flexible frame' actuator.Gs = 1; % TODO case 'flexible' actuator.Gs = -4898341; end else actuator.Gs = args.Gs; % Sensor gain [V/m] end #+end_src *** 2DoF parameters :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab actuator.k = args.k; % [N/m] actuator.ke = args.ke; % [N/m] actuator.ka = args.ka; % [N/m] actuator.c = args.c; % [N/(m/s)] actuator.ce = args.ce; % [N/(m/s)] actuator.ca = args.ca; % [N/(m/s)] actuator.Leq = args.Leq; % [m] #+end_src *** Flexible frame and fully flexible :PROPERTIES: :UNNUMBERED: t :END: #+begin_src matlab switch args.type case 'flexible frame' actuator.K = readmatrix('APA300ML_b_mat_K.CSV'); % Stiffness Matrix actuator.M = readmatrix('APA300ML_b_mat_M.CSV'); % Mass Matrix actuator.P = extractNodes('APA300ML_b_out_nodes_3D.txt'); % Node coordinates [m] case 'flexible' actuator.K = readmatrix('full_APA300ML_K.CSV'); % Stiffness Matrix actuator.M = readmatrix('full_APA300ML_M.CSV'); % Mass Matrix actuator.P = extractNodes('full_APA300ML_out_nodes_3D.txt'); % Node coordiantes [m] actuator.d_align_bot = args.d_align_bot; actuator.d_align_top = args.d_align_top; end actuator.xi = args.xi; % Damping ratio actuator.ks = args.ks; % Stiffness of one stack [N/m] actuator.cs = args.cs; % Damping of one stack [N/m] #+end_src * Footnotes [fn:2]Heidenhain MT25, specified accuracy of $\pm 0.5\,\mu m$ [fn:1]Faro Arm Platinum 4ft, specified accuracy of $\pm 13\mu m$