diff --git a/figs/inkscape/convert_svg.sh b/figs/inkscape/convert_svg.sh new file mode 100755 index 0000000..c9c1755 --- /dev/null +++ b/figs/inkscape/convert_svg.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Directory containing SVG files +INPUT_DIR="." + +# Loop through all SVG files in the directory +for svg_file in "$INPUT_DIR"/*.svg; do + # Check if there are SVG files in the directory + if [ -f "$svg_file" ]; then + # Output PDF file name + pdf_file="../${svg_file%.svg}.pdf" + png_file="../${svg_file%.svg}" + + # Convert SVG to PDF using Inkscape + inkscape "$svg_file" --export-filename="$pdf_file" && \ + pdftocairo -png -singlefile -cropbox "$pdf_file" "$png_file" + fi +done diff --git a/figs/inkscape/ustation_cad_view.svg b/figs/inkscape/ustation_cad_view.svg new file mode 100644 index 0000000..386b0f6 Binary files /dev/null and b/figs/inkscape/ustation_cad_view.svg differ diff --git a/figs/inkscape/ustation_combined_transformation.svg b/figs/inkscape/ustation_combined_transformation.svg new file mode 100644 index 0000000..ec742dd Binary files /dev/null and b/figs/inkscape/ustation_combined_transformation.svg differ diff --git a/figs/inkscape/ustation_compliance_meas.svg b/figs/inkscape/ustation_compliance_meas.svg new file mode 100644 index 0000000..6f0b268 Binary files /dev/null and b/figs/inkscape/ustation_compliance_meas.svg differ diff --git a/figs/inkscape/ustation_errors_ty_setup.svg b/figs/inkscape/ustation_errors_ty_setup.svg new file mode 100644 index 0000000..b3374ea Binary files /dev/null and b/figs/inkscape/ustation_errors_ty_setup.svg differ diff --git a/figs/inkscape/ustation_hexapod_stage.svg b/figs/inkscape/ustation_hexapod_stage.svg new file mode 100644 index 0000000..a641a4b Binary files /dev/null and b/figs/inkscape/ustation_hexapod_stage.svg differ diff --git a/figs/inkscape/ustation_rotation.svg b/figs/inkscape/ustation_rotation.svg new file mode 100644 index 0000000..c9971da Binary files /dev/null and b/figs/inkscape/ustation_rotation.svg differ diff --git a/figs/inkscape/ustation_ry_stage.svg b/figs/inkscape/ustation_ry_stage.svg new file mode 100644 index 0000000..598ad02 Binary files /dev/null and b/figs/inkscape/ustation_ry_stage.svg differ diff --git a/figs/inkscape/ustation_rz_stage.svg b/figs/inkscape/ustation_rz_stage.svg new file mode 100644 index 0000000..85c6309 Binary files /dev/null and b/figs/inkscape/ustation_rz_stage.svg differ diff --git a/figs/inkscape/ustation_simscape_stage_example.svg b/figs/inkscape/ustation_simscape_stage_example.svg new file mode 100644 index 0000000..94532b8 Binary files /dev/null and b/figs/inkscape/ustation_simscape_stage_example.svg differ diff --git a/figs/inkscape/ustation_stage_motion.svg b/figs/inkscape/ustation_stage_motion.svg new file mode 100644 index 0000000..2686219 Binary files /dev/null and b/figs/inkscape/ustation_stage_motion.svg differ diff --git a/figs/inkscape/ustation_transformation.svg b/figs/inkscape/ustation_transformation.svg new file mode 100644 index 0000000..59f68b3 Binary files /dev/null and b/figs/inkscape/ustation_transformation.svg differ diff --git a/figs/inkscape/ustation_translation.svg b/figs/inkscape/ustation_translation.svg new file mode 100644 index 0000000..f6f8dae Binary files /dev/null and b/figs/inkscape/ustation_translation.svg differ diff --git a/figs/inkscape/ustation_ty_stage.svg b/figs/inkscape/ustation_ty_stage.svg new file mode 100644 index 0000000..e22ee01 Binary files /dev/null and b/figs/inkscape/ustation_ty_stage.svg differ diff --git a/figs/ustation_cad_view.pdf b/figs/ustation_cad_view.pdf new file mode 100644 index 0000000..fc3d624 Binary files /dev/null and b/figs/ustation_cad_view.pdf differ diff --git a/figs/ustation_cad_view.png b/figs/ustation_cad_view.png new file mode 100644 index 0000000..9c17084 Binary files /dev/null and b/figs/ustation_cad_view.png differ diff --git a/figs/ustation_combined_transformation.pdf b/figs/ustation_combined_transformation.pdf new file mode 100644 index 0000000..4ef7d18 Binary files /dev/null and b/figs/ustation_combined_transformation.pdf differ diff --git a/figs/ustation_combined_transformation.png b/figs/ustation_combined_transformation.png new file mode 100644 index 0000000..7dc3900 Binary files /dev/null and b/figs/ustation_combined_transformation.png differ diff --git a/figs/ustation_comp_com_response_hexa_y.pdf b/figs/ustation_comp_com_response_hexa_y.pdf new file mode 100644 index 0000000..9c24fc9 Binary files /dev/null and b/figs/ustation_comp_com_response_hexa_y.pdf differ diff --git a/figs/ustation_comp_com_response_hexa_y.png b/figs/ustation_comp_com_response_hexa_y.png new file mode 100644 index 0000000..28cab6d Binary files /dev/null and b/figs/ustation_comp_com_response_hexa_y.png differ diff --git a/figs/ustation_comp_com_response_ry_z.pdf b/figs/ustation_comp_com_response_ry_z.pdf new file mode 100644 index 0000000..565bfa6 Binary files /dev/null and b/figs/ustation_comp_com_response_ry_z.pdf differ diff --git a/figs/ustation_comp_com_response_ry_z.png b/figs/ustation_comp_com_response_ry_z.png new file mode 100644 index 0000000..059e4a8 Binary files /dev/null and b/figs/ustation_comp_com_response_ry_z.png differ diff --git a/figs/ustation_comp_com_response_rz_x.pdf b/figs/ustation_comp_com_response_rz_x.pdf new file mode 100644 index 0000000..3f9620f Binary files /dev/null and b/figs/ustation_comp_com_response_rz_x.pdf differ diff --git a/figs/ustation_comp_com_response_rz_x.png b/figs/ustation_comp_com_response_rz_x.png new file mode 100644 index 0000000..b2b0926 Binary files /dev/null and b/figs/ustation_comp_com_response_rz_x.png differ diff --git a/figs/ustation_comp_com_response_rz_z.pdf b/figs/ustation_comp_com_response_rz_z.pdf new file mode 100644 index 0000000..ea552d6 Binary files /dev/null and b/figs/ustation_comp_com_response_rz_z.pdf differ diff --git a/figs/ustation_comp_com_response_rz_z.png b/figs/ustation_comp_com_response_rz_z.png new file mode 100644 index 0000000..38d6f63 Binary files /dev/null and b/figs/ustation_comp_com_response_rz_z.png differ diff --git a/figs/ustation_compliance_meas.pdf b/figs/ustation_compliance_meas.pdf new file mode 100644 index 0000000..c5f1e96 Binary files /dev/null and b/figs/ustation_compliance_meas.pdf differ diff --git a/figs/ustation_compliance_meas.png b/figs/ustation_compliance_meas.png new file mode 100644 index 0000000..7b8fe7f Binary files /dev/null and b/figs/ustation_compliance_meas.png differ diff --git a/figs/ustation_errors_dy_vertical.pdf b/figs/ustation_errors_dy_vertical.pdf new file mode 100644 index 0000000..1a526eb Binary files /dev/null and b/figs/ustation_errors_dy_vertical.pdf differ diff --git a/figs/ustation_errors_dy_vertical.png b/figs/ustation_errors_dy_vertical.png new file mode 100644 index 0000000..82e0f02 Binary files /dev/null and b/figs/ustation_errors_dy_vertical.png differ diff --git a/figs/ustation_errors_dy_vertical_remove_mean.pdf b/figs/ustation_errors_dy_vertical_remove_mean.pdf new file mode 100644 index 0000000..7f6700c Binary files /dev/null and b/figs/ustation_errors_dy_vertical_remove_mean.pdf differ diff --git a/figs/ustation_errors_dy_vertical_remove_mean.png b/figs/ustation_errors_dy_vertical_remove_mean.png new file mode 100644 index 0000000..eb7932f Binary files /dev/null and b/figs/ustation_errors_dy_vertical_remove_mean.png differ diff --git a/figs/ustation_errors_spindle_axial.pdf b/figs/ustation_errors_spindle_axial.pdf new file mode 100644 index 0000000..691fbe7 Binary files /dev/null and b/figs/ustation_errors_spindle_axial.pdf differ diff --git a/figs/ustation_errors_spindle_axial.png b/figs/ustation_errors_spindle_axial.png new file mode 100644 index 0000000..afb81e1 Binary files /dev/null and b/figs/ustation_errors_spindle_axial.png differ diff --git a/figs/ustation_errors_spindle_radial.pdf b/figs/ustation_errors_spindle_radial.pdf new file mode 100644 index 0000000..97a38f7 Binary files /dev/null and b/figs/ustation_errors_spindle_radial.pdf differ diff --git a/figs/ustation_errors_spindle_radial.png b/figs/ustation_errors_spindle_radial.png new file mode 100644 index 0000000..71f0580 Binary files /dev/null and b/figs/ustation_errors_spindle_radial.png differ diff --git a/figs/ustation_errors_spindle_tilt.pdf b/figs/ustation_errors_spindle_tilt.pdf new file mode 100644 index 0000000..4c5d85d Binary files /dev/null and b/figs/ustation_errors_spindle_tilt.pdf differ diff --git a/figs/ustation_errors_spindle_tilt.png b/figs/ustation_errors_spindle_tilt.png new file mode 100644 index 0000000..d7f8004 Binary files /dev/null and b/figs/ustation_errors_spindle_tilt.png differ diff --git a/figs/ustation_errors_ty_setup.pdf b/figs/ustation_errors_ty_setup.pdf new file mode 100644 index 0000000..f7a2d3c Binary files /dev/null and b/figs/ustation_errors_ty_setup.pdf differ diff --git a/figs/ustation_errors_ty_setup.png b/figs/ustation_errors_ty_setup.png new file mode 100644 index 0000000..e2ad268 Binary files /dev/null and b/figs/ustation_errors_ty_setup.png differ diff --git a/figs/ustation_frf_compliance_Rxyz.pdf b/figs/ustation_frf_compliance_Rxyz.pdf new file mode 100644 index 0000000..2f2356c Binary files /dev/null and b/figs/ustation_frf_compliance_Rxyz.pdf differ diff --git a/figs/ustation_frf_compliance_Rxyz.png b/figs/ustation_frf_compliance_Rxyz.png new file mode 100644 index 0000000..58c4d17 Binary files /dev/null and b/figs/ustation_frf_compliance_Rxyz.png differ diff --git a/figs/ustation_frf_compliance_Rxyz_model.pdf b/figs/ustation_frf_compliance_Rxyz_model.pdf new file mode 100644 index 0000000..61e4fc2 Binary files /dev/null and b/figs/ustation_frf_compliance_Rxyz_model.pdf differ diff --git a/figs/ustation_frf_compliance_Rxyz_model.png b/figs/ustation_frf_compliance_Rxyz_model.png new file mode 100644 index 0000000..5db9e4a Binary files /dev/null and b/figs/ustation_frf_compliance_Rxyz_model.png differ diff --git a/figs/ustation_frf_compliance_xyz.pdf b/figs/ustation_frf_compliance_xyz.pdf new file mode 100644 index 0000000..7a1c12c Binary files /dev/null and b/figs/ustation_frf_compliance_xyz.pdf differ diff --git a/figs/ustation_frf_compliance_xyz.png b/figs/ustation_frf_compliance_xyz.png new file mode 100644 index 0000000..77c2013 Binary files /dev/null and b/figs/ustation_frf_compliance_xyz.png differ diff --git a/figs/ustation_frf_compliance_xyz_model.pdf b/figs/ustation_frf_compliance_xyz_model.pdf new file mode 100644 index 0000000..7f73a2f Binary files /dev/null and b/figs/ustation_frf_compliance_xyz_model.pdf differ diff --git a/figs/ustation_frf_compliance_xyz_model.png b/figs/ustation_frf_compliance_xyz_model.png new file mode 100644 index 0000000..546e85a Binary files /dev/null and b/figs/ustation_frf_compliance_xyz_model.png differ diff --git a/figs/ustation_hexapod_stage.pdf b/figs/ustation_hexapod_stage.pdf new file mode 100644 index 0000000..93bdf4f Binary files /dev/null and b/figs/ustation_hexapod_stage.pdf differ diff --git a/figs/ustation_hexapod_stage.png b/figs/ustation_hexapod_stage.png new file mode 100644 index 0000000..7f23fd4 Binary files /dev/null and b/figs/ustation_hexapod_stage.png differ diff --git a/figs/ustation_model_sensitivity_ground_motion.pdf b/figs/ustation_model_sensitivity_ground_motion.pdf new file mode 100644 index 0000000..e3768ec Binary files /dev/null and b/figs/ustation_model_sensitivity_ground_motion.pdf differ diff --git a/figs/ustation_model_sensitivity_ground_motion.png b/figs/ustation_model_sensitivity_ground_motion.png new file mode 100644 index 0000000..9f7f942 Binary files /dev/null and b/figs/ustation_model_sensitivity_ground_motion.png differ diff --git a/figs/ustation_model_sensitivity_rz.pdf b/figs/ustation_model_sensitivity_rz.pdf new file mode 100644 index 0000000..5e89c4a Binary files /dev/null and b/figs/ustation_model_sensitivity_rz.pdf differ diff --git a/figs/ustation_model_sensitivity_rz.png b/figs/ustation_model_sensitivity_rz.png new file mode 100644 index 0000000..ddc6f16 Binary files /dev/null and b/figs/ustation_model_sensitivity_rz.png differ diff --git a/figs/ustation_model_sensitivity_ty.pdf b/figs/ustation_model_sensitivity_ty.pdf new file mode 100644 index 0000000..f91e64b Binary files /dev/null and b/figs/ustation_model_sensitivity_ty.pdf differ diff --git a/figs/ustation_model_sensitivity_ty.png b/figs/ustation_model_sensitivity_ty.png new file mode 100644 index 0000000..3d1b431 Binary files /dev/null and b/figs/ustation_model_sensitivity_ty.png differ diff --git a/figs/ustation_rotation.pdf b/figs/ustation_rotation.pdf new file mode 100644 index 0000000..c69f5d9 Binary files /dev/null and b/figs/ustation_rotation.pdf differ diff --git a/figs/ustation_rotation.png b/figs/ustation_rotation.png new file mode 100644 index 0000000..672abce Binary files /dev/null and b/figs/ustation_rotation.png differ diff --git a/figs/ustation_ry_stage.pdf b/figs/ustation_ry_stage.pdf new file mode 100644 index 0000000..7dd89af Binary files /dev/null and b/figs/ustation_ry_stage.pdf differ diff --git a/figs/ustation_ry_stage.png b/figs/ustation_ry_stage.png new file mode 100644 index 0000000..703ff73 Binary files /dev/null and b/figs/ustation_ry_stage.png differ diff --git a/figs/ustation_rz_meas_lion.jpg b/figs/ustation_rz_meas_lion.jpg new file mode 100644 index 0000000..480a356 Binary files /dev/null and b/figs/ustation_rz_meas_lion.jpg differ diff --git a/figs/ustation_rz_meas_lion_zoom.jpg b/figs/ustation_rz_meas_lion_zoom.jpg new file mode 100644 index 0000000..5523fcb Binary files /dev/null and b/figs/ustation_rz_meas_lion_zoom.jpg differ diff --git a/figs/ustation_rz_stage.pdf b/figs/ustation_rz_stage.pdf new file mode 100644 index 0000000..b3dc6f4 Binary files /dev/null and b/figs/ustation_rz_stage.pdf differ diff --git a/figs/ustation_rz_stage.png b/figs/ustation_rz_stage.png new file mode 100644 index 0000000..b44eeb2 Binary files /dev/null and b/figs/ustation_rz_stage.png differ diff --git a/figs/ustation_simscape_stage_example.pdf b/figs/ustation_simscape_stage_example.pdf new file mode 100644 index 0000000..4b930b8 Binary files /dev/null and b/figs/ustation_simscape_stage_example.pdf differ diff --git a/figs/ustation_simscape_stage_example.png b/figs/ustation_simscape_stage_example.png new file mode 100644 index 0000000..9e6f755 Binary files /dev/null and b/figs/ustation_simscape_stage_example.png differ diff --git a/figs/ustation_stage_motion.pdf b/figs/ustation_stage_motion.pdf new file mode 100644 index 0000000..6693041 Binary files /dev/null and b/figs/ustation_stage_motion.pdf differ diff --git a/figs/ustation_stage_motion.png b/figs/ustation_stage_motion.png new file mode 100644 index 0000000..37f5f49 Binary files /dev/null and b/figs/ustation_stage_motion.png differ diff --git a/figs/ustation_transformation.pdf b/figs/ustation_transformation.pdf new file mode 100644 index 0000000..5cf3dd4 Binary files /dev/null and b/figs/ustation_transformation.pdf differ diff --git a/figs/ustation_transformation.png b/figs/ustation_transformation.png new file mode 100644 index 0000000..752c3cf Binary files /dev/null and b/figs/ustation_transformation.png differ diff --git a/figs/ustation_translation.pdf b/figs/ustation_translation.pdf new file mode 100644 index 0000000..d827a17 Binary files /dev/null and b/figs/ustation_translation.pdf differ diff --git a/figs/ustation_translation.png b/figs/ustation_translation.png new file mode 100644 index 0000000..bb48263 Binary files /dev/null and b/figs/ustation_translation.png differ diff --git a/figs/ustation_ty_stage.pdf b/figs/ustation_ty_stage.pdf new file mode 100644 index 0000000..5d880a7 Binary files /dev/null and b/figs/ustation_ty_stage.pdf differ diff --git a/figs/ustation_ty_stage.png b/figs/ustation_ty_stage.png new file mode 100644 index 0000000..5aad655 Binary files /dev/null and b/figs/ustation_ty_stage.png differ diff --git a/matlab/src/initializeDisturbances.m b/matlab/src/initializeDisturbances.m index d7b8214..3e7cbc1 100644 --- a/matlab/src/initializeDisturbances.m +++ b/matlab/src/initializeDisturbances.m @@ -19,6 +19,10 @@ args.Fty_x logical {mustBeNumericOrLogical} = true % Translation Stage - Z direction args.Fty_z logical {mustBeNumericOrLogical} = true + % Spindle - X direction + args.Frz_x logical {mustBeNumericOrLogical} = true + % Spindle - Y direction + args.Frz_y logical {mustBeNumericOrLogical} = true % Spindle - Z direction args.Frz_z logical {mustBeNumericOrLogical} = true end @@ -106,6 +110,38 @@ Fty_z = zeros(length(t), 1); end + % if args.Frz_x && args.enable + % phi = dist_f.psd_rz; + % C = zeros(N/2,1); + % for i = 1:N/2 + % C(i) = sqrt(phi(i)*df); + % end + % rng(131); + % theta = 2*pi*rand(N/2,1); % Generate random phase [rad] + % Cx = [0 ; C.*complex(cos(theta),sin(theta))]; + % Cx = [Cx; flipud(conj(Cx(2:end)))];; + % u = N/sqrt(2)*ifft(Cx); % Disturbance Force Rz z [N] + % Frz_x = u; + % else + Frz_x = zeros(length(t), 1); + % end + + % if args.Frz_y && args.enable + % phi = dist_f.psd_rz; + % C = zeros(N/2,1); + % for i = 1:N/2 + % C(i) = sqrt(phi(i)*df); + % end + % rng(131); + % theta = 2*pi*rand(N/2,1); % Generate random phase [rad] + % Cx = [0 ; C.*complex(cos(theta),sin(theta))]; + % Cx = [Cx; flipud(conj(Cx(2:end)))];; + % u = N/sqrt(2)*ifft(Cx); % Disturbance Force Rz z [N] + % Frz_z = u; + % else + Frz_y = zeros(length(t), 1); + % end + if args.Frz_z && args.enable phi = dist_f.psd_rz; C = zeros(N/2,1); @@ -134,14 +170,14 @@ if exist('./mat', 'dir') if exist('./mat/nass_disturbances.mat', 'file') - save('mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_z', 'Fd', 'Ts', 't', 'args', '-append'); + save('mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_x', 'Frz_y', 'Frz_z', 'Fd', 'Ts', 't', 'args', '-append'); else - save('mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_z', 'Fd', 'Ts', 't', 'args'); + save('mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_x', 'Frz_y', 'Frz_z', 'Fd', 'Ts', 't', 'args'); end elseif exist('./matlab', 'dir') if exist('./matlab/mat/nass_disturbances.mat', 'file') - save('matlab/mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_z', 'Fd', 'Ts', 't', 'args', '-append'); + save('matlab/mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_x', 'Frz_y', 'Frz_z', 'Fd', 'Ts', 't', 'args', '-append'); else - save('matlab/mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_z', 'Fd', 'Ts', 't', 'args'); + save('matlab/mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_x', 'Frz_y', 'Frz_z', 'Fd', 'Ts', 't', 'args'); end end diff --git a/matlab/subsystems/metrology_6dof.slx b/matlab/subsystems/metrology_6dof.slx index b60400d..602d778 100644 Binary files a/matlab/subsystems/metrology_6dof.slx and b/matlab/subsystems/metrology_6dof.slx differ diff --git a/matlab/subsystems/micro_hexapod_strut_rigid.slx b/matlab/subsystems/micro_hexapod_strut_rigid.slx index 162fccd..aecf0e6 100644 Binary files a/matlab/subsystems/micro_hexapod_strut_rigid.slx and b/matlab/subsystems/micro_hexapod_strut_rigid.slx differ diff --git a/matlab/ustation_simscape.slx b/matlab/ustation_simscape.slx index 78d4b80..bbabff0 100644 Binary files a/matlab/ustation_simscape.slx and b/matlab/ustation_simscape.slx differ diff --git a/simscape-micro-station.org b/simscape-micro-station.org index ecb8174..02bc89f 100644 --- a/simscape-micro-station.org +++ b/simscape-micro-station.org @@ -178,35 +178,108 @@ CLOSED: [2024-10-31 Thu 10:36] SCHEDULED: <2024-10-31 Thu> Z: 50N/um From the geometry, compute the strut stiffness: should be 10N/um (currently configured at 20N/um) -** TODO [#A] Import all relevant report to this file +** DONE [#A] Import all relevant report to this file +CLOSED: [2024-11-05 Tue 22:56] Based on: - [X] [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-simscape/org/kinematics.org][kinematics]]: compute sample's motion from each stage motion - [X] [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-simscape/org/simscape_subsystems.org][simscape_subsystems]]: general presentation of the micro-station. Used model: solid body + joints. Presentation of each stage. - [X] [[file:~/Cloud/work-projects/ID31-NASS/documents/work-package-1/work-package-1.org::*Specification of requirements][Specification of requirements]] - [X] [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-simscape/org/identification.org][identification]]: comparison of measurements and simscape model (not so good?) -- [ ] file:/home/thomas/Cloud/meetings/esrf-meetings/2018-04-24-Simscape-Model/2018-04-24-Simscape-Model.pdf -- [ ] [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-simscape/org/experiments.org][experiments]]: simulation of experiments with the Simscape model -- [ ] Disturbances: Similar to what was done for the uniaxial model (the same?) - - [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-simscape/org/disturbances.org::+TITLE: Identification of the disturbances]] -- [ ] Measurement of disturbances / things that will have to be corrected using the NASS: - - [ ] [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-measurements/static-to-dynamic/index.org]] - - [ ] [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-measurements/disturbance-control-system/index.org]] - - [ ] [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-measurements/disturbance-sr-rz/index.org]] - - [ ] [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-measurements/ground-motion/index.org]] +- [X] file:/home/thomas/Cloud/meetings/esrf-meetings/2018-04-24-Simscape-Model/2018-04-24-Simscape-Model.pdf +- [X] [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-simscape/org/experiments.org][experiments]]: simulation of experiments with the Simscape model +- [X] Disturbances: Similar to what was done for the uniaxial model (the same?): [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-simscape/org/disturbances.org::+TITLE: Identification of the disturbances]] +- [-] Measurement of disturbances / things that will have to be corrected using the NASS: + - [X] [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-measurements/disturbance-control-system/index.org]] + - [X] [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-measurements/disturbance-sr-rz/index.org]] + Already discussed in the uniaxial report + - [X] [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-measurements/ground-motion/index.org]] + Already discussed in the uniaxial report - [ ] [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-measurements/static-spindle/index.org]] - - [ ] Check [[file:~/Cloud/work-projects/ID31-NASS/specifications/id-31-spindle-meas][this directory]] and [[file:~/Cloud/work-projects/ID31-NASS/specifications/stage-by-stage][this directory]] + Can be nice to have all errors of the Spindle (angular and linear) + - [ ] [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-measurements/static-to-dynamic/index.org]] + Similarly, errors of the translation stage are computed + - [X] Check [[file:~/Cloud/work-projects/ID31-NASS/specifications/id-31-spindle-meas][this directory]] + Nice pictures if necessary + - [X] Check [[file:~/Cloud/work-projects/ID31-NASS/specifications/stage-by-stage][this directory]] -** TODO [#B] Make good "init" for the Simscape model +** DONE [#B] Make good "init" for the Simscape model +CLOSED: [2024-11-05 Tue 22:57] In model properties => Callbacks => Init Fct There are some loading of .mat files. Is it the best option? -** TODO [#C] Check the effect of each stage on the compliance +** DONE [#C] Check the effect of each stage on the compliance +CLOSED: [2024-10-31 Thu 10:37] -- [ ] Put =rigid= mode one by one to see the effect +- [X] Put =rigid= mode one by one to see the effect + - Mode at 20Hz is Rx,Ry mode of the granite + - Mode at 60Hz in vertical is granite + Ty + - Main modes are due to micro-hexapod +** DONE [#C] Add two perturbations: =Frz_x= and =Frz_y= +CLOSED: [2024-11-05 Tue 21:44] +Maybe I can estimate them from the measurements that was made on the spindle? + +** DONE [#B] Verify Kinematics +CLOSED: [2024-11-05 Tue 08:55] + +- [ ] Move all stages +- [ ] From kinematics, estimate pose of micro-hexapod top platform +- [ ] Compare with 6DoF metrology + +** DONE [#C] Determine which Degree-Of-Freedom to keep and which to constrain +CLOSED: [2024-10-31 Thu 10:38] + +For instance, for now the granite can not rotate, but in reality, the modes may be linked to the granite's rotation. +By constraining more DoF, the simulation will be faster and the obtain state space will have a lower order. + +=> *All are 6dof* + +** DONE [#B] Compute eigenvalues of the model to see if we have similar frequencies than the modal analysis? +CLOSED: [2024-10-31 Thu 10:38] + +Yes, it is pretty good! + +** DONE [#B] Describe sample's position from all stage 6DoF motion +CLOSED: [2024-11-05 Tue 13:30] + +** CANC [#B] Maybe speak about Screw axis? +CLOSED: [2024-11-05 Tue 13:30] + +- State "CANC" from "TODO" [2024-11-05 Tue 13:30] +Can be computed from rotation matrix. +It seems it is used for the computation of the errors + +** DONE [#C] Rework disturbance measurements +CLOSED: [2024-11-05 Tue 21:44] + +Model vibrations induced by the scanning of stages. +Therefore, we don't model vibrations of the Ry stage or Micro-Hexapod. + +*The goal of this section is to make this =dist_psd.mat= file containing the description of all disturbances* + +- *Ground motion* already measured (similar in 3 directions?) +- *Spindle*: already measured but only in vertical direction + - [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-measurements/static-spindle/index.org]] + Here it is in the *PEL* laboratory, without the micro-station. + This is not too problematic. + - [X] Picture of the measurement setup + - [X] Plot measurement errors (X/Y, Z, Rx/Ry) + - [X] Extract PSD of disturbance forces (Probably X, Y and Z) +- *Ty stage*: new measurement + - [[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-measurements/static-to-dynamic/index.org]] + - [ ] Picture of the measurement setup + - [ ] Plot measurement + - [ ] Extract PSD of vertical disturbance force + +Say which disturbances are considered: +- Ground motions: x, y and z +- Ty: x and z +- Rz: z, x and y ? + +** TODO [#C] Add screenshot of Simscape model ** TODO [#C] Make a comparison of the measured vibrations of the micro-station with the vibrations of the simscape model of the micro-station Do we have a correlation? At least in the frequency domain? @@ -218,286 +291,25 @@ Procedure: - [ ] Compare with the measured vibrations -** TODO [#C] Add two perturbations: =Frz_x= and =Frz_y= -Maybe I can estimate them from the measurements that was made on the spindle? +** WAIT [#B] I have no measurement of horizontal ground motion :@marc: -** TODO [#C] Determine which Degree-Of-Freedom to keep and which to constrain +- Wait for Marc reply -For instance, for now the granite can not rotate, but in reality, the modes may be linked to the granite's rotation. -By constraining more DoF, the simulation will be faster and the obtain state space will have a lower order. +** TODO [#A] Update the disturbances PSD signals -** TODO [#B] Compute eigenvalues of the model to see if we have similar frequencies than the modal analysis? +[[*=initializeDisturbances=: Initialize Disturbances][=initializeDisturbances=: Initialize Disturbances]] -* Introduction :ignore: +- [ ] It is suppose in this script that all disturbances have the same frequency vectors, and therefore the same time vector... +- [ ] See how to deal with that +- [ ] Ground motion, X, Y and Z +- [ ] Ty stage, X and Z +- [ ] Rz stage, X, Y and Z + - Maybe say that we remove the excentricity (by circle fit: show it in the figure) + - Then the rest is modelled by stochastic disturbance -# #+name: tab:ustation_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: | =ustation_1_.m= | - - -* Micro-Station Kinematics -:PROPERTIES: -:HEADER-ARGS:matlab+: :tangle matlab/.m -:END: -<> -** Introduction :ignore: - -[[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-simscape/org/kinematics.org]] - -# - Small overview of each stage and associated stiffnesses / inertia -# - schematic that shows to considered DoF -# - import from CAD - -** Matlab Init :noexport:ignore: -#+begin_src matlab -%% .m -#+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 - -#+begin_src matlab :noweb yes -<> -#+end_src - -** Motion Stages -*** Translation Stage -*** Tilt Stage -*** Spindle -*** Micro-Hexapod -** Specification for each stage -<> - -Figure here: file:/home/thomas/Cloud/work-projects/ID31-NASS/documents/work-package-1/figures - -For each stage, after a quick presentation, the specifications (stroke, precision, ...) of the stage, the metrology used with that stage and the parasitic motions associated to it are given. - -*** Translation along Y -**** Presentation -This is the first stage, it is fixed directly on the granite. -In order to minimize the parasitic motions, two cylinders are used to guide the stage. -The motor used to drive the stage is one linear motor. -The 3D model of this translation stage is shown figure ref:fig:stage_translation. - -#+name: fig:stage_translation -#+caption: Translation stage -[[./figures/stages/stage_translation.pdf]] - -**** Specifications -#+attr_latex: :align |c|c|c|c|c| :placement [!htpb] -#+CAPTION: Specifications for the translation stage along Y -#+NAME: fig:spec-t-y -|--------+------------------------+--------------------------+--------------+--------------| -| Motion | Mode | Stroke | Repetability | MIM[fn:3] | -|--------+------------------------+--------------------------+--------------+--------------| -| $T_y$ | P[fn:1]/S[fn:2] | $\pm5 mm$ | $0.04 \mu m$ | $0.02 \mu m$ | -| | rotation stage along Y | ($\pm10 mm$ if possible) | | | -|--------+------------------------+--------------------------+--------------+--------------| - -**** Metrology -A linear digital encoder is used to measure the displacement of the translation stage along the y axis. - -**** Parasitic motions -#+attr_latex: :align |c|c|c| :placement [!htpb] -#+CAPTION: Parasitic motions for the translation stage along Y -#+NAME: fig:parasitic-motions-t-y -|--------------------+-----------------------+------------------------------| -| Axial Motion ($y$) | Radial Motion ($y-z$) | Rotation motion ($\theta-z$) | -|--------------------+-----------------------+------------------------------| -| $10nm$ | $20nm$ | $< 1.7 \mu rad$ | -|--------------------+-----------------------+------------------------------| - -*** Rotation around Y -**** Presentation -This stage is mainly use for the reflectivity experiment. This permit to make the sample rotates around the y axis. -The rotation axis should be parallel to the y-axis and cross the X-ray. - -As it is located below the Spindle, it make the axis of rotation of the spindle to also tilt with respect to the X-ray. - -4 joints are used in order to pre-stress the system. - -The model of the stage is shown figure ref:fig:stage_tilt. - -#+name: fig:stage_tilt -#+caption: Tilt Stage -[[./figures/stages/stage_tilt.pdf]] - -**** Specifications -#+attr_latex: :align |c|c|c|c|c| :placement [!htpb] -#+CAPTION: Specifications for the rotation stage along Y -#+NAME: fig:spec-r-y -|------------+------+----------------------+--------------+-------------| -| Motion | Mode | Stroke | Repetability | MIM | -|------------+------+----------------------+--------------+-------------| -| $\theta_y$ | S | $\pm51 mrad$ | $5 \mu rad$ | $2 \mu rad$ | -| | | Speed: $\pm 3^o/min$ | | | -|------------+------+----------------------+--------------+-------------| - -**** Metrology -Two linear digital encoders are used (one on each side). - -**** Parasitic motions -#+attr_latex: :align |c|c|c| :placement [!htpb] -#+CAPTION: Parasitic motions for the rotation stage along Y -#+NAME: fig:parasitic-motions-r-y -|-------------------+--------------------+---------------| -| Axial Error ($y$) | Radial Error ($z$) | Tilt error () | -|-------------------+--------------------+---------------| -| $0.5\mu m$ | $10nm$ | $1.5 \mu rad$ | -|-------------------+--------------------+---------------| - -*** Spindle -**** Presentation -The Spindle consist of one stator (attached to the tilt stage) and one rotor. - -The rotor is separated from the stator thanks to an air bearing. - -The spindle is represented figure ref:fig:stage_spindle. - -It has been developed by Lab-Leuven[fn:5]. - -#+name: fig:stage_spindle -#+caption: Spindle -[[./figures/stages/stage_spindle.pdf]] - -**** Specifications -#+attr_latex: :align |c|c|c|c|c| :placement [!htpb] -#+CAPTION: Specifications for the Spindle -#+NAME: fig:spec-r-y -|------------+------+----------------------+--------------+-------------| -| Motion | Mode | Stroke | Repetability | MIM | -|------------+------+----------------------+--------------+-------------| -| $\theta_z$ | S | $\pm51 mrad$ | $5 \mu rad$ | $2 \mu rad$ | -| | | Speed: $\pm 3^o/min$ | | | -|------------+------+----------------------+--------------+-------------| - -**** Metrology -There is an incremental rotation encoder. - -**** Parasitic motions -#+attr_latex: :align |c|c| :placement [!htpb] -#+CAPTION: Parasitic motions for the Spindle -#+NAME: fig:parasitic-motions-r-z -|------------------------+----------------------| -| Radial Error ($x$-$y$) | Vertical Error ($z$) | -|------------------------+----------------------| -| $0.33\mu m$ | $0.07\mu m$ | -|------------------------+----------------------| - -More complete measurements have been conducted at the PEL[fn:7]. - -*** Long Stroke Hexapod -**** Presentation -The long stroke hexapod consists of 6 legs, each composed of: -- one linear actuators -- one limit switch -- one absolute linear encoder -- one ball joint at each side, one is fixed on the fixed platform, the other on the mobile platform - -This long stroke hexapod has been developed by Symetrie[fn:4] and is shown figure ref:fig:stage_hexapod. - -#+name: fig:stage_hexapod -#+caption: Hexapod Symetrie -[[./figures/stages/stage_hexapod.pdf]] - -**** Specifications -#+attr_latex: :align |c|c|c|c|c| :placement [!htpb] -#+CAPTION: Specifications for the long stroke hexapod -#+NAME: fig:spec-hexa -|------------------+--------------+----------------+--------------+---------------| -| Motion | Stroke | Repetability | MIM | Stiffness | -|------------------+--------------+----------------+--------------+---------------| -| $T_{\mu_x}$ | $\pm10mm$ | $\pm1\mu m$ | $0.5\mu m$ | $>12N/\mu m$ | -| $T_{\mu_y}$ | $\pm10mm$ | $\pm1\mu m$ | $0.5\mu m$ | $>12N/\mu m$ | -| $T_{\mu_z}$ | $\pm10mm$ | $\pm1\mu m$ | $0.5\mu m$ | $>135N/\mu m$ | -| $\theta_{\mu_x}$ | $\pm3 deg$ | $\pm5 \mu rad$ | $2.5\mu rad$ | | -| $\theta_{\mu_y}$ | $\pm3 deg$ | $\pm5 \mu rad$ | $2.5\mu rad$ | | -| $\theta_{\mu_z}$ | $\pm0.5 deg$ | $\pm5 \mu rad$ | $2.5\mu rad$ | | -|------------------+--------------+----------------+--------------+---------------| - -**** Metrology -The metrology consist of one absolute linear encoder in each leg. - -**** Parasitic motions -#+attr_latex: :align |c|c|c| :placement [!htpb] -#+CAPTION: Parasitic motions for the Spindle -#+NAME: fig:parasitic-motions-r-z -|------------------+--------------+----------------| -| Movement | Resolution | Repeatability | -|------------------+--------------+----------------| -| $T_{\mu_x}$ | $0.5\mu m$ | $\pm 1\mu m$ | -| $T_{\mu_y}$ | $0.5\mu m$ | $\pm 1\mu m$ | -| $T_{\mu_z}$ | $0.1\mu m$ | $\pm 1\mu m$ | -| $\theta_{\mu_x}$ | $2.5\mu rad$ | $\pm 4\mu rad$ | -| $\theta_{\mu_y}$ | $2.5\mu rad$ | $\pm 4\mu rad$ | -|------------------+--------------+----------------| -*** Short Stroke Hexapod -**** Presentation -This last stage is located just below the sample to study. -This is the only stage that is not yet build nor designed. - -**** Specifications -#+attr_latex: :align |c|c|c|c|c| :placement [!htpb] -#+CAPTION: Specifications for the nano-stage -#+NAME: fig:spec-nano -|------------------+----------------+--------------+-------| -| Motion | Stroke | Repetability | MIM | -|------------------+----------------+--------------+-------| -| $T_{\nu_x}$ | $\pm10\mu m$ | $10nm$ | $3nm$ | -| $T_{\nu_y}$ | $\pm10\mu m$ | $10nm$ | $3nm$ | -| $T_{\nu_z}$ | $\pm10\mu m$ | $10nm$ | $3nm$ | -| $\theta_{\nu_x}$ | $\pm10\mu rad$ | $1.7\mu rad$ | | -| $\theta_{\nu_y}$ | $\pm10\mu rad$ | $1.7\mu rad$ | | -| $\theta_{\nu_z}$ | $\pm10\mu rad$ | | | -|------------------+----------------+--------------+-------| - -**** Dimensions -- Bottom plate : - - Inner diameter: $>150mm$ - - External diameter: $<305mm$ -- Top plate - - External diameter: $<300mm$ -- Height: $90mm$ -- Location of the rotation point: Centered, at $175mm$ above the top platform - -** Compute sample's motion from stage motion -*** Introduction :ignore: -#+begin_quote -Rx = [1 0 0; - 0 cos(t) -sin(t); - 0 sin(t) cos(t)]; - -Ry = [ cos(t) 0 sin(t); - 0 1 0; - -sin(t) 0 cos(t)]; - -Rz = [cos(t) -sin(t) 0; - sin(t) cos(t) 0; - 0 0 1]; -#+end_quote - +** Backup - Kinematics +*** Frames Let's define the following frames: - $\{W\}$ the frame that is *fixed to the granite* and its origin at the theoretical meeting point between the X-ray and the spindle axis. - $\{S\}$ the frame *attached to the sample* (in reality attached to the top platform of the nano-hexapod) with its origin at 175mm above the top platform of the nano-hexapod. @@ -507,131 +319,13 @@ Let's define the following frames: The origin of $T$ is $O_T$ and is the wanted position of the sample. Thus: -- the *measurement* of the position of the sample corresponds to ${}^W O_S = \begin{bmatrix} {}^WP_{x,m} & {}^WP_{y,m} & {}^WP_{z,m} \end{bmatrix}^T$ in translation and to $\theta_m {}^W\bm{s}_m = \theta_m \cdot \begin{bmatrix} {}^Ws_{x,m} & {}^Ws_{y,m} & {}^Ws_{z,m} \end{bmatrix}^T$ in rotations -- the *wanted position* of the sample expressed w.r.t. the granite is ${}^W O_T = \begin{bmatrix} {}^WP_{x,r} & {}^WP_{y,r} & {}^WP_{z,r} \end{bmatrix}^T$ in translation and to $\theta_r {}^W\bm{s}_r = \theta_r \cdot \begin{bmatrix} {}^Ws_{x,r} & {}^Ws_{y,r} & {}^Ws_{z,r} \end{bmatrix}^T$ in rotations - -*** Wanted Position of the Sample with respect to the Granite -Let's define the wanted position of each stage. -#+begin_src matlab - Ty = 0; % [m] - Ry = 3*pi/180; % [rad] - Rz = 180*pi/180; % [rad] - - % Hexapod (first consider only translations) - Thx = 0; % [m] - Thy = 0; % [m] - Thz = 0; % [m] -#+end_src - -Now, we compute the corresponding wanted translation and rotation of the sample with respect to the granite frame $\{W\}$. -This corresponds to ${}^WO_T$ and $\theta_m {}^Ws_m$. - -To do so, we have to define the homogeneous transformation for each stage. -#+begin_src matlab - % Translation Stage - Rty = [1 0 0 0; - 0 1 0 Ty; - 0 0 1 0; - 0 0 0 1]; - - % Tilt Stage - Pure rotating aligned with Ob - Rry = [ cos(Ry) 0 sin(Ry) 0; - 0 1 0 0; - -sin(Ry) 0 cos(Ry) 0; - 0 0 0 1]; - - % Spindle - Rotation along the Z axis - Rrz = [cos(Rz) -sin(Rz) 0 0 ; - sin(Rz) cos(Rz) 0 0 ; - 0 0 1 0 ; - 0 0 0 1 ]; - - % Micro-Hexapod (only rotations first) - Rh = [1 0 0 Thx ; - 0 1 0 Thy ; - 0 0 1 Thz ; - 0 0 0 1 ]; -#+end_src - -We combine the individual homogeneous transformations into one homogeneous transformation for all the station. -#+begin_src matlab - Ttot = Rty*Rry*Rrz*Rh; -#+end_src - -Using this homogeneous transformation, we can compute the wanted position and orientation of the sample with respect to the granite. - -Translation. -#+begin_src matlab - WOr = Ttot*[0;0;0;1]; - WOr = WOr(1:3); -#+end_src - -Rotation. -#+begin_src matlab - thetar = acos((trace(Ttot(1:3, 1:3))-1)/2) - if thetar == 0 - WSr = [0; 0; 0]; - else - [V, D] = eig(Ttot(1:3, 1:3)); - WSr = thetar*V(:, abs(diag(D) - 1) < eps(1)); - end -#+end_src - -#+begin_src matlab - WPr = [WOr ; WSr]; -#+end_src - -*** Measured Position of the Sample with respect to the Granite -The measurement of the position of the sample using the metrology system gives the position and orientation of the sample with respect to the granite. -#+begin_src matlab - % Measurements: Xm, Ym, Zm, Rx, Ry, Rz - Dxm = 0; % [m] - Dym = 0; % [m] - Dzm = 0; % [m] - - Rxm = 0*pi/180; % [rad] - Rym = 0*pi/180; % [rad] - Rzm = 180*pi/180; % [rad] -#+end_src - -Let's compute the corresponding orientation using screw axis. -#+begin_src matlab - Trxm = [1 0 0; - 0 cos(Rxm) -sin(Rxm); - 0 sin(Rxm) cos(Rxm)]; - Trym = [ cos(Rym) 0 sin(Rym); - 0 1 0; - -sin(Rym) 0 cos(Rym)]; - Trzm = [cos(Rzm) -sin(Rzm) 0; - sin(Rzm) cos(Rzm) 0; - 0 0 1]; - - STw = [[ Trym*Trxm*Trzm , [Dxm; Dym; Dzm]]; 0 0 0 1]; -#+end_src - -We then obtain the orientation measurement in the form of screw coordinate $\theta_m ({}^Ws_{x,m},\ {}^Ws_{y,m},\ {}^Ws_{z,m})^T$ where: -- $\theta_m = \cos^{-1} \frac{\text{Tr}(R) - 1}{2}$ -- ${}^W\bm{s}_m$ is the eigen vector of the rotation matrix $R$ corresponding to the eigen value $\lambda = 1$ - -#+begin_src matlab - thetam = acos((trace(STw(1:3, 1:3))-1)/2); % [rad] - if thetam == 0 - WSm = [0; 0; 0]; - else - [V, D] = eig(STw(1:3, 1:3)); - WSm = thetam*V(:, abs(diag(D) - 1) < eps(1)); - end -#+end_src - -#+begin_src matlab - WPm = [Dxm ; Dym ; Dzm ; WSm]; -#+end_src - +- the *measurement* of the position of the sample corresponds to ${}^W O_S = \begin{bmatrix} {}^WP_{x,m} & {}^WP_{y,m} & {}^WP_{z,m} \end{bmatrix}^T$ in translation and to $\theta_m {}^W\mathbf{s}_m = \theta_m \cdot \begin{bmatrix} {}^Ws_{x,m} & {}^Ws_{y,m} & {}^Ws_{z,m} \end{bmatrix}^T$ in rotations +- the *wanted position* of the sample expressed w.r.t. the granite is ${}^W O_T = \begin{bmatrix} {}^WP_{x,r} & {}^WP_{y,r} & {}^WP_{z,r} \end{bmatrix}^T$ in translation and to $\theta_r {}^W\mathbf{s}_r = \theta_r \cdot \begin{bmatrix} {}^Ws_{x,r} & {}^Ws_{y,r} & {}^Ws_{z,r} \end{bmatrix}^T$ in rotations *** Positioning Error with respect to the Granite The wanted position expressed with respect to the granite is ${}^WO_T$ and the measured position with respect to the granite is ${}^WO_S$, thus the *position error* expressed in $\{W\}$ is \[ {}^W E = {}^W O_T - {}^W O_S \] The same is true for rotations: -\[ \theta_\epsilon {}^W\bm{s}_\epsilon = \theta_r {}^W\bm{s}_r - \theta_m {}^W\bm{s}_m \] +\[ \theta_\epsilon {}^W\mathbf{s}_\epsilon = \theta_r {}^W\mathbf{s}_r - \theta_m {}^W\mathbf{s}_m \] #+begin_src matlab WPe = WPr - WPm; @@ -684,6 +378,7 @@ Rotation Error. #+begin_src matlab Etot = [SEm ; SEr] #+end_src + *** Another try Let's denote: - $\{W\}$ the initial fixed frame @@ -714,36 +409,475 @@ Orientation error: MTr(1:3, 1:3) #+end_src -*** Verification -How can we verify that the computation is correct? -Options: -- Test with simscape multi-body - - Impose motion on each stage - - Measure the position error w.r.t. the NASS - - Compare with the computation -* Stage Modeling + +*** Measured Position of the Sample with respect to the Granite +The measurement of the position of the sample using the metrology system gives the position and orientation of the sample with respect to the granite. +#+begin_src matlab + % Measurements: Xm, Ym, Zm, Rx, Ry, Rz + Dxm = 0; % [m] + Dym = 0; % [m] + Dzm = 0; % [m] + + Rxm = 0*pi/180; % [rad] + Rym = 0*pi/180; % [rad] + Rzm = 180*pi/180; % [rad] +#+end_src + +Let's compute the corresponding orientation using screw axis. +#+begin_src matlab + Trxm = [1 0 0; + 0 cos(Rxm) -sin(Rxm); + 0 sin(Rxm) cos(Rxm)]; + Trym = [ cos(Rym) 0 sin(Rym); + 0 1 0; + -sin(Rym) 0 cos(Rym)]; + Trzm = [cos(Rzm) -sin(Rzm) 0; + sin(Rzm) cos(Rzm) 0; + 0 0 1]; + + STw = [[ Trym*Trxm*Trzm , [Dxm; Dym; Dzm]]; 0 0 0 1]; +#+end_src + +We then obtain the orientation measurement in the form of screw coordinate $\theta_m ({}^Ws_{x,m},\ {}^Ws_{y,m},\ {}^Ws_{z,m})^T$ where: +- $\theta_m = \cos^{-1} \frac{\text{Tr}(R) - 1}{2}$ +- ${}^W\mathbf{s}_m$ is the eigen vector of the rotation matrix $R$ corresponding to the eigen value $\lambda = 1$ + +#+begin_src matlab + thetam = acos((trace(STw(1:3, 1:3))-1)/2); % [rad] + if thetam == 0 + WSm = [0; 0; 0]; + else + [V, D] = eig(STw(1:3, 1:3)); + WSm = thetam*V(:, abs(diag(D) - 1) < eps(1)); + end +#+end_src + +#+begin_src matlab + WPm = [Dxm ; Dym ; Dzm ; WSm]; +#+end_src + +*** Get resonance frequencies +#+begin_src matlab +%% Initialize simulation with default parameters (flexible elements) +initializeGround(); +initializeGranite(); +initializeTy(); +initializeRy(); +initializeRz(); +initializeMicroHexapod(); + +initializeReferences(); +initializeDisturbances(); +initializeSimscapeConfiguration(); +initializeLoggingConfiguration(); +#+end_src + +And we identify the dynamics from forces/torques applied on the micro-hexapod top platform to the motion of the micro-hexapod top platform at the same point. + +#+begin_src matlab +%% Identification of the compliance +% Input/Output definition +clear io; io_i = 1; +io(io_i) = linio([mdl, '/Micro-Station/Micro Hexapod/Flexible/Fm'], 1, 'openinput'); io_i = io_i + 1; % Direct Forces/Torques applied on the micro-hexapod top platform +io(io_i) = linio([mdl, '/Micro-Station/Micro Hexapod/Flexible/Dm'], 1, 'output'); io_i = io_i + 1; % Absolute displacement of the top platform + +% Run the linearization +Gm = linearize(mdl, io, 0); +Gm.InputName = {'Fmx', 'Fmy', 'Fmz', 'Mmx', 'Mmy', 'Mmz'}; +Gm.OutputName = {'Dx', 'Dy', 'Dz', 'Drx', 'Dry', 'Drz'}; +#+end_src + +#+begin_src matlab +modes_freq = imag(eig(Gm))/2/pi; +modes_freq = sort(modes_freq(modes_freq>0)); +#+end_src + +#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) +data2orgtable([modes_freq(1:16), [11.9, 18.6, 37.8, 39.1, 56.3, 69.8, 72.5, 84.8, 91.3, 105.5, 106.6, 112.7, 124.2, 145.3, 150.5, 165.4]'], {'1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16'}, {'Mode', 'Simscape', 'Modal analysis'}, ' %.1f '); +#+end_src + +#+RESULTS: +| Mode | Simscape | Modal analysis | +|------+----------+----------------| +| 1 | 11.7 | 11.9 | +| 2 | 21.3 | 18.6 | +| 3 | 26.1 | 37.8 | +| 4 | 57.5 | 39.1 | +| 5 | 60.6 | 56.3 | +| 6 | 73.0 | 69.8 | +| 7 | 97.9 | 72.5 | +| 8 | 120.2 | 84.8 | +| 9 | 126.2 | 91.3 | +| 10 | 142.4 | 105.5 | +| 11 | 155.9 | 106.6 | +| 12 | 178.5 | 112.7 | +| 13 | 179.3 | 124.2 | +| 14 | 182.6 | 145.3 | +| 15 | 223.6 | 150.5 | +| 16 | 226.4 | 165.4 | + +*** Noise Budget +<> + +- [ ] Compare the PSD of the Z relative motion of the sample due to all disturbances +- [ ] Is it relevant here as it should be more relevant when doing control / with the nano-hexapod, here we just want to make sure that we have a good model! + +From the obtained spectral density of the disturbance sources, we can compute the resulting relative motion of the Hexapod with respect to the granite using the model. + +This is equivalent as doing the inverse that was done in the previous section. +This is done in order to verify that this is coherent with the measurements. + +The power spectral density of the relative motion is computed below and the result is shown in Figure ref:fig:psd_effect_dist_verif. +We can see that this is exactly the same as the Figure ref:fig:dist_effect_relative_motion. +#+begin_src matlab +psd_gm_d = gm.psd_gm.*abs(squeeze(freqresp(G('Dz', 'Dw')/s, gm.f, 'Hz'))).^2; +psd_ty_d = tyz.psd_f.*abs(squeeze(freqresp(G('Dz', 'Fty')/s, tyz.f, 'Hz'))).^2; +psd_rz_d = rz.psd_f.*abs(squeeze(freqresp(G('Dz', 'Frz')/s, rz.f, 'Hz'))).^2; +#+end_src + +#+begin_src matlab :exports none +figure; +hold on; +plot(gm.f, sqrt(psd_gm_d), 'DisplayName', 'Ground Motion'); +plot(tyz.f, sqrt(psd_ty_d), 'DisplayName', 'Ty'); +plot(rz.f, sqrt(psd_rz_d), 'DisplayName', 'Rz'); +hold off; +set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log'); +xlabel('Frequency [Hz]'); ylabel('ASD of the relative motion $\left[\frac{m}{\sqrt{Hz}}\right]$') +legend('Location', 'southwest'); +xlim([2, 500]); +#+end_src + +*** Time Domain Disturbances +Let's initialize the time domain disturbances and load them. +#+begin_src matlab +initializeDisturbances(); +dist = load('nass_disturbances.mat'); +#+end_src + +The time domain disturbance signals are shown in Figure ref:fig:disturbances_time_domain. + +#+begin_src matlab :exports none +figure; + +ax1 = subplot(2, 2, 1); +hold on; +plot(dist.t, dist.Dwx, 'DisplayName', '$D_{w,x}$') +plot(dist.t, dist.Dwy, 'DisplayName', '$D_{w,y}$') +plot(dist.t, dist.Dwz, 'DisplayName', '$D_{w,z}$') +hold off; +xlabel('Time [s]'); +ylabel('Ground Motion [m]'); +legend(); + +ax2 = subplot(2, 2, 2); +hold on; +plot(dist.t, dist.Fty_x, 'DisplayName', '$F_{ty,x}$') +hold off; +xlabel('Time [s]'); +ylabel('Ty Forces [N]'); +legend(); + +ax3 = subplot(2, 2, 3); +hold on; +plot(dist.t, dist.Fty_z, 'DisplayName', '$F_{ty,z}$') +hold off; +xlabel('Time [s]'); +ylabel('Ty Forces [N]'); +legend(); + +ax4 = subplot(2, 2, 4); +hold on; +plot(dist.t, dist.Frz_z, 'DisplayName', '$F_{rz,z}$') +hold off; +xlabel('Time [s]'); +ylabel('Rz Forces [N]'); +legend(); + +linkaxes([ax1,ax2,ax3,ax4], 'x'); +xlim([0, dist.t(end)]); +#+end_src + +*** Time Domain Effect of Disturbances +**** Initialization of the Experiment +We initialize all the stages with the default parameters. +#+begin_src matlab + initializeGround(); + initializeGranite(); + initializeTy(); + initializeRy(); + initializeRz(); + initializeMicroHexapod(); + initializeAxisc(); + initializeMirror(); +#+end_src + +The nano-hexapod is a piezoelectric hexapod and the sample has a mass of 50kg. +#+begin_src matlab + initializeNanoHexapod('type', 'rigid'); + initializeSample('mass', 1); +#+end_src + +#+begin_src matlab + initializeReferences(); + initializeController('type', 'open-loop'); + initializeSimscapeConfiguration('gravity', false); + initializeLoggingConfiguration('log', 'all'); +#+end_src + +#+begin_src matlab + load('mat/conf_simulink.mat'); + set_param(conf_simulink, 'StopTime', '2'); +#+end_src + +**** Simulations + +No disturbances: +#+begin_src matlab + initializeDisturbances('enable', false); + sim('nass_model'); + sim_no = simout; +#+end_src + +Ground Motion: +#+begin_src matlab + initializeDisturbances('Fty_x', false, 'Fty_z', false, 'Frz_z', false); + sim('nass_model'); + sim_gm = simout; +#+end_src + +Translation Stage Vibrations: +#+begin_src matlab + initializeDisturbances('Dwx', false, 'Dwy', false, 'Dwz', false, 'Frz_z', false); + sim('nass_model'); + sim_ty = simout; +#+end_src + +Rotation Stage Vibrations: +#+begin_src matlab + initializeDisturbances('Dwx', false, 'Dwy', false, 'Dwz', false, 'Fty_x', false, 'Fty_z', false); + sim('nass_model'); + sim_rz = simout; +#+end_src + +**** Comparison +Let's now compare the effect of those perturbations on the position error of the sample (Figure ref:fig:effect_disturbances_position_error) + +#+begin_src matlab :exports none + figure; + ax1 = subplot(2, 3, 1); + hold on; + plot(sim_no.Em.En.Time, sim_no.Em.En.Data(:, 1)) + plot(sim_gm.Em.En.Time, sim_gm.Em.En.Data(:, 1)) + plot(sim_ty.Em.En.Time, sim_ty.Em.En.Data(:, 1)) + plot(sim_rz.Em.En.Time, sim_rz.Em.En.Data(:, 1)) + hold off; + xlabel('Time [s]'); + ylabel('Dx [m]'); + + ax2 = subplot(2, 3, 2); + hold on; + plot(sim_no.Em.En.Time, sim_no.Em.En.Data(:, 2)) + plot(sim_gm.Em.En.Time, sim_gm.Em.En.Data(:, 2)) + plot(sim_ty.Em.En.Time, sim_ty.Em.En.Data(:, 2)) + plot(sim_rz.Em.En.Time, sim_rz.Em.En.Data(:, 2)) + hold off; + xlabel('Time [s]'); + ylabel('Dy [m]'); + + ax3 = subplot(2, 3, 3); + hold on; + plot(sim_no.Em.En.Time, sim_no.Em.En.Data(:, 3)) + plot(sim_gm.Em.En.Time, sim_gm.Em.En.Data(:, 3)) + plot(sim_ty.Em.En.Time, sim_ty.Em.En.Data(:, 3)) + plot(sim_rz.Em.En.Time, sim_rz.Em.En.Data(:, 3)) + hold off; + xlabel('Time [s]'); + ylabel('Dz [m]'); + + ax4 = subplot(2, 3, 4); + hold on; + plot(sim_no.Em.En.Time, sim_no.Em.En.Data(:, 4)) + plot(sim_gm.Em.En.Time, sim_gm.Em.En.Data(:, 4)) + plot(sim_ty.Em.En.Time, sim_ty.Em.En.Data(:, 4)) + plot(sim_rz.Em.En.Time, sim_rz.Em.En.Data(:, 4)) + hold off; + xlabel('Time [s]'); + ylabel('Rx [rad]'); + + ax5 = subplot(2, 3, 5); + hold on; + plot(sim_no.Em.En.Time, sim_no.Em.En.Data(:, 5)) + plot(sim_gm.Em.En.Time, sim_gm.Em.En.Data(:, 5)) + plot(sim_ty.Em.En.Time, sim_ty.Em.En.Data(:, 5)) + plot(sim_rz.Em.En.Time, sim_rz.Em.En.Data(:, 5)) + hold off; + xlabel('Time [s]'); + ylabel('Ry [rad]'); + + ax6 = subplot(2, 3, 6); + hold on; + plot(sim_no.Em.En.Time, sim_no.Em.En.Data(:, 6), 'DisplayName', 'No') + plot(sim_gm.Em.En.Time, sim_gm.Em.En.Data(:, 6), 'DisplayName', 'Dw') + plot(sim_ty.Em.En.Time, sim_ty.Em.En.Data(:, 6), 'DisplayName', 'Ty') + plot(sim_rz.Em.En.Time, sim_rz.Em.En.Data(:, 6), 'DisplayName', 'Rz') + hold off; + xlabel('Time [s]'); + ylabel('Rz [rad]'); + legend(); + + linkaxes([ax1,ax2,ax3,ax4,ax5,ax6],'x'); +#+end_src + +#+header: :tangle no :exports results :results none :noweb yes +#+begin_src matlab :var filepath="figs/effect_disturbances_position_error.pdf" :var figsize="full-tall" :post pdf2svg(file=*this*, ext="png") +<> +#+end_src + +#+name: fig:effect_disturbances_position_error +#+caption: Effect of Perturbations on the position error ([[./figs/effect_disturbances_position_error.png][png]], [[./figs/effect_disturbances_position_error.pdf][pdf]]) +[[file:figs/effect_disturbances_position_error.png]] + + +*** Power Spectral Density of the effect of the disturbances + +#+begin_src matlab +figure; +hold on; +hold off; +set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log'); +xlabel('Frequency [Hz]'); ylabel('ASD $\left[\frac{\mu m}{\sqrt{Hz}}\right]$') +#+end_src + +#+begin_src matlab +figure; +hold on; +plot(f_rz, sqrt(pxx_rz_dx), 'DisplayName', '$D_x$') +plot(f_rz, sqrt(pxx_rz_dy), 'DisplayName', '$D_y$') +plot(f_rz, sqrt(pxx_rz_dz), 'DisplayName', '$D_z$') +plot(f_dy, sqrt(pxx_dy_dz)) +hold off; +set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log'); +xlabel('Frequency [Hz]'); ylabel('ASD $\left[\frac{m}{\sqrt{Hz}}\right]$') +xlim([1, 200]); +legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1); +#+end_src + +#+begin_src matlab :results none :exports results +figure; +hold on; +plot(f_rz(f_rz>1&f_rz<200), 1e9*sqrt(flip(-cumtrapz(flip(f_rz(f_rz>1&f_rz<200)),flip(pxx_rz_dx(f_rz>1&f_rz<200))))), 'DisplayName', 'Spindle - $D_x$'); +plot(f_rz(f_rz>1&f_rz<200), 1e9*sqrt(flip(-cumtrapz(flip(f_rz(f_rz>1&f_rz<200)),flip(pxx_rz_dy(f_rz>1&f_rz<200))))), 'DisplayName', 'Spindle - $D_y$'); +plot(f_rz(f_rz>1&f_rz<200), 1e9*sqrt(flip(-cumtrapz(flip(f_rz(f_rz>1&f_rz<200)),flip(pxx_rz_dz(f_rz>1&f_rz<200))))), 'DisplayName', 'Spindle - $D_z$'); +plot(f_dy(f_dy>1&f_dy<200), 1e9*sqrt(flip(-cumtrapz(flip(f_dy(f_dy>1&f_dy<200)),flip(pxx_dy_dz(f_dy>1&f_dy<200))))), 'DisplayName', 'Spindle - $D_z$'); +hold off; +set(gca, 'xscale', 'log'); +set(gca, 'yscale', 'log'); +xlabel('Frequency [Hz]'); ylabel('CAS [nm RMS]') +legend('Location', 'southwest'); +xlim([1, 200]); +#+end_src + + +#+begin_src matlab +gm = load('matlab/mat/dist/psd_gm.mat', 'f', 'psd_gm'); +rz = load('matlab/mat/dist/pxsp_r.mat', 'f', 'pxsp_r'); +tyz = load('matlab/mat/dist/pxz_ty_r.mat', 'f', 'pxz_ty_r'); +tyx = load('matlab/mat/dist/pxe_ty_r.mat', 'f', 'pxe_ty_r'); +#+end_src + +#+begin_src matlab :exports none +gm.f = gm.f(2:end); +rz.f = rz.f(2:end); +tyz.f = tyz.f(2:end); +tyx.f = tyx.f(2:end); + +gm.psd_gm = gm.psd_gm(2:end); % PSD of Ground Motion [m^2/Hz] +rz.pxsp_r = rz.pxsp_r(2:end); % PSD of Relative Velocity [(m/s)^2/Hz] +tyz.pxz_ty_r = tyz.pxz_ty_r(2:end); % PSD of Relative Velocity [(m/s)^2/Hz] +tyx.pxe_ty_r = tyx.pxe_ty_r(2:end); % PSD of Relative Velocity [(m/s)^2/Hz] +#+end_src + +Because some 50Hz and harmonics were present in the ground motion measurement, we remove these peaks with the following code: +#+begin_src matlab +f0s = [50, 100, 150, 200, 250, 350, 450]; +for f0 = f0s + i = find(gm.f > f0-0.5 & gm.f < f0+0.5); + gm.psd_gm(i) = linspace(gm.psd_gm(i(1)), gm.psd_gm(i(end)), length(i)); +end +#+end_src + +We now compute the relative velocity between the hexapod and the granite due to ground motion. +#+begin_src matlab +gm.psd_rv = gm.psd_gm.*abs(squeeze(freqresp(G('Dz', 'Dw'), gm.f, 'Hz'))).^2; +#+end_src + +#+begin_src matlab :exports none +figure; +hold on; +plot(gm.f, sqrt(gm.psd_rv), 'DisplayName', 'Ground Motion'); +plot(tyz.f, sqrt(tyz.pxz_ty_r), 'DisplayName', 'Ty'); +plot(rz.f, sqrt(rz.pxsp_r), 'DisplayName', 'Rz'); +hold off; +set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log'); +xlabel('Frequency [Hz]'); ylabel('ASD of the measured velocity $\left[\frac{m/s}{\sqrt{Hz}}\right]$') +legend('Location', 'southwest'); +xlim([2, 500]); +#+end_src + +* Introduction :ignore: + + +#+name: tab:ustation_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:ustation_kinematics | =ustation_1_kinematics.m= | +| Section ref:sec:ustation_modeling | =ustation_2_modeling.m= | +| Section ref:sec:ustation_disturbances | =ustation_3_disturbances.m= | +| Section ref:sec:ustation_experiments | =ustation_4_experiments.m= | + +* Micro-Station Kinematics :PROPERTIES: -:HEADER-ARGS:matlab+: :tangle matlab/.m +:HEADER-ARGS:matlab+: :tangle matlab/ustation_1_kinematics.m :END: <> ** Introduction :ignore: -The goal here is to tune the Simscape model of the station in order to have a good dynamical representation of the real system. +The micro-station consists of 4 stacked positioning stages (Figure ref:fig:ustation_cad_view). +From bottom to top, the stacked stages are the translation stage $D_y$, the tilt stage $R_y$, the rotation stage (Spindle) $R_z$ and the positioning hexapod. -In order to do so, we reproduce the Modal Analysis done on the station using the Simscape model. +Such stacked architecture allows high mobility, but the overall stiffness is reduced and the dynamics is very complex. complex dynamics. +The micro-station degrees-of-freedom are summarized in Table ref:tab:ustation_dof_summary. -We can then compare the measured Frequency Response Functions with the identified dynamics of the model. +#+name: fig:ustation_cad_view +#+caption: CAD view of the micro-station with the translation stage (in blue), the tilt stage (in red), the rotation stage (in yellow) and the positioning hexapod (in purple). On top of these four stages, a solid part (shown in green) will be replaced by the stabilization stage. +#+attr_latex: :width \linewidth +[[file:figs/ustation_cad_view.png]] -Finally, this should help to tune the parameters of the model such that the dynamics is closer to the measured FRF. +#+name: tab:ustation_dof_summary +#+caption: Summary of the micro-station degrees-of-freedom +#+attr_latex: :environment tabularx :width \linewidth :align lX +#+attr_latex: :center t :booktabs t +| *Stage* | *Degrees of Freedom* | +|-------------------+-------------------------------------------------------| +| Translation stage | $D_y = \pm 10\,mm$ | +| Tilt stage | $R_y = \pm 3\,\text{deg}$ | +| Spindle | $R_z = 360\,\text{deg}$ | +| Micro Hexapod | $D_{xyz} = \pm 10\,mm$, $R_{xyz} = \pm 3\,\text{deg}$ | -# Validation of the Model -# - Most important metric: support compliance -# - Compare model and measurement +There are different ways of modelling the stage dynamics in a multi-body model. +The one chosen in this work consists of modelling each stage by two solid bodies connected by one 6-DoF joint. +The stiffness and damping properties of the joint can be tuned separately for each DoF. + +The "controlled" DoF of each stage (for instance the $D_y$ direction for the translation stage) is modelled as infinitely rigid (i.e. its motion is imposed by a "setpoint") while the other DoFs have limited stiffness to model the different micro-station modes. ** Matlab Init :noexport:ignore: #+begin_src matlab -%% .m +%% ustation_1_kinematics.m #+end_src #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) @@ -770,25 +904,495 @@ Finally, this should help to tune the parameters of the model such that the dyna <> #+end_src -** Some notes about the Simscape Model +** Motion Stages +<> -The Simscape Model of the micro-station consists of several solid bodies: -- Bottom Granite -- Top Granite -- Translation Stage -- Tilt Stage -- Spindle -- Hexapod +**** Translation Stage -Each solid body has some characteristics: Center of Mass, mass, moment of inertia, etc... -These parameters are automatically computed from the geometry and from the density of the materials. +The translation stage is used to position and scan the sample laterally with respect to the X-ray beam. -Then, the solid bodies are connected with springs and dampers. -Some of the springs and dampers values can be estimated from the joints/stages specifications, however, we here prefer to tune these values based on the measurements. +A linear motor was first used to be able to perform fast and accurate scans. +It was later replaced with a stepper motor and lead-screw, as the feedback control used for the linear motor was unreliable, probably caused by rust of the linear guides along its stroke. +An optical linear encoder is used to measure the stage motion and for PID control of the position. + +Four cylindrical bearings[fn:4] are used to guide the motion (i.e. minimize the parasitic motions) and have high stiffness. + +#+name: fig:ustation_ty_stage +#+caption: Translation Stage +[[file:figs/ustation_ty_stage.png]] + +# | Axial Motion ($y$) | Radial Motion ($y-z$) | Rotation motion ($\theta-z$) | +# |--------------------+-----------------------+------------------------------| +# | $40nm$ repeat | $20nm$ | $< 1.7 \mu rad$ | + +**** Tilt Stage + +The tilt stage is guided by four linear motion guides[fn:1] which are placed such that the center of rotation coincide with the X-ray beam. +Each linear guide has high stiffness in radial directions such that the only DoF with low stiffness is in $R_y$. + +This stage is mainly used for /reflectivity/ experiments where the sample $R_y$ angle is scanned. +This stage can also be used to tilt the rotation axis of the Spindle. + +To precisely control the $R_y$ angle, a stepper motor as well as two optical encoders are used in a PID feedback loop. + +#+name: fig:ustation_ry_stage +#+caption: Tilt Stage +[[file:figs/ustation_ry_stage.png]] + +# | Axial Error ($y$) | Radial Error ($z$) | Tilt error ($R_y$) | +# |-------------------+--------------------+--------------------| +# | $0.5\mu m$ | $10nm$ | $5 \mu rad$ repeat | + +**** Spindle + +Then, a rotation stage is used for tomography experiments. +It is composed of an air bearing spindle[fn:2], whose angular position is controlled with a 3 phase synchronous motor based on the reading of 4 optical encoders. + +Additional rotary unions and slip-rings to be able to pass through the rotation many electrical signals and fluids and gazes. + +#+name: fig:ustation_rz_stage +#+caption: Rotation Stage (Spindle) +[[file:figs/ustation_rz_stage.png]] + +# | Radial Error ($x$-$y$) | Vertical Error ($z$) | Rz | +# |------------------------+----------------------+----------------------------| +# | $0.33\mu m$ | $0.07\mu m$ | $5\,\mu \text{rad}$ repeat | + +**** Micro-Hexapod + +Finally, a Stewart platform[fn:3] is used to position the sample. +It includes a DC motor and an optical linear encoders in each of the six strut. + +It is used to position the point of interest of the sample with respect to the spindle rotation axis. +It can also be used to precisely position the PoI vertically with respect to the x-ray. + +#+name: fig:ustation_hexapod_stage +#+caption: Micro Hexapod +[[file:figs/ustation_hexapod_stage.png]] + +# | Motion | Stroke | Repetability | MIM | Stiffness | +# |------------------+--------------+----------------+--------------+---------------| +# | $T_{\mu_x}$ | $\pm10mm$ | $\pm1\mu m$ | $0.5\mu m$ | $>12N/\mu m$ | +# | $T_{\mu_y}$ | $\pm10mm$ | $\pm1\mu m$ | $0.5\mu m$ | $>12N/\mu m$ | +# | $T_{\mu_z}$ | $\pm10mm$ | $\pm1\mu m$ | $0.5\mu m$ | $>135N/\mu m$ | +# | $\theta_{\mu_x}$ | $\pm3 deg$ | $\pm5 \mu rad$ | $2.5\mu rad$ | | +# | $\theta_{\mu_y}$ | $\pm3 deg$ | $\pm5 \mu rad$ | $2.5\mu rad$ | | +# | $\theta_{\mu_z}$ | $\pm0.5 deg$ | $\pm5 \mu rad$ | $2.5\mu rad$ | | + +** Mathematical description of a rigid body motion +<> +**** Introduction :ignore: + +The goal here is to introduce mathematical tools[fn:6] that are used to describe the motion of positioning stages and ultimately the sample. + +First, the tools to described the pose of a solid body (i.e. it's position and orientation) are introduced. +Then, the motion induced by a positioning stage is described using transformation matrices. +Finally, the motion of all stacked stages are combined, and the sample's motion is computed from each stage motion. + +**** Spatial motion representation + +The /pose/ of a solid body with respect to a specific frame can be described by six independent parameters. +Three parameters are usually describing its position, and three other parameters are describing its orientation. + +The /position/ of a point $P$ with respect to a frame $\{A\}$ can be described by a $3 \times 1$ position vector eqref:eq:ustation_position. +The name of the frame is usually added as a leading superscript: ${}^AP$ which reads as vector $P$ in frame $\{A\}$. + +\begin{equation}\label{eq:ustation_position} + {}^AP = \begin{bmatrix} P_x\\ P_y\\ P_z \end{bmatrix} +\end{equation} + +A pure translation of a solid body (i.e. of a frame $\{B\}$ attached to the solid body) can be described by the position ${}^AP_{O_B}$ as shown in Figure ref:fig:ustation_translation. + +#+name: fig:ustation_transformation_schematics +#+caption: Rigid body motion representation. (\subref{fig:ustation_translation}) pure translation. (\subref{fig:ustation_rotation}) pure rotation. (\subref{fig:ustation_transformation}) combined rotation and translation. +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:ustation_translation}Pure translation} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 0.8 +[[file:figs/ustation_translation.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:ustation_rotation}Pure rotation} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 0.8 +[[file:figs/ustation_rotation.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:ustation_transformation}General transformation} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :scale 0.8 +[[file:figs/ustation_transformation.png]] +#+end_subfigure +#+end_figure + +The /orientation/ of a rigid body is the same for all its points (by definition). +Hence, the orientation of a rigid body can be viewed as that for the orientation of a moving frame attached to the rigid body. +It can be represented in several different ways: the rotation matrix, the screw axis representation and Euler angles are common descriptions. + +A rotation matrix ${}^A\mathbf{R}_B$ is a $3 \times 3$ matrix containing the Cartesian unit vectors of frame $\{\mathbf{B}\}$ represented in frame $\{\mathbf{A}\}$ eqref:eq:ustation_rotation_matrix. + +\begin{equation}\label{eq:ustation_rotation_matrix} + {}^A\mathbf{R}_B = \left[ {}^A\hat{\mathbf{x}}_B | {}^A\hat{\mathbf{y}}_B | {}^A\hat{\mathbf{z}}_B \right] = \begin{bmatrix} + u_{x} & v_{x} & z_{x} \\ + u_{y} & v_{y} & z_{y} \\ + u_{z} & v_{z} & z_{z} + \end{bmatrix} +\end{equation} + +Consider a pure rotation of a rigid body ($\{\bm{A}\}$ and $\{\bm{B}\}$ are coincident at their origins, as shown in Figure ref:fig:ustation_rotation). +The rotation matrix can be used to express the coordinates of a point $P$ in a fixed frame $\{A\}$ (i.e. ${}^AP$) from its coordinate in the moving frame $\{B\}$ using Equation eqref:eq:ustation_rotation. + +\begin{equation} \label{eq:ustation_rotation} + {}^AP = {}^A\mathbf{R}_B {}^BP +\end{equation} + + +For rotations along $x$, $y$ or $z$ axis, formulas are given in Equation eqref:eq:ustation_rotation_matrices_xyz. + +\begin{subequations}\label{eq:ustation_rotation_matrices_xyz} +\begin{align} +\mathbf{R}_x(\theta_x) &= \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos(\theta_x) & -\sin(\theta_x) \\ 0 & \sin(\theta_x) & \cos(\theta_x) \end{bmatrix} \\ +\mathbf{R}_y(\theta_y) &= \begin{bmatrix} \cos(\theta_y) & 0 & \sin(\theta_y) \\ 0 & 1 & 0 \\ -\sin(\theta_y) & 0 & \cos(\theta_y) \end{bmatrix} \\ +\mathbf{R}_z(\theta_z) &= \begin{bmatrix} \cos(\theta_z) & -\sin(\theta_z) & 0 \\ \sin(\theta_z) & \cos(\theta_x) & 0 \\ 0 & 0 & 1 \end{bmatrix} +\end{align} +\end{subequations} + +Sometimes, it is useful to express a rotation as a combination of three rotations described by $\mathbf{R}_x$, $\mathbf{R}_y$ and $\mathbf{R}_z$. +As the order of rotation is very important[fn:5], in this work we choose to express rotations as three successive rotations about the coordinate axes of the moving frame eqref;eq:ustation_rotation_combination. + +\begin{equation}\label{eq:ustation_rotation_combination} +{}^A\mathbf{R}_B(\alpha, \beta, \gamma) = \mathbf{R}_u(\alpha) \mathbf{R}_v(\beta) \mathbf{R}_c(\gamma) +\end{equation} + +Such rotation can be parameterized by three Euler angles $(\alpha,\ \beta,\ \gamma)$, which can be computed from a given rotation matrix using equations eqref:eq:ustation_euler_angles. + +\begin{subequations}\label{eq:ustation_euler_angles} +\begin{align} +\alpha &= \text{atan2}(-R_{23}/\cos(\beta),\ R_{33}/\cos(\beta)) \\ +\beta &= \text{atan2}( R_{13},\ \sqrt{R_{11}^2 + R_{12}^2}) \\ +\gamma &= \text{atan2}(-R_{12}/\cos(\beta),\ R_{11}/\cos(\beta)) +\end{align} +\end{subequations} + +**** Motion of a Rigid Body + +Since the relative positions of a rigid body with respect to a moving frame $\{B\}$ attached to it is fixed for all time, it is sufficient to know the position of the origin of the frame $O_B$ and the orientation of the frame $\{B\}$ with respect to the fixed frame $\{A\}$, to represent the position of any point $P$ in the space. + +Therefore, the pose of a rigid body, can be fully determined by: +1. The position vector of point $O_B$ with respect to frame $\{A\}$ which is denoted ${}^AP_{O_B}$ +2. The orientation of the rigid body, or the moving frame $\{B\}$ attached to it with respect to the fixed frame $\{A\}$, that is represented by ${}^A\mathbf{R}_B$. + +The position of any point $P$ of the rigid body with respect to the fixed frame $\{\mathbf{A}\}$, which is denoted ${}^A\mathbf{P}$ may be determined thanks to the /Chasles' theorem/, which states that if the pose of a rigid body $\{{}^A\mathbf{R}_B, {}^AP_{O_B}\}$ is given, then the position of any point $P$ of this rigid body with respect to $\{\mathbf{A}\}$ is given by Equation eqref:eq:ustation_chasles_therorem. + +\begin{equation} \label{eq:ustation_chasles_therorem} + {}^AP = {}^A\mathbf{R}_B {}^BP + {}^AP_{O_B} +\end{equation} + +While equation eqref:eq:ustation_chasles_therorem can describe the motion of a rigid body, it can be written in a more convenient way using $4 \times 4$ homogeneous transformation matrices and $4 \times 1$ homogeneous coordinates. +The homogeneous transformation matrix is composed of the rotation matrix ${}^A\mathbf{R}_B$ representing the orientation and the position vector ${}^AP_{O_B}$ representing the translation. +It is partitioned as shown in Equation eqref:eq:ustation_homogeneous_transformation_parts. + +\begin{equation}\label{eq:ustation_homogeneous_transformation_parts} + {}^A\mathbf{T}_B = + \left[ \begin{array}{ccc|c} + & & & \\ + & {}^A\mathbf{R}_B & & {}^AP_{O_B} \\ + & & & \cr + \hline + 0 & 0 & 0 & 1 + \end{array} \right] +\end{equation} + +Then, ${}^AP$ can be computed from ${}^BP$ and the homogeneous transformation matrix using eqref:eq:ustation_homogeneous_transformation. + +\begin{equation}\label{eq:ustation_homogeneous_transformation} + \left[ \begin{array}{c} \\ {}^AP \\ \cr \hline 1 \end{array} \right] + = + \left[ \begin{array}{ccc|c} + & & & \\ + & {}^A\mathbf{R}_B & & {}^AP_{O_B} \\ + & & & \cr + \hline + 0 & 0 & 0 & 1 + \end{array} \right] + \left[ \begin{array}{c} \\ {}^BP \\ \cr \hline 1 \end{array} \right] \quad \Rightarrow \quad {}^AP = {}^A\mathbf{R}_B {}^BP + {}^AP_{O_B} +\end{equation} + +One key advantage of using homogeneous transformation is that it can easily be generalized for consecutive transformations. +Let us consider the motion of a rigid body described at three locations (Figure ref:fig:ustation_combined_transformation). +Frame $\{A\}$ represents the initial location, frame $\{B\}$ is an intermediate location, and frame $\{C\}$ represents the rigid body at its final location. + +#+name: fig:ustation_combined_transformation +#+caption: Motion of a rigid body represented at three locations by frame $\{A\}$, $\{B\}$ and $\{C\}$ +[[file:figs/ustation_combined_transformation.png]] + +Furthermore, suppose the position vector of a point $P$ of the rigid body is given in the final location, that is ${}^CP$ is given, and the position of this point is to be found in the fixed frame $\{A\}$, that is ${}^AP$. +Since the locations of the rigid body is known relative to each other, ${}^CP$ can be transformed to ${}^BP$ using ${}^B\mathbf{T}_C$ using ${}^BP = {}^B\mathbf{T}_C {}^CP$. +Similarly, ${}^BP$ can be transformed into ${}^AP$ using ${}^AP = {}^A\mathbf{T}_B {}^BP$. + +Combining the two relations, Equation eqref:eq:ustation_consecutive_transformations is obtained. +This shows that combining multiple transformations is equivalent as to compute $4 \times 4$ matrix multiplications. + +\begin{equation}\label{eq:ustation_consecutive_transformations} +{}^AP = \underbrace{{}^A\mathbf{T}_B {}^B\mathbf{T}_C}_{{}^A\mathbf{T}_C} {}^CP +\end{equation} + +Another key advantage of using homogeneous transformation is the easy inverse transformation that can be computed using Equation eqref:eq:ustation_inverse_homogeneous_transformation. + +\begin{equation}\label{eq:ustation_inverse_homogeneous_transformation} + {}^B\mathbf{T}_A = {}^A\mathbf{T}_B^{-1} = + \left[ \begin{array}{ccc|c} + & & & \\ + & {}^A\mathbf{R}_B^T & & -{}^A \mathbf{R}_B^T {}^AP_{O_B} \\ + & & & \cr + \hline + 0 & 0 & 0 & 1 \\ + \end{array} \right] +\end{equation} + +** Micro-Station Kinematics +<> + +Each stage is described by two frames, one is attached to the fixed platform $\{A\}$ while the other is fixed to the mobile platform $\{B\}$. +At "rest" position, the two are having the same pose and coincide with the point of interest ($O_A = O_B$). +An example is shown in Figure ref:fig:ustation_stage_motion for the tilt-stage. +Note that the mobile frame of the translation stage equals the fixed frame of the tilt stage: $\{B_{D_y}\} = \{A_{R_y}\}$. +Similarly, the mobile frame of the tilt stage equals the fixed frame of the spindle: $\{B_{R_y}\} = \{A_{R_z}\}$. + +#+name: fig:ustation_stage_motion +#+caption: Example of the motion induced by the tilt-stage $R_y$. "Rest" position in shown in blue while a arbitrary position in shown in red. Parasitic motions are here magnified for clarity. +[[file:figs/ustation_stage_motion.png]] + +The motion induced by a positioning stage may be described by a homogeneous transformation matrix from frame $\{A\}$ to frame $\{B\}$ as explain in Section ref:ssec:ustation_kinematics. +As any motion stage induces parasitic motion in all 6 DoF, the transformation matrix representing its induced motion can be written as in eqref:eq:ustation_translation_stage_errors. + +\begin{equation}\label{eq:ustation_translation_stage_errors} +{}^A\mathbf{T}_B(D_x, D_y, D_z, \theta_x, \theta_y, \theta_z) = +\left[ \begin{array}{ccc|c} + & & & D_x \\ + & \mathbf{R}_x(\theta_x) \mathbf{R}_y(\theta_y) \mathbf{R}_z(\theta_z) & & D_y \\ + & & & D_z \cr + \hline + 0 & 0 & 0 & 1 +\end{array} \right] +\end{equation} + +The homogeneous transformation matrix corresponding to the micro-station $\mathbf{T}_{\mu\text{-station}}$ is simply equal to the matrix multiplication of the homogeneous transformation matrices of the individual stages as shown in Equation eqref:eq:ustation_transformation_station. + +\begin{equation}\label{eq:ustation_transformation_station} +\mathbf{T}_{\mu\text{-station}} = \mathbf{T}_{D_y} \cdot \mathbf{T}_{R_y} \cdot \mathbf{T}_{R_z} \cdot \mathbf{T}_{\mu\text{-hexapod}} +\end{equation} + +$\mathbf{T}_{\mu\text{-station}}$ represents the pose of the sample (supposed to be rigidly fixed on top of the positioning-hexapod) with respect to the granite. + +If the transformation matrices of the individual stages are representing a perfect motion (i.e. the stages are supposed to have no parasitic motion), $\mathbf{T}_{\mu\text{-station}}$ is representing the pose setpoint of the sample with respect to the granite. +The transformation matrices for the translation stage, tilt stage, spindle and positioning hexapod can be written as shown in Equation eqref:eq:ustation_transformation_matrices_stages. + +\begin{equation}\label{eq:ustation_transformation_matrices_stages} +\begin{align} +\mathbf{T}_{D_y} &= \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & D_y \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} \quad +\mathbf{T}_{\mu\text{-hexapod}} = +\left[ \begin{array}{ccc|c} + & & & D_{\mu x} \\ + & \mathbf{R}_x(\theta_{\mu x}) \mathbf{R}_y(\theta_{\mu y}) \mathbf{R}_{z}(\theta_{\mu z}) & & D_{\mu y} \\ + & & & D_{\mu z} \cr + \hline + 0 & 0 & 0 & 1 +\end{array} \right] \\ +\mathbf{T}_{R_z} &= \begin{bmatrix} + \cos(\theta_z) & -\sin(\theta_z) & 0 & 0 \\ + \sin(\theta_z) & \cos(\theta_z) & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} \quad +\mathbf{T}_{R_y} = \begin{bmatrix} + \cos(\theta_y) & 0 & \sin(\theta_y) & 0 \\ + 0 & 1 & 0 & 0 \\ + -\sin(\theta_y) & 0 & \cos(\theta_y) & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +\end{align} +\end{equation} -** Compare with measurements at the CoM of each element #+begin_src matlab -%% All stages are initialized +%% Stage setpoints +Dy = 1e-3; % Translation Stage [m] +Ry = 3*pi/180; % Tilt Stage [rad] +Rz = 180*pi/180; % Spindle [rad] + +%% Stage individual Homogeneous transformations +% Translation Stage +Rty = [1 0 0 0; + 0 1 0 Dy; + 0 0 1 0; + 0 0 0 1]; + +% Tilt Stage - Pure rotating aligned with Ob +Rry = [ cos(Ry) 0 sin(Ry) 0; + 0 1 0 0; + -sin(Ry) 0 cos(Ry) 0; + 0 0 0 1]; + +% Spindle - Rotation along the Z axis +Rrz = [cos(Rz) -sin(Rz) 0 0 ; + sin(Rz) cos(Rz) 0 0 ; + 0 0 1 0 ; + 0 0 0 1 ]; + +% Micro-Station homogeneous transformation +Ttot = Rty*Rry*Rrz; + +%% Compute translations and rotations (Euler angles) induced by the micro-station +ustation_dx = Ttot(1,4); +ustation_dy = Ttot(2,4); +ustation_dz = Ttot(3,4); +ustation_ry = atan2( Ttot(1, 3), sqrt(Ttot(1, 1)^2 + Ttot(1, 2)^2)); +ustation_rx = atan2(-Ttot(2, 3)/cos(Ery), Ttot(3, 3)/cos(Ery)); +ustation_rz = atan2(-Ttot(1, 2)/cos(Ery), Ttot(1, 1)/cos(Ery)); + +%% Verification using the Simscape model +% All stages are initialized as rigid bodies to avoid any guiding error +initializeGround( 'type', 'rigid'); +initializeGranite( 'type', 'rigid'); +initializeTy( 'type', 'rigid'); +initializeRy( 'type', 'rigid'); +initializeRz( 'type', 'rigid'); +initializeMicroHexapod('type', 'rigid'); + +initializeLoggingConfiguration('log', 'all'); + +initializeReferences('Dy_amplitude', Dy, ... + 'Ry_amplitude', Ry, ... + 'Rz_amplitude', Rz); + +initializeDisturbances('enable', false); + +load('mat/conf_simulink.mat'); +set_param(conf_simulink, 'StopTime', '0.5'); + +% Simulation is performed +sim(mdl); + +% Sample's motion is computed from "external metrology" +T_sim = [simout.y.R.Data(:,:,end), [simout.y.x.Data(end); simout.y.y.Data(end); simout.y.z.Data(end)]; [0,0,0,1]]; +sim_dx = T_sim(1,4); +sim_dy = T_sim(2,4); +sim_dz = T_sim(3,4); +sim_ry = atan2( T_sim(1, 3), sqrt(T_sim(1, 1)^2 + T_sim(1, 2)^2)); +sim_rx = atan2(-T_sim(2, 3)/cos(Ery), T_sim(3, 3)/cos(Ery)); +sim_rz = atan2(-T_sim(1, 2)/cos(Ery), T_sim(1, 1)/cos(Ery)); +#+end_src + +* Micro-Station Dynamics +:PROPERTIES: +:HEADER-ARGS:matlab+: :tangle matlab/ustation_2_modeling.m +:END: +<> +** Introduction :ignore: + +In this section, the Simscape model of the micro-station is briefly presented. +It consists of several rigid bodies connected by springs and dampers. +The inertia of the solid bodies as well as the stiffness properties of the guiding mechanisms are first estimated based on the CAD model and part data-sheets (Section ref:ssec:ustation_model_simscape). + +The obtained dynamics is then compared with the modal analysis performed on the micro-station (Section ref:ssec:ustation_meas_compliance). + +# TODO - Add reference to uniaxial model +As the dynamics of the nano-hexapod is impacted by the micro-station compliance, the most important dynamical characteristic that should be well modeled is the overall compliance of the micro-station. +To do so, the 6-DoF compliance of the micro-station is measured (Section ref:ssec:ustation_meas_compliance) and then compared with the 6-DoF compliance extracted from the Simscape model (Section ref:ssec:ustation_model_compliance). + +** Matlab Init :noexport:ignore: +#+begin_src matlab +%% ustation_2_modeling.m +#+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 + +#+begin_src matlab :noweb yes +<> +#+end_src + +** Multi-Body Model +<> + +By performing a modal analysis of the micro-station, it could be verified that in the frequency range of interest, each stage behaved as a rigid body. +This confirms that a multi-body model can be used to properly model the micro-station. + +A multi-body model consists of several solid bodies connected with joints. +Each solid body can be represented by inertia properties (most of the time computed automatically from the 3D model and material density). +Joints are used to impose kinematic constraints between solid bodies, and to specify dynamical properties (i.e. spring stiffness and damping coefficient). +External forces can be used to model disturbances, and "sensors" can be used to measure the relative pose between two defined frames. + +The micro-station is therefore modeled by several solid bodies connected by joints. +A typical stage (here the tilt-stage) is modelled as shown in Figure ref:fig:ustation_simscape_stage_example where two solid bodies (the fixed part and the mobile part) are connected by a 6-DoF joint. +One DoF of the 6-DoF joint is "imposed" by a setpoint (i.e. modeled as infinitely stiff) while the other 5 are each modelled by a spring and a damper. +Additional forces can be used to model disturbances induced by the stage motion. + +#+name: fig:ustation_simscape_stage_example +#+caption: Example of a stage (here the tilt-stage) represented in the multi-body model (Simscape). It is composed of two solid bodies connected by a 6-DoF joint. One joint DoF (here the tilt angle) can be imposed, the other ones are represented by springs and dampers. Additional disturbances forces for all DoF can be included +[[file:figs/ustation_simscape_stage_example.png]] + +The Ground is modelled by a solid body connected to the "world frame" through a joint only allowing 3 translations. +The granite is then connected to the ground by a 6-DoF joint. +The translation stage is connected to the granite by a 6-DoF joint, but the $D_y$ motion is imposed. +Similarly, the tilt-stage and the spindle are connected to the stage below using a 6-DoF joint, with 1-DoF being imposed. +Finally, the positioning hexapod has 6-DoF. + +The total number of "free" degrees of freedom is 27, and therefore the model has 54 states. +The springs and dampers values were first estimated from the joints/stages specifications and were later fined tuned based on measurements. +The spring values are summarized in Table ref:tab:ustation_6dof_stiffness_values. + +#+name: tab:ustation_6dof_stiffness_values +#+caption: Summary of the stage stiffnesses. Contrained degrees-of-freedom are indicated by "-". The location of the 6-DoF joints in which the stiffnesses are defined are indicated by the frame in figures of Section ref:ssec:ustation_stages +#+attr_latex: :environment tabularx :width \linewidth :align Xcccccc +#+attr_latex: :center t :booktabs t +| *Stage* | $D_x$ | $D_y$ | $D_z$ | $R_x$ | $R_y$ | $R_z$ | +|-------------+-----------------+-----------------+-----------------+-------------------------+------------------------+-------------------------| +| Granite | $5\,kN/\mu m$ | $5\,kN/\mu m$ | $5\,kN/\mu m$ | $25\,Nm/\mu\text{rad}$ | $25\,Nm/\mu\text{rad}$ | $10\,Nm/\mu\text{rad}$ | +| Translation | $200\,N/\mu m$ | - | $200\,N/\mu m$ | $60\,Nm/\mu\text{rad}$ | $90\,Nm/\mu\text{rad}$ | $60\,Nm/\mu\text{rad}$ | +| Tilt | $380\,N/\mu m$ | $400\,N/\mu m$ | $380\,N/\mu m$ | $120\,Nm/\mu\text{rad}$ | - | $120\,Nm/\mu\text{rad}$ | +| Spindle | $700\,N/\mu m$ | $700\,N/\mu m$ | $2\,kN/\mu m$ | $10\,Nm/\mu\text{rad}$ | $10\,Nm/\mu\text{rad}$ | - | +| Hexapod | $10\,N/\mu m$ | $10\,N/\mu m$ | $100\,N/\mu m$ | $1.5\,Nm/rad$ | $1.5\,Nm/rad$ | $0.27\,Nm/rad$ | + +** With comparison with the measurements + +The dynamics of the micro-station was measured by placing accelerometers on each stage and by impacting the translation stage with an instrumented hammer in three directions. +The obtained FRF were then projected at the CoM of each stage. + +In order to have a first idea of the accuracy of the obtained model, the FRF from the hammer impacts to the acceleration of each stage is extracted from the Simscape model and compared with the measurements in Figure ref:fig:ustation_comp_com_response. + +Even though there is some similarity between the model and the measurements (similar overall shapes and amplitudes), it is clear that the Simscape model does not represent very accurately the complex micro-station dynamics. +Tuning the numerous model parameters to better match the measurements is an highly non-linear optimization problem which is difficult to solve in practice. + +#+begin_src matlab +%% Indentify the model dynamics from the 3 hammer imapcts +% To the motion of each solid body at their CoM + +% All stages are initialized initializeGround( 'type', 'rigid'); initializeGranite( 'type', 'flexible'); initializeTy( 'type', 'flexible'); @@ -800,13 +1404,7 @@ initializeLoggingConfiguration('log', 'none'); initializeReferences(); initializeDisturbances('enable', false); -#+end_src -We now use a new Simscape Model where 6DoF inertial sensors are located at the Center of Mass of each solid body. - -We use the =linearize= function in order to estimate the dynamics from forces applied on the Translation stage at the same position used for the real modal analysis to the inertial sensors. -#+begin_src matlab -%% Identification % Input/Output definition clear io; io_i = 1; io(io_i) = linio([mdl, '/Micro-Station/Translation Stage/Flexible/F_hammer'], 1, 'openinput'); io_i = io_i + 1; @@ -818,8 +1416,6 @@ io(io_i) = linio([mdl, '/Micro-Station/Micro Hexapod/Flexible/accelerometer'], % Run the linearization G_ms = linearize(mdl, io, 0); - -% Input/Output definition G_ms.InputName = {'Fx', 'Fy', 'Fz'}; G_ms.OutputName = {'gtop_x', 'gtop_y', 'gtop_z', 'gtop_rx', 'gtop_ry', 'gtop_rz', ... 'ty_x', 'ty_y', 'ty_z', 'ty_rx', 'ty_ry', 'ty_rz', ... @@ -827,166 +1423,133 @@ G_ms.OutputName = {'gtop_x', 'gtop_y', 'gtop_z', 'gtop_rx', 'gtop_ry', 'gtop_rz' 'rz_x', 'rz_y', 'rz_z', 'rz_rx', 'rz_ry', 'rz_rz', ... 'hexa_x', 'hexa_y', 'hexa_z', 'hexa_rx', 'hexa_ry', 'hexa_rz'}; -% Put the output of G in displacements instead of acceleration -G_ms = G_ms/s^2; -#+end_src - -#+begin_src matlab -%% Load estimated FRF at CoM +% Load estimated FRF at CoM load('/home/thomas/Cloud/work-projects/ID31-NASS/phd-thesis-chapters/A3-micro-station-modal-analysis/matlab/mat/frf_matrix.mat', 'freqs'); load('/home/thomas/Cloud/work-projects/ID31-NASS/phd-thesis-chapters/A3-micro-station-modal-analysis/matlab/mat/frf_com.mat', 'frfs_CoM'); -#+end_src -#+begin_src matlab :exports none -%% Compare the two +% Initialization of some variables to the figures dirs = {'x', 'y', 'z', 'rx', 'ry', 'rz'}; stages = {'gbot', 'gtop', 'ty', 'ry', 'rz', 'hexa'} +f = logspace(log10(10), log10(500), 1000); +#+end_src -n_stg = 3; -n_dir = 6; % x, y, z, Rx, Ry, Rz -n_exc = 2; % x, y, z - -f = logspace(0, 3, 1000); +#+begin_src matlab :exports none :results none +%% Spindle - X response +n_stg = 5; % Measured Stage +n_dir = 1; % Measured DoF: x, y, z, Rx, Ry, Rz +n_exc = 1; % Hammer impact: x, y, z figure; hold on; -plot(freqs, abs(squeeze(frfs_CoM(6*(n_stg-1) + n_dir, n_exc, :)))./((2*pi*freqs).^2)'); -plot(f, abs(squeeze(freqresp(G_ms([stages{n_stg}, '_', dirs{n_dir}], ['F', dirs{n_exc}]), f, 'Hz')))); -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -ylabel('Amplitude [m/N]'); +plot(freqs, abs(squeeze(frfs_CoM(6*(n_stg-1) + n_dir, n_exc, :))), 'DisplayName', 'Measurement'); +plot(f, abs(squeeze(freqresp(G_ms([stages{n_stg}, '_', dirs{n_dir}], ['F', dirs{n_exc}]), f, 'Hz'))), 'DisplayName', 'Model'); +text(50, 2e-2,{'$D_x/F_x$ - Spindle'},'VerticalAlignment','bottom','HorizontalAlignment','center') hold off; -xlim([1, 200]); +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('Magnitude [$m/s^2/N$]'); +leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +xlim([10, 200]); +ylim([1e-6, 1e-1]) #+end_src -#+begin_src matlab :exports none -dirs = {'x', 'y', 'z', 'rx', 'ry', 'rz'}; -stages = {'gtop', 'ty', 'ry', 'rz', 'hexa'} +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/ustation_comp_com_response_rz_x.pdf', 'width', 'third', 'height', 'normal'); +#+end_src -f = logspace(1, 3, 1000); +#+begin_src matlab :exports none :results none +%% Hexapod - Y response +n_stg = 6; % Measured Stage +n_dir = 2; % Measured DoF: x, y, z, Rx, Ry, Rz +n_exc = 2; % Hammer impact: x, y, z figure; -for n_stg = 1:2 - for n_dir = 1:3 - subplot(3, 2, (n_dir-1)*2 + n_stg); - title(['F ', dirs{n_dir}, ' to ', stages{n_stg}, ' ', dirs{n_dir}]); - hold on; - plot(freqs, abs(squeeze(frfs_CoM(6*(n_stg) + n_dir, n_dir, :)))./((2*pi*freqs).^2)'); - plot(f, abs(squeeze(freqresp(G_ms([stages{n_stg}, '_', dirs{n_dir}], ['F', dirs{n_dir}]), f, 'Hz')))); - set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); - ylabel('Amplitude [m/N]'); - if n_dir == 3 - xlabel('Frequency [Hz]'); - end - hold off; - xlim([10, 1000]); - ylim([1e-12, 1e-6]); - end -end +hold on; +plot(freqs, abs(squeeze(frfs_CoM(6*(n_stg-1) + n_dir, n_exc, :))), 'DisplayName', 'Measurement'); +plot(f, abs(squeeze(freqresp(G_ms([stages{n_stg}, '_', dirs{n_dir}], ['F', dirs{n_exc}]), f, 'Hz'))), 'DisplayName', 'Model'); +text(50, 2e-2,{'$D_y/F_y$ - Hexapod'},'VerticalAlignment','bottom','HorizontalAlignment','center') +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('Magnitude [$m/s^2/N$]'); +leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +xlim([10, 200]); +ylim([1e-6, 1e-1]) #+end_src -#+begin_src matlab :exports none - dirs = {'x', 'y', 'z', 'rx', 'ry', 'rz'}; - stages = {'ry', 'rz', 'hexa'} - - f = logspace(1, 3, 1000); - - figure; - for n_stg = 1:2 - for n_dir = 1:3 - subplot(3, 2, (n_dir-1)*2 + n_stg); - title(['F ', dirs{n_dir}, ' to ', stages{n_stg}, ' ', dirs{n_dir}]); - hold on; - plot(freqs, abs(squeeze(frfs_CoM(6*(n_stg+2) + n_dir, n_dir, :)))./((2*pi*freqs).^2)'); - plot(f, abs(squeeze(freqresp(G_ms([stages{n_stg}, '_', dirs{n_dir}], ['F', dirs{n_dir}]), f, 'Hz')))); - set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); - ylabel('Amplitude [m/N]'); - if n_dir == 3 - xlabel('Frequency [Hz]'); - end - hold off; - xlim([10, 1000]); - ylim([1e-12, 1e-6]); - end - end +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/ustation_comp_com_response_hexa_y.pdf', 'width', 'third', 'height', 'normal'); #+end_src -#+begin_src matlab :exports none - dirs = {'x', 'y', 'z', 'rx', 'ry', 'rz'}; - stages = {'hexa'} +#+begin_src matlab :exports none :results none +%% Tilt stage - Z response +n_stg = 4; % Measured Stage +n_dir = 3; % Measured DoF: x, y, z, Rx, Ry, Rz +n_exc = 3; % Hammer impact: x, y, z - f = logspace(1, 3, 1000); - - figure; - for n_stg = 1 - for n_dir = 1:3 - subplot(3, 1, (n_dir-1) + n_stg); - title(['F ', dirs{n_dir}, ' to ', stages{n_stg}, ' ', dirs{n_dir}]); - hold on; - plot(freqs, abs(squeeze(frfs_CoM(6*(n_stg+4) + n_dir, n_dir, :)))./((2*pi*freqs).^2)'); - plot(f, abs(squeeze(freqresp(G_ms([stages{n_stg}, '_', dirs{n_dir}], ['F', dirs{n_dir}]), f, 'Hz')))); - set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); - ylabel('Amplitude [m/N]'); - if n_dir == 3 - xlabel('Frequency [Hz]'); - end - hold off; - xlim([10, 1000]); - ylim([1e-12, 1e-6]); - end - end +figure; +hold on; +plot(freqs, abs(squeeze(frfs_CoM(6*(n_stg-1) + n_dir, n_exc, :))), 'DisplayName', 'Measurement'); +plot(f, abs(squeeze(freqresp(G_ms([stages{n_stg}, '_', dirs{n_dir}], ['F', dirs{n_exc}]), f, 'Hz'))), 'DisplayName', 'Model'); +text(50, 2e-2,{'$D_z/F_z$ - Tilt'},'VerticalAlignment','bottom','HorizontalAlignment','center') +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('Magnitude [$m/s^2/N$]'); +leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +xlim([10, 200]); +ylim([1e-6, 1e-1]) #+end_src -** Measured micro-station compliance -*** Introduction :ignore: +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/ustation_comp_com_response_ry_z.pdf', 'width', 'third', 'height', 'normal'); +#+end_src -The most important dynamical characteristic of the micro-station that should be well modeled is its compliance. -This is what can impact the nano-hexapod dynamics. +#+name: fig:ustation_comp_com_response +#+caption: FRF between the hammer impacts on the translation stage and measured stage acceleration expressed at its CoM. Comparison of the measured FRF and the ones extracted from the Simscape model. Different directions are computed and for different stages. +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:ustation_comp_com_response_rz_x}Spindle, $x$ response} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.9\linewidth +[[file:figs/ustation_comp_com_response_rz_x.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:ustation_comp_com_response_hexa_y}Hexapod, $y$ response} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.9\linewidth +[[file:figs/ustation_comp_com_response_hexa_y.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:ustation_comp_com_response_ry_z}Tilt, $z$ response} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.9\linewidth +[[file:figs/ustation_comp_com_response_ry_z.png]] +#+end_subfigure +#+end_figure -- [ ] Add schematic of the experiment with Micro-Hexapod top platform, location of accelerometers, of impacts, etc... +** Micro-station compliance - Measurement +<> -- 4 3-axis accelerometers -- 10 hammer impacts on the micro-hexapod top plaftorm -- *Was the rotation compensation axis present?* (I don't think so) +As was shown in the previous section, the dynamics of the micro-station is complex and tuning the multi-body model parameters to obtain a perfect match is hard. -*** Position of inertial sensors on top of the micro-hexapod +When considering the NASS, the most important dynamical characteristics of the micro-station is its compliance as it is what can impact the plant dynamics. +The adopted strategy is therefore to accurately model the micro-station compliance. -4 accelerometers are fixed to the micro-hexapod top platform. +The micro-station compliance is experimentally measured using the setup schematically shown in Figure ref:fig:ustation_compliance_meas. +Four 3-axis accelerometers are fixed to the micro-hexapod top platform. +The micro-hexapod top platform is impacted at 10 different points. +For each impact position, 10 impacts are performed for averaging and improving the data quality. -# | *Num* | *Position* | *Orientation* | *Sensibility* | *Channels* | -# |-------+------------+---------------+---------------+------------| -# | 1 | [0, +A, 0] | [x, y, z] | 1V/g | 1-3 | -# | 2 | [-B, 0, 0] | [x, y, z] | 1V/g | 4-6 | -# | 3 | [0, -A, 0] | [x, y, z] | 0.1V/g | 7-9 | -# | 4 | [+B, 0, 0] | [x, y, z] | 1V/g | 10-12 | +#+name: fig:ustation_compliance_meas +#+caption: Schematic of the measurement setup to estimate the compliance of the micro-station. The top platform of the positioning hexapod is shown with four 3-axis accelerometers (shown in red) are on top. 10 hammer impacts are performed at different locations (shown in blue). +[[file:figs/ustation_compliance_meas.png]] -# Instrumented Hammer: -# - Channel 13 -# - Sensibility: 230 uV/N +To convert the 12 acceleration signals $a_{\mathcal{L}} = [a_{1x}\ a_{1y}\ a_{1z}\ a_{2x}\ \dots\ a_{4z}]$ to the acceleration expressed in the frame $\{\mathcal{X}\}$ $a_{\mathcal{X}} = [a_{dx}\ a_{dy}\ a_{dz}\ a_{rx}\ a_{ry}\ a_{rz}]$, a Jacobian matrix $\mathbf{J}_a$ is written based on the positions and orientations of the accelerometers eqref:eq:ustation_compliance_acc_jacobian. -# | Acc Number | Dir | Channel Number | -# |------------+-----+----------------| -# | 1 | x | 1 | -# | 1 | y | 2 | -# | 1 | z | 3 | -# | 2 | x | 4 | -# | 2 | y | 5 | -# | 2 | z | 6 | -# | 3 | x | 7 | -# | 3 | y | 8 | -# | 3 | z | 9 | -# | 4 | x | 10 | -# | 4 | y | 11 | -# | 4 | z | 12 | -# | Hammer | | 13 | - -To convert the 12 acceleration signals $\mathbf{a}_{\mathcal{L}} = [a_{1x}\ a_{1y}\ a_{1z}\ a_{2x}\ \dots\ a_{4z}]$ to the acceleration expressed in cartesian coordinate $\mathbf{a}_{\mathcal{X}} [a_{dx}\ a_{dy}\ a_{dz}\ a_{rx}\ a_{ry}\ a_{rz}]$, a Jacobian matrix can be written based on the positions and orientations of the accelerometers. - -\begin{equation} -\mathbf{a}_{\mathcal{L}} = J_a \cdot \mathbf{a}_{\mathcal{X}} -\end{equation} - -\begin{equation} -J_a = \begin{bmatrix} +\begin{equation}\label{eq:ustation_compliance_acc_jacobian} +\mathbf{J}_a = \begin{bmatrix} 1 & 0 & 0 & 0 & 0 &-d \\ 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & d & 0 & 0 \\ @@ -1002,14 +1565,83 @@ J_a = \begin{bmatrix} \end{bmatrix} \end{equation} -Then, the acceleration in the cartesian frame can be computed -\begin{equation} -\mathbf{a}_{\mathcal{X}} = J_a^\dagger \cdot \mathbf{a}_{\mathcal{L}} +Then, the acceleration in the cartesian frame can be computed using eqref:eq:ustation_compute_cart_acc. + +\begin{equation}\label{eq:ustation_compute_cart_acc} +a_{\mathcal{X}} = \mathbf{J}_a^\dagger \cdot a_{\mathcal{L}} \end{equation} +Similar to what is done for the accelerometers, a Jacobian matrix $\mathbf{J}_F$ is computed eqref:eq:ustation_compliance_force_jacobian and used to convert the individual hammer forces $F_{\mathcal{L}}$ to force and torques $F_{\mathcal{X}}$ applied at the center of the micro-hexapod top plate (defined by frame $\{\mathcal{X}\}$ in Figure ref:fig:ustation_compliance_meas). + +\begin{equation}\label{eq:ustation_compliance_force_jacobian} +\mathbf{J}_F = \begin{bmatrix} + 0 & -1 & 0 & 0 & 0 & 0\\ + 0 & 0 & -1 & -d & 0 & 0\\ + 1 & 0 & 0 & 0 & 0 & 0\\ + 0 & 0 & -1 & 0 & -d & 0\\ + 0 & 1 & 0 & 0 & 0 & 0\\ + 0 & 0 & -1 & d & 0 & 0\\ +-1 & 0 & 0 & 0 & 0 & 0\\ + 0 & 0 & -1 & 0 & d & 0\\ +-1 & 0 & 0 & 0 & 0 & -d\\ +-1 & 0 & 0 & 0 & 0 & d +\end{bmatrix} +\end{equation} + +Force and torques applied at center of $\{\mathcal{X}\}$ are then computed using eqref:eq:ustation_compute_cart_force. + +\begin{equation}\label{eq:ustation_compute_cart_force} +F_{\mathcal{X}} = \mathbf{J}_F^t \cdot F_{\mathcal{L}} +\end{equation} + +Using the two Jacobian matrices, the FRF from the 10 hammer impacts to the 12 accelerometer outputs can be converted to the FRF from 6 forces/torques applied at the origin of frame $\{\mathcal{X}\}$ to the 6 linear/angular accelerations of the top platform expressed with respect to $\{\mathcal{X}\}$. +The obtained FRF from forces to linear motion are shown in Figure ref:fig:ustation_frf_compliance_xyz while the FRF from torques to angular motion are shown in Figure ref:fig:ustation_frf_compliance_Rxyz. + #+begin_src matlab +% Positions and orientation of accelerometers +% | *Num* | *Position* | *Orientation* | *Sensibility* | *Channels* | +% |-------+------------+---------------+---------------+------------| +% | 1 | [0, +A, 0] | [x, y, z] | 1V/g | 1-3 | +% | 2 | [-B, 0, 0] | [x, y, z] | 1V/g | 4-6 | +% | 3 | [0, -A, 0] | [x, y, z] | 0.1V/g | 7-9 | +% | 4 | [+B, 0, 0] | [x, y, z] | 1V/g | 10-12 | +% + +% Measuerment channels +% +% | Acc Number | Dir | Channel Number | +% |------------+-----+----------------| +% | 1 | x | 1 | +% | 1 | y | 2 | +% | 1 | z | 3 | +% | 2 | x | 4 | +% | 2 | y | 5 | +% | 2 | z | 6 | +% | 3 | x | 7 | +% | 3 | y | 8 | +% | 3 | z | 9 | +% | 4 | x | 10 | +% | 4 | y | 11 | +% | 4 | z | 12 | +% | Hammer | | 13 | + +% 10 measurements corresponding to 10 different Hammer impact locations +% | *Num* | *Direction* | *Position* | Accelerometer position | Jacobian number | +% |-------+-------------+------------+------------------------+-----------------| +% | 1 | -Y | [0, +A, 0] | 1 | -2 | +% | 2 | -Z | [0, +A, 0] | 1 | -3 | +% | 3 | X | [-B, 0, 0] | 2 | 4 | +% | 4 | -Z | [-B, 0, 0] | 2 | -6 | +% | 5 | Y | [0, -A, 0] | 3 | 8 | +% | 6 | -Z | [0, -A, 0] | 3 | -9 | +% | 7 | -X | [+B, 0, 0] | 4 | -10 | +% | 8 | -Z | [+B, 0, 0] | 4 | -12 | +% | 9 | -X | [0, -A, 0] | 3 | -7 | +% | 10 | -X | [0, +A, 0] | 1 | -1 | + + %% Jacobian for accelerometers -% L = Ja X +% aX = Ja . aL d = 0.14; % [m] Ja = [1 0 0 0 0 -d; 0 1 0 0 0 0; @@ -1025,61 +1657,7 @@ Ja = [1 0 0 0 0 -d; 0 0 1 0 -d 0]; Ja_inv = pinv(Ja); -#+end_src -#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) -data2orgtable(Ja_inv, {'Dx', 'Dy', 'Dz', 'Rx', 'Ry', 'Rz'}, {'d1x', 'd1y', 'd1z', 'd2x', 'd2y', 'd2z', 'd3x', 'd3y', 'd3z', 'd4x', 'd4y', 'd4z'}, ' %.5f '); -#+end_src - -#+RESULTS: -| | d1x | d1y | d1z | d2x | d2y | d2z | d3x | d3y | d3z | d4x | d4y | d4z | -|----+----------+------+---------+------+----------+---------+---------+------+----------+------+---------+----------| -| Dx | 0.25 | 0.0 | 0.0 | 0.25 | 0.0 | 0.0 | 0.25 | 0.0 | 0.0 | 0.25 | 0.0 | 0.0 | -| Dy | 0.0 | 0.25 | 0.0 | 0.0 | 0.25 | 0.0 | 0.0 | 0.25 | 0.0 | 0.0 | 0.25 | 0.0 | -| Dz | 0.0 | 0.0 | 0.25 | 0.0 | 0.0 | 0.25 | 0.0 | 0.0 | 0.25 | 0.0 | 0.0 | 0.25 | -| Rx | 0.0 | 0.0 | 3.57143 | 0.0 | 0.0 | -0.0 | 0.0 | 0.0 | -3.57143 | 0.0 | 0.0 | -0.0 | -| Ry | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 3.57143 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | -3.57143 | -| Rz | -1.78571 | 0.0 | -0.0 | 0.0 | -1.78571 | 0.0 | 1.78571 | 0.0 | -0.0 | 0.0 | 1.78571 | -0.0 | - -*** Hammer blow position/orientation - -10 hammer hits are performed as shown in Figure ... - -| *Num* | *Direction* | *Position* | Accelerometer position | Jacobian number | -|-------+-------------+------------+------------------------+-----------------| -| 1 | -Y | [0, +A, 0] | 1 | -2 | -| 2 | -Z | [0, +A, 0] | 1 | -3 | -| 3 | X | [-B, 0, 0] | 2 | 4 | -| 4 | -Z | [-B, 0, 0] | 2 | -6 | -| 5 | Y | [0, -A, 0] | 3 | 8 | -| 6 | -Z | [0, -A, 0] | 3 | -9 | -| 7 | -X | [+B, 0, 0] | 4 | -10 | -| 8 | -Z | [+B, 0, 0] | 4 | -12 | -| 9 | -X | [0, -A, 0] | 3 | -7 | -| 10 | -X | [0, +A, 0] | 1 | -1 | - -Similar to what is done for the accelerometers, a Jacobian matrix can be computed to convert the individual hammer forces to force and torques applied at the center of the micro-hexapod top plate. - -\begin{equation} -\mathbf{F}_{\mathcal{X}} = J_F^t \cdot \mathbf{F}_{\mathcal{L}} -\end{equation} - -\begin{equation} -J_F = \begin{bmatrix} - 0 & -1 & 0 & 0 & 0 & 0\\ - 0 & 0 & -1 & -d & 0 & 0\\ - 1 & 0 & 0 & 0 & 0 & 0\\ - 0 & 0 & -1 & 0 & -d & 0\\ - 0 & 1 & 0 & 0 & 0 & 0\\ - 0 & 0 & -1 & d & 0 & 0\\ --1 & 0 & 0 & 0 & 0 & 0\\ - 0 & 0 & -1 & 0 & d & 0\\ --1 & 0 & 0 & 0 & 0 & -d\\ --1 & 0 & 0 & 0 & 0 & d -\end{bmatrix} -\end{equation} - -#+begin_src matlab %% Jacobian for hammer impacts % F = Jf' tau Jf = [0 -1 0 0 0 0; @@ -1093,25 +1671,7 @@ Jf = [0 -1 0 0 0 0; -1 0 0 0 0 -d; -1 0 0 0 0 d]'; Jf_inv = pinv(Jf); -#+end_src -#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) -data2orgtable(Jf, {'Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz'}, {'-F1y', '-F1z', '+F2x', '-F2z', '+F3y', '-F3z', '-F4x', '-F4z', '-F3x', '-F1x'}, ' %.2f '); -#+end_src - -#+RESULTS: -| | -F1y | -F1z | +F2x | -F2z | +F3y | -F3z | -F4x | -F4z | -F3x | -F1x | -|----+------+-------+------+-------+------+------+------+------+-------+------| -| Fx | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | -1.0 | 0.0 | -1.0 | -1.0 | -| Fy | -1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | -| Fz | 0.0 | -1.0 | 0.0 | -1.0 | 0.0 | -1.0 | 0.0 | -1.0 | 0.0 | 0.0 | -| Mx | 0.0 | -0.14 | 0.0 | 0.0 | 0.0 | 0.14 | 0.0 | 0.0 | 0.0 | 0.0 | -| My | 0.0 | 0.0 | 0.0 | -0.14 | 0.0 | 0.0 | 0.0 | 0.14 | 0.0 | 0.0 | -| Mz | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | -0.14 | 0.14 | - -*** Compute FRF - -#+begin_src matlab %% Load raw measurement data % "Track1" to "Track12" are the 12 accelerometers % "Track13" is the instrumented hammer force sensor @@ -1182,12 +1742,12 @@ FRF_cartesian = pagemtimes(Ja_inv, pagemtimes(G_raw, Jf_inv)); #+end_src #+begin_src matlab :exports none :results none -%% Measured FRF of the compliance of the micro-station in the Cartesian frame +%% Measured FRF of the compliance of the micro-station in the Cartesian frame - Translations/Forces figure; hold on; -plot(f, abs(squeeze(FRF_cartesian(1,1,:))), '.', 'color', colors(1,:), 'DisplayName', '$D_x/F_x$') -plot(f, abs(squeeze(FRF_cartesian(2,2,:))), '.', 'color', colors(2,:), 'DisplayName', '$D_y/F_y$') -plot(f, abs(squeeze(FRF_cartesian(3,3,:))), '.', 'color', colors(3,:), 'DisplayName', '$D_z/F_z$') +plot(f, abs(squeeze(FRF_cartesian(1,1,:))), '-', 'color', colors(1,:), 'DisplayName', '$D_x/F_x$') +plot(f, abs(squeeze(FRF_cartesian(2,2,:))), '-', 'color', colors(2,:), 'DisplayName', '$D_y/F_y$') +plot(f, abs(squeeze(FRF_cartesian(3,3,:))), '-', 'color', colors(3,:), 'DisplayName', '$D_z/F_z$') hold off; leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; @@ -1197,33 +1757,59 @@ xlim([20, 500]); ylim([1e-9, 2e-6]); xticks([20, 50, 100, 200, 500]) #+end_src -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/ustation_frf_compliance_xyz.pdf', 'width', 'wide', 'height', 'normal'); +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/ustation_frf_compliance_xyz.pdf', 'width', 'half', 'height', 'normal'); #+end_src -#+name: fig:ustation_frf_compliance_xyz -#+caption: Measured FRF of the compliance of the micro-station in the Cartesian frame -#+RESULTS: -[[file:figs/ustation_frf_compliance_xyz.png]] - -#+begin_src matlab +#+begin_src matlab :exports none :results none +%% Measured FRF of the compliance of the micro-station in the Cartesian frame - Rotations/Torques figure; hold on; -plot(f, abs(squeeze(FRF_cartesian(4,4,:))), '-', 'color', colors(1,:), 'DisplayName', '$D_x/F_x$') -plot(f, abs(squeeze(FRF_cartesian(5,5,:))), '-', 'color', colors(2,:), 'DisplayName', '$D_y/F_y$') -plot(f, abs(squeeze(FRF_cartesian(6,6,:))), '-', 'color', colors(3,:), 'DisplayName', '$D_z/F_z$') +plot(f, abs(squeeze(FRF_cartesian(4,4,:))), '-', 'color', colors(1,:), 'DisplayName', '$R_x/M_x$') +plot(f, abs(squeeze(FRF_cartesian(5,5,:))), '-', 'color', colors(2,:), 'DisplayName', '$R_y/M_y$') +plot(f, abs(squeeze(FRF_cartesian(6,6,:))), '-', 'color', colors(3,:), 'DisplayName', '$R_z/M_z$') hold off; -set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -xlabel('Frequency [Hz]'); ylabel('Magnitude [m/N]'); -xlim([30, 300]); ylim([1e-9, 2e-6]); leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); leg.ItemTokenSize(1) = 15; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +xlabel('Frequency [Hz]'); ylabel('Magnitude [rad/Nm]'); +xlim([20, 500]); ylim([2e-7, 1e-4]); +xticks([20, 50, 100, 200, 500]) #+end_src +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/ustation_frf_compliance_Rxyz.pdf', 'width', 'half', 'height', 'normal'); +#+end_src + +#+name: fig:ustation_frf_compliance +#+caption: Measured FRF of the compliance of the micro-station expressed in frame $\{\mathcal{X}\}$. Both translation terms (\subref{fig:ustation_frf_compliance_xyz}) and rotational terms (\subref{fig:ustation_frf_compliance_Rxyz}) are displayed. +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:ustation_frf_compliance_xyz}sub caption a} +#+attr_latex: :options {0.49\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.95\linewidth +[[file:figs/ustation_frf_compliance_xyz.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:ustation_frf_compliance_Rxyz}sub caption b} +#+attr_latex: :options {0.49\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.95\linewidth +[[file:figs/ustation_frf_compliance_Rxyz.png]] +#+end_subfigure +#+end_figure + ** Compare with the Model +<> + +The compliance of the micro-station is extracted from the Simscape model by computing the transfer function from forces/torques applied to the positioning hexapod's top platform to the "absolute" motion of the top platform. +These are compared with the measurements in Figure ref:fig:ustation_frf_compliance_model. +Considering how complex the micro-station compliance dynamics is, the model compliance is matching sufficiently well the measurements for the current application. #+begin_src matlab -%% Initialize simulation with default parameters (flexible elements) +%% Identification of the compliance of the micro-station + +% Initialize simulation with default parameters (flexible elements) initializeGround(); initializeGranite(); initializeTy(); @@ -1232,15 +1818,9 @@ initializeRz(); initializeMicroHexapod(); initializeReferences(); -initializeDisturbances(); initializeSimscapeConfiguration(); initializeLoggingConfiguration(); -#+end_src -And we identify the dynamics from forces/torques applied on the micro-hexapod top platform to the motion of the micro-hexapod top platform at the same point. - -#+begin_src matlab -%% Identification of the compliance % Input/Output definition clear io; io_i = 1; io(io_i) = linio([mdl, '/Micro-Station/Micro Hexapod/Flexible/Fm'], 1, 'openinput'); io_i = io_i + 1; % Direct Forces/Torques applied on the micro-hexapod top platform @@ -1256,12 +1836,12 @@ Gm.OutputName = {'Dx', 'Dy', 'Dz', 'Drx', 'Dry', 'Drz'}; %% Extracted FRF of the compliance of the micro-station in the Cartesian frame from the Simscape model figure; hold on; -plot(f, abs(squeeze(FRF_cartesian(1,1,:))), '.', 'color', colors(1,:), 'DisplayName', '$D_x/F_x$ - Measured') -plot(f, abs(squeeze(FRF_cartesian(2,2,:))), '.', 'color', colors(2,:), 'DisplayName', '$D_y/F_y$ - Measured') -plot(f, abs(squeeze(FRF_cartesian(3,3,:))), '.', 'color', colors(3,:), 'DisplayName', '$D_z/F_z$ - Measured') -plot(freqs, abs(squeeze(freqresp(Gm(1,1), freqs, 'Hz'))), '--', 'color', colors(1,:), 'DisplayName', '$D_x/F_x$ - Model') -plot(freqs, abs(squeeze(freqresp(Gm(2,2), freqs, 'Hz'))), '--', 'color', colors(2,:), 'DisplayName', '$D_y/F_y$ - Model') -plot(freqs, abs(squeeze(freqresp(Gm(3,3), freqs, 'Hz'))), '--', 'color', colors(3,:), 'DisplayName', '$D_z/F_z$ - Model') +plot(f, abs(squeeze(FRF_cartesian(1,1,:))), '-', 'color', [colors(1,:), 0.5], 'DisplayName', '$D_x/F_x$ - Measured') +plot(f, abs(squeeze(FRF_cartesian(2,2,:))), '-', 'color', [colors(2,:), 0.5], 'DisplayName', '$D_y/F_y$ - Measured') +plot(f, abs(squeeze(FRF_cartesian(3,3,:))), '-', 'color', [colors(3,:), 0.5], 'DisplayName', '$D_z/F_z$ - Measured') +plot(f, abs(squeeze(freqresp(Gm(1,1), f, 'Hz'))), '--', 'color', colors(1,:), 'DisplayName', '$D_x/F_x$ - Model') +plot(f, abs(squeeze(freqresp(Gm(2,2), f, 'Hz'))), '--', 'color', colors(2,:), 'DisplayName', '$D_y/F_y$ - Model') +plot(f, abs(squeeze(freqresp(Gm(3,3), f, 'Hz'))), '--', 'color', colors(3,:), 'DisplayName', '$D_z/F_z$ - Model') hold off; leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2); leg.ItemTokenSize(1) = 15; @@ -1271,46 +1851,356 @@ xlim([20, 500]); ylim([2e-10, 1e-6]); xticks([20, 50, 100, 200, 500]) #+end_src -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/ustation_frf_compliance_xyz_model.pdf', 'width', 'wide', 'height', 'normal'); +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/ustation_frf_compliance_xyz_model.pdf', 'width', 'half', 'height', 'normal'); #+end_src -#+name: fig:ustation_frf_compliance_xyz_model -#+caption: Extracted FRF of the compliance of the micro-station in the Cartesian frame from the Simscape model -#+RESULTS: -[[file:figs/ustation_frf_compliance_xyz_model.png]] - #+begin_src matlab :exports none :results none %% Extracted FRF of the compliance of the micro-station in the Cartesian frame from the Simscape model figure; hold on; -plot(f, abs(squeeze(FRF_cartesian(4,4,:))), '.', 'color', colors(1,:), 'DisplayName', '$R_x/M_x$ - Measured') -plot(f, abs(squeeze(FRF_cartesian(5,5,:))), '.', 'color', colors(2,:), 'DisplayName', '$R_y/M_y$ - Measured') -plot(f, abs(squeeze(FRF_cartesian(6,6,:))), '.', 'color', colors(3,:), 'DisplayName', '$R_z/M_z$ - Measured') -plot(freqs, abs(squeeze(freqresp(Gm(4,4), freqs, 'Hz'))), '--', 'color', colors(1,:), 'DisplayName', '$R_x/M_x$ - Model') -plot(freqs, abs(squeeze(freqresp(Gm(5,5), freqs, 'Hz'))), '--', 'color', colors(2,:), 'DisplayName', '$R_y/M_y$ - Model') -plot(freqs, abs(squeeze(freqresp(Gm(6,6), freqs, 'Hz'))), '--', 'color', colors(3,:), 'DisplayName', '$R_z/M_z$ - Model') +plot(f, abs(squeeze(FRF_cartesian(4,4,:))), '-', 'color', [colors(1,:), 0.5], 'DisplayName', '$R_x/M_x$ - Measured') +plot(f, abs(squeeze(FRF_cartesian(5,5,:))), '-', 'color', [colors(2,:), 0.5], 'DisplayName', '$R_y/M_y$ - Measured') +plot(f, abs(squeeze(FRF_cartesian(6,6,:))), '-', 'color', [colors(3,:), 0.5], 'DisplayName', '$R_z/M_z$ - Measured') +plot(f, abs(squeeze(freqresp(Gm(4,4), f, 'Hz'))), '--', 'color', colors(1,:), 'DisplayName', '$R_x/M_x$ - Model') +plot(f, abs(squeeze(freqresp(Gm(5,5), f, 'Hz'))), '--', 'color', colors(2,:), 'DisplayName', '$R_y/M_y$ - Model') +plot(f, abs(squeeze(freqresp(Gm(6,6), f, 'Hz'))), '--', 'color', colors(3,:), 'DisplayName', '$R_z/M_z$ - Model') hold off; leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2); leg.ItemTokenSize(1) = 15; set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); -xlabel('Frequency [Hz]'); ylabel('Magnitude [m/N]'); +xlabel('Frequency [Hz]'); ylabel('Magnitude [rad/Nm]'); xlim([20, 500]); ylim([2e-7, 1e-4]); xticks([20, 50, 100, 200, 500]) #+end_src -#+begin_src matlab :tangle no :exports results :results file replace -exportFig('figs/ustation_frf_compliance_Rxyz_model.pdf', 'width', 'wide', 'height', 'normal'); +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/ustation_frf_compliance_Rxyz_model.pdf', 'width', 'half', 'height', 'normal'); #+end_src -#+name: fig:ustation_frf_compliance_Rxyz_model -#+caption: Extracted FRF of the compliance of the micro-station in the Cartesian frame from the Simscape model -#+RESULTS: +#+name: fig:ustation_frf_compliance_model +#+caption: Measured FRF of the compliance of the micro-station expressed in frame $\{\mathcal{X}\}$. Both translation terms (\subref{fig:ustation_frf_compliance_xyz_model}) and rotational terms (\subref{fig:ustation_frf_compliance_Rxyz_model}) are displayed. +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:ustation_frf_compliance_xyz_model}sub caption a} +#+attr_latex: :options {0.49\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.95\linewidth +[[file:figs/ustation_frf_compliance_xyz_model.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:ustation_frf_compliance_Rxyz_model}sub caption b} +#+attr_latex: :options {0.49\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.95\linewidth [[file:figs/ustation_frf_compliance_Rxyz_model.png]] +#+end_subfigure +#+end_figure -** Get resonance frequencies +* Estimation of disturbances +:PROPERTIES: +:HEADER-ARGS:matlab+: :tangle matlab/ustation_3_disturbances.m +:END: +<> +** Introduction :ignore: + +The goal in this section is to obtain realistic representation of disturbances affecting the micro-station. +These disturbance sources will then be used during time domain simulations to accurately model the micro-station behavior. +The focus is made on stochastic disturbances, as it is in principle possible to calibrate the repeatable part of disturbances. +Such disturbance includes ground motion, and vibrations induces by the scanning of the translation stage and the spindle. + +In the multi-body model, stage vibrations are modelled as internal forces applied in the stage's joint. +In practice, the disturbance forces cannot be directly measured, and the effect of those perturbations on the vibration of the micro-station's top platform is measured instead (Section ref:ssec:ustation_disturbances_meas). + +To estimate the equivalent disturbance force that induces such vibration, the transfer function from disturbances sources (i.e. forces applied in the stages' joint) to the displacement of the micro-station's top platform with respect to the granite are extracted from the Simscape model (Section ref:ssec:ustation_disturbances_sensitivity). +Finally, the obtained disturbance sources are compared in Section ref:ssec:ustation_disturbances_results. + +** Matlab Init :noexport:ignore: #+begin_src matlab -%% Initialize simulation with default parameters (flexible elements) +%% ustation_3_disturbances.m +#+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 + +#+begin_src matlab :noweb yes +<> +#+end_src + +** Measurements of disturbances +<> +**** Introduction :ignore: +In this section, the ground motion disturbances is directly measured using geophones. +Vibrations induced by the scanning of the translation stage and of the spindle are also measured using dedicated setups. + +The tilt stage and the micro-hexapod also have positioning errors, they are however not modelled here as these two stages are only used for pre-positioning and not for scanning. +Therefore, from a control point of view, they are not important. + +**** TODO Ground Motion + +The ground motion is simply measured by using a sensitive 3-axis geophone placed on the ground. +The generated voltages are recorded with a high resolution DAC, and converted to displacement using the Geophone sensitivity transfer function. + +#+begin_src matlab +%% Ground Motion +% Load measured voltage generated by the geophone in X,Y and Z directions +load('ustation_dist_meas_ground_motion.mat', 'data'); + +% Sensitivity of the geophone +S0 = 88; % Sensitivity [V/(m/s)] +f0 = 2; % Cut-off frequency [Hz] + +S = S0*(s/2/pi/f0)/(1+s/2/pi/f0); + +% Estimate the velocity and displacement from the measured Voltage +est_vel = lsim(inv(G0*S)*(s/2/pi)/(1+s/2/pi), data(:, 1), data(:, 3)); % Estimated velocity above 1Hz +est_vel = est_vel - mean(est_vel(data(:,3)>10)); % The mean value of the velocity if removed +est_dis = lsim(1/(1+s/2/pi), est_vel, data(:, 3)); % The velocity is integrated above 1Hz +#+end_src + +**** Ty Stage + +To measure the positioning errors of the translation stage, the setup shown in Figure ref:fig:ustation_errors_ty_setup is used. +A special optical element (called a "straightness interferometer"[fn:9]) is fixed on top of the micro-station, while a laser source[fn:10] and a straightness reflector are fixed on the ground. +A similar setup is used to measure the horizontal deviation (i.e. in the $x$ direction), as well as the pitch and yaw errors of the translation stage. + +#+name: fig:ustation_errors_ty_setup +#+caption: Experimental setup to measure the flatness (vertical deviation) of the translation stage +[[file:figs/ustation_errors_ty_setup.png]] + +Six scans are performed between $-4.5\,mm$ and $4.5\,mm$. +The results for each individual scan are shown in Figure ref:fig:ustation_errors_dy_vertical. +As the measurement axis may not be perfectly aligned with the displacement axis of the translation stage, a linear fit may be removed from the measurement. +The remaining vertical displacement is shown in Figure ref:fig:ustation_errors_dy_vertical_remove_mean. +A vertical error of $\pm300\,nm$ induced by the translation stage is to be expected. +Similar result is obtain for the $x$ lateral direction. + +#+begin_src matlab +%% Ty errors +% Setpoint is in [mm] +% Vertical error is in [um] +ty_errors = load('ustation_errors_ty.mat'); + +% Compute best straight line to remove it from data +average_error = mean(ty_errors.ty_z')'; +straight_line = average_error - detrend(average_error, 1); +#+end_src + +#+begin_src matlab :exports none :results none +%% Measurement of the linear (vertical) deviation of the Translation stage +figure; +hold on; +plot(ty_errors.setpoint, ty_errors.ty_z(:,1), '-', 'color', colors(1,:), 'DisplayName', 'Raw data') +plot(ty_errors.setpoint, ty_errors.ty_z(:,2:end), '-', 'color', colors(1,:), 'HandleVisibility', 'off') +plot(ty_errors.setpoint, straight_line, '--', 'color', colors(2,:), 'DisplayName', 'Linear fit') +hold off; +xlabel('$D_y$ position [mm]'); ylabel('Vertical error [$\mu$m]'); +xlim([-5, 5]); ylim([-8, 8]); +legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +xticks([-5:1:5]); yticks([-8:2:8]); +exportFig('figs/ustation_errors_dy_vertical.pdf', 'width', 'half', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Measurement of the linear (vertical) deviation of the Translation stage - Remove best linear fit +figure; +plot(ty_errors.setpoint, ty_errors.ty_z - straight_line, 'k-') +xlabel('$D_y$ position [mm]'); ylabel('Vertical error [$\mu$m]'); +xlim([-5, 5]); ylim([-0.4, 0.4]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +xticks([-5:1:5]); yticks([-0.4:0.1:0.4]); +exportFig('figs/ustation_errors_dy_vertical_remove_mean.pdf', 'width', 'half', 'height', 'normal'); +#+end_src + +#+name: fig:ustation_errors_dy +#+caption: Measurement of the linear (vertical) deviation of the Translation stage (\subref{fig:ustation_errors_dy_vertical}). A linear fit is then removed from the data (\subref{fig:ustation_errors_dy_vertical_remove_mean}). +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:ustation_errors_dy_vertical}Measured vertical error} +#+attr_latex: :options {0.49\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.95\linewidth +[[file:figs/ustation_errors_dy_vertical.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:ustation_errors_dy_vertical_remove_mean}Error after removing linear fit} +#+attr_latex: :options {0.49\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.95\linewidth +[[file:figs/ustation_errors_dy_vertical_remove_mean.png]] +#+end_subfigure +#+end_figure + +#+begin_src matlab +%% Convert the data to frequency domain +% Suppose a certain constant velocity scan +delta_ty = (ty_errors.setpoint(end) - ty_errors.setpoint(1))/(length(ty_errors.setpoint) - 1); % [mm] +ty_vel = 8*1.125; % [mm/s] +Ts = delta_ty/ty_vel; +Fs = 1/Ts + +% Frequency Analysis +Nfft = floor(length(ty_errors.setpoint)); % Number of frequency points +win = hanning(Nfft); % Windowing +Noverlap = floor(Nfft/2); % Overlap for frequency analysis + +% Comnpute the power spectral density +[pxx_dy_dz, f_dy] = pwelch(1e-6*detrend(ty_errors.ty_z, 1), win, Noverlap, Nfft, Fs); +pxx_dy_dz = mean(pxx_dy_dz')'; +#+end_src + +**** Spindle + +In order to measure the positioning errors induced by the Spindle, a "Spindle error analyzer"[fn:7] is used as shown in Figure ref:fig:ustation_rz_meas_lion_setup. +A specific target is fixed on top of the micro-station which consists of two sphere with 1 inch diameter precisely aligned with the spindle rotation axis. +Five capacitive sensors[fn:8] are pointing at the two spheres as shown in Figure ref:fig:ustation_rz_meas_lion_zoom. +From the 5 measured displacements $[d_1,\,d_2,\,d_3,\,d_4,\,d_5]$, the translations and rotations $[D_x,\,D_y,\,D_z,\,R_x,\,R_y]$ of the target can be estimated. + +#+name: fig:ustation_rz_meas_lion_setup +#+caption: Experimental setup used to estimate the errors induced by the Spindle rotation (\subref{fig:ustation_rz_meas_lion}). The motion of the two reference sphere is done using 5 capacitive sensors (\subref{fig:ustation_rz_meas_lion_zoom}) +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:ustation_rz_meas_lion}Micro-station and 5-DoF metrology} +#+attr_latex: :options {0.49\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.9\linewidth +[[file:figs/ustation_rz_meas_lion.jpg]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:ustation_rz_meas_lion_zoom}Zoom on the metrology system} +#+attr_latex: :options {0.49\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.9\linewidth +[[file:figs/ustation_rz_meas_lion_zoom.jpg]] +#+end_subfigure +#+end_figure + +A measurement is performed at 60rpm during 10 turns, and the obtained results are shown in Figure ref:fig:ustation_errors_spindle. +A fraction of the radial (Figure ref:fig:ustation_errors_spindle_radial) and tilt (Figure ref:fig:ustation_errors_spindle_tilt) errors is linked to the fact that the two spheres are not perfectly aligned with the rotation axis of the Spindle. +However, it is in practice very difficult to align the "point-of-interest" of the sample with the rotation axis, so the NASS will be used to actively keep the PoI on the rotation axis. +The vertical motion induced by the scanning of the spindle is in the order of $\pm 30\,nm$ (Figure ref:fig:ustation_errors_spindle_axial). + +#+begin_src matlab +%% Spindle Errors +% Errors are already converted to x,y,z,Rx,Ry +% Units are in [m] and [rad] +spindle_errors = load('ustation_errors_spindle.mat'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Measured radial errors of the Spindle +figure; +plot(1e6*spindle_errors.Dx(1:100:end), 1e6*spindle_errors.Dy(1:100:end)) +xlabel('X displacement [$\mu$m]'); ylabel('Y displacement [$\mu$m]'); +axis equal +xlim([-1, 1]); ylim([-1, 1]); +xticks([-1, -0.5, 0, 0.5, 1]); +yticks([-1, -0.5, 0, 0.5, 1]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/ustation_errors_spindle_radial.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab +%% Measured axial errors of the Spindle +figure; +plot(spindle_errors.deg(1:100:end)/360, 1e9*spindle_errors.Dz(1:100:end)) +xlabel('Rotation [turn]'); ylabel('Z displacement [nm]'); +axis square +xlim([0,2]); ylim([-40, 40]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/ustation_errors_spindle_axial.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Measured tilt errors of the Spindle +figure; +plot(1e6*spindle_errors.Rx(1:100:end), 1e6*spindle_errors.Ry(1:100:end)) +xlabel('X angle [$\mu$rad]'); ylabel('Y angle [$\mu$rad]'); +axis equal +xlim([-35, 35]); ylim([-35, 35]); +xticks([-30, -15, 0, 15, 30]); +yticks([-30, -15, 0, 15, 30]); +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/ustation_errors_spindle_tilt.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+name: fig:ustation_errors_spindle +#+caption: Measurement of the radial (\subref{fig:ustation_errors_spindle_radial}), axial (\subref{fig:ustation_errors_spindle_axial}) and tilt (\subref{fig:ustation_errors_spindle_tilt}) Spindle errors during a 60rpm spindle rotation. +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:ustation_errors_spindle_radial}Radial errors} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.9\linewidth +[[file:figs/ustation_errors_spindle_radial.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:ustation_errors_spindle_axial}Axial error} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.9\linewidth +[[file:figs/ustation_errors_spindle_axial.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:ustation_errors_spindle_tilt}Tilt errors} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.9\linewidth +[[file:figs/ustation_errors_spindle_tilt.png]] +#+end_subfigure +#+end_figure + +#+begin_src matlab +%% Convert the data to frequency domain +Ts = (spindle_errors.t(end) - spindle_errors.t(1))/(length(spindle_errors.t)-1); % [s] +Fs = 1/Ts; % [Hz] + +% Frequency Analysis +Nfft = floor(2.0*Fs); % Number of frequency points +win = hanning(Nfft); % Windowing +Noverlap = floor(Nfft/2); % Overlap for frequency analysis + +% Comnpute the power spectral density +[pxx_rz_dz, f_rz] = pwelch(spindle_errors.Dz, win, Noverlap, Nfft, Fs); +[pxx_rz_dx, ~ ] = pwelch(spindle_errors.Dx, win, Noverlap, Nfft, Fs); +[pxx_rz_dy, ~ ] = pwelch(spindle_errors.Dy, win, Noverlap, Nfft, Fs); +[pxx_rz_rx, ~ ] = pwelch(spindle_errors.Rx, win, Noverlap, Nfft, Fs); +[pxx_rz_ry, ~ ] = pwelch(spindle_errors.Ry, win, Noverlap, Nfft, Fs); +#+end_src + +** Sensitivity to disturbances +<> + +In order to compute the disturbance source (i.e. forces) that induced the measured vibrations in Section ref:ssec:ustation_disturbances_meas, the transfer function from the disturbance sources to the stage vibration (i.e. the "sensitivity to disturbances") needs to be estimated. +This is done using the multi-body that was presented in Section ref:sec:ustation_modeling. +The obtained transfer functions are shown in Figure ref:fig:ustation_model_sensitivity. + +#+begin_src matlab +%% Extract sensitivity to disturbances from the Simscape model +% Initialize stages initializeGround(); initializeGranite(); initializeTy(); @@ -1318,99 +2208,189 @@ initializeRy(); initializeRz(); initializeMicroHexapod(); -initializeReferences(); initializeDisturbances(); -initializeSimscapeConfiguration(); +initializeSimscapeConfiguration('gravity', false); initializeLoggingConfiguration(); -#+end_src -And we identify the dynamics from forces/torques applied on the micro-hexapod top platform to the motion of the micro-hexapod top platform at the same point. - -#+begin_src matlab -%% Identification of the compliance -% Input/Output definition +% Configure inputs and outputs clear io; io_i = 1; -io(io_i) = linio([mdl, '/Micro-Station/Micro Hexapod/Flexible/Fm'], 1, 'openinput'); io_i = io_i + 1; % Direct Forces/Torques applied on the micro-hexapod top platform -io(io_i) = linio([mdl, '/Micro-Station/Micro Hexapod/Flexible/Dm'], 1, 'output'); io_i = io_i + 1; % Absolute displacement of the top platform +io(io_i) = linio([mdl, '/Disturbances/Dwx'], 1, 'openinput'); io_i = io_i + 1; % Vertical Ground Motion +io(io_i) = linio([mdl, '/Disturbances/Dwy'], 1, 'openinput'); io_i = io_i + 1; % Vertical Ground Motion +io(io_i) = linio([mdl, '/Disturbances/Dwz'], 1, 'openinput'); io_i = io_i + 1; % Vertical Ground Motion +io(io_i) = linio([mdl, '/Disturbances/Fty_x'], 1, 'openinput'); io_i = io_i + 1; % Parasitic force Ty +io(io_i) = linio([mdl, '/Disturbances/Fty_z'], 1, 'openinput'); io_i = io_i + 1; % Parasitic force Ty +io(io_i) = linio([mdl, '/Disturbances/Frz_x'], 1, 'openinput'); io_i = io_i + 1; % Parasitic force Rz +io(io_i) = linio([mdl, '/Disturbances/Frz_y'], 1, 'openinput'); io_i = io_i + 1; % Parasitic force Rz +io(io_i) = linio([mdl, '/Disturbances/Frz_z'], 1, 'openinput'); io_i = io_i + 1; % Parasitic force Rz +io(io_i) = linio([mdl, '/Micro-Station/metrology_6dof/x'], 1, 'openoutput'); io_i = io_i + 1; % Relative motion - Hexapod/Granite +io(io_i) = linio([mdl, '/Micro-Station/metrology_6dof/y'], 1, 'openoutput'); io_i = io_i + 1; % Relative motion - Hexapod/Granite +io(io_i) = linio([mdl, '/Micro-Station/metrology_6dof/z'], 1, 'openoutput'); io_i = io_i + 1; % Relative motion - Hexapod/Granite % Run the linearization -Gm = linearize(mdl, io, 0); -Gm.InputName = {'Fmx', 'Fmy', 'Fmz', 'Mmx', 'Mmy', 'Mmz'}; -Gm.OutputName = {'Dx', 'Dy', 'Dz', 'Drx', 'Dry', 'Drz'}; +Gd = linearize(mdl, io, 0); +Gd.InputName = {'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_x', 'Frz_y', 'Frz_z'}; +Gd.OutputName = {'Dx', 'Dy', 'Dz'}; +#+end_src + +#+begin_src matlab :exports none :tangle no +% The identified dynamics are then saved for further use. +save('matlab/mat/ustation_disturbance_sensitivity.mat', 'Gd') +#+end_src + +#+begin_src matlab :eval no +% The identified dynamics are then saved for further use. +save('./mat/ustation_disturbance_sensitivity.mat', 'Gd') +#+end_src + +#+begin_src matlab :exports none :results none +%% Sensitivity to Ground motion +freqs = logspace(log10(10), log10(2e2), 1000); + +figure; +hold on; +plot(freqs, abs(squeeze(freqresp(Gd('Dx', 'Dwx'), freqs, 'Hz'))), 'DisplayName', '$D_x/D_{xf}$'); +plot(freqs, abs(squeeze(freqresp(Gd('Dy', 'Dwy'), freqs, 'Hz'))), 'DisplayName', '$D_y/D_{yf}$'); +plot(freqs, abs(squeeze(freqresp(Gd('Dz', 'Dwz'), freqs, 'Hz'))), 'DisplayName', '$D_z/D_{zf}$'); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude [m/m]'); xlabel('Frequency [Hz]'); +leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/ustation_model_sensitivity_ground_motion.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Sensitivity to Translation stage disturbance forces +figure; +hold on; +plot(freqs, abs(squeeze(freqresp(Gd('Dx', 'Fty_x'), freqs, 'Hz'))), 'color', colors(1,:), 'DisplayName', '$D_x/F_{xD_y}$'); +plot(freqs, abs(squeeze(freqresp(Gd('Dz', 'Fty_z'), freqs, 'Hz'))), 'color', colors(3,:), 'DisplayName', '$D_z/F_{zD_y}$'); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); +ylim([1e-10, 1e-7]); +leg = legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/ustation_model_sensitivity_ty.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+begin_src matlab :exports none :results none +%% Sensitivity to Spindle disturbance forces +figure; +hold on; +plot(freqs, abs(squeeze(freqresp(Gd('Dx', 'Frz_x'), freqs, 'Hz'))), 'DisplayName', '$D_x/F_{xR_z}$'); +plot(freqs, abs(squeeze(freqresp(Gd('Dy', 'Frz_y'), freqs, 'Hz'))), 'DisplayName', '$D_y/F_{yR_z}$'); +plot(freqs, abs(squeeze(freqresp(Gd('Dz', 'Frz_z'), freqs, 'Hz'))), 'DisplayName', '$D_z/F_{zR_z}$'); +hold off; +set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log'); +ylabel('Amplitude [m/N]'); xlabel('Frequency [Hz]'); +ylim([1e-10, 1e-7]); +leg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1); +leg.ItemTokenSize(1) = 15; +#+end_src + +#+begin_src matlab :tangle no :exports results :results file none +exportFig('figs/ustation_model_sensitivity_rz.pdf', 'width', 'third', 'height', 'normal'); +#+end_src + +#+name: fig:ustation_model_sensitivity +#+caption: Extracted transfer functions from disturbances to relative motion between the micro-station's top platform and the granite. The considered disturbances are the ground motion (\subref{fig:ustation_model_sensitivity_ground_motion}), the translation stage vibrations (\subref{fig:ustation_model_sensitivity_ty}), and the spindle vibrations (\subref{fig:ustation_model_sensitivity_rz}). +#+attr_latex: :options [htbp] +#+begin_figure +#+attr_latex: :caption \subcaption{\label{fig:ustation_model_sensitivity_ground_motion}Ground motion} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.9\linewidth +[[file:figs/ustation_model_sensitivity_ground_motion.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:ustation_model_sensitivity_ty}Translation stage} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.9\linewidth +[[file:figs/ustation_model_sensitivity_ty.png]] +#+end_subfigure +#+attr_latex: :caption \subcaption{\label{fig:ustation_model_sensitivity_rz}Spindle} +#+attr_latex: :options {0.33\textwidth} +#+begin_subfigure +#+attr_latex: :width 0.9\linewidth +[[file:figs/ustation_model_sensitivity_rz.png]] +#+end_subfigure +#+end_figure + +** TODO Obtained disturbance sources +<> + +- [ ] Display PSD of disturbances + +#+begin_src matlab +rz.psd_f = rz.pxsp_r./abs(squeeze(freqresp(G('Dz', 'Frz'), rz.f, 'Hz'))).^2; +tyz.psd_f = tyz.pxz_ty_r./abs(squeeze(freqresp(G('Dz', 'Fty'), tyz.f, 'Hz'))).^2; #+end_src #+begin_src matlab -modes_freq = imag(eig(Gm))/2/pi; -modes_freq = sort(modes_freq(modes_freq>0)); +dist_f = struct(); + +dist_f.f = gm.f; % Frequency Vector [Hz] + +dist_f.psd_gm = gm.psd_gm; % Power Spectral Density of the Ground Motion [m^2/Hz] +dist_f.psd_ty = tyz.psd_f; % Power Spectral Density of the force induced by the Ty stage in the Z direction [N^2/Hz] +dist_f.psd_rz = rz.psd_f; % Power Spectral Density of the force induced by the Rz stage in the Z direction [N^2/Hz] + +save('./mat/dist_psd.mat', 'dist_f'); #+end_src -#+begin_src matlab :exports results :results value table replace :tangle no :post addhdr(*this*) -data2orgtable([modes_freq(1:16), [11.9, 18.6, 37.8, 39.1, 56.3, 69.8, 72.5, 84.8, 91.3, 105.5, 106.6, 112.7, 124.2, 145.3, 150.5, 165.4]'], {'1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16'}, {'Mode', 'Simscape', 'Modal analysis'}, ' %.1f '); +The obtained amplitude spectral densities of the disturbance forces are shown in Figure ref:fig:dist_force_psd. + +#+begin_src matlab :exports none +figure; +hold on; +set(gca,'ColorOrderIndex',2); +plot(tyz.f, sqrt(tyz.psd_f), 'DisplayName', 'F - Ty'); +plot(rz.f, sqrt(rz.psd_f), 'DisplayName', 'F - Rz'); +hold off; +set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log'); +xlabel('Frequency [Hz]'); ylabel('ASD of the disturbance force $\left[\frac{N}{\sqrt{Hz}}\right]$') +legend('Location', 'southwest'); +xlim([2, 500]); #+end_src -#+RESULTS: -| Mode | Simscape | Modal analysis | -|------+----------+----------------| -| 1 | 11.7 | 11.9 | -| 2 | 21.3 | 18.6 | -| 3 | 26.1 | 37.8 | -| 4 | 57.5 | 39.1 | -| 5 | 60.6 | 56.3 | -| 6 | 73.0 | 69.8 | -| 7 | 97.9 | 72.5 | -| 8 | 120.2 | 84.8 | -| 9 | 126.2 | 91.3 | -| 10 | 142.4 | 105.5 | -| 11 | 155.9 | 106.6 | -| 12 | 178.5 | 112.7 | -| 13 | 179.3 | 124.2 | -| 14 | 182.6 | 145.3 | -| 15 | 223.6 | 150.5 | -| 16 | 226.4 | 165.4 | - -** Conclusion -For such a complex system, we believe that the Simscape Model represents the dynamics of the system with enough fidelity. - -* Measurement of Positioning Errors -:PROPERTIES: -:HEADER-ARGS:matlab+: :tangle matlab/ustation_2_kinematics.m -:END: -<> -** Introduction :ignore: - -[[file:~/Cloud/work-projects/ID31-NASS/matlab/nass-simscape/org/kinematics.org]] - -** 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 - - - * Simulation of Scientific Experiments :PROPERTIES: -:HEADER-ARGS:matlab+: :tangle matlab/.m +:HEADER-ARGS:matlab+: :tangle matlab/ustation_4_experiments.m :END: -<> +<> + ** Introduction :ignore: +- [ ] Perfect tomography => no error +- [ ] Add vibrations and some off-center => results, compare with measurements +- [ ] Ty scans (-4.5mm to 4.5mm) => compare with measurements + +# The goal here is to simulate some scientific experiments with the Simscape model when no control is applied to the nano-hexapod. + +# This has several goals: +# - Validate the model +# - Estimate the expected error motion for the experiments +# - Estimate the stroke that we may need for the nano-hexapod +# - Compare with experiments when control is applied + +# The document in organized as follow: +# - In section ref:sec:tomo_no_dist a tomography experiment is performed where the sample is aligned with the rotation axis. No disturbance is included +# - In section ref:sec:tomo_dist, the same is done but with disturbance included +# - In section ref:sec:tomo_hexa_trans the micro-hexapod translate the sample such that its center of mass is no longer aligned with the rotation axis. No disturbance is included +# - In section ref:sec:ty_scans, scans with the translation stage are simulated with no perturbation included + ** Matlab Init :noexport:ignore: +#+begin_src matlab +%% ustation_4_experiments.m +#+end_src + #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> #+end_src @@ -1432,8 +2412,141 @@ For such a complex system, we believe that the Simscape Model represents the dyn #+end_src -* Estimation of disturbances -This was already done in uni-axial model. +** Tomography Experiment with no disturbances +#+begin_src matlab +%% Prepare the Simscape model for simulation +load('mat/conf_simulink.mat'); +set_param(conf_simulink, 'StopTime', '10'); + +initializeGround(); +initializeGranite(); +initializeTy(); +initializeRy(); +initializeRz(); +initializeMicroHexapod(); + +initializeSimscapeConfiguration('gravity', false); +initializeLoggingConfiguration('log', 'all'); +#+end_src + +#+begin_src matlab +%% First, perform "perfect tomography experiment" +initializeDisturbances(... + 'Dwx', false, ... % Ground Motion - X direction + 'Dwy', false, ... % Ground Motion - Y direction + 'Dwz', false, ... % Ground Motion - Z direction + 'Fty_x', false, ... % Translation Stage - X direction + 'Fty_z', false, ... % Translation Stage - Z direction + 'Frz_x', false, ... % Spindle - X direction + 'Frz_y', false, ... % Spindle - Y direction + 'Frz_z', false); % Spindle - Z direction + +initializeReferences(... + 'Rz_type', 'rotating', ... + 'Rz_period', 1); + +sim(mdl) +tomo_align_no_dist = simout; +#+end_src + +#+begin_src matlab +start_t = 5; +#+end_src + +#+begin_src matlab :exports none +figure; +hold on; +plot(tomo_align_no_dist.y.x.Time(1e3*start_t+1:end)-start_t, 1e9*tomo_align_no_dist.y.x.Data(1e3*start_t+1:end)) +plot(tomo_align_no_dist.y.y.Time(1e3*start_t+1:end)-start_t, 1e9*tomo_align_no_dist.y.y.Data(1e3*start_t+1:end)) +plot(tomo_align_no_dist.y.z.Time(1e3*start_t+1:end)-start_t, 1e9*detrend(tomo_align_no_dist.y.z.Data(1e3*start_t+1:end), 0)) +hold off; +xlabel('Time [s]'); +ylabel('Error [nm]') +#+end_src + +** Tomography Experiment with included disturbances +#+begin_src matlab +%% Prepare the Simscape model for simulation +load('mat/conf_simulink.mat'); +set_param(conf_simulink, 'StopTime', '2'); + +initializeGround(); +initializeGranite(); +initializeTy(); +initializeRy(); +initializeRz(); +initializeMicroHexapod(); + +initializeSimscapeConfiguration('gravity', false); +initializeLoggingConfiguration('log', 'all'); + +initializeDisturbances(... + 'Dwx', true, ... % Ground Motion - X direction + 'Dwy', true, ... % Ground Motion - Y direction + 'Dwz', true, ... % Ground Motion - Z direction + 'Fty_x', false, ... % Translation Stage - X direction + 'Fty_z', false, ... % Translation Stage - Z direction + 'Frz_x', false, ... % Spindle - X direction + 'Frz_y', false, ... % Spindle - Y direction + 'Frz_z', true); % Spindle - Z direction + +initializeReferences(... + 'Rz_type', 'rotating', ... + 'Rz_period', 1); + +sim(mdl) +tomo_align_dist = simout; +#+end_src + +#+begin_src matlab :exports none +figure; +hold on; +plot(tomo_align_dist.y.x.Time, tomo_align_dist.y.x.Data) +plot(tomo_align_dist.y.y.Time, tomo_align_dist.y.y.Data) +plot(tomo_align_dist.y.z.Time, tomo_align_dist.y.z.Data) +hold off; +#+end_src + +** Tomography when the micro-hexapod is not centered +#+begin_src matlab +%% Tomography when the micro-hexapod is not centered by 1um +P_micro_hexapod = [1e-6; 0; 0]; % [m] +initializeMicroHexapod('AP', P_micro_hexapod); + +initializeDisturbances(... + 'Dwx', false, ... % Ground Motion - X direction + 'Dwy', false, ... % Ground Motion - Y direction + 'Dwz', false, ... % Ground Motion - Z direction + 'Fty_x', false, ... % Translation Stage - X direction + 'Fty_z', false, ... % Translation Stage - Z direction + 'Frz_x', false, ... % Spindle - X direction + 'Frz_y', false, ... % Spindle - Y direction + 'Frz_z', false); % Spindle - Z direction + +initializeReferences(... + 'Rz_type', 'rotating', ... + 'Rz_period', 1, ... + 'Dh_pos', [P_micro_hexapod; 0; 0; 0]); + +sim(mdl); +tomo_not_align = simout; +#+end_src + +#+begin_src matlab :exports none +figure; +hold on; +plot(1e6*tomo_not_align.y.x.Data, 1e6*tomo_not_align.y.y.Data) +hold off; +#+end_src + +** Raster Scans with the translation stage +<> +#+begin_src matlab + initializeReferences('Dy_type', 'triangular', 'Dy_amplitude', 10e-3, 'Dy_period', 1); + sim(mdl); + ty_scan_triangle = simout; + % save('./mat/experiment_tomography.mat', 'ty_scan_triangle', '-append'); +#+end_src * Conclusion <> @@ -1482,25 +2595,20 @@ colors = colororder; %% Frequency Vector freqs = logspace(log10(10), log10(2e3), 1000); #+END_SRC + * Matlab Functions :noexport: -** Simscape Configuration +** =initializeSimscapeConfiguration=: Simscape Configuration :PROPERTIES: :header-args:matlab+: :tangle matlab/src/initializeSimscapeConfiguration.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: *** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab function [] = initializeSimscapeConfiguration(args) #+end_src *** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab arguments args.gravity logical {mustBeNumericOrLogical} = true @@ -1508,17 +2616,11 @@ freqs = logspace(log10(10), log10(2e3), 1000); #+end_src *** Structure initialization -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab conf_simscape = struct(); #+end_src *** Add Type -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab if args.gravity conf_simscape.type = 1; @@ -1544,24 +2646,18 @@ elseif exist('./matlab', 'dir') end #+end_src -** Logging Configuration +** =initializeLoggingConfiguration=: Logging Configuration :PROPERTIES: :header-args:matlab+: :tangle matlab/src/initializeLoggingConfiguration.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: *** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab function [] = initializeLoggingConfiguration(args) #+end_src *** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab arguments args.log char {mustBeMember(args.log,{'none', 'all', 'forces'})} = 'none' @@ -1570,17 +2666,11 @@ end #+end_src *** Structure initialization -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab conf_log = struct(); #+end_src *** Add Type -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab switch args.log case 'none' @@ -1593,9 +2683,6 @@ end #+end_src *** Sampling Time -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab conf_log.Ts = args.Ts; #+end_src @@ -1617,674 +2704,18 @@ elseif exist('./matlab', 'dir') end #+end_src -** Ground -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/initializeGround.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [ground] = initializeGround(args) -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - args.type char {mustBeMember(args.type,{'none', 'rigid'})} = 'rigid' - args.rot_point (3,1) double {mustBeNumeric} = zeros(3,1) % Rotation point for the ground motion [m] - end -#+end_src - -*** Structure initialization -:PROPERTIES: -:UNNUMBERED: t -:END: -First, we initialize the =granite= structure. -#+begin_src matlab - ground = struct(); -#+end_src - -*** Add Type -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - switch args.type - case 'none' - ground.type = 0; - case 'rigid' - ground.type = 1; - end -#+end_src - -*** Ground Solid properties -:PROPERTIES: -:UNNUMBERED: t -:END: -We set the shape and density of the ground solid element. -#+begin_src matlab - ground.shape = [2, 2, 0.5]; % [m] - ground.density = 2800; % [kg/m3] -#+end_src - -*** Rotation Point -:PROPERTIES: -:UNNUMBERED: t -:END: - -#+begin_src matlab - ground.rot_point = args.rot_point; -#+end_src - -*** Save the Structure -#+begin_src matlab -if exist('./mat', 'dir') - if exist('./mat/nass_stages.mat', 'file') - save('mat/nass_stages.mat', 'ground', '-append'); - else - save('mat/nass_stages.mat', 'ground'); - end -elseif exist('./matlab', 'dir') - if exist('./matlab/mat/nass_stages.mat', 'file') - save('matlab/mat/nass_stages.mat', 'ground', '-append'); - else - save('matlab/mat/nass_stages.mat', 'ground'); - end -end -#+end_src - -** Granite -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/initializeGranite.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [granite] = initializeGranite(args) -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - args.type char {mustBeMember(args.type,{'rigid', 'flexible', 'none'})} = 'flexible' - args.density (1,1) double {mustBeNumeric, mustBeNonnegative} = 2800 % Density [kg/m3] - args.K (6,1) double {mustBeNumeric, mustBeNonnegative} = [5e9; 5e9; 5e9; 2.5e7; 2.5e7; 1e7] % [N/m] - args.C (6,1) double {mustBeNumeric, mustBeNonnegative} = [4.0e5; 1.1e5; 9.0e5; 2e4; 2e4; 1e4] % [N/(m/s)] - args.x0 (1,1) double {mustBeNumeric} = 0 % Rest position of the Joint in the X direction [m] - args.y0 (1,1) double {mustBeNumeric} = 0 % Rest position of the Joint in the Y direction [m] - args.z0 (1,1) double {mustBeNumeric} = 0 % Rest position of the Joint in the Z direction [m] - args.sample_pos (1,1) double {mustBeNumeric} = 0.8 % Height of the measurment point [m] - end -#+end_src - -*** Structure initialization -:PROPERTIES: -:UNNUMBERED: t -:END: -First, we initialize the =granite= structure. -#+begin_src matlab - granite = struct(); -#+end_src - -*** Add Granite Type -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - switch args.type - case 'none' - granite.type = 0; - case 'rigid' - granite.type = 1; - case 'flexible' - granite.type = 2; - end -#+end_src - -*** Material and Geometry -:PROPERTIES: -:UNNUMBERED: t -:END: - -Properties of the Material and link to the geometry of the granite. -#+begin_src matlab - granite.density = args.density; % [kg/m3] - granite.STEP = 'granite.STEP'; -#+end_src - -Z-offset for the initial position of the sample with respect to the granite top surface. -#+begin_src matlab - granite.sample_pos = args.sample_pos; % [m] -#+end_src - -*** Stiffness and Damping properties -:PROPERTIES: -:UNNUMBERED: t -:END: - -#+begin_src matlab - granite.K = args.K; % [N/m] - granite.C = args.C; % [N/(m/s)] -#+end_src - -*** Save the Structure -#+begin_src matlab -if exist('./mat', 'dir') - if exist('./mat/nass_stages.mat', 'file') - save('mat/nass_stages.mat', 'granite', '-append'); - else - save('mat/nass_stages.mat', 'granite'); - end -elseif exist('./matlab', 'dir') - if exist('./matlab/mat/nass_stages.mat', 'file') - save('matlab/mat/nass_stages.mat', 'granite', '-append'); - else - save('matlab/mat/nass_stages.mat', 'granite'); - end -end -#+end_src - -** Translation Stage -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/initializeTy.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [ty] = initializeTy(args) -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - args.type char {mustBeMember(args.type,{'none', 'rigid', 'flexible'})} = 'flexible' - end -#+end_src - -*** Structure initialization -:PROPERTIES: -:UNNUMBERED: t -:END: -First, we initialize the =ty= structure. -#+begin_src matlab - ty = struct(); -#+end_src - -*** Add Translation Stage Type -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - switch args.type - case 'none' - ty.type = 0; - case 'rigid' - ty.type = 1; - case 'flexible' - ty.type = 2; - end -#+end_src - -*** Material and Geometry -:PROPERTIES: -:UNNUMBERED: t -:END: -Define the density of the materials as well as the geometry (STEP files). -#+begin_src matlab - % Ty Granite frame - ty.granite_frame.density = 7800; % [kg/m3] => 43kg - ty.granite_frame.STEP = 'Ty_Granite_Frame.STEP'; - - % Guide Translation Ty - ty.guide.density = 7800; % [kg/m3] => 76kg - ty.guide.STEP = 'Ty_Guide.STEP'; - - % Ty - Guide_Translation12 - ty.guide12.density = 7800; % [kg/m3] - ty.guide12.STEP = 'Ty_Guide_12.STEP'; - - % Ty - Guide_Translation11 - ty.guide11.density = 7800; % [kg/m3] - ty.guide11.STEP = 'Ty_Guide_11.STEP'; - - % Ty - Guide_Translation22 - ty.guide22.density = 7800; % [kg/m3] - ty.guide22.STEP = 'Ty_Guide_22.STEP'; - - % Ty - Guide_Translation21 - ty.guide21.density = 7800; % [kg/m3] - ty.guide21.STEP = 'Ty_Guide_21.STEP'; - - % Ty - Plateau translation - ty.frame.density = 7800; % [kg/m3] - ty.frame.STEP = 'Ty_Stage.STEP'; - - % Ty Stator Part - ty.stator.density = 5400; % [kg/m3] - ty.stator.STEP = 'Ty_Motor_Stator.STEP'; - - % Ty Rotor Part - ty.rotor.density = 5400; % [kg/m3] - ty.rotor.STEP = 'Ty_Motor_Rotor.STEP'; -#+end_src - -*** Stiffness and Damping properties -:PROPERTIES: -:UNNUMBERED: t -:END: - -#+begin_src matlab - ty.K = [2e8; 1e8; 2e8; 6e7; 9e7; 6e7]; % [N/m, N*m/rad] - ty.C = [8e4; 5e4; 8e4; 2e4; 3e4; 1e4]; % [N/(m/s), N*m/(rad/s)] -#+end_src - -*** Save the Structure -#+begin_src matlab -if exist('./mat', 'dir') - if exist('./mat/nass_stages.mat', 'file') - save('mat/nass_stages.mat', 'ty', '-append'); - else - save('mat/nass_stages.mat', 'ty'); - end -elseif exist('./matlab', 'dir') - if exist('./matlab/mat/nass_stages.mat', 'file') - save('matlab/mat/nass_stages.mat', 'ty', '-append'); - else - save('matlab/mat/nass_stages.mat', 'ty'); - end -end -#+end_src - -** Tilt Stage -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/initializeRy.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [ry] = initializeRy(args) -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - args.type char {mustBeMember(args.type,{'none', 'rigid', 'flexible'})} = 'flexible' - args.Ry_init (1,1) double {mustBeNumeric} = 0 - end -#+end_src - -*** Structure initialization -:PROPERTIES: -:UNNUMBERED: t -:END: -First, we initialize the =ry= structure. -#+begin_src matlab - ry = struct(); -#+end_src - - -*** Add Tilt Type -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - switch args.type - case 'none' - ry.type = 0; - case 'rigid' - ry.type = 1; - case 'flexible' - ry.type = 2; - end -#+end_src - -*** Material and Geometry -:PROPERTIES: -:UNNUMBERED: t -:END: -Properties of the Material and link to the geometry of the Tilt stage. -#+begin_src matlab - % Ry - Guide for the tilt stage - ry.guide.density = 7800; % [kg/m3] - ry.guide.STEP = 'Tilt_Guide.STEP'; - - % Ry - Rotor of the motor - ry.rotor.density = 2400; % [kg/m3] - ry.rotor.STEP = 'Tilt_Motor_Axis.STEP'; - - % Ry - Motor - ry.motor.density = 3200; % [kg/m3] - ry.motor.STEP = 'Tilt_Motor.STEP'; - - % Ry - Plateau Tilt - ry.stage.density = 7800; % [kg/m3] - ry.stage.STEP = 'Tilt_Stage.STEP'; -#+end_src - -Z-Offset so that the center of rotation matches the sample center; -#+begin_src matlab - ry.z_offset = 0.58178; % [m] -#+end_src - -#+begin_src matlab - ry.Ry_init = args.Ry_init; % [rad] -#+end_src - -*** Stiffness and Damping properties -:PROPERTIES: -:UNNUMBERED: t -:END: - -#+begin_src matlab - ry.K = [3.8e8; 4e8; 3.8e8; 1.2e8; 6e4; 1.2e8]; - ry.C = [1e5; 1e5; 1e5; 3e4; 1e3; 3e4]; -#+end_src - -*** Save the Structure -#+begin_src matlab -if exist('./mat', 'dir') - if exist('./mat/nass_stages.mat', 'file') - save('mat/nass_stages.mat', 'ry', '-append'); - else - save('mat/nass_stages.mat', 'ry'); - end -elseif exist('./matlab', 'dir') - if exist('./matlab/mat/nass_stages.mat', 'file') - save('matlab/mat/nass_stages.mat', 'ry', '-append'); - else - save('matlab/mat/nass_stages.mat', 'ry'); - end -end -#+end_src - -** Spindle -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/initializeRz.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [rz] = initializeRz(args) -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - args.type char {mustBeMember(args.type,{'none', 'rigid', 'flexible'})} = 'flexible' - end -#+end_src - -*** Structure initialization -:PROPERTIES: -:UNNUMBERED: t -:END: -First, we initialize the =rz= structure. -#+begin_src matlab - rz = struct(); -#+end_src - -*** Add Spindle Type -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - switch args.type - case 'none' - rz.type = 0; - case 'rigid' - rz.type = 1; - case 'flexible' - rz.type = 2; - end -#+end_src - -*** Material and Geometry -:PROPERTIES: -:UNNUMBERED: t -:END: - -Properties of the Material and link to the geometry of the spindle. -#+begin_src matlab - % Spindle - Slip Ring - rz.slipring.density = 7800; % [kg/m3] - rz.slipring.STEP = 'Spindle_Slip_Ring.STEP'; - - % Spindle - Rotor - rz.rotor.density = 7800; % [kg/m3] - rz.rotor.STEP = 'Spindle_Rotor.STEP'; - - % Spindle - Stator - rz.stator.density = 7800; % [kg/m3] - rz.stator.STEP = 'Spindle_Stator.STEP'; -#+end_src - -*** Stiffness and Damping properties -:PROPERTIES: -:UNNUMBERED: t -:END: - -#+begin_src matlab - rz.K = [7e8; 7e8; 2e9; 1e7; 1e7; 1e7]; - rz.C = [4e4; 4e4; 7e4; 1e4; 1e4; 1e4]; -#+end_src - -*** Save the Structure -#+begin_src matlab -if exist('./mat', 'dir') - if exist('./mat/nass_stages.mat', 'file') - save('mat/nass_stages.mat', 'rz', '-append'); - else - save('mat/nass_stages.mat', 'rz'); - end -elseif exist('./matlab', 'dir') - if exist('./matlab/mat/nass_stages.mat', 'file') - save('matlab/mat/nass_stages.mat', 'rz', '-append'); - else - save('matlab/mat/nass_stages.mat', 'rz'); - end -end -#+end_src - -** Micro Hexapod -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/initializeMicroHexapod.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [micro_hexapod] = initializeMicroHexapod(args) -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - args.type char {mustBeMember(args.type,{'none', 'rigid', 'flexible'})} = 'flexible' - % initializeFramesPositions - args.H (1,1) double {mustBeNumeric, mustBePositive} = 350e-3 - args.MO_B (1,1) double {mustBeNumeric} = 270e-3 - % generateGeneralConfiguration - args.FH (1,1) double {mustBeNumeric, mustBePositive} = 50e-3 - args.FR (1,1) double {mustBeNumeric, mustBePositive} = 175.5e-3 - args.FTh (6,1) double {mustBeNumeric} = [-10, 10, 120-10, 120+10, 240-10, 240+10]*(pi/180) - args.MH (1,1) double {mustBeNumeric, mustBePositive} = 45e-3 - args.MR (1,1) double {mustBeNumeric, mustBePositive} = 118e-3 - args.MTh (6,1) double {mustBeNumeric} = [-60+10, 60-10, 60+10, 180-10, 180+10, -60-10]*(pi/180) - % initializeStrutDynamics - args.Ki (6,1) double {mustBeNumeric, mustBeNonnegative} = 2e7*ones(6,1) - args.Ci (6,1) double {mustBeNumeric, mustBeNonnegative} = 1.4e3*ones(6,1) - % initializeCylindricalPlatforms - args.Fpm (1,1) double {mustBeNumeric, mustBePositive} = 10 - args.Fph (1,1) double {mustBeNumeric, mustBePositive} = 26e-3 - args.Fpr (1,1) double {mustBeNumeric, mustBePositive} = 207.5e-3 - args.Mpm (1,1) double {mustBeNumeric, mustBePositive} = 10 - args.Mph (1,1) double {mustBeNumeric, mustBePositive} = 26e-3 - args.Mpr (1,1) double {mustBeNumeric, mustBePositive} = 150e-3 - % initializeCylindricalStruts - args.Fsm (1,1) double {mustBeNumeric, mustBePositive} = 1 - args.Fsh (1,1) double {mustBeNumeric, mustBePositive} = 100e-3 - args.Fsr (1,1) double {mustBeNumeric, mustBePositive} = 25e-3 - args.Msm (1,1) double {mustBeNumeric, mustBePositive} = 1 - args.Msh (1,1) double {mustBeNumeric, mustBePositive} = 100e-3 - args.Msr (1,1) double {mustBeNumeric, mustBePositive} = 25e-3 - % inverseKinematics - args.AP (3,1) double {mustBeNumeric} = zeros(3,1) - args.ARB (3,3) double {mustBeNumeric} = eye(3) - end -#+end_src - -*** Function content -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - stewart = initializeStewartPlatform(); - - stewart = initializeFramesPositions(stewart, ... - 'H', args.H, ... - 'MO_B', args.MO_B); - - stewart = generateGeneralConfiguration(stewart, ... - 'FH', args.FH, ... - 'FR', args.FR, ... - 'FTh', args.FTh, ... - 'MH', args.MH, ... - 'MR', args.MR, ... - 'MTh', args.MTh); - - stewart = computeJointsPose(stewart); -#+end_src - -#+begin_src matlab - stewart = initializeStrutDynamics(stewart, ... - 'K', args.Ki, ... - 'C', args.Ci); - - stewart = initializeJointDynamics(stewart, ... - 'type_F', 'universal_p', ... - 'type_M', 'spherical_p'); -#+end_src - -#+begin_src matlab - stewart = initializeCylindricalPlatforms(stewart, ... - 'Fpm', args.Fpm, ... - 'Fph', args.Fph, ... - 'Fpr', args.Fpr, ... - 'Mpm', args.Mpm, ... - 'Mph', args.Mph, ... - 'Mpr', args.Mpr); - - stewart = initializeCylindricalStruts(stewart, ... - 'Fsm', args.Fsm, ... - 'Fsh', args.Fsh, ... - 'Fsr', args.Fsr, ... - 'Msm', args.Msm, ... - 'Msh', args.Msh, ... - 'Msr', args.Msr); - - stewart = computeJacobian(stewart); - - stewart = initializeStewartPose(stewart, ... - 'AP', args.AP, ... - 'ARB', args.ARB); -#+end_src - -#+begin_src matlab - stewart = initializeInertialSensor(stewart, 'type', 'none'); -#+end_src - -*** Add Type -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - switch args.type - case 'none' - stewart.type = 0; - case 'rigid' - stewart.type = 1; - case 'flexible' - stewart.type = 2; - end -#+end_src - -*** Save the Structure -#+begin_src matlab -micro_hexapod = stewart; -if exist('./mat', 'dir') - if exist('./mat/nass_stages.mat', 'file') - save('mat/nass_stages.mat', 'micro_hexapod', '-append'); - else - save('mat/nass_stages.mat', 'micro_hexapod'); - end -elseif exist('./matlab', 'dir') - if exist('./matlab/mat/nass_stages.mat', 'file') - save('matlab/mat/nass_stages.mat', 'micro_hexapod', '-append'); - else - save('matlab/mat/nass_stages.mat', 'micro_hexapod'); - end -end -#+end_src - -** Generate Reference Signals +** =initializeReferences=: Generate Reference Signals :PROPERTIES: :header-args:matlab+: :tangle matlab/src/initializeReferences.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: *** Function Declaration and Documentation -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab function [ref] = initializeReferences(args) #+end_src *** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab arguments % Sampling Frequency [s] @@ -2326,9 +2757,6 @@ end *** Initialize Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab %% Set Sampling Time Ts = args.Ts; @@ -2342,9 +2770,6 @@ end #+end_src *** Translation Stage -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab %% Translation stage - Dy t = 0:Ts:Tmax; % Time Vector [s] @@ -2379,9 +2804,6 @@ end #+end_src *** Tilt Stage -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab %% Tilt Stage - Ry t = 0:Ts:Tmax; % Time Vector [s] @@ -2417,9 +2839,6 @@ end #+end_src *** Spindle -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab %% Spindle - Rz t = 0:Ts:Tmax; % Time Vector [s] @@ -2461,9 +2880,6 @@ end #+end_src *** Micro Hexapod -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab %% Micro-Hexapod t = [0, Ts]; @@ -2520,7 +2936,7 @@ end #+end_src -** Initialize Disturbances +** =initializeDisturbances=: Initialize Disturbances :PROPERTIES: :header-args:matlab+: :tangle matlab/src/initializeDisturbances.m :header-args:matlab+: :comments none :mkdirp yes @@ -2528,133 +2944,118 @@ end :END: *** Function Declaration and Documentation -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab - function [] = initializeDisturbances(args) - % initializeDisturbances - Initialize the disturbances - % - % Syntax: [] = initializeDisturbances(args) - % - % Inputs: - % - args - +function [] = initializeDisturbances(args) +% initializeDisturbances - Initialize the disturbances +% +% Syntax: [] = initializeDisturbances(args) +% +% Inputs: +% - args - #+end_src *** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab - arguments - % Global parameter to enable or disable the disturbances - args.enable logical {mustBeNumericOrLogical} = true - % Ground Motion - X direction - args.Dwx logical {mustBeNumericOrLogical} = true - % Ground Motion - Y direction - args.Dwy logical {mustBeNumericOrLogical} = true - % Ground Motion - Z direction - args.Dwz logical {mustBeNumericOrLogical} = true - % Translation Stage - X direction - args.Fty_x logical {mustBeNumericOrLogical} = true - % Translation Stage - Z direction - args.Fty_z logical {mustBeNumericOrLogical} = true - % Spindle - Z direction - args.Frz_z logical {mustBeNumericOrLogical} = true - end +arguments + % Global parameter to enable or disable the disturbances + args.enable logical {mustBeNumericOrLogical} = true + % Ground Motion - X direction + args.Dwx logical {mustBeNumericOrLogical} = true + % Ground Motion - Y direction + args.Dwy logical {mustBeNumericOrLogical} = true + % Ground Motion - Z direction + args.Dwz logical {mustBeNumericOrLogical} = true + % Translation Stage - X direction + args.Fty_x logical {mustBeNumericOrLogical} = true + % Translation Stage - Z direction + args.Fty_z logical {mustBeNumericOrLogical} = true + % Spindle - X direction + args.Frz_x logical {mustBeNumericOrLogical} = true + % Spindle - Y direction + args.Frz_y logical {mustBeNumericOrLogical} = true + % Spindle - Z direction + args.Frz_z logical {mustBeNumericOrLogical} = true +end #+end_src - *** Load Data -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab - load('dist_psd.mat', 'dist_f'); +load('dist_psd.mat', 'dist_f'); #+end_src We remove the first frequency point that usually is very large. #+begin_src matlab :exports none - dist_f.f = dist_f.f(2:end); - dist_f.psd_gm = dist_f.psd_gm(2:end); - dist_f.psd_ty = dist_f.psd_ty(2:end); - dist_f.psd_rz = dist_f.psd_rz(2:end); +dist_f.f = dist_f.f(2:end); +dist_f.psd_gm = dist_f.psd_gm(2:end); +dist_f.psd_ty = dist_f.psd_ty(2:end); +dist_f.psd_rz = dist_f.psd_rz(2:end); #+end_src *** Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: We define some parameters that will be used in the algorithm. #+begin_src matlab - Fs = 2*dist_f.f(end); % Sampling Frequency of data is twice the maximum frequency of the PSD vector [Hz] - N = 2*length(dist_f.f); % Number of Samples match the one of the wanted PSD - T0 = N/Fs; % Signal Duration [s] - df = 1/T0; % Frequency resolution of the DFT [Hz] - % Also equal to (dist_f.f(2)-dist_f.f(1)) - t = linspace(0, T0, N+1)'; % Time Vector [s] - Ts = 1/Fs; % Sampling Time [s] +Fs = 2*dist_f.f(end); % Sampling Frequency of data is twice the maximum frequency of the PSD vector [Hz] +N = 2*length(dist_f.f); % Number of Samples match the one of the wanted PSD +T0 = N/Fs; % Signal Duration [s] +df = 1/T0; % Frequency resolution of the DFT [Hz] + % Also equal to (dist_f.f(2)-dist_f.f(1)) +t = linspace(0, T0, N+1)'; % Time Vector [s] +Ts = 1/Fs; % Sampling Time [s] #+end_src *** Ground Motion -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab - phi = dist_f.psd_gm; - C = zeros(N/2,1); - for i = 1:N/2 +phi = dist_f.psd_gm; +C = zeros(N/2,1); +for i = 1:N/2 C(i) = sqrt(phi(i)*df); - end +end #+end_src #+begin_src matlab - if args.Dwx && args.enable +if args.Dwx && args.enable rng(111); theta = 2*pi*rand(N/2,1); % Generate random phase [rad] Cx = [0 ; C.*complex(cos(theta),sin(theta))]; Cx = [Cx; flipud(conj(Cx(2:end)))];; Dwx = N/sqrt(2)*ifft(Cx); % Ground Motion - x direction [m] - else +else Dwx = zeros(length(t), 1); - end +end #+end_src #+begin_src matlab - if args.Dwy && args.enable +if args.Dwy && args.enable rng(112); theta = 2*pi*rand(N/2,1); % Generate random phase [rad] Cx = [0 ; C.*complex(cos(theta),sin(theta))]; Cx = [Cx; flipud(conj(Cx(2:end)))];; Dwy = N/sqrt(2)*ifft(Cx); % Ground Motion - y direction [m] - else +else Dwy = zeros(length(t), 1); - end +end #+end_src #+begin_src matlab - if args.Dwy && args.enable +if args.Dwy && args.enable rng(113); theta = 2*pi*rand(N/2,1); % Generate random phase [rad] Cx = [0 ; C.*complex(cos(theta),sin(theta))]; Cx = [Cx; flipud(conj(Cx(2:end)))];; Dwz = N/sqrt(2)*ifft(Cx); % Ground Motion - z direction [m] - else +else Dwz = zeros(length(t), 1); - end +end #+end_src *** Translation Stage - X direction -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab - if args.Fty_x && args.enable +if args.Fty_x && args.enable phi = dist_f.psd_ty; % TODO - we take here the vertical direction which is wrong but approximate C = zeros(N/2,1); for i = 1:N/2 - C(i) = sqrt(phi(i)*df); + C(i) = sqrt(phi(i)*df); end rng(121); theta = 2*pi*rand(N/2,1); % Generate random phase [rad] @@ -2662,21 +3063,18 @@ We define some parameters that will be used in the algorithm. Cx = [Cx; flipud(conj(Cx(2:end)))];; u = N/sqrt(2)*ifft(Cx); % Disturbance Force Ty x [N] Fty_x = u; - else +else Fty_x = zeros(length(t), 1); - end +end #+end_src *** Translation Stage - Z direction -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab - if args.Fty_z && args.enable +if args.Fty_z && args.enable phi = dist_f.psd_ty; C = zeros(N/2,1); for i = 1:N/2 - C(i) = sqrt(phi(i)*df); + C(i) = sqrt(phi(i)*df); end rng(122); theta = 2*pi*rand(N/2,1); % Generate random phase [rad] @@ -2684,21 +3082,56 @@ We define some parameters that will be used in the algorithm. Cx = [Cx; flipud(conj(Cx(2:end)))];; u = N/sqrt(2)*ifft(Cx); % Disturbance Force Ty z [N] Fty_z = u; - else +else Fty_z = zeros(length(t), 1); - end +end +#+end_src + +*** Spindle - X direction +#+begin_src matlab +% if args.Frz_x && args.enable +% phi = dist_f.psd_rz; +% C = zeros(N/2,1); +% for i = 1:N/2 +% C(i) = sqrt(phi(i)*df); +% end +% rng(131); +% theta = 2*pi*rand(N/2,1); % Generate random phase [rad] +% Cx = [0 ; C.*complex(cos(theta),sin(theta))]; +% Cx = [Cx; flipud(conj(Cx(2:end)))];; +% u = N/sqrt(2)*ifft(Cx); % Disturbance Force Rz z [N] +% Frz_x = u; +% else +Frz_x = zeros(length(t), 1); +% end +#+end_src + +*** Spindle - Y direction +#+begin_src matlab +% if args.Frz_y && args.enable +% phi = dist_f.psd_rz; +% C = zeros(N/2,1); +% for i = 1:N/2 +% C(i) = sqrt(phi(i)*df); +% end +% rng(131); +% theta = 2*pi*rand(N/2,1); % Generate random phase [rad] +% Cx = [0 ; C.*complex(cos(theta),sin(theta))]; +% Cx = [Cx; flipud(conj(Cx(2:end)))];; +% u = N/sqrt(2)*ifft(Cx); % Disturbance Force Rz z [N] +% Frz_z = u; +% else +Frz_y = zeros(length(t), 1); +% end #+end_src *** Spindle - Z direction -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab - if args.Frz_z && args.enable +if args.Frz_z && args.enable phi = dist_f.psd_rz; C = zeros(N/2,1); for i = 1:N/2 - C(i) = sqrt(phi(i)*df); + C(i) = sqrt(phi(i)*df); end rng(131); theta = 2*pi*rand(N/2,1); % Generate random phase [rad] @@ -2706,1303 +3139,44 @@ We define some parameters that will be used in the algorithm. Cx = [Cx; flipud(conj(Cx(2:end)))];; u = N/sqrt(2)*ifft(Cx); % Disturbance Force Rz z [N] Frz_z = u; - else +else Frz_z = zeros(length(t), 1); - end +end #+end_src *** Direct Forces -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab - u = zeros(length(t), 6); - Fd = u; +u = zeros(length(t), 6); +Fd = u; #+end_src *** Set initial value to zero -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab - Dwx = Dwx - Dwx(1); - Dwy = Dwy - Dwy(1); - Dwz = Dwz - Dwz(1); - Fty_x = Fty_x - Fty_x(1); - Fty_z = Fty_z - Fty_z(1); - Frz_z = Frz_z - Frz_z(1); +Dwx = Dwx - Dwx(1); +Dwy = Dwy - Dwy(1); +Dwz = Dwz - Dwz(1); +Fty_x = Fty_x - Fty_x(1); +Fty_z = Fty_z - Fty_z(1); +Frz_z = Frz_z - Frz_z(1); #+end_src *** Save the Structure #+begin_src matlab if exist('./mat', 'dir') if exist('./mat/nass_disturbances.mat', 'file') - save('mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_z', 'Fd', 'Ts', 't', 'args', '-append'); + save('mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_x', 'Frz_y', 'Frz_z', 'Fd', 'Ts', 't', 'args', '-append'); else - save('mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_z', 'Fd', 'Ts', 't', 'args'); + save('mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_x', 'Frz_y', 'Frz_z', 'Fd', 'Ts', 't', 'args'); end elseif exist('./matlab', 'dir') if exist('./matlab/mat/nass_disturbances.mat', 'file') - save('matlab/mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_z', 'Fd', 'Ts', 't', 'args', '-append'); + save('matlab/mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_x', 'Frz_y', 'Frz_z', 'Fd', 'Ts', 't', 'args', '-append'); else - save('matlab/mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_z', 'Fd', 'Ts', 't', 'args'); + save('matlab/mat/nass_disturbances.mat', 'Dwx', 'Dwy', 'Dwz', 'Fty_x', 'Fty_z', 'Frz_x', 'Frz_y', 'Frz_z', 'Fd', 'Ts', 't', 'args'); end end #+end_src -** =initializeStewartPlatform=: Initialize the Stewart Platform structure -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/initializeStewartPlatform.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Documentation -:PROPERTIES: -:UNNUMBERED: t -:END: - -#+name: fig:stewart-frames-position -#+caption: Definition of the position of the frames -[[file:figs/stewart-frames-position.png]] - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [stewart] = initializeStewartPlatform() - % initializeStewartPlatform - Initialize the stewart structure - % - % Syntax: [stewart] = initializeStewartPlatform(args) - % - % Outputs: - % - stewart - A structure with the following sub-structures: - % - platform_F - - % - platform_M - - % - joints_F - - % - joints_M - - % - struts_F - - % - struts_M - - % - actuators - - % - geometry - - % - properties - -#+end_src - -*** Initialize the Stewart structure -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - stewart = struct(); - stewart.platform_F = struct(); - stewart.platform_M = struct(); - stewart.joints_F = struct(); - stewart.joints_M = struct(); - stewart.struts_F = struct(); - stewart.struts_M = struct(); - stewart.actuators = struct(); - stewart.sensors = struct(); - stewart.sensors.inertial = struct(); - stewart.sensors.force = struct(); - stewart.sensors.relative = struct(); - stewart.geometry = struct(); - stewart.kinematics = struct(); -#+end_src - -** =initializeFramesPositions=: Initialize the positions of frames {A}, {B}, {F} and {M} -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/initializeFramesPositions.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Documentation -:PROPERTIES: -:UNNUMBERED: t -:END: - -#+name: fig:stewart-frames-position -#+caption: Definition of the position of the frames -[[file:figs/stewart-frames-position.png]] - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [stewart] = initializeFramesPositions(stewart, args) - % initializeFramesPositions - Initialize the positions of frames {A}, {B}, {F} and {M} - % - % Syntax: [stewart] = initializeFramesPositions(stewart, args) - % - % Inputs: - % - args - Can have the following fields: - % - H [1x1] - Total Height of the Stewart Platform (height from {F} to {M}) [m] - % - MO_B [1x1] - Height of the frame {B} with respect to {M} [m] - % - % Outputs: - % - stewart - A structure with the following fields: - % - geometry.H [1x1] - Total Height of the Stewart Platform [m] - % - geometry.FO_M [3x1] - Position of {M} with respect to {F} [m] - % - platform_M.MO_B [3x1] - Position of {B} with respect to {M} [m] - % - platform_F.FO_A [3x1] - Position of {A} with respect to {F} [m] -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - stewart - args.H (1,1) double {mustBeNumeric, mustBePositive} = 90e-3 - args.MO_B (1,1) double {mustBeNumeric} = 50e-3 - end -#+end_src - -*** Compute the position of each frame -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - H = args.H; % Total Height of the Stewart Platform [m] - - FO_M = [0; 0; H]; % Position of {M} with respect to {F} [m] - - MO_B = [0; 0; args.MO_B]; % Position of {B} with respect to {M} [m] - - FO_A = MO_B + FO_M; % Position of {A} with respect to {F} [m] -#+end_src - -*** Populate the =stewart= structure -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - stewart.geometry.H = H; - stewart.geometry.FO_M = FO_M; - stewart.platform_M.MO_B = MO_B; - stewart.platform_F.FO_A = FO_A; -#+end_src - -** =generateGeneralConfiguration=: Generate a Very General Configuration -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/generateGeneralConfiguration.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Documentation -:PROPERTIES: -:UNNUMBERED: t -:END: -Joints are positions on a circle centered with the Z axis of {F} and {M} and at a chosen distance from {F} and {M}. -The radius of the circles can be chosen as well as the angles where the joints are located (see Figure [[fig:joint_position_general]]). - -#+begin_src latex :file stewart_bottom_plate.pdf :tangle no - \begin{tikzpicture} - % Internal and external limit - \draw[fill=white!80!black] (0, 0) circle [radius=3]; - % Circle where the joints are located - \draw[dashed] (0, 0) circle [radius=2.5]; - - % Bullets for the positions of the joints - \node[] (J1) at ( 80:2.5){$\bullet$}; - \node[] (J2) at (100:2.5){$\bullet$}; - \node[] (J3) at (200:2.5){$\bullet$}; - \node[] (J4) at (220:2.5){$\bullet$}; - \node[] (J5) at (320:2.5){$\bullet$}; - \node[] (J6) at (340:2.5){$\bullet$}; - - % Name of the points - \node[above right] at (J1) {$a_{1}$}; - \node[above left] at (J2) {$a_{2}$}; - \node[above left] at (J3) {$a_{3}$}; - \node[right ] at (J4) {$a_{4}$}; - \node[left ] at (J5) {$a_{5}$}; - \node[above right] at (J6) {$a_{6}$}; - - % First 2 angles - \draw[dashed, ->] (0:1) arc [start angle=0, end angle=80, radius=1] node[below right]{$\theta_{1}$}; - \draw[dashed, ->] (0:1.5) arc [start angle=0, end angle=100, radius=1.5] node[left ]{$\theta_{2}$}; - - % Division of 360 degrees by 3 - \draw[dashed] (0, 0) -- ( 80:3.2); - \draw[dashed] (0, 0) -- (100:3.2); - \draw[dashed] (0, 0) -- (200:3.2); - \draw[dashed] (0, 0) -- (220:3.2); - \draw[dashed] (0, 0) -- (320:3.2); - \draw[dashed] (0, 0) -- (340:3.2); - - % Radius for the position of the joints - \draw[<->] (0, 0) --node[near end, above]{$R$} (180:2.5); - - \draw[->] (0, 0) -- ++(3.4, 0) node[above]{$x$}; - \draw[->] (0, 0) -- ++(0, 3.4) node[left]{$y$}; - \end{tikzpicture} -#+end_src - -#+name: fig:joint_position_general -#+caption: Position of the joints -#+RESULTS: -[[file:figs/stewart_bottom_plate.png]] - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [stewart] = generateGeneralConfiguration(stewart, args) - % generateGeneralConfiguration - Generate a Very General Configuration - % - % Syntax: [stewart] = generateGeneralConfiguration(stewart, args) - % - % Inputs: - % - args - Can have the following fields: - % - FH [1x1] - Height of the position of the fixed joints with respect to the frame {F} [m] - % - FR [1x1] - Radius of the position of the fixed joints in the X-Y [m] - % - FTh [6x1] - Angles of the fixed joints in the X-Y plane with respect to the X axis [rad] - % - MH [1x1] - Height of the position of the mobile joints with respect to the frame {M} [m] - % - FR [1x1] - Radius of the position of the mobile joints in the X-Y [m] - % - MTh [6x1] - Angles of the mobile joints in the X-Y plane with respect to the X axis [rad] - % - % Outputs: - % - stewart - updated Stewart structure with the added fields: - % - platform_F.Fa [3x6] - Its i'th column is the position vector of joint ai with respect to {F} - % - platform_M.Mb [3x6] - Its i'th column is the position vector of joint bi with respect to {M} -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - stewart - args.FH (1,1) double {mustBeNumeric, mustBePositive} = 15e-3 - args.FR (1,1) double {mustBeNumeric, mustBePositive} = 115e-3; - args.FTh (6,1) double {mustBeNumeric} = [-10, 10, 120-10, 120+10, 240-10, 240+10]*(pi/180); - args.MH (1,1) double {mustBeNumeric, mustBePositive} = 15e-3 - args.MR (1,1) double {mustBeNumeric, mustBePositive} = 90e-3; - args.MTh (6,1) double {mustBeNumeric} = [-60+10, 60-10, 60+10, 180-10, 180+10, -60-10]*(pi/180); - end -#+end_src - -*** Compute the pose -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - Fa = zeros(3,6); - Mb = zeros(3,6); -#+end_src - -#+begin_src matlab - for i = 1:6 - Fa(:,i) = [args.FR*cos(args.FTh(i)); args.FR*sin(args.FTh(i)); args.FH]; - Mb(:,i) = [args.MR*cos(args.MTh(i)); args.MR*sin(args.MTh(i)); -args.MH]; - end -#+end_src - -*** Populate the =stewart= structure -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - stewart.platform_F.Fa = Fa; - stewart.platform_M.Mb = Mb; -#+end_src - -** =computeJointsPose=: Compute the Pose of the Joints -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/computeJointsPose.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Documentation -:PROPERTIES: -:UNNUMBERED: t -:END: - -#+name: fig:stewart-struts -#+caption: Position and orientation of the struts -[[file:figs/stewart-struts.png]] - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [stewart] = computeJointsPose(stewart) - % computeJointsPose - - % - % Syntax: [stewart] = computeJointsPose(stewart) - % - % Inputs: - % - stewart - A structure with the following fields - % - platform_F.Fa [3x6] - Its i'th column is the position vector of joint ai with respect to {F} - % - platform_M.Mb [3x6] - Its i'th column is the position vector of joint bi with respect to {M} - % - platform_F.FO_A [3x1] - Position of {A} with respect to {F} - % - platform_M.MO_B [3x1] - Position of {B} with respect to {M} - % - geometry.FO_M [3x1] - Position of {M} with respect to {F} - % - % Outputs: - % - stewart - A structure with the following added fields - % - geometry.Aa [3x6] - The i'th column is the position of ai with respect to {A} - % - geometry.Ab [3x6] - The i'th column is the position of bi with respect to {A} - % - geometry.Ba [3x6] - The i'th column is the position of ai with respect to {B} - % - geometry.Bb [3x6] - The i'th column is the position of bi with respect to {B} - % - geometry.l [6x1] - The i'th element is the initial length of strut i - % - geometry.As [3x6] - The i'th column is the unit vector of strut i expressed in {A} - % - geometry.Bs [3x6] - The i'th column is the unit vector of strut i expressed in {B} - % - struts_F.l [6x1] - Length of the Fixed part of the i'th strut - % - struts_M.l [6x1] - Length of the Mobile part of the i'th strut - % - platform_F.FRa [3x3x6] - The i'th 3x3 array is the rotation matrix to orientate the bottom of the i'th strut from {F} - % - platform_M.MRb [3x3x6] - The i'th 3x3 array is the rotation matrix to orientate the top of the i'th strut from {M} -#+end_src - -*** Check the =stewart= structure elements -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - assert(isfield(stewart.platform_F, 'Fa'), 'stewart.platform_F should have attribute Fa') - Fa = stewart.platform_F.Fa; - - assert(isfield(stewart.platform_M, 'Mb'), 'stewart.platform_M should have attribute Mb') - Mb = stewart.platform_M.Mb; - - assert(isfield(stewart.platform_F, 'FO_A'), 'stewart.platform_F should have attribute FO_A') - FO_A = stewart.platform_F.FO_A; - - assert(isfield(stewart.platform_M, 'MO_B'), 'stewart.platform_M should have attribute MO_B') - MO_B = stewart.platform_M.MO_B; - - assert(isfield(stewart.geometry, 'FO_M'), 'stewart.geometry should have attribute FO_M') - FO_M = stewart.geometry.FO_M; -#+end_src - -*** Compute the position of the Joints -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - Aa = Fa - repmat(FO_A, [1, 6]); - Bb = Mb - repmat(MO_B, [1, 6]); - - Ab = Bb - repmat(-MO_B-FO_M+FO_A, [1, 6]); - Ba = Aa - repmat( MO_B+FO_M-FO_A, [1, 6]); -#+end_src - -*** Compute the strut length and orientation -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - As = (Ab - Aa)./vecnorm(Ab - Aa); % As_i is the i'th vector of As - - l = vecnorm(Ab - Aa)'; -#+end_src - -#+begin_src matlab - Bs = (Bb - Ba)./vecnorm(Bb - Ba); -#+end_src - -*** Compute the orientation of the Joints -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - FRa = zeros(3,3,6); - MRb = zeros(3,3,6); - - for i = 1:6 - FRa(:,:,i) = [cross([0;1;0], As(:,i)) , cross(As(:,i), cross([0;1;0], As(:,i))) , As(:,i)]; - FRa(:,:,i) = FRa(:,:,i)./vecnorm(FRa(:,:,i)); - - MRb(:,:,i) = [cross([0;1;0], Bs(:,i)) , cross(Bs(:,i), cross([0;1;0], Bs(:,i))) , Bs(:,i)]; - MRb(:,:,i) = MRb(:,:,i)./vecnorm(MRb(:,:,i)); - end -#+end_src - -*** Populate the =stewart= structure -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - stewart.geometry.Aa = Aa; - stewart.geometry.Ab = Ab; - stewart.geometry.Ba = Ba; - stewart.geometry.Bb = Bb; - stewart.geometry.As = As; - stewart.geometry.Bs = Bs; - stewart.geometry.l = l; - - stewart.struts_F.l = l/2; - stewart.struts_M.l = l/2; - - stewart.platform_F.FRa = FRa; - stewart.platform_M.MRb = MRb; -#+end_src - -** =initializeCylindricalPlatforms=: Initialize the geometry of the Fixed and Mobile Platforms -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/initializeCylindricalPlatforms.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [stewart] = initializeCylindricalPlatforms(stewart, args) - % initializeCylindricalPlatforms - Initialize the geometry of the Fixed and Mobile Platforms - % - % Syntax: [stewart] = initializeCylindricalPlatforms(args) - % - % Inputs: - % - args - Structure with the following fields: - % - Fpm [1x1] - Fixed Platform Mass [kg] - % - Fph [1x1] - Fixed Platform Height [m] - % - Fpr [1x1] - Fixed Platform Radius [m] - % - Mpm [1x1] - Mobile Platform Mass [kg] - % - Mph [1x1] - Mobile Platform Height [m] - % - Mpr [1x1] - Mobile Platform Radius [m] - % - % Outputs: - % - stewart - updated Stewart structure with the added fields: - % - platform_F [struct] - structure with the following fields: - % - type = 1 - % - M [1x1] - Fixed Platform Mass [kg] - % - I [3x3] - Fixed Platform Inertia matrix [kg*m^2] - % - H [1x1] - Fixed Platform Height [m] - % - R [1x1] - Fixed Platform Radius [m] - % - platform_M [struct] - structure with the following fields: - % - M [1x1] - Mobile Platform Mass [kg] - % - I [3x3] - Mobile Platform Inertia matrix [kg*m^2] - % - H [1x1] - Mobile Platform Height [m] - % - R [1x1] - Mobile Platform Radius [m] -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - stewart - args.Fpm (1,1) double {mustBeNumeric, mustBePositive} = 1 - args.Fph (1,1) double {mustBeNumeric, mustBePositive} = 10e-3 - args.Fpr (1,1) double {mustBeNumeric, mustBePositive} = 125e-3 - args.Mpm (1,1) double {mustBeNumeric, mustBePositive} = 1 - args.Mph (1,1) double {mustBeNumeric, mustBePositive} = 10e-3 - args.Mpr (1,1) double {mustBeNumeric, mustBePositive} = 100e-3 - end -#+end_src - -*** Compute the Inertia matrices of platforms -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - I_F = diag([1/12*args.Fpm * (3*args.Fpr^2 + args.Fph^2), ... - 1/12*args.Fpm * (3*args.Fpr^2 + args.Fph^2), ... - 1/2 *args.Fpm * args.Fpr^2]); -#+end_src - -#+begin_src matlab - I_M = diag([1/12*args.Mpm * (3*args.Mpr^2 + args.Mph^2), ... - 1/12*args.Mpm * (3*args.Mpr^2 + args.Mph^2), ... - 1/2 *args.Mpm * args.Mpr^2]); -#+end_src - -*** Populate the =stewart= structure -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - stewart.platform_F.type = 1; - - stewart.platform_F.I = I_F; - stewart.platform_F.M = args.Fpm; - stewart.platform_F.R = args.Fpr; - stewart.platform_F.H = args.Fph; -#+end_src - -#+begin_src matlab - stewart.platform_M.type = 1; - - stewart.platform_M.I = I_M; - stewart.platform_M.M = args.Mpm; - stewart.platform_M.R = args.Mpr; - stewart.platform_M.H = args.Mph; -#+end_src - -** =initializeCylindricalStruts=: Define the inertia of cylindrical struts -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/initializeCylindricalStruts.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [stewart] = initializeCylindricalStruts(stewart, args) - % initializeCylindricalStruts - Define the mass and moment of inertia of cylindrical struts - % - % Syntax: [stewart] = initializeCylindricalStruts(args) - % - % Inputs: - % - args - Structure with the following fields: - % - Fsm [1x1] - Mass of the Fixed part of the struts [kg] - % - Fsh [1x1] - Height of cylinder for the Fixed part of the struts [m] - % - Fsr [1x1] - Radius of cylinder for the Fixed part of the struts [m] - % - Msm [1x1] - Mass of the Mobile part of the struts [kg] - % - Msh [1x1] - Height of cylinder for the Mobile part of the struts [m] - % - Msr [1x1] - Radius of cylinder for the Mobile part of the struts [m] - % - % Outputs: - % - stewart - updated Stewart structure with the added fields: - % - struts_F [struct] - structure with the following fields: - % - M [6x1] - Mass of the Fixed part of the struts [kg] - % - I [3x3x6] - Moment of Inertia for the Fixed part of the struts [kg*m^2] - % - H [6x1] - Height of cylinder for the Fixed part of the struts [m] - % - R [6x1] - Radius of cylinder for the Fixed part of the struts [m] - % - struts_M [struct] - structure with the following fields: - % - M [6x1] - Mass of the Mobile part of the struts [kg] - % - I [3x3x6] - Moment of Inertia for the Mobile part of the struts [kg*m^2] - % - H [6x1] - Height of cylinder for the Mobile part of the struts [m] - % - R [6x1] - Radius of cylinder for the Mobile part of the struts [m] -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - stewart - args.Fsm (1,1) double {mustBeNumeric, mustBePositive} = 0.1 - args.Fsh (1,1) double {mustBeNumeric, mustBePositive} = 50e-3 - args.Fsr (1,1) double {mustBeNumeric, mustBePositive} = 5e-3 - args.Msm (1,1) double {mustBeNumeric, mustBePositive} = 0.1 - args.Msh (1,1) double {mustBeNumeric, mustBePositive} = 50e-3 - args.Msr (1,1) double {mustBeNumeric, mustBePositive} = 5e-3 - end -#+end_src - -*** Compute the properties of the cylindrical struts -:PROPERTIES: -:UNNUMBERED: t -:END: - -#+begin_src matlab - Fsm = ones(6,1).*args.Fsm; - Fsh = ones(6,1).*args.Fsh; - Fsr = ones(6,1).*args.Fsr; - - Msm = ones(6,1).*args.Msm; - Msh = ones(6,1).*args.Msh; - Msr = ones(6,1).*args.Msr; -#+end_src - -#+begin_src matlab - I_F = zeros(3, 3, 6); % Inertia of the "fixed" part of the strut - I_M = zeros(3, 3, 6); % Inertia of the "mobile" part of the strut - - for i = 1:6 - I_F(:,:,i) = diag([1/12 * Fsm(i) * (3*Fsr(i)^2 + Fsh(i)^2), ... - 1/12 * Fsm(i) * (3*Fsr(i)^2 + Fsh(i)^2), ... - 1/2 * Fsm(i) * Fsr(i)^2]); - - I_M(:,:,i) = diag([1/12 * Msm(i) * (3*Msr(i)^2 + Msh(i)^2), ... - 1/12 * Msm(i) * (3*Msr(i)^2 + Msh(i)^2), ... - 1/2 * Msm(i) * Msr(i)^2]); - end -#+end_src - -*** Populate the =stewart= structure -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - stewart.struts_M.type = 1; - - stewart.struts_M.I = I_M; - stewart.struts_M.M = Msm; - stewart.struts_M.R = Msr; - stewart.struts_M.H = Msh; -#+end_src - -#+begin_src matlab - stewart.struts_F.type = 1; - - stewart.struts_F.I = I_F; - stewart.struts_F.M = Fsm; - stewart.struts_F.R = Fsr; - stewart.struts_F.H = Fsh; -#+end_src - -** =initializeStrutDynamics=: Add Stiffness and Damping properties of each strut -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/initializeStrutDynamics.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Documentation -:PROPERTIES: -:UNNUMBERED: t -:END: - -#+name: fig:piezoelectric_stack -#+attr_html: :width 500px -#+caption: Example of a piezoelectric stach actuator (PI) -[[file:figs/piezoelectric_stack.jpg]] - -A simplistic model of such amplified actuator is shown in Figure [[fig:actuator_model_simple]] where: -- $K$ represent the vertical stiffness of the actuator -- $C$ represent the vertical damping of the actuator -- $F$ represents the force applied by the actuator -- $F_{m}$ represents the total measured force -- $v_{m}$ represents the absolute velocity of the top part of the actuator -- $d_{m}$ represents the total relative displacement of the actuator - -#+begin_src latex :file actuator_model_simple.pdf :tangle no - \begin{tikzpicture} - \draw (-1, 0) -- (1, 0); - - % Spring, Damper, and Actuator - \draw[spring] (-1, 0) -- (-1, 1.5) node[midway, left=0.1]{$K$}; - \draw[damper] ( 0, 0) -- ( 0, 1.5) node[midway, left=0.2]{$C$}; - \draw[actuator] ( 1, 0) -- ( 1, 1.5) node[midway, left=0.1](F){$F$}; - - \node[forcesensor={2}{0.2}] (fsens) at (0, 1.5){}; - - \node[left] at (fsens.west) {$F_{m}$}; - - \draw[dashed] (1, 0) -- ++(0.4, 0); - \draw[dashed] (1, 1.7) -- ++(0.4, 0); - - \draw[->] (0, 1.7)node[]{$\bullet$} -- ++(0, 0.5) node[right]{$v_{m}$}; - - \draw[<->] (1.4, 0) -- ++(0, 1.7) node[midway, right]{$d_{m}$}; - \end{tikzpicture} -#+end_src - -#+name: fig:actuator_model_simple -#+caption: Simple model of an Actuator -#+RESULTS: -[[file:figs/actuator_model_simple.png]] - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [stewart] = initializeStrutDynamics(stewart, args) - % initializeStrutDynamics - Add Stiffness and Damping properties of each strut - % - % Syntax: [stewart] = initializeStrutDynamics(args) - % - % Inputs: - % - args - Structure with the following fields: - % - K [6x1] - Stiffness of each strut [N/m] - % - C [6x1] - Damping of each strut [N/(m/s)] - % - % Outputs: - % - stewart - updated Stewart structure with the added fields: - % - actuators.type = 1 - % - actuators.K [6x1] - Stiffness of each strut [N/m] - % - actuators.C [6x1] - Damping of each strut [N/(m/s)] -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - stewart - args.type char {mustBeMember(args.type,{'classical', 'amplified'})} = 'classical' - args.K (6,1) double {mustBeNumeric, mustBeNonnegative} = 20e6*ones(6,1) - args.C (6,1) double {mustBeNumeric, mustBeNonnegative} = 2e1*ones(6,1) - args.k1 (6,1) double {mustBeNumeric} = 1e6*ones(6,1) - args.ke (6,1) double {mustBeNumeric} = 5e6*ones(6,1) - args.ka (6,1) double {mustBeNumeric} = 60e6*ones(6,1) - args.c1 (6,1) double {mustBeNumeric} = 10*ones(6,1) - args.F_gain (6,1) double {mustBeNumeric} = 1*ones(6,1) - args.me (6,1) double {mustBeNumeric} = 0.01*ones(6,1) - args.ma (6,1) double {mustBeNumeric} = 0.01*ones(6,1) - end -#+end_src - -*** Add Stiffness and Damping properties of each strut -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - if strcmp(args.type, 'classical') - stewart.actuators.type = 1; - elseif strcmp(args.type, 'amplified') - stewart.actuators.type = 2; - end - - stewart.actuators.K = args.K; - stewart.actuators.C = args.C; - - stewart.actuators.k1 = args.k1; - stewart.actuators.c1 = args.c1; - - stewart.actuators.ka = args.ka; - stewart.actuators.ke = args.ke; - - stewart.actuators.F_gain = args.F_gain; - - stewart.actuators.ma = args.ma; - stewart.actuators.me = args.me; -#+end_src - -** =initializeJointDynamics=: Add Stiffness and Damping properties for spherical joints -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/initializeJointDynamics.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [stewart] = initializeJointDynamics(stewart, args) - % initializeJointDynamics - Add Stiffness and Damping properties for the spherical joints - % - % Syntax: [stewart] = initializeJointDynamics(args) - % - % Inputs: - % - args - Structure with the following fields: - % - type_F - 'universal', 'spherical', 'universal_p', 'spherical_p' - % - type_M - 'universal', 'spherical', 'universal_p', 'spherical_p' - % - Kf_M [6x1] - Bending (Rx, Ry) Stiffness for each top joints [(N.m)/rad] - % - Kt_M [6x1] - Torsion (Rz) Stiffness for each top joints [(N.m)/rad] - % - Cf_M [6x1] - Bending (Rx, Ry) Damping of each top joint [(N.m)/(rad/s)] - % - Ct_M [6x1] - Torsion (Rz) Damping of each top joint [(N.m)/(rad/s)] - % - Kf_F [6x1] - Bending (Rx, Ry) Stiffness for each bottom joints [(N.m)/rad] - % - Kt_F [6x1] - Torsion (Rz) Stiffness for each bottom joints [(N.m)/rad] - % - Cf_F [6x1] - Bending (Rx, Ry) Damping of each bottom joint [(N.m)/(rad/s)] - % - Cf_F [6x1] - Torsion (Rz) Damping of each bottom joint [(N.m)/(rad/s)] - % - % Outputs: - % - stewart - updated Stewart structure with the added fields: - % - stewart.joints_F and stewart.joints_M: - % - type - 1 (universal), 2 (spherical), 3 (universal perfect), 4 (spherical perfect) - % - Kx, Ky, Kz [6x1] - Translation (Tx, Ty, Tz) Stiffness [N/m] - % - Kf [6x1] - Flexion (Rx, Ry) Stiffness [(N.m)/rad] - % - Kt [6x1] - Torsion (Rz) Stiffness [(N.m)/rad] - % - Cx, Cy, Cz [6x1] - Translation (Rx, Ry) Damping [N/(m/s)] - % - Cf [6x1] - Flexion (Rx, Ry) Damping [(N.m)/(rad/s)] - % - Cb [6x1] - Torsion (Rz) Damping [(N.m)/(rad/s)] -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - stewart - args.type_F char {mustBeMember(args.type_F,{'universal', 'spherical', 'universal_p', 'spherical_p', 'universal_3dof', 'spherical_3dof', 'flexible'})} = 'universal' - args.type_M char {mustBeMember(args.type_M,{'universal', 'spherical', 'universal_p', 'spherical_p', 'universal_3dof', 'spherical_3dof', 'flexible'})} = 'spherical' - args.Kf_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 33*ones(6,1) - args.Cf_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e-4*ones(6,1) - args.Kt_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 236*ones(6,1) - args.Ct_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e-3*ones(6,1) - args.Kf_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 33*ones(6,1) - args.Cf_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e-4*ones(6,1) - args.Kt_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 236*ones(6,1) - args.Ct_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e-3*ones(6,1) - args.Ka_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 1.2e8*ones(6,1) - args.Ca_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e1*ones(6,1) - args.Kr_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 1.1e7*ones(6,1) - args.Cr_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e1*ones(6,1) - args.Ka_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 1.2e8*ones(6,1) - args.Ca_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e1*ones(6,1) - args.Kr_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 1.1e7*ones(6,1) - args.Cr_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e1*ones(6,1) - args.K_M double {mustBeNumeric} = zeros(6,6) - args.M_M double {mustBeNumeric} = zeros(6,6) - args.n_xyz_M double {mustBeNumeric} = zeros(2,3) - args.xi_M double {mustBeNumeric} = 0.1 - args.step_file_M char {} = '' - args.K_F double {mustBeNumeric} = zeros(6,6) - args.M_F double {mustBeNumeric} = zeros(6,6) - args.n_xyz_F double {mustBeNumeric} = zeros(2,3) - args.xi_F double {mustBeNumeric} = 0.1 - args.step_file_F char {} = '' - end -#+end_src - -*** Add Actuator Type -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - switch args.type_F - case 'universal' - stewart.joints_F.type = 1; - case 'spherical' - stewart.joints_F.type = 2; - case 'universal_p' - stewart.joints_F.type = 3; - case 'spherical_p' - stewart.joints_F.type = 4; - case 'flexible' - stewart.joints_F.type = 5; - case 'universal_3dof' - stewart.joints_F.type = 6; - case 'spherical_3dof' - stewart.joints_F.type = 7; - end - - switch args.type_M - case 'universal' - stewart.joints_M.type = 1; - case 'spherical' - stewart.joints_M.type = 2; - case 'universal_p' - stewart.joints_M.type = 3; - case 'spherical_p' - stewart.joints_M.type = 4; - case 'flexible' - stewart.joints_M.type = 5; - case 'universal_3dof' - stewart.joints_M.type = 6; - case 'spherical_3dof' - stewart.joints_M.type = 7; - end -#+end_src - -*** Add Stiffness and Damping in Translation of each strut -:PROPERTIES: -:UNNUMBERED: t -:END: -Axial and Radial (shear) Stiffness -#+begin_src matlab - stewart.joints_M.Ka = args.Ka_M; - stewart.joints_M.Kr = args.Kr_M; - - stewart.joints_F.Ka = args.Ka_F; - stewart.joints_F.Kr = args.Kr_F; -#+end_src - -Translation Damping -#+begin_src matlab - stewart.joints_M.Ca = args.Ca_M; - stewart.joints_M.Cr = args.Cr_M; - - stewart.joints_F.Ca = args.Ca_F; - stewart.joints_F.Cr = args.Cr_F; -#+end_src - -*** Add Stiffness and Damping in Rotation of each strut -:PROPERTIES: -:UNNUMBERED: t -:END: -Rotational Stiffness -#+begin_src matlab - stewart.joints_M.Kf = args.Kf_M; - stewart.joints_M.Kt = args.Kt_M; - - stewart.joints_F.Kf = args.Kf_F; - stewart.joints_F.Kt = args.Kt_F; -#+end_src - -Rotational Damping -#+begin_src matlab - stewart.joints_M.Cf = args.Cf_M; - stewart.joints_M.Ct = args.Ct_M; - - stewart.joints_F.Cf = args.Cf_F; - stewart.joints_F.Ct = args.Ct_F; -#+end_src - -*** Stiffness and Mass matrices for flexible joint -:PROPERTIES: -:UNNUMBERED: t -:END: - -#+begin_src matlab - stewart.joints_F.M = args.M_F; - stewart.joints_F.K = args.K_F; - stewart.joints_F.n_xyz = args.n_xyz_F; - stewart.joints_F.xi = args.xi_F; - stewart.joints_F.xi = args.xi_F; - stewart.joints_F.step_file = args.step_file_F; - - stewart.joints_M.M = args.M_M; - stewart.joints_M.K = args.K_M; - stewart.joints_M.n_xyz = args.n_xyz_M; - stewart.joints_M.xi = args.xi_M; - stewart.joints_M.step_file = args.step_file_M; -#+end_src - -** =initializeStewartPose=: Determine the initial stroke in each leg to have the wanted pose -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/initializeStewartPose.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [stewart] = initializeStewartPose(stewart, args) - % initializeStewartPose - Determine the initial stroke in each leg to have the wanted pose - % It uses the inverse kinematic - % - % Syntax: [stewart] = initializeStewartPose(stewart, args) - % - % Inputs: - % - stewart - A structure with the following fields - % - Aa [3x6] - The positions ai expressed in {A} - % - Bb [3x6] - The positions bi expressed in {B} - % - args - Can have the following fields: - % - AP [3x1] - The wanted position of {B} with respect to {A} - % - ARB [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A} - % - % Outputs: - % - stewart - updated Stewart structure with the added fields: - % - actuators.Leq [6x1] - The 6 needed displacement of the struts from the initial position in [m] to have the wanted pose of {B} w.r.t. {A} -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - stewart - args.AP (3,1) double {mustBeNumeric} = zeros(3,1) - args.ARB (3,3) double {mustBeNumeric} = eye(3) - end -#+end_src - -*** Use the Inverse Kinematic function -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - [Li, dLi] = inverseKinematics(stewart, 'AP', args.AP, 'ARB', args.ARB); -#+end_src - -*** Populate the =stewart= structure -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - stewart.actuators.Leq = dLi; -#+end_src - -** =computeJacobian=: Compute the Jacobian Matrix -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/computeJacobian.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [stewart] = computeJacobian(stewart) - % computeJacobian - - % - % Syntax: [stewart] = computeJacobian(stewart) - % - % Inputs: - % - stewart - With at least the following fields: - % - geometry.As [3x6] - The 6 unit vectors for each strut expressed in {A} - % - geometry.Ab [3x6] - The 6 position of the joints bi expressed in {A} - % - actuators.K [6x1] - Total stiffness of the actuators - % - % Outputs: - % - stewart - With the 3 added field: - % - kinematics.J [6x6] - The Jacobian Matrix - % - kinematics.K [6x6] - The Stiffness Matrix - % - kinematics.C [6x6] - The Compliance Matrix -#+end_src - -*** Check the =stewart= structure elements -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - assert(isfield(stewart.geometry, 'As'), 'stewart.geometry should have attribute As') - As = stewart.geometry.As; - - assert(isfield(stewart.geometry, 'Ab'), 'stewart.geometry should have attribute Ab') - Ab = stewart.geometry.Ab; - - assert(isfield(stewart.actuators, 'K'), 'stewart.actuators should have attribute K') - Ki = stewart.actuators.K; -#+end_src - - -*** Compute Jacobian Matrix -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - J = [As' , cross(Ab, As)']; -#+end_src - -*** Compute Stiffness Matrix -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - K = J'*diag(Ki)*J; -#+end_src - -*** Compute Compliance Matrix -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - C = inv(K); -#+end_src - -*** Populate the =stewart= structure -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - stewart.kinematics.J = J; - stewart.kinematics.K = K; - stewart.kinematics.C = C; -#+end_src - -** =initializeInertialSensor=: Initialize the inertial sensor in each strut -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/initializeInertialSensor.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Geophone - Working Principle -:PROPERTIES: -:UNNUMBERED: t -:END: -From the schematic of the Z-axis geophone shown in Figure [[fig:z_axis_geophone]], we can write the transfer function from the support velocity $\dot{w}$ to the relative velocity of the inertial mass $\dot{d}$: -\[ \frac{\dot{d}}{\dot{w}} = \frac{-\frac{s^2}{{\omega_0}^2}}{\frac{s^2}{{\omega_0}^2} + 2 \xi \frac{s}{\omega_0} + 1} \] -with: -- $\omega_0 = \sqrt{\frac{k}{m}}$ -- $\xi = \frac{1}{2} \sqrt{\frac{m}{k}}$ - -#+name: fig:z_axis_geophone -#+caption: Schematic of a Z-Axis geophone -[[file:figs/inertial_sensor.png]] - -We see that at frequencies above $\omega_0$: -\[ \frac{\dot{d}}{\dot{w}} \approx -1 \] - -And thus, the measurement of the relative velocity of the mass with respect to its support gives the absolute velocity of the support. - -We generally want to have the smallest resonant frequency $\omega_0$ to measure low frequency absolute velocity, however there is a trade-off between $\omega_0$ and the mass of the inertial mass. - -*** Accelerometer - Working Principle -:PROPERTIES: -:UNNUMBERED: t -:END: -From the schematic of the Z-axis accelerometer shown in Figure [[fig:z_axis_accelerometer]], we can write the transfer function from the support acceleration $\ddot{w}$ to the relative position of the inertial mass $d$: -\[ \frac{d}{\ddot{w}} = \frac{-\frac{1}{{\omega_0}^2}}{\frac{s^2}{{\omega_0}^2} + 2 \xi \frac{s}{\omega_0} + 1} \] -with: -- $\omega_0 = \sqrt{\frac{k}{m}}$ -- $\xi = \frac{1}{2} \sqrt{\frac{m}{k}}$ - -#+name: fig:z_axis_accelerometer -#+caption: Schematic of a Z-Axis geophone -[[file:figs/inertial_sensor.png]] - -We see that at frequencies below $\omega_0$: -\[ \frac{d}{\ddot{w}} \approx -\frac{1}{{\omega_0}^2} \] - -And thus, the measurement of the relative displacement of the mass with respect to its support gives the absolute acceleration of the support. - -Note that there is trade-off between: -- the highest measurable acceleration $\omega_0$ -- the sensitivity of the accelerometer which is equal to $-\frac{1}{{\omega_0}^2}$ - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [stewart] = initializeInertialSensor(stewart, args) - % initializeInertialSensor - Initialize the inertial sensor in each strut - % - % Syntax: [stewart] = initializeInertialSensor(args) - % - % Inputs: - % - args - Structure with the following fields: - % - type - 'geophone', 'accelerometer', 'none' - % - mass [1x1] - Weight of the inertial mass [kg] - % - freq [1x1] - Cutoff frequency [Hz] - % - % Outputs: - % - stewart - updated Stewart structure with the added fields: - % - stewart.sensors.inertial - % - type - 1 (geophone), 2 (accelerometer), 3 (none) - % - K [1x1] - Stiffness [N/m] - % - C [1x1] - Damping [N/(m/s)] - % - M [1x1] - Inertial Mass [kg] - % - G [1x1] - Gain -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - stewart - args.type char {mustBeMember(args.type,{'geophone', 'accelerometer', 'none'})} = 'none' - args.mass (1,1) double {mustBeNumeric, mustBeNonnegative} = 1e-2 - args.freq (1,1) double {mustBeNumeric, mustBeNonnegative} = 1e3 - end -#+end_src - -*** Compute the properties of the sensor -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - sensor = struct(); - - switch args.type - case 'geophone' - sensor.type = 1; - - sensor.M = args.mass; - sensor.K = sensor.M * (2*pi*args.freq)^2; - sensor.C = 2*sqrt(sensor.M * sensor.K); - case 'accelerometer' - sensor.type = 2; - - sensor.M = args.mass; - sensor.K = sensor.M * (2*pi*args.freq)^2; - sensor.C = 2*sqrt(sensor.M * sensor.K); - sensor.G = -sensor.K/sensor.M; - case 'none' - sensor.type = 3; - end -#+end_src - -*** Populate the =stewart= structure -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - stewart.sensors.inertial = sensor; -#+end_src - - - -** =inverseKinematics=: Compute Inverse Kinematics -:PROPERTIES: -:header-args:matlab+: :tangle matlab/src/inverseKinematics.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: - -*** Theory -:PROPERTIES: -:UNNUMBERED: t -:END: -For inverse kinematic analysis, it is assumed that the position ${}^A\bm{P}$ and orientation of the moving platform ${}^A\bm{R}_B$ are given and the problem is to obtain the joint variables, namely, $\bm{L} = [l_1, l_2, \dots, l_6]^T$. - -From the geometry of the manipulator, the loop closure for each limb, $i = 1, 2, \dots, 6$ can be written as -\begin{align*} - l_i {}^A\hat{\bm{s}}_i &= {}^A\bm{A} + {}^A\bm{b}_i - {}^A\bm{a}_i \\ - &= {}^A\bm{A} + {}^A\bm{R}_b {}^B\bm{b}_i - {}^A\bm{a}_i -\end{align*} - -To obtain the length of each actuator and eliminate $\hat{\bm{s}}_i$, it is sufficient to dot multiply each side by itself: -\begin{equation} - l_i^2 \left[ {}^A\hat{\bm{s}}_i^T {}^A\hat{\bm{s}}_i \right] = \left[ {}^A\bm{P} + {}^A\bm{R}_B {}^B\bm{b}_i - {}^A\bm{a}_i \right]^T \left[ {}^A\bm{P} + {}^A\bm{R}_B {}^B\bm{b}_i - {}^A\bm{a}_i \right] -\end{equation} - -Hence, for $i = 1, 2, \dots, 6$, each limb length can be uniquely determined by: -\begin{equation} - l_i = \sqrt{{}^A\bm{P}^T {}^A\bm{P} + {}^B\bm{b}_i^T {}^B\bm{b}_i + {}^A\bm{a}_i^T {}^A\bm{a}_i - 2 {}^A\bm{P}^T {}^A\bm{a}_i + 2 {}^A\bm{P}^T \left[{}^A\bm{R}_B {}^B\bm{b}_i\right] - 2 \left[{}^A\bm{R}_B {}^B\bm{b}_i\right]^T {}^A\bm{a}_i} -\end{equation} - -If the position and orientation of the moving platform lie in the feasible workspace of the manipulator, one unique solution to the limb length is determined by the above equation. -Otherwise, when the limbs' lengths derived yield complex numbers, then the position or orientation of the moving platform is not reachable. - -*** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - function [Li, dLi] = inverseKinematics(stewart, args) - % inverseKinematics - Compute the needed length of each strut to have the wanted position and orientation of {B} with respect to {A} - % - % Syntax: [stewart] = inverseKinematics(stewart) - % - % Inputs: - % - stewart - A structure with the following fields - % - geometry.Aa [3x6] - The positions ai expressed in {A} - % - geometry.Bb [3x6] - The positions bi expressed in {B} - % - geometry.l [6x1] - Length of each strut - % - args - Can have the following fields: - % - AP [3x1] - The wanted position of {B} with respect to {A} - % - ARB [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A} - % - % Outputs: - % - Li [6x1] - The 6 needed length of the struts in [m] to have the wanted pose of {B} w.r.t. {A} - % - dLi [6x1] - The 6 needed displacement of the struts from the initial position in [m] to have the wanted pose of {B} w.r.t. {A} -#+end_src - -*** Optional Parameters -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - arguments - stewart - args.AP (3,1) double {mustBeNumeric} = zeros(3,1) - args.ARB (3,3) double {mustBeNumeric} = eye(3) - end -#+end_src - -*** Check the =stewart= structure elements -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - assert(isfield(stewart.geometry, 'Aa'), 'stewart.geometry should have attribute Aa') - Aa = stewart.geometry.Aa; - - assert(isfield(stewart.geometry, 'Bb'), 'stewart.geometry should have attribute Bb') - Bb = stewart.geometry.Bb; - - assert(isfield(stewart.geometry, 'l'), 'stewart.geometry should have attribute l') - l = stewart.geometry.l; -#+end_src - - -*** Compute -:PROPERTIES: -:UNNUMBERED: t -:END: -#+begin_src matlab - Li = sqrt(args.AP'*args.AP + diag(Bb'*Bb) + diag(Aa'*Aa) - (2*args.AP'*Aa)' + (2*args.AP'*(args.ARB*Bb))' - diag(2*(args.ARB*Bb)'*Aa)); -#+end_src - -#+begin_src matlab - dLi = Li-l; -#+end_src - ** =describeMicroStationSetup= :PROPERTIES: :header-args:matlab+: :tangle matlab/src/describeMicroStationSetup.m @@ -4010,9 +3184,6 @@ Otherwise, when the limbs' lengths derived yield complex numbers, then the posit :END: *** Function description -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab function [] = describeMicroStationSetup() % describeMicroStationSetup - @@ -4027,9 +3198,6 @@ Otherwise, when the limbs' lengths derived yield complex numbers, then the posit #+end_src *** Simscape Configuration -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab load('./mat/conf_simscape.mat', 'conf_simscape'); #+end_src @@ -4047,9 +3215,6 @@ Otherwise, when the limbs' lengths derived yield complex numbers, then the posit #+end_src *** Disturbances -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab load('./mat/nass_disturbances.mat', 'args'); #+end_src @@ -4073,9 +3238,6 @@ Otherwise, when the limbs' lengths derived yield complex numbers, then the posit #+end_src *** References -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab load('./mat/nass_references.mat', 'args'); #+end_src @@ -4135,9 +3297,6 @@ Otherwise, when the limbs' lengths derived yield complex numbers, then the posit #+end_src *** Controller -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab load('./mat/controller.mat', 'controller'); #+end_src @@ -4149,9 +3308,6 @@ Otherwise, when the limbs' lengths derived yield complex numbers, then the posit #+end_src *** Micro-Station -:PROPERTIES: -:UNNUMBERED: t -:END: #+begin_src matlab load('./mat/stages.mat', 'ground', 'granite', 'ty', 'ry', 'rz', 'micro_hexapod', 'axisc'); #+end_src @@ -4289,3 +3445,1641 @@ Otherwise, when the limbs' lengths derived yield complex numbers, then the posit end #+end_src +** Initialize Micro-Station Stages +*** =initializeGround=: Ground +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/initializeGround.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Function description +#+begin_src matlab + function [ground] = initializeGround(args) +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + args.type char {mustBeMember(args.type,{'none', 'rigid'})} = 'rigid' + args.rot_point (3,1) double {mustBeNumeric} = zeros(3,1) % Rotation point for the ground motion [m] + end +#+end_src + +**** Structure initialization +First, we initialize the =granite= structure. +#+begin_src matlab + ground = struct(); +#+end_src + +**** Add Type +#+begin_src matlab + switch args.type + case 'none' + ground.type = 0; + case 'rigid' + ground.type = 1; + end +#+end_src + +**** Ground Solid properties +We set the shape and density of the ground solid element. +#+begin_src matlab + ground.shape = [2, 2, 0.5]; % [m] + ground.density = 2800; % [kg/m3] +#+end_src + +**** Rotation Point + +#+begin_src matlab + ground.rot_point = args.rot_point; +#+end_src + +**** Save the Structure +#+begin_src matlab +if exist('./mat', 'dir') + if exist('./mat/nass_stages.mat', 'file') + save('mat/nass_stages.mat', 'ground', '-append'); + else + save('mat/nass_stages.mat', 'ground'); + end +elseif exist('./matlab', 'dir') + if exist('./matlab/mat/nass_stages.mat', 'file') + save('matlab/mat/nass_stages.mat', 'ground', '-append'); + else + save('matlab/mat/nass_stages.mat', 'ground'); + end +end +#+end_src + +*** =initializeGranite=: Granite +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/initializeGranite.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Function description +#+begin_src matlab + function [granite] = initializeGranite(args) +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + args.type char {mustBeMember(args.type,{'rigid', 'flexible', 'none'})} = 'flexible' + args.density (1,1) double {mustBeNumeric, mustBeNonnegative} = 2800 % Density [kg/m3] + args.K (6,1) double {mustBeNumeric, mustBeNonnegative} = [5e9; 5e9; 5e9; 2.5e7; 2.5e7; 1e7] % [N/m] + args.C (6,1) double {mustBeNumeric, mustBeNonnegative} = [4.0e5; 1.1e5; 9.0e5; 2e4; 2e4; 1e4] % [N/(m/s)] + args.x0 (1,1) double {mustBeNumeric} = 0 % Rest position of the Joint in the X direction [m] + args.y0 (1,1) double {mustBeNumeric} = 0 % Rest position of the Joint in the Y direction [m] + args.z0 (1,1) double {mustBeNumeric} = 0 % Rest position of the Joint in the Z direction [m] + args.sample_pos (1,1) double {mustBeNumeric} = 0.8 % Height of the measurment point [m] + end +#+end_src + +**** Structure initialization +First, we initialize the =granite= structure. +#+begin_src matlab + granite = struct(); +#+end_src + +**** Add Granite Type +#+begin_src matlab + switch args.type + case 'none' + granite.type = 0; + case 'rigid' + granite.type = 1; + case 'flexible' + granite.type = 2; + end +#+end_src + +**** Material and Geometry + +Properties of the Material and link to the geometry of the granite. +#+begin_src matlab + granite.density = args.density; % [kg/m3] + granite.STEP = 'granite.STEP'; +#+end_src + +Z-offset for the initial position of the sample with respect to the granite top surface. +#+begin_src matlab + granite.sample_pos = args.sample_pos; % [m] +#+end_src + +**** Stiffness and Damping properties + +#+begin_src matlab + granite.K = args.K; % [N/m] + granite.C = args.C; % [N/(m/s)] +#+end_src + +**** Save the Structure +#+begin_src matlab +if exist('./mat', 'dir') + if exist('./mat/nass_stages.mat', 'file') + save('mat/nass_stages.mat', 'granite', '-append'); + else + save('mat/nass_stages.mat', 'granite'); + end +elseif exist('./matlab', 'dir') + if exist('./matlab/mat/nass_stages.mat', 'file') + save('matlab/mat/nass_stages.mat', 'granite', '-append'); + else + save('matlab/mat/nass_stages.mat', 'granite'); + end +end +#+end_src + +*** =initializeTy=: Translation Stage +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/initializeTy.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Function description +#+begin_src matlab + function [ty] = initializeTy(args) +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + args.type char {mustBeMember(args.type,{'none', 'rigid', 'flexible'})} = 'flexible' + end +#+end_src + +**** Structure initialization +First, we initialize the =ty= structure. +#+begin_src matlab + ty = struct(); +#+end_src + +**** Add Translation Stage Type +#+begin_src matlab + switch args.type + case 'none' + ty.type = 0; + case 'rigid' + ty.type = 1; + case 'flexible' + ty.type = 2; + end +#+end_src + +**** Material and Geometry +Define the density of the materials as well as the geometry (STEP files). +#+begin_src matlab + % Ty Granite frame + ty.granite_frame.density = 7800; % [kg/m3] => 43kg + ty.granite_frame.STEP = 'Ty_Granite_Frame.STEP'; + + % Guide Translation Ty + ty.guide.density = 7800; % [kg/m3] => 76kg + ty.guide.STEP = 'Ty_Guide.STEP'; + + % Ty - Guide_Translation12 + ty.guide12.density = 7800; % [kg/m3] + ty.guide12.STEP = 'Ty_Guide_12.STEP'; + + % Ty - Guide_Translation11 + ty.guide11.density = 7800; % [kg/m3] + ty.guide11.STEP = 'Ty_Guide_11.STEP'; + + % Ty - Guide_Translation22 + ty.guide22.density = 7800; % [kg/m3] + ty.guide22.STEP = 'Ty_Guide_22.STEP'; + + % Ty - Guide_Translation21 + ty.guide21.density = 7800; % [kg/m3] + ty.guide21.STEP = 'Ty_Guide_21.STEP'; + + % Ty - Plateau translation + ty.frame.density = 7800; % [kg/m3] + ty.frame.STEP = 'Ty_Stage.STEP'; + + % Ty Stator Part + ty.stator.density = 5400; % [kg/m3] + ty.stator.STEP = 'Ty_Motor_Stator.STEP'; + + % Ty Rotor Part + ty.rotor.density = 5400; % [kg/m3] + ty.rotor.STEP = 'Ty_Motor_Rotor.STEP'; +#+end_src + +**** Stiffness and Damping properties + +#+begin_src matlab + ty.K = [2e8; 1e8; 2e8; 6e7; 9e7; 6e7]; % [N/m, N*m/rad] + ty.C = [8e4; 5e4; 8e4; 2e4; 3e4; 1e4]; % [N/(m/s), N*m/(rad/s)] +#+end_src + +**** Save the Structure +#+begin_src matlab +if exist('./mat', 'dir') + if exist('./mat/nass_stages.mat', 'file') + save('mat/nass_stages.mat', 'ty', '-append'); + else + save('mat/nass_stages.mat', 'ty'); + end +elseif exist('./matlab', 'dir') + if exist('./matlab/mat/nass_stages.mat', 'file') + save('matlab/mat/nass_stages.mat', 'ty', '-append'); + else + save('matlab/mat/nass_stages.mat', 'ty'); + end +end +#+end_src + +*** =initializeRy=: Tilt Stage +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/initializeRy.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Function description +#+begin_src matlab + function [ry] = initializeRy(args) +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + args.type char {mustBeMember(args.type,{'none', 'rigid', 'flexible'})} = 'flexible' + args.Ry_init (1,1) double {mustBeNumeric} = 0 + end +#+end_src + +**** Structure initialization +First, we initialize the =ry= structure. +#+begin_src matlab + ry = struct(); +#+end_src + + +**** Add Tilt Type +#+begin_src matlab + switch args.type + case 'none' + ry.type = 0; + case 'rigid' + ry.type = 1; + case 'flexible' + ry.type = 2; + end +#+end_src + +**** Material and Geometry +Properties of the Material and link to the geometry of the Tilt stage. +#+begin_src matlab + % Ry - Guide for the tilt stage + ry.guide.density = 7800; % [kg/m3] + ry.guide.STEP = 'Tilt_Guide.STEP'; + + % Ry - Rotor of the motor + ry.rotor.density = 2400; % [kg/m3] + ry.rotor.STEP = 'Tilt_Motor_Axis.STEP'; + + % Ry - Motor + ry.motor.density = 3200; % [kg/m3] + ry.motor.STEP = 'Tilt_Motor.STEP'; + + % Ry - Plateau Tilt + ry.stage.density = 7800; % [kg/m3] + ry.stage.STEP = 'Tilt_Stage.STEP'; +#+end_src + +Z-Offset so that the center of rotation matches the sample center; +#+begin_src matlab + ry.z_offset = 0.58178; % [m] +#+end_src + +#+begin_src matlab + ry.Ry_init = args.Ry_init; % [rad] +#+end_src + +**** Stiffness and Damping properties + +#+begin_src matlab + ry.K = [3.8e8; 4e8; 3.8e8; 1.2e8; 6e4; 1.2e8]; + ry.C = [1e5; 1e5; 1e5; 3e4; 1e3; 3e4]; +#+end_src + +**** Save the Structure +#+begin_src matlab +if exist('./mat', 'dir') + if exist('./mat/nass_stages.mat', 'file') + save('mat/nass_stages.mat', 'ry', '-append'); + else + save('mat/nass_stages.mat', 'ry'); + end +elseif exist('./matlab', 'dir') + if exist('./matlab/mat/nass_stages.mat', 'file') + save('matlab/mat/nass_stages.mat', 'ry', '-append'); + else + save('matlab/mat/nass_stages.mat', 'ry'); + end +end +#+end_src + +*** =initializeRz=: Spindle +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/initializeRz.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Function description +#+begin_src matlab + function [rz] = initializeRz(args) +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + args.type char {mustBeMember(args.type,{'none', 'rigid', 'flexible'})} = 'flexible' + end +#+end_src + +**** Structure initialization +First, we initialize the =rz= structure. +#+begin_src matlab + rz = struct(); +#+end_src + +**** Add Spindle Type +#+begin_src matlab + switch args.type + case 'none' + rz.type = 0; + case 'rigid' + rz.type = 1; + case 'flexible' + rz.type = 2; + end +#+end_src + +**** Material and Geometry + +Properties of the Material and link to the geometry of the spindle. +#+begin_src matlab + % Spindle - Slip Ring + rz.slipring.density = 7800; % [kg/m3] + rz.slipring.STEP = 'Spindle_Slip_Ring.STEP'; + + % Spindle - Rotor + rz.rotor.density = 7800; % [kg/m3] + rz.rotor.STEP = 'Spindle_Rotor.STEP'; + + % Spindle - Stator + rz.stator.density = 7800; % [kg/m3] + rz.stator.STEP = 'Spindle_Stator.STEP'; +#+end_src + +**** Stiffness and Damping properties + +#+begin_src matlab + rz.K = [7e8; 7e8; 2e9; 1e7; 1e7; 1e7]; + rz.C = [4e4; 4e4; 7e4; 1e4; 1e4; 1e4]; +#+end_src + +**** Save the Structure +#+begin_src matlab +if exist('./mat', 'dir') + if exist('./mat/nass_stages.mat', 'file') + save('mat/nass_stages.mat', 'rz', '-append'); + else + save('mat/nass_stages.mat', 'rz'); + end +elseif exist('./matlab', 'dir') + if exist('./matlab/mat/nass_stages.mat', 'file') + save('matlab/mat/nass_stages.mat', 'rz', '-append'); + else + save('matlab/mat/nass_stages.mat', 'rz'); + end +end +#+end_src + +*** =initializeMicroHexapod=: Micro Hexapod +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/initializeMicroHexapod.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Function description +#+begin_src matlab + function [micro_hexapod] = initializeMicroHexapod(args) +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + args.type char {mustBeMember(args.type,{'none', 'rigid', 'flexible'})} = 'flexible' + % initializeFramesPositions + args.H (1,1) double {mustBeNumeric, mustBePositive} = 350e-3 + args.MO_B (1,1) double {mustBeNumeric} = 270e-3 + % generateGeneralConfiguration + args.FH (1,1) double {mustBeNumeric, mustBePositive} = 50e-3 + args.FR (1,1) double {mustBeNumeric, mustBePositive} = 175.5e-3 + args.FTh (6,1) double {mustBeNumeric} = [-10, 10, 120-10, 120+10, 240-10, 240+10]*(pi/180) + args.MH (1,1) double {mustBeNumeric, mustBePositive} = 45e-3 + args.MR (1,1) double {mustBeNumeric, mustBePositive} = 118e-3 + args.MTh (6,1) double {mustBeNumeric} = [-60+10, 60-10, 60+10, 180-10, 180+10, -60-10]*(pi/180) + % initializeStrutDynamics + args.Ki (6,1) double {mustBeNumeric, mustBeNonnegative} = 2e7*ones(6,1) + args.Ci (6,1) double {mustBeNumeric, mustBeNonnegative} = 1.4e3*ones(6,1) + % initializeCylindricalPlatforms + args.Fpm (1,1) double {mustBeNumeric, mustBePositive} = 10 + args.Fph (1,1) double {mustBeNumeric, mustBePositive} = 26e-3 + args.Fpr (1,1) double {mustBeNumeric, mustBePositive} = 207.5e-3 + args.Mpm (1,1) double {mustBeNumeric, mustBePositive} = 10 + args.Mph (1,1) double {mustBeNumeric, mustBePositive} = 26e-3 + args.Mpr (1,1) double {mustBeNumeric, mustBePositive} = 150e-3 + % initializeCylindricalStruts + args.Fsm (1,1) double {mustBeNumeric, mustBePositive} = 1 + args.Fsh (1,1) double {mustBeNumeric, mustBePositive} = 100e-3 + args.Fsr (1,1) double {mustBeNumeric, mustBePositive} = 25e-3 + args.Msm (1,1) double {mustBeNumeric, mustBePositive} = 1 + args.Msh (1,1) double {mustBeNumeric, mustBePositive} = 100e-3 + args.Msr (1,1) double {mustBeNumeric, mustBePositive} = 25e-3 + % inverseKinematics + args.AP (3,1) double {mustBeNumeric} = zeros(3,1) + args.ARB (3,3) double {mustBeNumeric} = eye(3) + end +#+end_src + +**** Function content +#+begin_src matlab + stewart = initializeStewartPlatform(); + + stewart = initializeFramesPositions(stewart, ... + 'H', args.H, ... + 'MO_B', args.MO_B); + + stewart = generateGeneralConfiguration(stewart, ... + 'FH', args.FH, ... + 'FR', args.FR, ... + 'FTh', args.FTh, ... + 'MH', args.MH, ... + 'MR', args.MR, ... + 'MTh', args.MTh); + + stewart = computeJointsPose(stewart); +#+end_src + +#+begin_src matlab + stewart = initializeStrutDynamics(stewart, ... + 'K', args.Ki, ... + 'C', args.Ci); + + stewart = initializeJointDynamics(stewart, ... + 'type_F', 'universal_p', ... + 'type_M', 'spherical_p'); +#+end_src + +#+begin_src matlab + stewart = initializeCylindricalPlatforms(stewart, ... + 'Fpm', args.Fpm, ... + 'Fph', args.Fph, ... + 'Fpr', args.Fpr, ... + 'Mpm', args.Mpm, ... + 'Mph', args.Mph, ... + 'Mpr', args.Mpr); + + stewart = initializeCylindricalStruts(stewart, ... + 'Fsm', args.Fsm, ... + 'Fsh', args.Fsh, ... + 'Fsr', args.Fsr, ... + 'Msm', args.Msm, ... + 'Msh', args.Msh, ... + 'Msr', args.Msr); + + stewart = computeJacobian(stewart); + + stewart = initializeStewartPose(stewart, ... + 'AP', args.AP, ... + 'ARB', args.ARB); +#+end_src + +#+begin_src matlab + stewart = initializeInertialSensor(stewart, 'type', 'none'); +#+end_src + +**** Add Type +#+begin_src matlab + switch args.type + case 'none' + stewart.type = 0; + case 'rigid' + stewart.type = 1; + case 'flexible' + stewart.type = 2; + end +#+end_src + +**** Save the Structure +#+begin_src matlab +micro_hexapod = stewart; +if exist('./mat', 'dir') + if exist('./mat/nass_stages.mat', 'file') + save('mat/nass_stages.mat', 'micro_hexapod', '-append'); + else + save('mat/nass_stages.mat', 'micro_hexapod'); + end +elseif exist('./matlab', 'dir') + if exist('./matlab/mat/nass_stages.mat', 'file') + save('matlab/mat/nass_stages.mat', 'micro_hexapod', '-append'); + else + save('matlab/mat/nass_stages.mat', 'micro_hexapod'); + end +end +#+end_src + +** Stewart platform +*** =initializeStewartPlatform=: Initialize the Stewart Platform structure +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/initializeStewartPlatform.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Documentation + +#+name: fig:stewart-frames-position +#+caption: Definition of the position of the frames +[[file:figs/stewart-frames-position.png]] + +**** Function description +#+begin_src matlab + function [stewart] = initializeStewartPlatform() + % initializeStewartPlatform - Initialize the stewart structure + % + % Syntax: [stewart] = initializeStewartPlatform(args) + % + % Outputs: + % - stewart - A structure with the following sub-structures: + % - platform_F - + % - platform_M - + % - joints_F - + % - joints_M - + % - struts_F - + % - struts_M - + % - actuators - + % - geometry - + % - properties - +#+end_src + +**** Initialize the Stewart structure +#+begin_src matlab + stewart = struct(); + stewart.platform_F = struct(); + stewart.platform_M = struct(); + stewart.joints_F = struct(); + stewart.joints_M = struct(); + stewart.struts_F = struct(); + stewart.struts_M = struct(); + stewart.actuators = struct(); + stewart.sensors = struct(); + stewart.sensors.inertial = struct(); + stewart.sensors.force = struct(); + stewart.sensors.relative = struct(); + stewart.geometry = struct(); + stewart.kinematics = struct(); +#+end_src + +*** =initializeFramesPositions=: Initialize the positions of frames {A}, {B}, {F} and {M} +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/initializeFramesPositions.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Documentation + +#+name: fig:stewart-frames-position +#+caption: Definition of the position of the frames +[[file:figs/stewart-frames-position.png]] + +**** Function description +#+begin_src matlab + function [stewart] = initializeFramesPositions(stewart, args) + % initializeFramesPositions - Initialize the positions of frames {A}, {B}, {F} and {M} + % + % Syntax: [stewart] = initializeFramesPositions(stewart, args) + % + % Inputs: + % - args - Can have the following fields: + % - H [1x1] - Total Height of the Stewart Platform (height from {F} to {M}) [m] + % - MO_B [1x1] - Height of the frame {B} with respect to {M} [m] + % + % Outputs: + % - stewart - A structure with the following fields: + % - geometry.H [1x1] - Total Height of the Stewart Platform [m] + % - geometry.FO_M [3x1] - Position of {M} with respect to {F} [m] + % - platform_M.MO_B [3x1] - Position of {B} with respect to {M} [m] + % - platform_F.FO_A [3x1] - Position of {A} with respect to {F} [m] +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + stewart + args.H (1,1) double {mustBeNumeric, mustBePositive} = 90e-3 + args.MO_B (1,1) double {mustBeNumeric} = 50e-3 + end +#+end_src + +**** Compute the position of each frame +#+begin_src matlab + H = args.H; % Total Height of the Stewart Platform [m] + + FO_M = [0; 0; H]; % Position of {M} with respect to {F} [m] + + MO_B = [0; 0; args.MO_B]; % Position of {B} with respect to {M} [m] + + FO_A = MO_B + FO_M; % Position of {A} with respect to {F} [m] +#+end_src + +**** Populate the =stewart= structure +#+begin_src matlab + stewart.geometry.H = H; + stewart.geometry.FO_M = FO_M; + stewart.platform_M.MO_B = MO_B; + stewart.platform_F.FO_A = FO_A; +#+end_src + +*** =generateGeneralConfiguration=: Generate a Very General Configuration +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/generateGeneralConfiguration.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Documentation +Joints are positions on a circle centered with the Z axis of {F} and {M} and at a chosen distance from {F} and {M}. +The radius of the circles can be chosen as well as the angles where the joints are located (see Figure ref:fig:joint_position_general). + +#+begin_src latex :file stewart_bottom_plate.pdf :tangle no + \begin{tikzpicture} + % Internal and external limit + \draw[fill=white!80!black] (0, 0) circle [radius=3]; + % Circle where the joints are located + \draw[dashed] (0, 0) circle [radius=2.5]; + + % Bullets for the positions of the joints + \node[] (J1) at ( 80:2.5){$\bullet$}; + \node[] (J2) at (100:2.5){$\bullet$}; + \node[] (J3) at (200:2.5){$\bullet$}; + \node[] (J4) at (220:2.5){$\bullet$}; + \node[] (J5) at (320:2.5){$\bullet$}; + \node[] (J6) at (340:2.5){$\bullet$}; + + % Name of the points + \node[above right] at (J1) {$a_{1}$}; + \node[above left] at (J2) {$a_{2}$}; + \node[above left] at (J3) {$a_{3}$}; + \node[right ] at (J4) {$a_{4}$}; + \node[left ] at (J5) {$a_{5}$}; + \node[above right] at (J6) {$a_{6}$}; + + % First 2 angles + \draw[dashed, ->] (0:1) arc [start angle=0, end angle=80, radius=1] node[below right]{$\theta_{1}$}; + \draw[dashed, ->] (0:1.5) arc [start angle=0, end angle=100, radius=1.5] node[left ]{$\theta_{2}$}; + + % Division of 360 degrees by 3 + \draw[dashed] (0, 0) -- ( 80:3.2); + \draw[dashed] (0, 0) -- (100:3.2); + \draw[dashed] (0, 0) -- (200:3.2); + \draw[dashed] (0, 0) -- (220:3.2); + \draw[dashed] (0, 0) -- (320:3.2); + \draw[dashed] (0, 0) -- (340:3.2); + + % Radius for the position of the joints + \draw[<->] (0, 0) --node[near end, above]{$R$} (180:2.5); + + \draw[->] (0, 0) -- ++(3.4, 0) node[above]{$x$}; + \draw[->] (0, 0) -- ++(0, 3.4) node[left]{$y$}; + \end{tikzpicture} +#+end_src + +#+name: fig:joint_position_general +#+caption: Position of the joints +#+RESULTS: +[[file:figs/stewart_bottom_plate.png]] + +**** Function description +#+begin_src matlab + function [stewart] = generateGeneralConfiguration(stewart, args) + % generateGeneralConfiguration - Generate a Very General Configuration + % + % Syntax: [stewart] = generateGeneralConfiguration(stewart, args) + % + % Inputs: + % - args - Can have the following fields: + % - FH [1x1] - Height of the position of the fixed joints with respect to the frame {F} [m] + % - FR [1x1] - Radius of the position of the fixed joints in the X-Y [m] + % - FTh [6x1] - Angles of the fixed joints in the X-Y plane with respect to the X axis [rad] + % - MH [1x1] - Height of the position of the mobile joints with respect to the frame {M} [m] + % - FR [1x1] - Radius of the position of the mobile joints in the X-Y [m] + % - MTh [6x1] - Angles of the mobile joints in the X-Y plane with respect to the X axis [rad] + % + % Outputs: + % - stewart - updated Stewart structure with the added fields: + % - platform_F.Fa [3x6] - Its i'th column is the position vector of joint ai with respect to {F} + % - platform_M.Mb [3x6] - Its i'th column is the position vector of joint bi with respect to {M} +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + stewart + args.FH (1,1) double {mustBeNumeric, mustBePositive} = 15e-3 + args.FR (1,1) double {mustBeNumeric, mustBePositive} = 115e-3; + args.FTh (6,1) double {mustBeNumeric} = [-10, 10, 120-10, 120+10, 240-10, 240+10]*(pi/180); + args.MH (1,1) double {mustBeNumeric, mustBePositive} = 15e-3 + args.MR (1,1) double {mustBeNumeric, mustBePositive} = 90e-3; + args.MTh (6,1) double {mustBeNumeric} = [-60+10, 60-10, 60+10, 180-10, 180+10, -60-10]*(pi/180); + end +#+end_src + +**** Compute the pose +#+begin_src matlab + Fa = zeros(3,6); + Mb = zeros(3,6); +#+end_src + +#+begin_src matlab + for i = 1:6 + Fa(:,i) = [args.FR*cos(args.FTh(i)); args.FR*sin(args.FTh(i)); args.FH]; + Mb(:,i) = [args.MR*cos(args.MTh(i)); args.MR*sin(args.MTh(i)); -args.MH]; + end +#+end_src + +**** Populate the =stewart= structure +#+begin_src matlab + stewart.platform_F.Fa = Fa; + stewart.platform_M.Mb = Mb; +#+end_src + +*** =computeJointsPose=: Compute the Pose of the Joints +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/computeJointsPose.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Documentation + +#+name: fig:stewart-struts +#+caption: Position and orientation of the struts +[[file:figs/stewart-struts.png]] + +**** Function description +#+begin_src matlab + function [stewart] = computeJointsPose(stewart) + % computeJointsPose - + % + % Syntax: [stewart] = computeJointsPose(stewart) + % + % Inputs: + % - stewart - A structure with the following fields + % - platform_F.Fa [3x6] - Its i'th column is the position vector of joint ai with respect to {F} + % - platform_M.Mb [3x6] - Its i'th column is the position vector of joint bi with respect to {M} + % - platform_F.FO_A [3x1] - Position of {A} with respect to {F} + % - platform_M.MO_B [3x1] - Position of {B} with respect to {M} + % - geometry.FO_M [3x1] - Position of {M} with respect to {F} + % + % Outputs: + % - stewart - A structure with the following added fields + % - geometry.Aa [3x6] - The i'th column is the position of ai with respect to {A} + % - geometry.Ab [3x6] - The i'th column is the position of bi with respect to {A} + % - geometry.Ba [3x6] - The i'th column is the position of ai with respect to {B} + % - geometry.Bb [3x6] - The i'th column is the position of bi with respect to {B} + % - geometry.l [6x1] - The i'th element is the initial length of strut i + % - geometry.As [3x6] - The i'th column is the unit vector of strut i expressed in {A} + % - geometry.Bs [3x6] - The i'th column is the unit vector of strut i expressed in {B} + % - struts_F.l [6x1] - Length of the Fixed part of the i'th strut + % - struts_M.l [6x1] - Length of the Mobile part of the i'th strut + % - platform_F.FRa [3x3x6] - The i'th 3x3 array is the rotation matrix to orientate the bottom of the i'th strut from {F} + % - platform_M.MRb [3x3x6] - The i'th 3x3 array is the rotation matrix to orientate the top of the i'th strut from {M} +#+end_src + +**** Check the =stewart= structure elements +#+begin_src matlab + assert(isfield(stewart.platform_F, 'Fa'), 'stewart.platform_F should have attribute Fa') + Fa = stewart.platform_F.Fa; + + assert(isfield(stewart.platform_M, 'Mb'), 'stewart.platform_M should have attribute Mb') + Mb = stewart.platform_M.Mb; + + assert(isfield(stewart.platform_F, 'FO_A'), 'stewart.platform_F should have attribute FO_A') + FO_A = stewart.platform_F.FO_A; + + assert(isfield(stewart.platform_M, 'MO_B'), 'stewart.platform_M should have attribute MO_B') + MO_B = stewart.platform_M.MO_B; + + assert(isfield(stewart.geometry, 'FO_M'), 'stewart.geometry should have attribute FO_M') + FO_M = stewart.geometry.FO_M; +#+end_src + +**** Compute the position of the Joints +#+begin_src matlab + Aa = Fa - repmat(FO_A, [1, 6]); + Bb = Mb - repmat(MO_B, [1, 6]); + + Ab = Bb - repmat(-MO_B-FO_M+FO_A, [1, 6]); + Ba = Aa - repmat( MO_B+FO_M-FO_A, [1, 6]); +#+end_src + +**** Compute the strut length and orientation +#+begin_src matlab + As = (Ab - Aa)./vecnorm(Ab - Aa); % As_i is the i'th vector of As + + l = vecnorm(Ab - Aa)'; +#+end_src + +#+begin_src matlab + Bs = (Bb - Ba)./vecnorm(Bb - Ba); +#+end_src + +**** Compute the orientation of the Joints +#+begin_src matlab + FRa = zeros(3,3,6); + MRb = zeros(3,3,6); + + for i = 1:6 + FRa(:,:,i) = [cross([0;1;0], As(:,i)) , cross(As(:,i), cross([0;1;0], As(:,i))) , As(:,i)]; + FRa(:,:,i) = FRa(:,:,i)./vecnorm(FRa(:,:,i)); + + MRb(:,:,i) = [cross([0;1;0], Bs(:,i)) , cross(Bs(:,i), cross([0;1;0], Bs(:,i))) , Bs(:,i)]; + MRb(:,:,i) = MRb(:,:,i)./vecnorm(MRb(:,:,i)); + end +#+end_src + +**** Populate the =stewart= structure +#+begin_src matlab + stewart.geometry.Aa = Aa; + stewart.geometry.Ab = Ab; + stewart.geometry.Ba = Ba; + stewart.geometry.Bb = Bb; + stewart.geometry.As = As; + stewart.geometry.Bs = Bs; + stewart.geometry.l = l; + + stewart.struts_F.l = l/2; + stewart.struts_M.l = l/2; + + stewart.platform_F.FRa = FRa; + stewart.platform_M.MRb = MRb; +#+end_src + +*** =initializeCylindricalPlatforms=: Initialize the geometry of the Fixed and Mobile Platforms +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/initializeCylindricalPlatforms.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Function description +#+begin_src matlab + function [stewart] = initializeCylindricalPlatforms(stewart, args) + % initializeCylindricalPlatforms - Initialize the geometry of the Fixed and Mobile Platforms + % + % Syntax: [stewart] = initializeCylindricalPlatforms(args) + % + % Inputs: + % - args - Structure with the following fields: + % - Fpm [1x1] - Fixed Platform Mass [kg] + % - Fph [1x1] - Fixed Platform Height [m] + % - Fpr [1x1] - Fixed Platform Radius [m] + % - Mpm [1x1] - Mobile Platform Mass [kg] + % - Mph [1x1] - Mobile Platform Height [m] + % - Mpr [1x1] - Mobile Platform Radius [m] + % + % Outputs: + % - stewart - updated Stewart structure with the added fields: + % - platform_F [struct] - structure with the following fields: + % - type = 1 + % - M [1x1] - Fixed Platform Mass [kg] + % - I [3x3] - Fixed Platform Inertia matrix [kg*m^2] + % - H [1x1] - Fixed Platform Height [m] + % - R [1x1] - Fixed Platform Radius [m] + % - platform_M [struct] - structure with the following fields: + % - M [1x1] - Mobile Platform Mass [kg] + % - I [3x3] - Mobile Platform Inertia matrix [kg*m^2] + % - H [1x1] - Mobile Platform Height [m] + % - R [1x1] - Mobile Platform Radius [m] +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + stewart + args.Fpm (1,1) double {mustBeNumeric, mustBePositive} = 1 + args.Fph (1,1) double {mustBeNumeric, mustBePositive} = 10e-3 + args.Fpr (1,1) double {mustBeNumeric, mustBePositive} = 125e-3 + args.Mpm (1,1) double {mustBeNumeric, mustBePositive} = 1 + args.Mph (1,1) double {mustBeNumeric, mustBePositive} = 10e-3 + args.Mpr (1,1) double {mustBeNumeric, mustBePositive} = 100e-3 + end +#+end_src + +**** Compute the Inertia matrices of platforms +#+begin_src matlab + I_F = diag([1/12*args.Fpm * (3*args.Fpr^2 + args.Fph^2), ... + 1/12*args.Fpm * (3*args.Fpr^2 + args.Fph^2), ... + 1/2 *args.Fpm * args.Fpr^2]); +#+end_src + +#+begin_src matlab + I_M = diag([1/12*args.Mpm * (3*args.Mpr^2 + args.Mph^2), ... + 1/12*args.Mpm * (3*args.Mpr^2 + args.Mph^2), ... + 1/2 *args.Mpm * args.Mpr^2]); +#+end_src + +**** Populate the =stewart= structure +#+begin_src matlab + stewart.platform_F.type = 1; + + stewart.platform_F.I = I_F; + stewart.platform_F.M = args.Fpm; + stewart.platform_F.R = args.Fpr; + stewart.platform_F.H = args.Fph; +#+end_src + +#+begin_src matlab + stewart.platform_M.type = 1; + + stewart.platform_M.I = I_M; + stewart.platform_M.M = args.Mpm; + stewart.platform_M.R = args.Mpr; + stewart.platform_M.H = args.Mph; +#+end_src + +*** =initializeCylindricalStruts=: Define the inertia of cylindrical struts +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/initializeCylindricalStruts.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Function description +#+begin_src matlab + function [stewart] = initializeCylindricalStruts(stewart, args) + % initializeCylindricalStruts - Define the mass and moment of inertia of cylindrical struts + % + % Syntax: [stewart] = initializeCylindricalStruts(args) + % + % Inputs: + % - args - Structure with the following fields: + % - Fsm [1x1] - Mass of the Fixed part of the struts [kg] + % - Fsh [1x1] - Height of cylinder for the Fixed part of the struts [m] + % - Fsr [1x1] - Radius of cylinder for the Fixed part of the struts [m] + % - Msm [1x1] - Mass of the Mobile part of the struts [kg] + % - Msh [1x1] - Height of cylinder for the Mobile part of the struts [m] + % - Msr [1x1] - Radius of cylinder for the Mobile part of the struts [m] + % + % Outputs: + % - stewart - updated Stewart structure with the added fields: + % - struts_F [struct] - structure with the following fields: + % - M [6x1] - Mass of the Fixed part of the struts [kg] + % - I [3x3x6] - Moment of Inertia for the Fixed part of the struts [kg*m^2] + % - H [6x1] - Height of cylinder for the Fixed part of the struts [m] + % - R [6x1] - Radius of cylinder for the Fixed part of the struts [m] + % - struts_M [struct] - structure with the following fields: + % - M [6x1] - Mass of the Mobile part of the struts [kg] + % - I [3x3x6] - Moment of Inertia for the Mobile part of the struts [kg*m^2] + % - H [6x1] - Height of cylinder for the Mobile part of the struts [m] + % - R [6x1] - Radius of cylinder for the Mobile part of the struts [m] +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + stewart + args.Fsm (1,1) double {mustBeNumeric, mustBePositive} = 0.1 + args.Fsh (1,1) double {mustBeNumeric, mustBePositive} = 50e-3 + args.Fsr (1,1) double {mustBeNumeric, mustBePositive} = 5e-3 + args.Msm (1,1) double {mustBeNumeric, mustBePositive} = 0.1 + args.Msh (1,1) double {mustBeNumeric, mustBePositive} = 50e-3 + args.Msr (1,1) double {mustBeNumeric, mustBePositive} = 5e-3 + end +#+end_src + +**** Compute the properties of the cylindrical struts + +#+begin_src matlab + Fsm = ones(6,1).*args.Fsm; + Fsh = ones(6,1).*args.Fsh; + Fsr = ones(6,1).*args.Fsr; + + Msm = ones(6,1).*args.Msm; + Msh = ones(6,1).*args.Msh; + Msr = ones(6,1).*args.Msr; +#+end_src + +#+begin_src matlab + I_F = zeros(3, 3, 6); % Inertia of the "fixed" part of the strut + I_M = zeros(3, 3, 6); % Inertia of the "mobile" part of the strut + + for i = 1:6 + I_F(:,:,i) = diag([1/12 * Fsm(i) * (3*Fsr(i)^2 + Fsh(i)^2), ... + 1/12 * Fsm(i) * (3*Fsr(i)^2 + Fsh(i)^2), ... + 1/2 * Fsm(i) * Fsr(i)^2]); + + I_M(:,:,i) = diag([1/12 * Msm(i) * (3*Msr(i)^2 + Msh(i)^2), ... + 1/12 * Msm(i) * (3*Msr(i)^2 + Msh(i)^2), ... + 1/2 * Msm(i) * Msr(i)^2]); + end +#+end_src + +**** Populate the =stewart= structure +#+begin_src matlab + stewart.struts_M.type = 1; + + stewart.struts_M.I = I_M; + stewart.struts_M.M = Msm; + stewart.struts_M.R = Msr; + stewart.struts_M.H = Msh; +#+end_src + +#+begin_src matlab + stewart.struts_F.type = 1; + + stewart.struts_F.I = I_F; + stewart.struts_F.M = Fsm; + stewart.struts_F.R = Fsr; + stewart.struts_F.H = Fsh; +#+end_src + +*** =initializeStrutDynamics=: Add Stiffness and Damping properties of each strut +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/initializeStrutDynamics.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Documentation + +#+name: fig:piezoelectric_stack +#+attr_html: :width 500px +#+caption: Example of a piezoelectric stach actuator (PI) +[[file:figs/piezoelectric_stack.jpg]] + +A simplistic model of such amplified actuator is shown in Figure ref:fig:actuator_model_simple where: +- $K$ represent the vertical stiffness of the actuator +- $C$ represent the vertical damping of the actuator +- $F$ represents the force applied by the actuator +- $F_{m}$ represents the total measured force +- $v_{m}$ represents the absolute velocity of the top part of the actuator +- $d_{m}$ represents the total relative displacement of the actuator + +#+begin_src latex :file actuator_model_simple.pdf :tangle no + \begin{tikzpicture} + \draw (-1, 0) -- (1, 0); + + % Spring, Damper, and Actuator + \draw[spring] (-1, 0) -- (-1, 1.5) node[midway, left=0.1]{$K$}; + \draw[damper] ( 0, 0) -- ( 0, 1.5) node[midway, left=0.2]{$C$}; + \draw[actuator] ( 1, 0) -- ( 1, 1.5) node[midway, left=0.1](F){$F$}; + + \node[forcesensor={2}{0.2}] (fsens) at (0, 1.5){}; + + \node[left] at (fsens.west) {$F_{m}$}; + + \draw[dashed] (1, 0) -- ++(0.4, 0); + \draw[dashed] (1, 1.7) -- ++(0.4, 0); + + \draw[->] (0, 1.7)node[]{$\bullet$} -- ++(0, 0.5) node[right]{$v_{m}$}; + + \draw[<->] (1.4, 0) -- ++(0, 1.7) node[midway, right]{$d_{m}$}; + \end{tikzpicture} +#+end_src + +#+name: fig:actuator_model_simple +#+caption: Simple model of an Actuator +#+RESULTS: +[[file:figs/actuator_model_simple.png]] + +**** Function description +#+begin_src matlab + function [stewart] = initializeStrutDynamics(stewart, args) + % initializeStrutDynamics - Add Stiffness and Damping properties of each strut + % + % Syntax: [stewart] = initializeStrutDynamics(args) + % + % Inputs: + % - args - Structure with the following fields: + % - K [6x1] - Stiffness of each strut [N/m] + % - C [6x1] - Damping of each strut [N/(m/s)] + % + % Outputs: + % - stewart - updated Stewart structure with the added fields: + % - actuators.type = 1 + % - actuators.K [6x1] - Stiffness of each strut [N/m] + % - actuators.C [6x1] - Damping of each strut [N/(m/s)] +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + stewart + args.type char {mustBeMember(args.type,{'classical', 'amplified'})} = 'classical' + args.K (6,1) double {mustBeNumeric, mustBeNonnegative} = 20e6*ones(6,1) + args.C (6,1) double {mustBeNumeric, mustBeNonnegative} = 2e1*ones(6,1) + args.k1 (6,1) double {mustBeNumeric} = 1e6*ones(6,1) + args.ke (6,1) double {mustBeNumeric} = 5e6*ones(6,1) + args.ka (6,1) double {mustBeNumeric} = 60e6*ones(6,1) + args.c1 (6,1) double {mustBeNumeric} = 10*ones(6,1) + args.F_gain (6,1) double {mustBeNumeric} = 1*ones(6,1) + args.me (6,1) double {mustBeNumeric} = 0.01*ones(6,1) + args.ma (6,1) double {mustBeNumeric} = 0.01*ones(6,1) + end +#+end_src + +**** Add Stiffness and Damping properties of each strut +#+begin_src matlab + if strcmp(args.type, 'classical') + stewart.actuators.type = 1; + elseif strcmp(args.type, 'amplified') + stewart.actuators.type = 2; + end + + stewart.actuators.K = args.K; + stewart.actuators.C = args.C; + + stewart.actuators.k1 = args.k1; + stewart.actuators.c1 = args.c1; + + stewart.actuators.ka = args.ka; + stewart.actuators.ke = args.ke; + + stewart.actuators.F_gain = args.F_gain; + + stewart.actuators.ma = args.ma; + stewart.actuators.me = args.me; +#+end_src + +*** =initializeJointDynamics=: Add Stiffness and Damping properties for spherical joints +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/initializeJointDynamics.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Function description +#+begin_src matlab + function [stewart] = initializeJointDynamics(stewart, args) + % initializeJointDynamics - Add Stiffness and Damping properties for the spherical joints + % + % Syntax: [stewart] = initializeJointDynamics(args) + % + % Inputs: + % - args - Structure with the following fields: + % - type_F - 'universal', 'spherical', 'universal_p', 'spherical_p' + % - type_M - 'universal', 'spherical', 'universal_p', 'spherical_p' + % - Kf_M [6x1] - Bending (Rx, Ry) Stiffness for each top joints [(N.m)/rad] + % - Kt_M [6x1] - Torsion (Rz) Stiffness for each top joints [(N.m)/rad] + % - Cf_M [6x1] - Bending (Rx, Ry) Damping of each top joint [(N.m)/(rad/s)] + % - Ct_M [6x1] - Torsion (Rz) Damping of each top joint [(N.m)/(rad/s)] + % - Kf_F [6x1] - Bending (Rx, Ry) Stiffness for each bottom joints [(N.m)/rad] + % - Kt_F [6x1] - Torsion (Rz) Stiffness for each bottom joints [(N.m)/rad] + % - Cf_F [6x1] - Bending (Rx, Ry) Damping of each bottom joint [(N.m)/(rad/s)] + % - Cf_F [6x1] - Torsion (Rz) Damping of each bottom joint [(N.m)/(rad/s)] + % + % Outputs: + % - stewart - updated Stewart structure with the added fields: + % - stewart.joints_F and stewart.joints_M: + % - type - 1 (universal), 2 (spherical), 3 (universal perfect), 4 (spherical perfect) + % - Kx, Ky, Kz [6x1] - Translation (Tx, Ty, Tz) Stiffness [N/m] + % - Kf [6x1] - Flexion (Rx, Ry) Stiffness [(N.m)/rad] + % - Kt [6x1] - Torsion (Rz) Stiffness [(N.m)/rad] + % - Cx, Cy, Cz [6x1] - Translation (Rx, Ry) Damping [N/(m/s)] + % - Cf [6x1] - Flexion (Rx, Ry) Damping [(N.m)/(rad/s)] + % - Cb [6x1] - Torsion (Rz) Damping [(N.m)/(rad/s)] +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + stewart + args.type_F char {mustBeMember(args.type_F,{'universal', 'spherical', 'universal_p', 'spherical_p', 'universal_3dof', 'spherical_3dof', 'flexible'})} = 'universal' + args.type_M char {mustBeMember(args.type_M,{'universal', 'spherical', 'universal_p', 'spherical_p', 'universal_3dof', 'spherical_3dof', 'flexible'})} = 'spherical' + args.Kf_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 33*ones(6,1) + args.Cf_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e-4*ones(6,1) + args.Kt_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 236*ones(6,1) + args.Ct_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e-3*ones(6,1) + args.Kf_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 33*ones(6,1) + args.Cf_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e-4*ones(6,1) + args.Kt_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 236*ones(6,1) + args.Ct_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e-3*ones(6,1) + args.Ka_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 1.2e8*ones(6,1) + args.Ca_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e1*ones(6,1) + args.Kr_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 1.1e7*ones(6,1) + args.Cr_F (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e1*ones(6,1) + args.Ka_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 1.2e8*ones(6,1) + args.Ca_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e1*ones(6,1) + args.Kr_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 1.1e7*ones(6,1) + args.Cr_M (6,1) double {mustBeNumeric, mustBeNonnegative} = 1e1*ones(6,1) + args.K_M double {mustBeNumeric} = zeros(6,6) + args.M_M double {mustBeNumeric} = zeros(6,6) + args.n_xyz_M double {mustBeNumeric} = zeros(2,3) + args.xi_M double {mustBeNumeric} = 0.1 + args.step_file_M char {} = '' + args.K_F double {mustBeNumeric} = zeros(6,6) + args.M_F double {mustBeNumeric} = zeros(6,6) + args.n_xyz_F double {mustBeNumeric} = zeros(2,3) + args.xi_F double {mustBeNumeric} = 0.1 + args.step_file_F char {} = '' + end +#+end_src + +**** Add Actuator Type +#+begin_src matlab + switch args.type_F + case 'universal' + stewart.joints_F.type = 1; + case 'spherical' + stewart.joints_F.type = 2; + case 'universal_p' + stewart.joints_F.type = 3; + case 'spherical_p' + stewart.joints_F.type = 4; + case 'flexible' + stewart.joints_F.type = 5; + case 'universal_3dof' + stewart.joints_F.type = 6; + case 'spherical_3dof' + stewart.joints_F.type = 7; + end + + switch args.type_M + case 'universal' + stewart.joints_M.type = 1; + case 'spherical' + stewart.joints_M.type = 2; + case 'universal_p' + stewart.joints_M.type = 3; + case 'spherical_p' + stewart.joints_M.type = 4; + case 'flexible' + stewart.joints_M.type = 5; + case 'universal_3dof' + stewart.joints_M.type = 6; + case 'spherical_3dof' + stewart.joints_M.type = 7; + end +#+end_src + +**** Add Stiffness and Damping in Translation of each strut +Axial and Radial (shear) Stiffness +#+begin_src matlab + stewart.joints_M.Ka = args.Ka_M; + stewart.joints_M.Kr = args.Kr_M; + + stewart.joints_F.Ka = args.Ka_F; + stewart.joints_F.Kr = args.Kr_F; +#+end_src + +Translation Damping +#+begin_src matlab + stewart.joints_M.Ca = args.Ca_M; + stewart.joints_M.Cr = args.Cr_M; + + stewart.joints_F.Ca = args.Ca_F; + stewart.joints_F.Cr = args.Cr_F; +#+end_src + +**** Add Stiffness and Damping in Rotation of each strut +Rotational Stiffness +#+begin_src matlab + stewart.joints_M.Kf = args.Kf_M; + stewart.joints_M.Kt = args.Kt_M; + + stewart.joints_F.Kf = args.Kf_F; + stewart.joints_F.Kt = args.Kt_F; +#+end_src + +Rotational Damping +#+begin_src matlab + stewart.joints_M.Cf = args.Cf_M; + stewart.joints_M.Ct = args.Ct_M; + + stewart.joints_F.Cf = args.Cf_F; + stewart.joints_F.Ct = args.Ct_F; +#+end_src + +**** Stiffness and Mass matrices for flexible joint + +#+begin_src matlab + stewart.joints_F.M = args.M_F; + stewart.joints_F.K = args.K_F; + stewart.joints_F.n_xyz = args.n_xyz_F; + stewart.joints_F.xi = args.xi_F; + stewart.joints_F.xi = args.xi_F; + stewart.joints_F.step_file = args.step_file_F; + + stewart.joints_M.M = args.M_M; + stewart.joints_M.K = args.K_M; + stewart.joints_M.n_xyz = args.n_xyz_M; + stewart.joints_M.xi = args.xi_M; + stewart.joints_M.step_file = args.step_file_M; +#+end_src + +*** =initializeStewartPose=: Determine the initial stroke in each leg to have the wanted pose +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/initializeStewartPose.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Function description +#+begin_src matlab + function [stewart] = initializeStewartPose(stewart, args) + % initializeStewartPose - Determine the initial stroke in each leg to have the wanted pose + % It uses the inverse kinematic + % + % Syntax: [stewart] = initializeStewartPose(stewart, args) + % + % Inputs: + % - stewart - A structure with the following fields + % - Aa [3x6] - The positions ai expressed in {A} + % - Bb [3x6] - The positions bi expressed in {B} + % - args - Can have the following fields: + % - AP [3x1] - The wanted position of {B} with respect to {A} + % - ARB [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A} + % + % Outputs: + % - stewart - updated Stewart structure with the added fields: + % - actuators.Leq [6x1] - The 6 needed displacement of the struts from the initial position in [m] to have the wanted pose of {B} w.r.t. {A} +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + stewart + args.AP (3,1) double {mustBeNumeric} = zeros(3,1) + args.ARB (3,3) double {mustBeNumeric} = eye(3) + end +#+end_src + +**** Use the Inverse Kinematic function +#+begin_src matlab + [Li, dLi] = inverseKinematics(stewart, 'AP', args.AP, 'ARB', args.ARB); +#+end_src + +**** Populate the =stewart= structure +#+begin_src matlab + stewart.actuators.Leq = dLi; +#+end_src + +*** =computeJacobian=: Compute the Jacobian Matrix +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/computeJacobian.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Function description +#+begin_src matlab + function [stewart] = computeJacobian(stewart) + % computeJacobian - + % + % Syntax: [stewart] = computeJacobian(stewart) + % + % Inputs: + % - stewart - With at least the following fields: + % - geometry.As [3x6] - The 6 unit vectors for each strut expressed in {A} + % - geometry.Ab [3x6] - The 6 position of the joints bi expressed in {A} + % - actuators.K [6x1] - Total stiffness of the actuators + % + % Outputs: + % - stewart - With the 3 added field: + % - kinematics.J [6x6] - The Jacobian Matrix + % - kinematics.K [6x6] - The Stiffness Matrix + % - kinematics.C [6x6] - The Compliance Matrix +#+end_src + +**** Check the =stewart= structure elements +#+begin_src matlab + assert(isfield(stewart.geometry, 'As'), 'stewart.geometry should have attribute As') + As = stewart.geometry.As; + + assert(isfield(stewart.geometry, 'Ab'), 'stewart.geometry should have attribute Ab') + Ab = stewart.geometry.Ab; + + assert(isfield(stewart.actuators, 'K'), 'stewart.actuators should have attribute K') + Ki = stewart.actuators.K; +#+end_src + + +**** Compute Jacobian Matrix +#+begin_src matlab + J = [As' , cross(Ab, As)']; +#+end_src + +**** Compute Stiffness Matrix +#+begin_src matlab + K = J'*diag(Ki)*J; +#+end_src + +**** Compute Compliance Matrix +#+begin_src matlab + C = inv(K); +#+end_src + +**** Populate the =stewart= structure +#+begin_src matlab + stewart.kinematics.J = J; + stewart.kinematics.K = K; + stewart.kinematics.C = C; +#+end_src + +*** =initializeInertialSensor=: Initialize the inertial sensor in each strut +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/initializeInertialSensor.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Geophone - Working Principle +From the schematic of the Z-axis geophone shown in Figure ref:fig:z_axis_geophone, we can write the transfer function from the support velocity $\dot{w}$ to the relative velocity of the inertial mass $\dot{d}$: +\[ \frac{\dot{d}}{\dot{w}} = \frac{-\frac{s^2}{{\omega_0}^2}}{\frac{s^2}{{\omega_0}^2} + 2 \xi \frac{s}{\omega_0} + 1} \] +with: +- $\omega_0 = \sqrt{\frac{k}{m}}$ +- $\xi = \frac{1}{2} \sqrt{\frac{m}{k}}$ + +#+name: fig:z_axis_geophone +#+caption: Schematic of a Z-Axis geophone +[[file:figs/inertial_sensor.png]] + +We see that at frequencies above $\omega_0$: +\[ \frac{\dot{d}}{\dot{w}} \approx -1 \] + +And thus, the measurement of the relative velocity of the mass with respect to its support gives the absolute velocity of the support. + +We generally want to have the smallest resonant frequency $\omega_0$ to measure low frequency absolute velocity, however there is a trade-off between $\omega_0$ and the mass of the inertial mass. + +**** Accelerometer - Working Principle +From the schematic of the Z-axis accelerometer shown in Figure ref:fig:z_axis_accelerometer, we can write the transfer function from the support acceleration $\ddot{w}$ to the relative position of the inertial mass $d$: +\[ \frac{d}{\ddot{w}} = \frac{-\frac{1}{{\omega_0}^2}}{\frac{s^2}{{\omega_0}^2} + 2 \xi \frac{s}{\omega_0} + 1} \] +with: +- $\omega_0 = \sqrt{\frac{k}{m}}$ +- $\xi = \frac{1}{2} \sqrt{\frac{m}{k}}$ + +#+name: fig:z_axis_accelerometer +#+caption: Schematic of a Z-Axis geophone +[[file:figs/inertial_sensor.png]] + +We see that at frequencies below $\omega_0$: +\[ \frac{d}{\ddot{w}} \approx -\frac{1}{{\omega_0}^2} \] + +And thus, the measurement of the relative displacement of the mass with respect to its support gives the absolute acceleration of the support. + +Note that there is trade-off between: +- the highest measurable acceleration $\omega_0$ +- the sensitivity of the accelerometer which is equal to $-\frac{1}{{\omega_0}^2}$ + +**** Function description +#+begin_src matlab + function [stewart] = initializeInertialSensor(stewart, args) + % initializeInertialSensor - Initialize the inertial sensor in each strut + % + % Syntax: [stewart] = initializeInertialSensor(args) + % + % Inputs: + % - args - Structure with the following fields: + % - type - 'geophone', 'accelerometer', 'none' + % - mass [1x1] - Weight of the inertial mass [kg] + % - freq [1x1] - Cutoff frequency [Hz] + % + % Outputs: + % - stewart - updated Stewart structure with the added fields: + % - stewart.sensors.inertial + % - type - 1 (geophone), 2 (accelerometer), 3 (none) + % - K [1x1] - Stiffness [N/m] + % - C [1x1] - Damping [N/(m/s)] + % - M [1x1] - Inertial Mass [kg] + % - G [1x1] - Gain +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + stewart + args.type char {mustBeMember(args.type,{'geophone', 'accelerometer', 'none'})} = 'none' + args.mass (1,1) double {mustBeNumeric, mustBeNonnegative} = 1e-2 + args.freq (1,1) double {mustBeNumeric, mustBeNonnegative} = 1e3 + end +#+end_src + +**** Compute the properties of the sensor +#+begin_src matlab + sensor = struct(); + + switch args.type + case 'geophone' + sensor.type = 1; + + sensor.M = args.mass; + sensor.K = sensor.M * (2*pi*args.freq)^2; + sensor.C = 2*sqrt(sensor.M * sensor.K); + case 'accelerometer' + sensor.type = 2; + + sensor.M = args.mass; + sensor.K = sensor.M * (2*pi*args.freq)^2; + sensor.C = 2*sqrt(sensor.M * sensor.K); + sensor.G = -sensor.K/sensor.M; + case 'none' + sensor.type = 3; + end +#+end_src + +**** Populate the =stewart= structure +#+begin_src matlab + stewart.sensors.inertial = sensor; +#+end_src + + + +*** =inverseKinematics=: Compute Inverse Kinematics +:PROPERTIES: +:header-args:matlab+: :tangle matlab/src/inverseKinematics.m +:header-args:matlab+: :comments none :mkdirp yes :eval no +:END: + +**** Theory +For inverse kinematic analysis, it is assumed that the position ${}^A\mathbf{P}$ and orientation of the moving platform ${}^A\mathbf{R}_B$ are given and the problem is to obtain the joint variables, namely, $\mathbf{L} = [l_1, l_2, \dots, l_6]^T$. + +From the geometry of the manipulator, the loop closure for each limb, $i = 1, 2, \dots, 6$ can be written as +\begin{align*} + l_i {}^A\hat{\mathbf{s}}_i &= {}^A\mathbf{A} + {}^A\mathbf{b}_i - {}^A\mathbf{a}_i \\ + &= {}^A\mathbf{A} + {}^A\mathbf{R}_b {}^B\mathbf{b}_i - {}^A\mathbf{a}_i +\end{align*} + +To obtain the length of each actuator and eliminate $\hat{\mathbf{s}}_i$, it is sufficient to dot multiply each side by itself: +\begin{equation} + l_i^2 \left[ {}^A\hat{\mathbf{s}}_i^T {}^A\hat{\mathbf{s}}_i \right] = \left[ {}^A\mathbf{P} + {}^A\mathbf{R}_B {}^B\mathbf{b}_i - {}^A\mathbf{a}_i \right]^T \left[ {}^A\mathbf{P} + {}^A\mathbf{R}_B {}^B\mathbf{b}_i - {}^A\mathbf{a}_i \right] +\end{equation} + +Hence, for $i = 1, 2, \dots, 6$, each limb length can be uniquely determined by: +\begin{equation} + l_i = \sqrt{{}^A\mathbf{P}^T {}^A\mathbf{P} + {}^B\mathbf{b}_i^T {}^B\mathbf{b}_i + {}^A\mathbf{a}_i^T {}^A\mathbf{a}_i - 2 {}^A\mathbf{P}^T {}^A\mathbf{a}_i + 2 {}^A\mathbf{P}^T \left[{}^A\mathbf{R}_B {}^B\mathbf{b}_i\right] - 2 \left[{}^A\mathbf{R}_B {}^B\mathbf{b}_i\right]^T {}^A\mathbf{a}_i} +\end{equation} + +If the position and orientation of the moving platform lie in the feasible workspace of the manipulator, one unique solution to the limb length is determined by the above equation. +Otherwise, when the limbs' lengths derived yield complex numbers, then the position or orientation of the moving platform is not reachable. + +**** Function description +#+begin_src matlab + function [Li, dLi] = inverseKinematics(stewart, args) + % inverseKinematics - Compute the needed length of each strut to have the wanted position and orientation of {B} with respect to {A} + % + % Syntax: [stewart] = inverseKinematics(stewart) + % + % Inputs: + % - stewart - A structure with the following fields + % - geometry.Aa [3x6] - The positions ai expressed in {A} + % - geometry.Bb [3x6] - The positions bi expressed in {B} + % - geometry.l [6x1] - Length of each strut + % - args - Can have the following fields: + % - AP [3x1] - The wanted position of {B} with respect to {A} + % - ARB [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A} + % + % Outputs: + % - Li [6x1] - The 6 needed length of the struts in [m] to have the wanted pose of {B} w.r.t. {A} + % - dLi [6x1] - The 6 needed displacement of the struts from the initial position in [m] to have the wanted pose of {B} w.r.t. {A} +#+end_src + +**** Optional Parameters +#+begin_src matlab + arguments + stewart + args.AP (3,1) double {mustBeNumeric} = zeros(3,1) + args.ARB (3,3) double {mustBeNumeric} = eye(3) + end +#+end_src + +**** Check the =stewart= structure elements +#+begin_src matlab + assert(isfield(stewart.geometry, 'Aa'), 'stewart.geometry should have attribute Aa') + Aa = stewart.geometry.Aa; + + assert(isfield(stewart.geometry, 'Bb'), 'stewart.geometry should have attribute Bb') + Bb = stewart.geometry.Bb; + + assert(isfield(stewart.geometry, 'l'), 'stewart.geometry should have attribute l') + l = stewart.geometry.l; +#+end_src + + +**** Compute +#+begin_src matlab + Li = sqrt(args.AP'*args.AP + diag(Bb'*Bb) + diag(Aa'*Aa) - (2*args.AP'*Aa)' + (2*args.AP'*(args.ARB*Bb))' - diag(2*(args.ARB*Bb)'*Aa)); +#+end_src + +#+begin_src matlab + dLi = Li-l; +#+end_src + +* Footnotes + +[fn:10]Laser source is manufactured by Agilent (5519b) +[fn:9]The special optics (straightness interferometer and reflector) are the manufactured by Agilent (10774A). +[fn:8]C8 capacitive sensors and CPL290 capacitive driver electronics from Lion Precision +[fn:7]The Spindle Error Analyzer is made by Lion Precision. +[fn:6]The tools presented here are largely taken from [[cite:&taghirad13_paral]]. +[fn:5]Rotations are non commutative in 3D +[fn:4]Ball cage (N501) and guide bush (N550) from Mahr are used +[fn:3]Modified Zonda Hexapod by Symetrie +[fn:2]Made by LAB Motion Systems +[fn:1]HCR 35 A C1, from THK diff --git a/simscape-micro-station.pdf b/simscape-micro-station.pdf index 9508e31..b27c14f 100644 Binary files a/simscape-micro-station.pdf and b/simscape-micro-station.pdf differ diff --git a/simscape-micro-station.tex b/simscape-micro-station.tex index 18ae06b..8ec0c39 100644 --- a/simscape-micro-station.tex +++ b/simscape-micro-station.tex @@ -1,4 +1,4 @@ -% Created 2024-10-30 Wed 10:53 +% Created 2024-11-05 Tue 22:36 % Intended LaTeX compiler: pdflatex \documentclass[a4paper, 10pt, DIV=12, parskip=full, bibliography=totoc]{scrreprt} @@ -22,7 +22,6 @@ \maketitle \tableofcontents -\clearpage \begin{table}[htbp] \caption{\label{tab:ustation_section_matlab_code}Report sections and corresponding Matlab files} @@ -31,23 +30,850 @@ \toprule \textbf{Sections} & \textbf{Matlab File}\\ \midrule -Section \ref{sec}: & \texttt{ustation\_1\_.m}\\ +Section \ref{sec:ustation_kinematics} & \texttt{ustation\_1\_kinematics.m}\\ +Section \ref{sec:ustation_modeling} & \texttt{ustation\_2\_modeling.m}\\ +Section \ref{sec:ustation_disturbances} & \texttt{ustation\_3\_disturbances.m}\\ +Section \ref{sec:ustation_experiments} & \texttt{ustation\_4\_experiments.m}\\ \bottomrule \end{tabularx} \end{table} - \chapter{Micro-Station Kinematics} \label{sec:ustation_kinematics} -\url{file:///home/thomas/Cloud/work-projects/ID31-NASS/matlab/nass-simscape/org/kinematics.org} -\chapter{Stage Modeling} -\label{sec:ustation_kinematics} -\chapter{Measurement of Positioning Errors} -\label{sec:ustation_kinematics} -\url{file:///home/thomas/Cloud/work-projects/ID31-NASS/matlab/nass-simscape/org/kinematics.org} -\chapter{Simulation of Scientific Experiments} -\label{sec:ustation_kinematics} +The micro-station consists of 4 stacked positioning stages (Figure \ref{fig:ustation_cad_view}). +From bottom to top, the stacked stages are the translation stage \(D_y\), the tilt stage \(R_y\), the rotation stage (Spindle) \(R_z\) and the positioning hexapod. + +Such stacked architecture allows high mobility, but the overall stiffness is reduced and the dynamics is very complex. complex dynamics. +The micro-station degrees-of-freedom are summarized in Table \ref{tab:ustation_dof_summary}. + +\begin{figure}[htbp] +\centering +\includegraphics[scale=1,width=\linewidth]{figs/ustation_cad_view.png} +\caption{\label{fig:ustation_cad_view}CAD view of the micro-station with the translation stage (in blue), the tilt stage (in red), the rotation stage (in yellow) and the positioning hexapod (in purple). On top of these four stages, a solid part (shown in green) will be replaced by the stabilization stage.} +\end{figure} + +\begin{table}[htbp] +\caption{\label{tab:ustation_dof_summary}Summary of the micro-station degrees-of-freedom} +\centering +\begin{tabularx}{\linewidth}{lX} +\toprule +\textbf{Stage} & \textbf{Degrees of Freedom}\\ +\midrule +Translation stage & \(D_y = \pm 10\,mm\)\\ +Tilt stage & \(R_y = \pm 3\,\text{deg}\)\\ +Spindle & \(R_z = 360\,\text{deg}\)\\ +Micro Hexapod & \(D_{xyz} = \pm 10\,mm\), \(R_{xyz} = \pm 3\,\text{deg}\)\\ +\bottomrule +\end{tabularx} +\end{table} + +There are different ways of modelling the stage dynamics in a multi-body model. +The one chosen in this work consists of modelling each stage by two solid bodies connected by one 6-DoF joint. +The stiffness and damping properties of the joint can be tuned separately for each DoF. + +The ``controlled'' DoF of each stage (for instance the \(D_y\) direction for the translation stage) is modelled as infinitely rigid (i.e. its motion is imposed by a ``setpoint'') while the other DoFs have limited stiffness to model the different micro-station modes. +\section{Motion Stages} +\label{ssec:ustation_stages} + +\paragraph{Translation Stage} + +The translation stage is used to position and scan the sample laterally with respect to the X-ray beam. + +A linear motor was first used to be able to perform fast and accurate scans. +It was later replaced with a stepper motor and lead-screw, as the feedback control used for the linear motor was unreliable, probably caused by rust of the linear guides along its stroke. +An optical linear encoder is used to measure the stage motion and for PID control of the position. + +Four cylindrical bearings\footnote{Ball cage (N501) and guide bush (N550) from Mahr are used} are used to guide the motion (i.e. minimize the parasitic motions) and have high stiffness. + +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/ustation_ty_stage.png} +\caption{\label{fig:ustation_ty_stage}Translation Stage} +\end{figure} + + +\paragraph{Tilt Stage} + +The tilt stage is guided by four linear motion guides\footnote{HCR 35 A C1, from THK} which are placed such that the center of rotation coincide with the X-ray beam. +Each linear guide has high stiffness in radial directions such that the only DoF with low stiffness is in \(R_y\). + +This stage is mainly used for \emph{reflectivity} experiments where the sample \(R_y\) angle is scanned. +This stage can also be used to tilt the rotation axis of the Spindle. + +To precisely control the \(R_y\) angle, a stepper motor as well as two optical encoders are used in a PID feedback loop. + +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/ustation_ry_stage.png} +\caption{\label{fig:ustation_ry_stage}Tilt Stage} +\end{figure} + + +\paragraph{Spindle} + +Then, a rotation stage is used for tomography experiments. +It is composed of an air bearing spindle\footnote{Made by LAB Motion Systems}, whose angular position is controlled with a 3 phase synchronous motor based on the reading of 4 optical encoders. + +Additional rotary unions and slip-rings to be able to pass through the rotation many electrical signals and fluids and gazes. + +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/ustation_rz_stage.png} +\caption{\label{fig:ustation_rz_stage}Rotation Stage (Spindle)} +\end{figure} + + +\paragraph{Micro-Hexapod} + +Finally, a Stewart platform\footnote{Modified Zonda Hexapod by Symetrie} is used to position the sample. +It includes a DC motor and an optical linear encoders in each of the six strut. + +It is used to position the point of interest of the sample with respect to the spindle rotation axis. +It can also be used to precisely position the PoI vertically with respect to the x-ray. + +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/ustation_hexapod_stage.png} +\caption{\label{fig:ustation_hexapod_stage}Micro Hexapod} +\end{figure} + + +\section{Mathematical description of a rigid body motion} +\label{ssec:ustation_motion_description} +The goal here is to introduce mathematical tools\footnote{The tools presented here are largely taken from \cite{taghirad13_paral}.} that are used to describe the motion of positioning stages and ultimately the sample. + +First, the tools to described the pose of a solid body (i.e. it's position and orientation) are introduced. +Then, the motion induced by a positioning stage is described using transformation matrices. +Finally, the motion of all stacked stages are combined, and the sample's motion is computed from each stage motion. +\paragraph{Spatial motion representation} + +The \emph{pose} of a solid body with respect to a specific frame can be described by six independent parameters. +Three parameters are usually describing its position, and three other parameters are describing its orientation. + +The \emph{position} of a point \(P\) with respect to a frame \(\{A\}\) can be described by a \(3 \times 1\) position vector \eqref{eq:ustation_position}. +The name of the frame is usually added as a leading superscript: \({}^AP\) which reads as vector \(P\) in frame \(\{A\}\). + +\begin{equation}\label{eq:ustation_position} + {}^AP = \begin{bmatrix} P_x\\ P_y\\ P_z \end{bmatrix} +\end{equation} + +A pure translation of a solid body (i.e. of a frame \(\{B\}\) attached to the solid body) can be described by the position \({}^AP_{O_B}\) as shown in Figure \ref{fig:ustation_translation}. + +\begin{figure}[htbp] +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=0.8]{figs/ustation_translation.png} +\end{center} +\subcaption{\label{fig:ustation_translation}Pure translation} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=0.8]{figs/ustation_rotation.png} +\end{center} +\subcaption{\label{fig:ustation_rotation}Pure rotation} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,scale=0.8]{figs/ustation_transformation.png} +\end{center} +\subcaption{\label{fig:ustation_transformation}General transformation} +\end{subfigure} +\caption{\label{fig:ustation_transformation_schematics}Rigid body motion representation. (\subref{fig:ustation_translation}) pure translation. (\subref{fig:ustation_rotation}) pure rotation. (\subref{fig:ustation_transformation}) combined rotation and translation.} +\end{figure} + +The \emph{orientation} of a rigid body is the same for all its points (by definition). +Hence, the orientation of a rigid body can be viewed as that for the orientation of a moving frame attached to the rigid body. +It can be represented in several different ways: the rotation matrix, the screw axis representation and Euler angles are common descriptions. + +A rotation matrix \({}^A\mathbf{R}_B\) is a \(3 \times 3\) matrix containing the Cartesian unit vectors of frame \(\{\mathbf{B}\}\) represented in frame \(\{\mathbf{A}\}\) \eqref{eq:ustation_rotation_matrix}. + +\begin{equation}\label{eq:ustation_rotation_matrix} + {}^A\mathbf{R}_B = \left[ {}^A\hat{\mathbf{x}}_B | {}^A\hat{\mathbf{y}}_B | {}^A\hat{\mathbf{z}}_B \right] = \begin{bmatrix} + u_{x} & v_{x} & z_{x} \\ + u_{y} & v_{y} & z_{y} \\ + u_{z} & v_{z} & z_{z} + \end{bmatrix} +\end{equation} + +Consider a pure rotation of a rigid body (\(\{\bm{A}\}\) and \(\{\bm{B}\}\) are coincident at their origins, as shown in Figure \ref{fig:ustation_rotation}). +The rotation matrix can be used to express the coordinates of a point \(P\) in a fixed frame \(\{A\}\) (i.e. \({}^AP\)) from its coordinate in the moving frame \(\{B\}\) using Equation \eqref{eq:ustation_rotation}. + +\begin{equation} \label{eq:ustation_rotation} + {}^AP = {}^A\mathbf{R}_B {}^BP +\end{equation} + + +For rotations along \(x\), \(y\) or \(z\) axis, formulas are given in Equation \eqref{eq:ustation_rotation_matrices_xyz}. + +\begin{subequations}\label{eq:ustation_rotation_matrices_xyz} +\begin{align} +\mathbf{R}_x(\theta_x) &= \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos(\theta_x) & -\sin(\theta_x) \\ 0 & \sin(\theta_x) & \cos(\theta_x) \end{bmatrix} \\ +\mathbf{R}_y(\theta_y) &= \begin{bmatrix} \cos(\theta_y) & 0 & \sin(\theta_y) \\ 0 & 1 & 0 \\ -\sin(\theta_y) & 0 & \cos(\theta_y) \end{bmatrix} \\ +\mathbf{R}_z(\theta_z) &= \begin{bmatrix} \cos(\theta_z) & -\sin(\theta_z) & 0 \\ \sin(\theta_z) & \cos(\theta_x) & 0 \\ 0 & 0 & 1 \end{bmatrix} +\end{align} +\end{subequations} + +Sometimes, it is useful to express a rotation as a combination of three rotations described by \(\mathbf{R}_x\), \(\mathbf{R}_y\) and \(\mathbf{R}_z\). +As the order of rotation is very important\footnote{Rotations are non commutative in 3D}, in this work we choose to express rotations as three successive rotations about the coordinate axes of the moving frame eqref;eq:ustation\_rotation\_combination. + +\begin{equation}\label{eq:ustation_rotation_combination} +{}^A\mathbf{R}_B(\alpha, \beta, \gamma) = \mathbf{R}_u(\alpha) \mathbf{R}_v(\beta) \mathbf{R}_c(\gamma) +\end{equation} + +Such rotation can be parameterized by three Euler angles \((\alpha,\ \beta,\ \gamma)\), which can be computed from a given rotation matrix using equations \eqref{eq:ustation_euler_angles}. + +\begin{subequations}\label{eq:ustation_euler_angles} +\begin{align} +\alpha &= \text{atan2}(-R_{23}/\cos(\beta),\ R_{33}/\cos(\beta)) \\ +\beta &= \text{atan2}( R_{13},\ \sqrt{R_{11}^2 + R_{12}^2}) \\ +\gamma &= \text{atan2}(-R_{12}/\cos(\beta),\ R_{11}/\cos(\beta)) +\end{align} +\end{subequations} + +\paragraph{Motion of a Rigid Body} + +Since the relative positions of a rigid body with respect to a moving frame \(\{B\}\) attached to it is fixed for all time, it is sufficient to know the position of the origin of the frame \(O_B\) and the orientation of the frame \(\{B\}\) with respect to the fixed frame \(\{A\}\), to represent the position of any point \(P\) in the space. + +Therefore, the pose of a rigid body, can be fully determined by: +\begin{enumerate} +\item The position vector of point \(O_B\) with respect to frame \(\{A\}\) which is denoted \({}^AP_{O_B}\) +\item The orientation of the rigid body, or the moving frame \(\{B\}\) attached to it with respect to the fixed frame \(\{A\}\), that is represented by \({}^A\mathbf{R}_B\). +\end{enumerate} + +The position of any point \(P\) of the rigid body with respect to the fixed frame \(\{\mathbf{A}\}\), which is denoted \({}^A\mathbf{P}\) may be determined thanks to the \emph{Chasles' theorem}, which states that if the pose of a rigid body \(\{{}^A\mathbf{R}_B, {}^AP_{O_B}\}\) is given, then the position of any point \(P\) of this rigid body with respect to \(\{\mathbf{A}\}\) is given by Equation \eqref{eq:ustation_chasles_therorem}. + +\begin{equation} \label{eq:ustation_chasles_therorem} + {}^AP = {}^A\mathbf{R}_B {}^BP + {}^AP_{O_B} +\end{equation} + +While equation \eqref{eq:ustation_chasles_therorem} can describe the motion of a rigid body, it can be written in a more convenient way using \(4 \times 4\) homogeneous transformation matrices and \(4 \times 1\) homogeneous coordinates. +The homogeneous transformation matrix is composed of the rotation matrix \({}^A\mathbf{R}_B\) representing the orientation and the position vector \({}^AP_{O_B}\) representing the translation. +It is partitioned as shown in Equation \eqref{eq:ustation_homogeneous_transformation_parts}. + +\begin{equation}\label{eq:ustation_homogeneous_transformation_parts} + {}^A\mathbf{T}_B = + \left[ \begin{array}{ccc|c} + & & & \\ + & {}^A\mathbf{R}_B & & {}^AP_{O_B} \\ + & & & \cr + \hline + 0 & 0 & 0 & 1 + \end{array} \right] +\end{equation} + +Then, \({}^AP\) can be computed from \({}^BP\) and the homogeneous transformation matrix using \eqref{eq:ustation_homogeneous_transformation}. + +\begin{equation}\label{eq:ustation_homogeneous_transformation} + \left[ \begin{array}{c} \\ {}^AP \\ \cr \hline 1 \end{array} \right] + = + \left[ \begin{array}{ccc|c} + & & & \\ + & {}^A\mathbf{R}_B & & {}^AP_{O_B} \\ + & & & \cr + \hline + 0 & 0 & 0 & 1 + \end{array} \right] + \left[ \begin{array}{c} \\ {}^BP \\ \cr \hline 1 \end{array} \right] \quad \Rightarrow \quad {}^AP = {}^A\mathbf{R}_B {}^BP + {}^AP_{O_B} +\end{equation} + +One key advantage of using homogeneous transformation is that it can easily be generalized for consecutive transformations. +Let us consider the motion of a rigid body described at three locations (Figure \ref{fig:ustation_combined_transformation}). +Frame \(\{A\}\) represents the initial location, frame \(\{B\}\) is an intermediate location, and frame \(\{C\}\) represents the rigid body at its final location. + +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/ustation_combined_transformation.png} +\caption{\label{fig:ustation_combined_transformation}Motion of a rigid body represented at three locations by frame \(\{A\}\), \(\{B\}\) and \(\{C\}\)} +\end{figure} + +Furthermore, suppose the position vector of a point \(P\) of the rigid body is given in the final location, that is \({}^CP\) is given, and the position of this point is to be found in the fixed frame \(\{A\}\), that is \({}^AP\). +Since the locations of the rigid body is known relative to each other, \({}^CP\) can be transformed to \({}^BP\) using \({}^B\mathbf{T}_C\) using \({}^BP = {}^B\mathbf{T}_C {}^CP\). +Similarly, \({}^BP\) can be transformed into \({}^AP\) using \({}^AP = {}^A\mathbf{T}_B {}^BP\). + +Combining the two relations, Equation \eqref{eq:ustation_consecutive_transformations} is obtained. +This shows that combining multiple transformations is equivalent as to compute \(4 \times 4\) matrix multiplications. + +\begin{equation}\label{eq:ustation_consecutive_transformations} +{}^AP = \underbrace{{}^A\mathbf{T}_B {}^B\mathbf{T}_C}_{{}^A\mathbf{T}_C} {}^CP +\end{equation} + +Another key advantage of using homogeneous transformation is the easy inverse transformation that can be computed using Equation \eqref{eq:ustation_inverse_homogeneous_transformation}. + +\begin{equation}\label{eq:ustation_inverse_homogeneous_transformation} + {}^B\mathbf{T}_A = {}^A\mathbf{T}_B^{-1} = + \left[ \begin{array}{ccc|c} + & & & \\ + & {}^A\mathbf{R}_B^T & & -{}^A \mathbf{R}_B^T {}^AP_{O_B} \\ + & & & \cr + \hline + 0 & 0 & 0 & 1 \\ + \end{array} \right] +\end{equation} + +\section{Micro-Station Kinematics} +\label{ssec:ustation_kinematics} + +Each stage is described by two frames, one is attached to the fixed platform \(\{A\}\) while the other is fixed to the mobile platform \(\{B\}\). +At ``rest'' position, the two are having the same pose and coincide with the point of interest (\(O_A = O_B\)). +An example is shown in Figure \ref{fig:ustation_stage_motion} for the tilt-stage. +Note that the mobile frame of the translation stage equals the fixed frame of the tilt stage: \(\{B_{D_y}\} = \{A_{R_y}\}\). +Similarly, the mobile frame of the tilt stage equals the fixed frame of the spindle: \(\{B_{R_y}\} = \{A_{R_z}\}\). + +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/ustation_stage_motion.png} +\caption{\label{fig:ustation_stage_motion}Example of the motion induced by the tilt-stage \(R_y\). ``Rest'' position in shown in blue while a arbitrary position in shown in red. Parasitic motions are here magnified for clarity.} +\end{figure} + +The motion induced by a positioning stage may be described by a homogeneous transformation matrix from frame \(\{A\}\) to frame \(\{B\}\) as explain in Section \ref{ssec:ustation_kinematics}. +As any motion stage induces parasitic motion in all 6 DoF, the transformation matrix representing its induced motion can be written as in \eqref{eq:ustation_translation_stage_errors}. + +\begin{equation}\label{eq:ustation_translation_stage_errors} +{}^A\mathbf{T}_B(D_x, D_y, D_z, \theta_x, \theta_y, \theta_z) = +\left[ \begin{array}{ccc|c} + & & & D_x \\ + & \mathbf{R}_x(\theta_x) \mathbf{R}_y(\theta_y) \mathbf{R}_z(\theta_z) & & D_y \\ + & & & D_z \cr + \hline + 0 & 0 & 0 & 1 +\end{array} \right] +\end{equation} + +The homogeneous transformation matrix corresponding to the micro-station \(\mathbf{T}_{\mu\text{-station}}\) is simply equal to the matrix multiplication of the homogeneous transformation matrices of the individual stages as shown in Equation \eqref{eq:ustation_transformation_station}. + +\begin{equation}\label{eq:ustation_transformation_station} +\mathbf{T}_{\mu\text{-station}} = \mathbf{T}_{D_y} \cdot \mathbf{T}_{R_y} \cdot \mathbf{T}_{R_z} \cdot \mathbf{T}_{\mu\text{-hexapod}} +\end{equation} + +\(\mathbf{T}_{\mu\text{-station}}\) represents the pose of the sample (supposed to be rigidly fixed on top of the positioning-hexapod) with respect to the granite. + +If the transformation matrices of the individual stages are representing a perfect motion (i.e. the stages are supposed to have no parasitic motion), \(\mathbf{T}_{\mu\text{-station}}\) is representing the pose setpoint of the sample with respect to the granite. +The transformation matrices for the translation stage, tilt stage, spindle and positioning hexapod can be written as shown in Equation \eqref{eq:ustation_transformation_matrices_stages}. + +\begin{equation}\label{eq:ustation_transformation_matrices_stages} +\begin{align} +\mathbf{T}_{D_y} &= \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & D_y \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} \quad +\mathbf{T}_{\mu\text{-hexapod}} = +\left[ \begin{array}{ccc|c} + & & & D_{\mu x} \\ + & \mathbf{R}_x(\theta_{\mu x}) \mathbf{R}_y(\theta_{\mu y}) \mathbf{R}_{z}(\theta_{\mu z}) & & D_{\mu y} \\ + & & & D_{\mu z} \cr + \hline + 0 & 0 & 0 & 1 +\end{array} \right] \\ +\mathbf{T}_{R_z} &= \begin{bmatrix} + \cos(\theta_z) & -\sin(\theta_z) & 0 & 0 \\ + \sin(\theta_z) & \cos(\theta_z) & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} \quad +\mathbf{T}_{R_y} = \begin{bmatrix} + \cos(\theta_y) & 0 & \sin(\theta_y) & 0 \\ + 0 & 1 & 0 & 0 \\ + -\sin(\theta_y) & 0 & \cos(\theta_y) & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +\end{align} +\end{equation} + +\chapter{Micro-Station Dynamics} +\label{sec:ustation_modeling} +In this section, the Simscape model of the micro-station is briefly presented. +It consists of several rigid bodies connected by springs and dampers. +The inertia of the solid bodies as well as the stiffness properties of the guiding mechanisms are first estimated based on the CAD model and part data-sheets (Section \ref{ssec:ustation_model_simscape}). + +The obtained dynamics is then compared with the modal analysis performed on the micro-station (Section \ref{ssec:ustation_meas_compliance}). + +As the dynamics of the nano-hexapod is impacted by the micro-station compliance, the most important dynamical characteristic that should be well modeled is the overall compliance of the micro-station. +To do so, the 6-DoF compliance of the micro-station is measured (Section \ref{ssec:ustation_meas_compliance}) and then compared with the 6-DoF compliance extracted from the Simscape model (Section \ref{ssec:ustation_model_compliance}). +\section{Multi-Body Model} +\label{ssec:ustation_model_simscape} + +By performing a modal analysis of the micro-station, it could be verified that in the frequency range of interest, each stage behaved as a rigid body. +This confirms that a multi-body model can be used to properly model the micro-station. + +A multi-body model consists of several solid bodies connected with joints. +Each solid body can be represented by inertia properties (most of the time computed automatically from the 3D model and material density). +Joints are used to impose kinematic constraints between solid bodies, and to specify dynamical properties (i.e. spring stiffness and damping coefficient). +External forces can be used to model disturbances, and ``sensors'' can be used to measure the relative pose between two defined frames. + +The micro-station is therefore modeled by several solid bodies connected by joints. +A typical stage (here the tilt-stage) is modelled as shown in Figure \ref{fig:ustation_simscape_stage_example} where two solid bodies (the fixed part and the mobile part) are connected by a 6-DoF joint. +One DoF of the 6-DoF joint is ``imposed'' by a setpoint (i.e. modeled as infinitely stiff) while the other 5 are each modelled by a spring and a damper. +Additional forces can be used to model disturbances induced by the stage motion. + +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/ustation_simscape_stage_example.png} +\caption{\label{fig:ustation_simscape_stage_example}Example of a stage (here the tilt-stage) represented in the multi-body model (Simscape). It is composed of two solid bodies connected by a 6-DoF joint. One joint DoF (here the tilt angle) can be imposed, the other ones are represented by springs and dampers. Additional disturbances forces for all DoF can be included} +\end{figure} + +The Ground is modelled by a solid body connected to the ``world frame'' through a joint only allowing 3 translations. +The granite is then connected to the ground by a 6-DoF joint. +The translation stage is connected to the granite by a 6-DoF joint, but the \(D_y\) motion is imposed. +Similarly, the tilt-stage and the spindle are connected to the stage below using a 6-DoF joint, with 1-DoF being imposed. +Finally, the positioning hexapod has 6-DoF. + +The total number of ``free'' degrees of freedom is 27, and therefore the model has 54 states. +The springs and dampers values were first estimated from the joints/stages specifications and were later fined tuned based on measurements. +The spring values are summarized in Table \ref{tab:ustation_6dof_stiffness_values}. + +\begin{table}[htbp] +\caption{\label{tab:ustation_6dof_stiffness_values}Summary of the stage stiffnesses. Contrained degrees-of-freedom are indicated by ``-''. The location of the 6-DoF joints in which the stiffnesses are defined are indicated by the frame in figures of Section \ref{ssec:ustation_stages}} +\centering +\begin{tabularx}{\linewidth}{Xcccccc} +\toprule +\textbf{Stage} & \(D_x\) & \(D_y\) & \(D_z\) & \(R_x\) & \(R_y\) & \(R_z\)\\ +\midrule +Granite & \(5\,kN/\mu m\) & \(5\,kN/\mu m\) & \(5\,kN/\mu m\) & \(25\,Nm/\mu\text{rad}\) & \(25\,Nm/\mu\text{rad}\) & \(10\,Nm/\mu\text{rad}\)\\ +Translation & \(200\,N/\mu m\) & - & \(200\,N/\mu m\) & \(60\,Nm/\mu\text{rad}\) & \(90\,Nm/\mu\text{rad}\) & \(60\,Nm/\mu\text{rad}\)\\ +Tilt & \(380\,N/\mu m\) & \(400\,N/\mu m\) & \(380\,N/\mu m\) & \(120\,Nm/\mu\text{rad}\) & - & \(120\,Nm/\mu\text{rad}\)\\ +Spindle & \(700\,N/\mu m\) & \(700\,N/\mu m\) & \(2\,kN/\mu m\) & \(10\,Nm/\mu\text{rad}\) & \(10\,Nm/\mu\text{rad}\) & -\\ +Hexapod & \(10\,N/\mu m\) & \(10\,N/\mu m\) & \(100\,N/\mu m\) & \(1.5\,Nm/rad\) & \(1.5\,Nm/rad\) & \(0.27\,Nm/rad\)\\ +\bottomrule +\end{tabularx} +\end{table} + +\section{With comparison with the measurements} + +The dynamics of the micro-station was measured by placing accelerometers on each stage and by impacting the translation stage with an instrumented hammer in three directions. +The obtained FRF were then projected at the CoM of each stage. + +In order to have a first idea of the accuracy of the obtained model, the FRF from the hammer impacts to the acceleration of each stage is extracted from the Simscape model and compared with the measurements in Figure \ref{fig:ustation_comp_com_response}. + +Even though there is some similarity between the model and the measurements (similar overall shapes and amplitudes), it is clear that the Simscape model does not represent very accurately the complex micro-station dynamics. +Tuning the numerous model parameters to better match the measurements is an highly non-linear optimization problem which is difficult to solve in practice. + +\begin{figure}[htbp] +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.9\linewidth]{figs/ustation_comp_com_response_rz_x.png} +\end{center} +\subcaption{\label{fig:ustation_comp_com_response_rz_x}Spindle, $x$ response} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.9\linewidth]{figs/ustation_comp_com_response_hexa_y.png} +\end{center} +\subcaption{\label{fig:ustation_comp_com_response_hexa_y}Hexapod, $y$ response} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.9\linewidth]{figs/ustation_comp_com_response_ry_z.png} +\end{center} +\subcaption{\label{fig:ustation_comp_com_response_ry_z}Tilt, $z$ response} +\end{subfigure} +\caption{\label{fig:ustation_comp_com_response}FRF between the hammer impacts on the translation stage and measured stage acceleration expressed at its CoM. Comparison of the measured FRF and the ones extracted from the Simscape model. Different directions are computed and for different stages.} +\end{figure} + +\section{Micro-station compliance - Measurement} +\label{ssec:ustation_meas_compliance} + +As was shown in the previous section, the dynamics of the micro-station is complex and tuning the multi-body model parameters to obtain a perfect match is hard. + +When considering the NASS, the most important dynamical characteristics of the micro-station is its compliance as it is what can impact the plant dynamics. +The adopted strategy is therefore to accurately model the micro-station compliance. + +The micro-station compliance is experimentally measured using the setup schematically shown in Figure \ref{fig:ustation_compliance_meas}. +Four 3-axis accelerometers are fixed to the micro-hexapod top platform. +The micro-hexapod top platform is impacted at 10 different points. +For each impact position, 10 impacts are performed for averaging and improving the data quality. + +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/ustation_compliance_meas.png} +\caption{\label{fig:ustation_compliance_meas}Schematic of the measurement setup to estimate the compliance of the micro-station. The top platform of the positioning hexapod is shown with four 3-axis accelerometers (shown in red) are on top. 10 hammer impacts are performed at different locations (shown in blue).} +\end{figure} + +To convert the 12 acceleration signals \(a_{\mathcal{L}} = [a_{1x}\ a_{1y}\ a_{1z}\ a_{2x}\ \dots\ a_{4z}]\) to the acceleration expressed in the frame \(\{\mathcal{X}\}\) \(a_{\mathcal{X}} = [a_{dx}\ a_{dy}\ a_{dz}\ a_{rx}\ a_{ry}\ a_{rz}]\), a Jacobian matrix \(\mathbf{J}_a\) is written based on the positions and orientations of the accelerometers \eqref{eq:ustation_compliance_acc_jacobian}. + +\begin{equation}\label{eq:ustation_compliance_acc_jacobian} +\mathbf{J}_a = \begin{bmatrix} +1 & 0 & 0 & 0 & 0 &-d \\ +0 & 1 & 0 & 0 & 0 & 0 \\ +0 & 0 & 1 & d & 0 & 0 \\ +1 & 0 & 0 & 0 & 0 & 0 \\ +0 & 1 & 0 & 0 & 0 &-d \\ +0 & 0 & 1 & 0 & d & 0 \\ +1 & 0 & 0 & 0 & 0 & d \\ +0 & 1 & 0 & 0 & 0 & 0 \\ +0 & 0 & 1 &-d & 0 & 0 \\ +1 & 0 & 0 & 0 & 0 & 0 \\ +0 & 1 & 0 & 0 & 0 & d \\ +0 & 0 & 1 & 0 &-d & 0 +\end{bmatrix} +\end{equation} + +Then, the acceleration in the cartesian frame can be computed using \eqref{eq:ustation_compute_cart_acc}. + +\begin{equation}\label{eq:ustation_compute_cart_acc} +a_{\mathcal{X}} = \mathbf{J}_a^\dagger \cdot a_{\mathcal{L}} +\end{equation} + +Similar to what is done for the accelerometers, a Jacobian matrix \(\mathbf{J}_F\) is computed \eqref{eq:ustation_compliance_force_jacobian} and used to convert the individual hammer forces \(F_{\mathcal{L}}\) to force and torques \(F_{\mathcal{X}}\) applied at the center of the micro-hexapod top plate (defined by frame \(\{\mathcal{X}\}\) in Figure \ref{fig:ustation_compliance_meas}). + +\begin{equation}\label{eq:ustation_compliance_force_jacobian} +\mathbf{J}_F = \begin{bmatrix} + 0 & -1 & 0 & 0 & 0 & 0\\ + 0 & 0 & -1 & -d & 0 & 0\\ + 1 & 0 & 0 & 0 & 0 & 0\\ + 0 & 0 & -1 & 0 & -d & 0\\ + 0 & 1 & 0 & 0 & 0 & 0\\ + 0 & 0 & -1 & d & 0 & 0\\ +-1 & 0 & 0 & 0 & 0 & 0\\ + 0 & 0 & -1 & 0 & d & 0\\ +-1 & 0 & 0 & 0 & 0 & -d\\ +-1 & 0 & 0 & 0 & 0 & d +\end{bmatrix} +\end{equation} + +Force and torques applied at center of \(\{\mathcal{X}\}\) are then computed using \eqref{eq:ustation_compute_cart_force}. + +\begin{equation}\label{eq:ustation_compute_cart_force} +F_{\mathcal{X}} = \mathbf{J}_F^t \cdot F_{\mathcal{L}} +\end{equation} + +Using the two Jacobian matrices, the FRF from the 10 hammer impacts to the 12 accelerometer outputs can be converted to the FRF from 6 forces/torques applied at the origin of frame \(\{\mathcal{X}\}\) to the 6 linear/angular accelerations of the top platform expressed with respect to \(\{\mathcal{X}\}\). +The obtained FRF from forces to linear motion are shown in Figure \ref{fig:ustation_frf_compliance_xyz} while the FRF from torques to angular motion are shown in Figure \ref{fig:ustation_frf_compliance_Rxyz}. + +\begin{figure}[htbp] +\begin{subfigure}{0.49\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.95\linewidth]{figs/ustation_frf_compliance_xyz.png} +\end{center} +\subcaption{\label{fig:ustation_frf_compliance_xyz}sub caption a} +\end{subfigure} +\begin{subfigure}{0.49\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.95\linewidth]{figs/ustation_frf_compliance_Rxyz.png} +\end{center} +\subcaption{\label{fig:ustation_frf_compliance_Rxyz}sub caption b} +\end{subfigure} +\caption{\label{fig:ustation_frf_compliance}Measured FRF of the compliance of the micro-station expressed in frame \(\{\mathcal{X}\}\). Both translation terms (\subref{fig:ustation_frf_compliance_xyz}) and rotational terms (\subref{fig:ustation_frf_compliance_Rxyz}) are displayed.} +\end{figure} + +\section{Compare with the Model} +\label{ssec:ustation_model_compliance} + +The compliance of the micro-station is extracted from the Simscape model by computing the transfer function from forces/torques applied to the positioning hexapod's top platform to the ``absolute'' motion of the top platform. +These are compared with the measurements in Figure \ref{fig:ustation_frf_compliance_model}. +Considering how complex the micro-station compliance dynamics is, the model compliance is matching sufficiently well the measurements for the current application. + +\begin{figure}[htbp] +\begin{subfigure}{0.49\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.95\linewidth]{figs/ustation_frf_compliance_xyz_model.png} +\end{center} +\subcaption{\label{fig:ustation_frf_compliance_xyz_model}sub caption a} +\end{subfigure} +\begin{subfigure}{0.49\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.95\linewidth]{figs/ustation_frf_compliance_Rxyz_model.png} +\end{center} +\subcaption{\label{fig:ustation_frf_compliance_Rxyz_model}sub caption b} +\end{subfigure} +\caption{\label{fig:ustation_frf_compliance_model}Measured FRF of the compliance of the micro-station expressed in frame \(\{\mathcal{X}\}\). Both translation terms (\subref{fig:ustation_frf_compliance_xyz_model}) and rotational terms (\subref{fig:ustation_frf_compliance_Rxyz_model}) are displayed.} +\end{figure} + \chapter{Estimation of disturbances} +\label{sec:ustation_disturbances} +The goal in this section is to obtain realistic representation of disturbances affecting the micro-station. +These disturbance sources will then be used during time domain simulations to accurately model the micro-station behavior. +The focus is made on stochastic disturbances, as it is in principle possible to calibrate the repeatable part of disturbances. +Such disturbance includes ground motion, and vibrations induces by the scanning of the translation stage and the spindle. + +In the multi-body model, stage vibrations are modelled as internal forces applied in the stage's joint. +In practice, the disturbance forces cannot be directly measured, and the effect of those perturbations on the vibration of the micro-station's top platform is measured instead (Section \ref{ssec:ustation_disturbances_meas}). + +To estimate the equivalent disturbance force that induces such vibration, the transfer function from disturbances sources (i.e. forces applied in the stages' joint) to the displacement of the micro-station's top platform with respect to the granite are extracted from the Simscape model (Section \ref{ssec:ustation_disturbances_sensitivity}). +Finally, the obtained disturbance sources are compared in Section \ref{ssec:ustation_disturbances_results}. +\section{Measurements of disturbances} +\label{ssec:ustation_disturbances_meas} +In this section, the ground motion disturbances is directly measured using geophones. +Vibrations induced by the scanning of the translation stage and of the spindle are also measured using dedicated setups. + +The tilt stage and the micro-hexapod also have positioning errors, they are however not modelled here as these two stages are only used for pre-positioning and not for scanning. +Therefore, from a control point of view, they are not important. +\paragraph{Ground Motion} + +The ground motion is simply measured by using a sensitive 3-axis geophone placed on the ground. +The generated voltages are recorded with a high resolution DAC, and converted to displacement using the Geophone sensitivity transfer function. + +\paragraph{Ty Stage} + +To measure the positioning errors of the translation stage, the setup shown in Figure \ref{fig:ustation_errors_ty_setup} is used. +A special optical element (called a ``straightness interferometer''\footnote{The special optics (straightness interferometer and reflector) are the manufactured by Agilent (10774A).}) is fixed on top of the micro-station, while a laser source\footnote{Laser source is manufactured by Agilent (5519b)} and a straightness reflector are fixed on the ground. +A similar setup is used to measure the horizontal deviation (i.e. in the \(x\) direction), as well as the pitch and yaw errors of the translation stage. + +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/ustation_errors_ty_setup.png} +\caption{\label{fig:ustation_errors_ty_setup}Experimental setup to measure the flatness (vertical deviation) of the translation stage} +\end{figure} + +Six scans are performed between \(-4.5\,mm\) and \(4.5\,mm\). +The results for each individual scan are shown in Figure \ref{fig:ustation_errors_dy_vertical}. +As the measurement axis may not be perfectly aligned with the displacement axis of the translation stage, a linear fit may be removed from the measurement. +The remaining vertical displacement is shown in Figure \ref{fig:ustation_errors_dy_vertical_remove_mean}. +A vertical error of \(\pm300\,nm\) induced by the translation stage is to be expected. +Similar result is obtain for the \(x\) lateral direction. + +\begin{figure}[htbp] +\begin{subfigure}{0.49\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.95\linewidth]{figs/ustation_errors_dy_vertical.png} +\end{center} +\subcaption{\label{fig:ustation_errors_dy_vertical}Measured vertical error} +\end{subfigure} +\begin{subfigure}{0.49\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.95\linewidth]{figs/ustation_errors_dy_vertical_remove_mean.png} +\end{center} +\subcaption{\label{fig:ustation_errors_dy_vertical_remove_mean}Error after removing linear fit} +\end{subfigure} +\caption{\label{fig:ustation_errors_dy}Measurement of the linear (vertical) deviation of the Translation stage (\subref{fig:ustation_errors_dy_vertical}). A linear fit is then removed from the data (\subref{fig:ustation_errors_dy_vertical_remove_mean}).} +\end{figure} + +\paragraph{Spindle} + +In order to measure the positioning errors induced by the Spindle, a ``Spindle error analyzer''\footnote{The Spindle Error Analyzer is made by Lion Precision.} is used as shown in Figure \ref{fig:ustation_rz_meas_lion_setup}. +A specific target is fixed on top of the micro-station which consists of two sphere with 1 inch diameter precisely aligned with the spindle rotation axis. +Five capacitive sensors\footnote{C8 capacitive sensors and CPL290 capacitive driver electronics from Lion Precision} are pointing at the two spheres as shown in Figure \ref{fig:ustation_rz_meas_lion_zoom}. +From the 5 measured displacements \([d_1,\,d_2,\,d_3,\,d_4,\,d_5]\), the translations and rotations \([D_x,\,D_y,\,D_z,\,R_x,\,R_y]\) of the target can be estimated. + +\begin{figure}[htbp] +\begin{subfigure}{0.49\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.9\linewidth]{figs/ustation_rz_meas_lion.jpg} +\end{center} +\subcaption{\label{fig:ustation_rz_meas_lion}Micro-station and 5-DoF metrology} +\end{subfigure} +\begin{subfigure}{0.49\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.9\linewidth]{figs/ustation_rz_meas_lion_zoom.jpg} +\end{center} +\subcaption{\label{fig:ustation_rz_meas_lion_zoom}Zoom on the metrology system} +\end{subfigure} +\caption{\label{fig:ustation_rz_meas_lion_setup}Experimental setup used to estimate the errors induced by the Spindle rotation (\subref{fig:ustation_rz_meas_lion}). The motion of the two reference sphere is done using 5 capacitive sensors (\subref{fig:ustation_rz_meas_lion_zoom})} +\end{figure} + +A measurement is performed at 60rpm during 10 turns, and the obtained results are shown in Figure \ref{fig:ustation_errors_spindle}. +A fraction of the radial (Figure \ref{fig:ustation_errors_spindle_radial}) and tilt (Figure \ref{fig:ustation_errors_spindle_tilt}) errors is linked to the fact that the two spheres are not perfectly aligned with the rotation axis of the Spindle. +However, it is in practice very difficult to align the ``point-of-interest'' of the sample with the rotation axis, so the NASS will be used to actively keep the PoI on the rotation axis. +The vertical motion induced by the scanning of the spindle is in the order of \(\pm 30\,nm\) (Figure \ref{fig:ustation_errors_spindle_axial}). + +\begin{figure}[htbp] +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.9\linewidth]{figs/ustation_errors_spindle_radial.png} +\end{center} +\subcaption{\label{fig:ustation_errors_spindle_radial}Radial errors} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.9\linewidth]{figs/ustation_errors_spindle_axial.png} +\end{center} +\subcaption{\label{fig:ustation_errors_spindle_axial}Axial error} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.9\linewidth]{figs/ustation_errors_spindle_tilt.png} +\end{center} +\subcaption{\label{fig:ustation_errors_spindle_tilt}Tilt errors} +\end{subfigure} +\caption{\label{fig:ustation_errors_spindle}Measurement of the radial (\subref{fig:ustation_errors_spindle_radial}), axial (\subref{fig:ustation_errors_spindle_axial}) and tilt (\subref{fig:ustation_errors_spindle_tilt}) Spindle errors.} +\end{figure} + +\section{Sensitivity to disturbances} +\label{ssec:ustation_disturbances_sensitivity} + +In order to compute the disturbance source (i.e. forces) that induced the measured vibrations in Section \ref{ssec:ustation_disturbances_meas}, the transfer function from the disturbance sources to the stage vibration (i.e. the ``sensitivity to disturbances'') needs to be estimated. +This is done using the multi-body that was presented in Section \ref{sec:ustation_modeling}. + +The obtained transfer functions are shown in Figure \ref{fig:ustation_model_sensitivity}. + +\begin{figure}[htbp] +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.9\linewidth]{figs/ustation_model_sensitivity_ground_motion.png} +\end{center} +\subcaption{\label{fig:ustation_model_sensitivity_ground_motion}Ground motion} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.9\linewidth]{figs/ustation_model_sensitivity_ty.png} +\end{center} +\subcaption{\label{fig:ustation_model_sensitivity_ty}Translation stage} +\end{subfigure} +\begin{subfigure}{0.33\textwidth} +\begin{center} +\includegraphics[scale=1,width=0.9\linewidth]{figs/ustation_model_sensitivity_rz.png} +\end{center} +\subcaption{\label{fig:ustation_model_sensitivity_rz}Spindle} +\end{subfigure} +\caption{\label{fig:ustation_model_sensitivity}Extracted transfer functions from disturbances to relative motion between the micro-station's top platform and the granite. The considered disturbances are the ground motion (\subref{fig:ustation_model_sensitivity_ground_motion}), the translation stage vibrations (\subref{fig:ustation_model_sensitivity_ty}), and the spindle vibrations (\subref{fig:ustation_model_sensitivity_rz}).} +\end{figure} + +\section{Obtained disturbance sources} +\label{ssec:ustation_disturbances_results} + +\begin{itemize} +\item[{$\square$}] Display PSD of disturbances +\end{itemize} + +The obtained amplitude spectral densities of the disturbance forces are shown in Figure \ref{fig:dist_force_psd}. + +\chapter{Simulation of Scientific Experiments} +\label{sec:ustation_experiments} +The goal here is to simulate some scientific experiments with the Simscape model when no control is applied to the nano-hexapod. + +This has several goals: +\begin{itemize} +\item Validate the model +\item Estimate the expected error motion for the experiments +\item Estimate the stroke that we may need for the nano-hexapod +\item Compare with experiments when control is applied +\end{itemize} + +The document in organized as follow: +\begin{itemize} +\item In section \ref{sec:simscape_model} the Simscape model is initialized +\item In section \ref{sec:tomo_no_dist} a tomography experiment is performed where the sample is aligned with the rotation axis. No disturbance is included +\item In section \ref{sec:tomo_dist}, the same is done but with disturbance included +\item In section \ref{sec:tomo_hexa_trans} the micro-hexapod translate the sample such that its center of mass is no longer aligned with the rotation axis. No disturbance is included +\item In section \ref{sec:ty_scans}, scans with the translation stage are simulated with no perturbation included +\end{itemize} +\section{Simscape Model} +\label{sec:simscape_model} + +We load the shared simulink configuration and we set the \texttt{StopTime}. +We first initialize all the stages. +The nano-hexapod is considered to be a rigid body. +No controller is used (Open Loop). +We don't gravity. +We log the signals for further analysis. +\section{Tomography Experiment with no disturbances} +\label{sec:tomo_no_dist} +In this section, a tomography experiment is performed with the sample aligned with the rotation axis. +No disturbance is included. +\subsection{Simulation Setup} +And we initialize the disturbances to be equal to zero. +We initialize the reference path for all the stages. +All stage is set to its zero position except the Spindle which is rotating at 60rpm. +We simulate the model. +And we save the obtained data. +\subsection{Analysis} +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/exp_tomo_without_dist.png} +\caption{\label{fig:exp_tomo_without_dist}X-Y-Z translation of the sample w.r.t. granite when performing tomography experiment with no disturbances (\href{./figs/exp\_tomo\_without\_dist.png}{png}, \href{./figs/exp\_tomo\_without\_dist.pdf}{pdf})} +\end{figure} + +\subsection{Conclusion} +\begin{important} +When everything is aligned, the resulting error motion is very small (nm range) and is quite negligible with respect to the error when disturbances are included. +This residual error motion probably comes from a small misalignment somewhere. +\end{important} + +\section{Tomography Experiment with included perturbations} +\label{sec:tomo_dist} +In this section, we also perform a tomography experiment with the sample's center of mass aligned with the rotation axis. +However this time, we include perturbations such as ground motion and stage vibrations. +\subsection{Simulation Setup} +We now activate the disturbances. +We initialize the reference path for all the stages. +All stage is set to its zero position except the Spindle which is rotating at 60rpm. +We simulate the model. +And we save the obtained data. +\subsection{Analysis} +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/exp_tomo_dist.png} +\caption{\label{fig:exp_tomo_dist}X-Y-Z translations and rotations of the sample w.r.t. the granite when performing tomography experiment with disturbances (\href{./figs/exp\_tomo\_dist.png}{png}, \href{./figs/exp\_tomo\_dist.pdf}{pdf})} +\end{figure} + +\subsection{Conclusion} +\begin{important} +Here, no vibration is included in the X and Y directions. +\end{important} + +\section{Tomography Experiment with Ty raster scans} +\label{sec:tomo_dist_ty_scans} +In this section, we also perform a tomography experiment with scans of the Translation stage. +All the perturbations are included. +\subsection{Simulation Setup} +We now activate the disturbances. +We initialize the reference path for all the stages. +The Spindle which is rotating at 60rpm and the translation stage not moving as it would take a long time to simulate. +However, vibrations of the Ty stage are included. +We simulate the model. +And we save the obtained data. +\subsection{Analysis} +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/exp_scans_rz_dist.png} +\caption{\label{fig:exp_scans_rz_dist}X-Y-Z translations and rotations of the sample w.r.t. the granite when performing tomography experiment and scans with the translation stage at the same time} +\end{figure} + +\subsection{Conclusion} + +\section{Tomography when the micro-hexapod is not centered} +\label{sec:tomo_hexa_trans} +In this section, the sample's center of mass is not aligned with the rotation axis anymore. +This is due to the fact that the micro-hexapod has performed some displacement. + +No disturbances are included. +\subsection{Simulation Setup} +We first set the wanted translation of the Micro Hexapod. +We initialize the reference path. +We initialize the stages. +And we initialize the disturbances to zero. +We simulate the model. +And we save the obtained data. +\subsection{Analysis} +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/exp_tomo_offset.png} +\caption{\label{fig:exp_tomo_offset}X-Y-Z translation of the sample w.r.t. granite when performing tomography experiment with no disturbances (\href{./figs/exp\_tomo\_offset.png}{png}, \href{./figs/exp\_tomo\_offset.pdf}{pdf})} +\end{figure} + +\subsection{Conclusion} +\begin{important} +The main motion error are 1Hz X-Y translations and constant Ry error. +This is mainly due to finite stiffness of the elements. +\end{important} + +\section{Raster Scans with the translation stage} +\label{sec:ty_scans} +In this section, scans with the translation stage are performed. +\subsection{Simulation Setup} +We initialize the stages. +And we initialize the disturbances to zero. +We set the reference path to be a triangular signal for the Translation Stage. +We simulate the model. +And we save the obtained data. +We now set the reference path to be a sinusoidal signal for the Translation Stage. +We simulate the model. +And we save the obtained data. +\subsection{Analysis} +\begin{figure}[htbp] +\centering +\includegraphics[scale=1]{figs/exp_ty_scan.png} +\caption{\label{fig:exp_ty_scan}X-Y-Z translation of the sample w.r.t. granite when performing tomography experiment with no disturbances (\href{./figs/exp\_ty\_scan.png}{png}, \href{./figs/exp\_ty\_scan.pdf}{pdf})} +\end{figure} + +\subsection{Conclusion} +\begin{important} +Scans with the translation stage induces some errors in the Y direction and Rx translations. + +Also, scanning with a sinusoidal wave induces less position errors and at lower frequencies. +Thus, this should be preferred. +\end{important} \chapter{Conclusion} \label{sec:uniaxial_conclusion}