DAQ: Added auto-centering

This commit is contained in:
2025-07-15 09:57:16 +02:00
parent 23a9ed826a
commit 000b597271
6 changed files with 116 additions and 37 deletions
+65 -34
View File
@@ -322,6 +322,40 @@ class AareDAQ:
else:
return None
def __auto_center(self, grid: RasterGridRequest) -> CompletedRasterGrid | None:
sample = self.sample
if sample is None:
raise Exception("Sample must be mounted to auto center")
self.__devs.aerotech.move(grid.omega_deg, wait=True)
old_prefix = grid.file_prefix
r = self.__ml_bounding_box(sample.db_id, grid.file_prefix)
if r is not None:
grid.smargon = r.smargon
grid.grid_size_mm = r.grid_size_mm
grid.n_x = r.n_x
grid.n_y = r.n_y
grid.file_prefix = f"{old_prefix}_{grid.omega_deg}deg"
res1 = self.__raster(grid)
# self.__devs.aerotech.move(grid.omega_deg + 90, wait=True)
self.__set_state(BeamlineStateEnum.SampleAlignment)
return res1
else:
return None
def auto_center(self, grid: RasterGridRequest) -> CompletedRasterGrid | None:
try:
self.__cfg.try_set_busy(timeout=360)
result = self.__auto_center(grid)
self.__cfg.state_busy = False
return result
except Exception as e:
self.__set_state(BeamlineStateEnum.SampleAlignment)
self.__cfg.state_busy = False
raise e
def __raster(self, r: RasterGridRequest) -> CompletedRasterGrid:
max_time = r.exp_time_s * r.n_y * r.n_x + 60
self.__cfg.dtz = r.dtz
@@ -367,11 +401,13 @@ class AareDAQ:
self.__devs.smargon.target = save_smargon_position
return CompletedRasterGrid(request=copy.deepcopy(r), result=result)
def measure_raster(self, r: RasterGridRequest) -> CompletedRasterGrid:
max_time = r.exp_time_s * r.n_y * r.n_x + 60
self.__cfg.try_set_busy(timeout=ceil(max_time + 360))
def measure_raster(self, r: RasterGridRequest, auto: bool) -> CompletedRasterGrid:
self.__cfg.try_set_busy(timeout=ceil(360))
try:
result = self.__raster(r)
if auto:
result = self.__auto_center(r)
else:
result = self.__raster(r)
self.__set_state(BeamlineStateEnum.SampleAlignment)
self.__cfg.state_busy = False
return result
@@ -565,7 +601,7 @@ class AareDAQ:
def listen_changes(self) -> redis.client.PubSub:
return self.__cfg.listen_changes()
def __ml_bounding_box(self, sample_id: int | None = None, filename: str | None = None, move: bool = False) -> BoundingBoxModel | None:
def __ml_bounding_box(self, sample_id: int | None = None, filename: str | None = None) -> RasterGridRequest | None:
time.sleep(0.2) # Just to be sure image is stable
#curr_image = self.camera_image
#box = self.__mlbox.predict(curr_image)
@@ -574,42 +610,37 @@ class AareDAQ:
if box is None:
if filename is not None:
cv2.imwrite(f"{filename}_no_detection.jpg", bgr_image)
self.__aare.upload_image(sample_id, f"{filename}_no_detection", bgr_image)
return None
x1, y1, x2, y2 = box
if filename is not None:
cv2.rectangle(bgr_image, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
cv2.imwrite(f"{filename}.jpg", bgr_image)
self.__aare.upload_image(sample_id, filename, bgr_image)
if move:
geom = self.sample_geometry
coord = geom.picture_to_smargon(Coordinate(x=x1, y=y1))
self.__devs.smargon.target = SmargonCoordinate(sh_mm=coord)
self.__devs.smargon.wait(60)
return BoundingBoxModel(bottom_x=x1, bottom_y=y1, top_x=x2, top_y=y2)
def ml_bounding_box(self, sample_id: int | None = None, filename: str | None = None, move: bool = False) -> RasterGridRequest | None:
geom = self.sample_geometry
start_coord = geom.picture_to_smargon(Coordinate(x=x1, y=y1))
grid_size = Coordinate(x=geom.beam_size_mm.x * 0.8, y=geom.beam_size_mm.y * 0.8)
n_x = abs(ceil((x2 - x1) * geom.pixel_in_mm / grid_size.x))
n_y = abs(ceil((y2 - y1) * geom.pixel_in_mm / grid_size.y))
return RasterGridRequest(
exp_time_s=0.02,
transmission=1.0,
smargon= SmargonCoordinate(chi_deg = geom.smargon.chi_deg,
phi_deg= geom.smargon.phi_deg,
sh_mm=start_coord),
n_x=n_x,
n_y=n_y,
grid_size_mm= grid_size,
omega_deg=geom.omega_deg
)
def ml_bounding_box(self, sample_id: int | None = None, filename: str | None = None) -> RasterGridRequest | None:
try:
self.__cfg.try_set_busy(timeout=360)
ml_box = self.__ml_bounding_box(sample_id, filename, move)
r = None
if ml_box is not None:
geom = self.sample_geometry
start_coord = geom.picture_to_smargon(Coordinate(x=ml_box.bottom_x, y=ml_box.bottom_y))
grid_size = Coordinate(x=geom.beam_size_mm.x * 0.8, y=geom.beam_size_mm.y * 0.8)
n_x = abs(ceil((ml_box.top_x - ml_box.bottom_x) * geom.pixel_in_mm / grid_size.x))
n_y = abs(ceil((ml_box.top_y - ml_box.bottom_y) * geom.pixel_in_mm / grid_size.y))
r = RasterGridRequest(
exp_time_s=0.05,
smargon= SmargonCoordinate(chi_deg = geom.smargon.chi_deg,
phi_deg= geom.smargon.phi_deg,
sh_mm=start_coord),
n_x=n_x,
n_y=n_y,
grid_size_mm= grid_size,
omega_deg=geom.omega_deg
)
r = self.__ml_bounding_box(sample_id, filename)
self.__cfg.state_busy = False
return r
except Exception:
@@ -748,7 +779,7 @@ class AareDAQ:
self.__devs.aerotech.move(0, wait=True)
self.__ml_bounding_box(sample.db_id, f"bb_raster_0", move=True)
self.__ml_bounding_box(sample.db_id, f"bb_raster_0")
self.__raster(
RasterGridRequest(
@@ -763,7 +794,7 @@ class AareDAQ:
self.__devs.aerotech.move(90, wait=True)
self.__ml_bounding_box(sample.db_id, f"bb_raster_90", move=True)
self.__ml_bounding_box(sample.db_id, f"bb_raster_90")
self.__raster(
RasterGridRequest(
+2 -2
View File
@@ -289,9 +289,9 @@ async def beam_location(token: str = Depends(oauth2_scheme)):
# Scans
@app.post("/scan/raster")
async def raster(val: RasterGridRequest, token: str = Depends(oauth2_scheme)) -> CompletedRasterGrid:
async def raster(val: RasterGridRequest, auto: bool = False, token: str = Depends(oauth2_scheme)) -> CompletedRasterGrid:
auth.check_jwt_rw(cfg, auth.parse_token(token))
return daq.measure_raster(val)
return daq.measure_raster(val, auto)
@app.post("/scan/rotation")
+2
View File
@@ -201,6 +201,7 @@ class MainWindow(QMainWindow):
self.sample_camera.evaluate_grid.connect(self.raster.run_grid_scan)
self.data_collection.raster.evaluate_grid.connect(self.raster.run_grid_scan)
self.data_collection.raster.evaluate_grid_auto.connect(self.raster.run_grid_scan_auto)
self.sample_camera.clear_evaluated_grids.connect(self.raster.clear_completed_grids)
self.sample_camera.clear_grid.connect(self.raster.clear_active_grid)
@@ -222,6 +223,7 @@ class MainWindow(QMainWindow):
self.data_collection.cancel.connect(self.daq.cancel)
self.raster.grid_scan.connect(self.daq.raster_scan)
self.raster.grid_scan_auto.connect(self.daq.raster_scan_auto)
self.data_collection.screening.rotation_scan.connect(self.daq.standard_scan)
self.raster.grid_scan_size_changed.connect(self.data_collection.raster.grid_scan_size_change)
@@ -13,6 +13,7 @@ class RasterDataCollectionPanel(ScanSettingsPanel):
grid_size_updated = Signal(float, float)
exp_time_updated = Signal(float)
evaluate_grid = Signal()
evaluate_grid_auto = Signal()
grid_metric_updated = Signal(RasterGridMetric)
raster_alpha_changed = Signal(int)
@@ -114,6 +115,11 @@ class RasterDataCollectionPanel(ScanSettingsPanel):
self.start_button.clicked.connect(self.evaluate_grid)
self._layout.addWidget(self.start_button, 11, 0, 1, 5)
self.auto_button = QPushButton("Feeling lucky")
self.auto_button.setStyleSheet("color: rgb(78, 154, 6);")
self.auto_button.clicked.connect(self.evaluate_grid_auto)
self._layout.addWidget(self.auto_button, 12, 0, 1, 5)
self.update_grid_scan_size()
@Slot(float)
@@ -73,7 +73,10 @@ def normalize_angle(angle_deg: float) -> float:
class RasterGridManager(QObject):
grid_updated = Signal()
grid_scan = Signal(RasterGridRequest)
grid_scan_auto = Signal(RasterGridRequest)
grid_scan_size_changed = Signal(int, int, float, float)
completed_grid_updated = Signal()
@@ -309,6 +312,10 @@ class RasterGridManager(QObject):
grid = copy.deepcopy(self.__active_grid)
self.grid_scan.emit(grid)
@Slot()
def run_grid_scan_auto(self):
grid = copy.deepcopy(self.__active_grid)
self.grid_scan_auto.emit(grid)
def spot_ice_ratio(self, obj):
if obj.spots_ice is None or obj.spots_low_res is None or obj.spots_low_res <= 0:
+34 -1
View File
@@ -250,13 +250,46 @@ class DAQWorker(QObject):
self.raster_scan_completed.emit(reply)
return
request = QNetworkRequest(QUrl(f"{self.__base_url}/scan/raster"))
request = QNetworkRequest(QUrl(f"{self.__base_url}/scan/raster?auto=false"))
request.setRawHeader(b"Authorization", f"Bearer {self.__token}".encode("utf-8"))
request.setRawHeader(b"Content-Type", b"application/json")
body = r.model_dump_json()
reply = self.__net_manager.post(request, QByteArray(body.encode("utf-8")))
reply.finished.connect(lambda: self.handle_raster_scan_response(reply))
@Slot(RasterGridRequest)
def raster_scan_auto(self, r: RasterGridRequest):
self.run_number_incremented.emit()
if self.__base_url is None:
print(f"POST /scan/raster: {r.model_dump_json()}")
image_number = r.get_image_number()
new_copy = copy.deepcopy(r)
images = []
for i in range(image_number):
images.append(ScanResultImagesInner(
number=i,
efficiency=1.0,
bkg=random.gauss(3.0, 0.1),
spots=random.randint(0, 250),
index=random.randint(0, 1),
mos=random.uniform(0, 0.1),
b=random.uniform(15.0, 80.0)
))
reply = CompletedRasterGrid(request=new_copy,
result=ScanResult(file_prefix=r.file_prefix, images=images))
self.raster_scan_completed.emit(reply)
return
request = QNetworkRequest(QUrl(f"{self.__base_url}/scan/raster?auto=true"))
request.setRawHeader(b"Authorization", f"Bearer {self.__token}".encode("utf-8"))
request.setRawHeader(b"Content-Type", b"application/json")
body = r.model_dump_json()
reply = self.__net_manager.post(request, QByteArray(body.encode("utf-8")))
reply.finished.connect(lambda: self.handle_raster_scan_response(reply))
@Slot()
def load_spreadsheet(self):
if self.__base_url is None: