added RM file with User Guide

This commit is contained in:
2025-09-08 12:11:39 +02:00
parent 50680e5ef9
commit ac69db2f38
7 changed files with 7952 additions and 140 deletions

View File

@@ -8,4 +8,7 @@
<orderEntry type="jdk" jdkName="Python 3.13 (StagePerformaceDocu)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PackageRequirementsSettings">
<option name="removeUnused" value="true" />
</component>
</module>

View File

@@ -1,5 +0,0 @@
{
"meas_scripts_dir": 'C:\Users\berti_r\Python_Projects\metrology\metrology'
"meas_scripts_dir_local": r"C:\Users\berti_r\Python_Projects\StagePerformaceDocu\Scripts"
"config_path": r"C:\Users\berti_r\Python_Projects\StagePerformaceDocu\Config\config.json"
}

View File

@@ -0,0 +1,72 @@
<h1>User Guide</h1>
This Project has three main Components:
<p></p>
<ol>
<li>Taking Measurements</li>
<li>Analyse the Data</li>
<li>Results and Documentation</li>
</ol>
<h3> Taking a measurement</h3>
For all measurments working with the standard TCMC Lib the notbook
Measurements offers a simple interface. My TwinCat project for that can be found under:_____
<p>Requierments:</p>
<ol>
<li> TwinCat Project setup acording to ESS dokumentation</li>
<li> All libraryies installed (requirents.txt)</li>
<li> Static paths on top of every file set</li>
<li> Correct AMS-net Id for PLC set in metrology_functions (line52)</li>
<li>Using the microscope X02DA-PG-USB:cam1 </li>
<li> The X-Axis needs to be linked to the reference Axis 2</li>
</ol>
If another microscope is used which can use the same epics interface, the ID can be changed in the AD.py file
<p>Location of static Paths:</p>
<ol>
<li> Y_Axis_Meas (line 31,36,39,55)</li>
<li> myutility (line 58)</li>
<li> metrology_functions (line 13-16)</li>
</ol>
<p>Meaurement types suprted by the Notebook:</p>
<ol>
<li> Image Test</li>
<li> Static short term</li>
<li> Static long term</li>
<li> Repetability</li>
<li> Repability motors of</li>
</ol>
<h3>Y-Axis Measurements </h3>
The used file to execute the measurement is the Y_AxisMeas.py
For the Y-Axis a new interface over ADS was needed. To minimize the required time for Testing
the Y-Axis was developed with as little cohesion to the other measurement scripts as possible.
On the beckhof side no TCMC/ESS lib was used. The interface consists of functions of the Beckhof Motion Liba linked to
variables and some custom functions for communicating states. The communication was done with the ADS protocol
writing/reading from GVLs. The project can be found under: _______
<p>Requirements:</p>
<ol>
<li> Custom TwinCat Project on PLC from:______</li>
<li> All libraries installed (requirents.txt)</li>
<li> Static paths adjusted in Y_Axis_Meas.py</li>
<li> Correct AMS-net Id for PLC set in metrology_functions (line52)</li>
<li> Using the microscope X02DA-PG-USB:cam1 </li>
<li> Vertical Axis are linked to reference Axis 1 and 4 </li>
</ol>
<h3> Analyzing new Data </h3>
For analyzing new data the notebook Measurements Analysis offers some functionalities.
The temperature measurement needs to be added manually. In generally the newest measurement is selected by default.
If no "conf_YearMoDa.json" is generated automatically with the measurement it must be copied from another measurement and
the name needs to be adjusted. Especially important is the pixel size variable.
<h3> Results </h3>
Overall result of the measurements can be found in the Results notebook.
Intermediate results are Documented in MessberichtXXXXXX notebooks where also a quick overview of the controller tuning
process can be found.

View File

@@ -310,7 +310,7 @@ if __name__ == "__main__":
#plc.write_by_name("GVL.StopCmd", False, pyads.PLCTYPE_BOOL)
#moveAbsolut(plc, 0, 37.68, 3)
#executeCmd(plc)
cyclic_meas(plc,[30,37.68],[5,25],100)
cyclic_meas(plc,[30,37.68],[5,25 ],100)
#time.sleep(3)
disableAxis(plc)
gearout(plc)

View File

@@ -8,9 +8,13 @@ import sys
import scipy.ndimage as spnd
import threading as th
from scipy.optimize import curve_fit
from skimage.io import imshow
from utils import get_datestr, get_timestr
config_path = r"C:\Users\berti_r\Python_Projects\StagePerformaceDocu\Config\config.json" #Path to the config file which has the parameters for the next measurement
library_path = r"C:\Users\berti_r\Python_Projects\templates\motion_libs" #Path to the motion function lib (ESS based)
measurement_mov_path = r"C:\Users\berti_r\Python_Projects\StagePerformaceDocu\Config\measurement.json"
workdir = \
os.path.expanduser(rf'C:\Users\berti_r\Python_Projects\StagePerformaceDocu\data\data{get_datestr()}_alignment_tests')
#error chatchign and hard code catch stuff
def check_path(path_str):
@@ -21,30 +25,24 @@ def check_path(path_str):
print(f"Path exists: {path_str}")
except FileNotFoundError as e:
print(f"Error: {e}")
config_path = r"C:\Users\berti_r\Python_Projects\StagePerformaceDocu\Config\config.json"
check_path(config_path)
library_path = r"C:\Users\berti_r\Python_Projects\templates\motion_libs"
check_path(library_path)
sys.path.append(library_path)
measurement_mov_path = r"C:\Users\berti_r\Python_Projects\StagePerformaceDocu\Config\measurement.json"
check_path(measurement_mov_path)
import motionFunctionsLib as mfl # ToDo: comment out when using torque test
from PIL import Image, ImageDraw
import numpy as np
from image_analysis import image_center_of_mass
from utils import get_datestr, get_timestr
import ad
import myutility as myu
import cv2
import json
import shutil
workdir = \
os.path.expanduser(rf'C:\Users\berti_r\Python_Projects\StagePerformaceDocu\data\data{get_datestr()}_alignment_tests')
if not os.path.exists(workdir):
os.makedirs(workdir)
@@ -175,12 +173,6 @@ def __process_img(img , retimg=0):
x = popt[1]
y = popt[2]
#result , path = gradient_ascent(img, (x_gues, y_gues))
#x,y = result
#y,x = np.unravel_index(np.argmax(z), z.shape)
"""ret1, th1 = cv2.threshold(z, 40, 1, cv2.THRESH_BINARY)
z = z * th1
x, y = image_center_of_mass(th1, plot=False, verbose=False)"""
if retimg:
return x,y,z
return x, y
@@ -294,117 +286,7 @@ def run_repeatability_series(
del camera
def run_repeatability_series_K(
motor_pv_prefix=0, ntries=100, save_images=True, run_analysis=False):
# improv
exit(-1)
ntries = init_nr_of_cycles()
print(f"started with {ntries} cycles")
if os.getenv("EPICS_CA_ADDR_LIST") is not None:
pass
else:
os.environ["EPICS_CA_ADDR_LIST"] = "129.129.181.64"
camera = ad.AD()
pixel_size = 1.1
savedir = os.path.join(workdir,
f'{get_timestr()}_repeatibility_{motor_pv_prefix}')
safe_meas_settings(savedir)
savefile = os.path.join(savedir,
f'repeatibility_{motor_pv_prefix}.dat')
os.makedirs(savedir)
camera.start()
# enable axis clean up later
axis1.setAcceleration(5.0)
axis1.setDeceleration(5.0)
axis1.setVelocity(3)
axis1.disableAxis()
sleep(1)
axis1.enableAxis()
sleep(1)
axis4.setAcceleration(5.0)
axis4.setDeceleration(5.0)
axis4.setVelocity(3)
axis4.disableAxis()
sleep(1)
axis4.enableAxis()
sleep(1)
# --------------------------------------load coordinates from file-----------------------
x_coordinates_json = myu.load_object(measurement_mov_path)
x_coordinates = x_coordinates_json.get('std_test_mov')
wait_x_json = myu.load_object(measurement_mov_path)
wait_x = wait_x_json.get('std_test_wait')
print("WaitPattern: ",wait_x)
print("movPattern",x_coordinates)
start1 = axis1.getActPos()
print("start1",start1)
print("target1",start1+x_coordinates[0])
start4 = axis4.getActPos()
for i in range(ntries):
# ---------------------------------------------move------------------------------------------
# add multithreading for simultanious movement of y and x axis
for mov, wait in zip(x_coordinates, wait_x):
t1 = start1+mov
print("t1",t1)
while axis1.getMovingStatus() or axis4.getMovingStatus():
print("waiting on axis")
axis4.moveAbsolute(start4+(mov))
axis1.moveAbsolute(t1)
sleep(0.05)
sleep(wait)
start_pos_rbv = 4 # ????
meas_pos_rbv = 5 # ????
# ---------------------------------------------capture------------------------------------------
x_array = []
y_array = []
for nr_img in range(10):
sleep(0.1)
im = camera.get_image()
sleep(0.1)
if (1 == init_image_processing_yes_no()):
com_x_tmp, com_y_tmp = __process_img(im)
else:
com_x_tmp, com_y_tmp = image_center_of_mass(im, plot=False, verbose=False)
x_array.append(com_x_tmp)
y_array.append(com_y_tmp)
com_x = np.average(x_array)
com_y = np.average(y_array)
data_str = " {:6d} {:18f} {:18f} {:8.3f} {:8.3f} {:14.3f}\n".format(
i, start_pos_rbv, meas_pos_rbv, com_x, com_y, time.time())
print(data_str, end='')
# -------------------------------------------Save----------------------------------------------------
with open(savefile, 'a') as fh:
fh.write(data_str)
if save_images:
imobj = Image.fromarray(im)
imfile = os.path.join(savedir,
f'im_{i:05d}.tif')
imobj.save(imfile)
# --------------------------------------------analyse----------------------------------------------
if run_analysis:
print("")
analyze_repeatability(savefile, pixel_size=pixel_size, units='um')
# -----------------------------------------cleanup-----------------------------------------
axis2.disableAxis()
camera.stop()
del camera
def run_repeatability_series_motor_off(
@@ -452,8 +334,8 @@ def run_repeatability_series_motor_off(
for mov, wait in zip(x_coordinates, wait_x):
axis2.moveRelativeAndWait(mov)
sleep(wait)
start_pos_rbv = 4 # ????
meas_pos_rbv = 5 # ????
start_pos_rbv = 4 # <-- only for perceiving the original formating of the measurement file
meas_pos_rbv = 5 # <-- only for perceiving the original formating of the measurement file
axis2.disableAxis()
# ---------------------------------------------capture------------------------------------------
x_array = []
@@ -577,11 +459,7 @@ def analyze_repeatability(input_file, pixel_size, units='um'):
'Y-neg', p2v_y_neg, rms_y_neg, sigma_y_neg, 3*sigma_y_neg))
print(result_str)
"""
result_file = os.path.splitext(input_file)[0] + "_results.dat"
with open(result_file, 'w') as fh:
fh.write(result_str)
print(f"Results saved in: {result_file:s}")"""
def plot_repeatability(
ax, index, com, mean, p2v, rms, pos_mask, neg_mask):
@@ -650,6 +528,7 @@ def camera_thread_function( img_queue):
if os.getenv("EPICS_CA_ADDR_LIST") is not None:
pass
else:
print("EPICS_CA_ADDR_LIST environment variable not set, if it fails after that change IP in metrology_functions.py line 532")
os.environ["EPICS_CA_ADDR_LIST"] = "129.129.181.64"
camera = ad.AD()

7848
notebooks/Results.html Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,15 @@
numpy~=2.2.6
plumbum~=1.9.0
pyads~=3.5.0
matplotlib~=3.10.3
scipy~=1.16.0
opencv-python~=4.12.0.88
pillow~=11.3.0
scikit-learn~=1.7.1
scikit-image~=0.25.2
pandas~=2.3.1
seaborn~=0.13.2
ipywidgets~=8.1.7
ipython~=9.4.0
webcolors~=24.11.1
tifffile~=2025.6.11