Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I24: get the beam centre from the #55

Merged
merged 19 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ dependencies = [
"matplotlib",
"requests",
"opencv-python",
"dls-dodal @ git+https://github.com/DiamondLightSource/dodal.git@main",
"dls-dodal @ git+https://github.com/DiamondLightSource/dodal.git@b01bf2f78c088b879b0f5a7d0bfc3691da505abb",
]
dynamic = ["version"]
license.file = "LICENSE"
Expand Down
212 changes: 130 additions & 82 deletions src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,60 @@
Robin Owen 12 Jan 2021
"""
import logging
from typing import Dict

import bluesky.plan_stubs as bps
import cv2 as cv
from bluesky.run_engine import RunEngine
from dodal.beamlines import i24
from dodal.devices.oav.oav_detector import OAV
from dodal.devices.oav.oav_parameters import OAVParameters

from mx_bluesky.I24.serial.fixed_target import i24ssx_Chip_Manager_py3v1 as manager
from mx_bluesky.I24.serial.parameters.constants import OAV1_CAM, OAV_CONFIG_FILES
from mx_bluesky.I24.serial.setup_beamline import caput, pv

logger = logging.getLogger("I24ssx.moveonclick")

# Set beam position and scale.
# TODO grab these from somewhere else, no hard coding!
beamX = 599 # 577
beamY = 388 # 409
# Set scale.
# TODO See https://github.com/DiamondLightSource/mx_bluesky/issues/44
zoomcalibrator = 6 # 8 seems to work well for zoom 2


def _read_zoom_level(oav: OAV):
zoom_level = yield from bps.rd(oav.zoom_controller.level)
return float(zoom_level)


def _get_beam_centre(oav: OAV, oav_params: OAVParameters):
"""Extract the beam centre x/y positions from the display.configuration file.

Args:
oav (OAV): OAV device for i24.
oav_params (OAVParamters): the OAV parameters.
"""
RE = RunEngine(call_returns_result=True)

Check warning on line 38 in src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py

View check run for this annotation

Codecov / codecov/patch

src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py#L38

Added line #L38 was not covered by tests

zoom_level = RE(_read_zoom_level(oav)).plan_result

Check warning on line 40 in src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py

View check run for this annotation

Codecov / codecov/patch

src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py#L40

Added line #L40 was not covered by tests

beamX, beamY = oav_params.get_beam_position_from_zoom(zoom_level)
return beamX, beamY

Check warning on line 43 in src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py

View check run for this annotation

Codecov / codecov/patch

src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py#L42-L43

Added lines #L42 - L43 were not covered by tests


# TODO In the future, this should be done automatically in the OAV device
# See https://github.com/DiamondLightSource/dodal/issues/224
def get_beam_centre_from_oav(oav_config: Dict = OAV_CONFIG_FILES):
# Get I24 oav device from dodal
oav = i24.oav()

Check warning on line 50 in src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py

View check run for this annotation

Codecov / codecov/patch

src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py#L50

Added line #L50 was not covered by tests
# Use xraycentering as context, not super relevant here.
oav_params = OAVParameters("xrayCentring", **oav_config)

Check warning on line 52 in src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py

View check run for this annotation

Codecov / codecov/patch

src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py#L52

Added line #L52 was not covered by tests

return _get_beam_centre(oav, oav_params)

Check warning on line 54 in src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py

View check run for this annotation

Codecov / codecov/patch

src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py#L54

Added line #L54 was not covered by tests


# Register clicks and move chip stages
def onMouse(event, x, y, flags, param):
beamX, beamY = get_beam_centre_from_oav()
if event == cv.EVENT_LBUTTONUP:
logger.info("Clicked X and Y %s %s" % (x, y))
xmove = -1 * (beamX - x) * zoomcalibrator
Expand All @@ -31,9 +68,91 @@
caput(pv.me14e_pmac_str, ymovepmacstring)


if __name__ == "__main__":
def update_ui(frame):
# Get beam x and y values
beamX, beamY = get_beam_centre_from_oav()

# Overlay text and beam centre
cv.ellipse(
frame, (beamX, beamY), (12, 8), 0.0, 0.0, 360, (0, 255, 255), thickness=2
)
# putText(frame,'text',bottomLeftCornerOfText, font, fontScale, fontColor, thickness, lineType)
cv.putText(
frame,
"Key bindings",
(20, 40),
cv.FONT_HERSHEY_COMPLEX_SMALL,
1,
(0, 255, 255),
1,
1,
)
cv.putText(
frame,
"Q / A : go to / set as f0",
(25, 70),
cv.FONT_HERSHEY_COMPLEX_SMALL,
0.8,
(0, 255, 255),
1,
1,
)
cv.putText(
frame,
"W / S : go to / set as f1",
(25, 90),
cv.FONT_HERSHEY_COMPLEX_SMALL,
0.8,
(0, 255, 255),
1,
1,
)
cv.putText(
frame,
"E / D : go to / set as f2",
(25, 110),
cv.FONT_HERSHEY_COMPLEX_SMALL,
0.8,
(0, 255, 255),
1,
1,
)
cv.putText(
frame,
"I / O : in /out of focus",
(25, 130),
cv.FONT_HERSHEY_COMPLEX_SMALL,
0.8,
(0, 255, 255),
1,
1,
)
cv.putText(
frame,
"C : Create CS",
(25, 150),
cv.FONT_HERSHEY_COMPLEX_SMALL,
0.8,
(0, 255, 255),
1,
1,
)
cv.putText(
frame,
"esc : close window",
(25, 170),
cv.FONT_HERSHEY_COMPLEX_SMALL,
0.8,
(0, 255, 255),
1,
1,
)
cv.imshow("OAV1view", frame)


def start_viewer(oav1: str = OAV1_CAM):
# Create a video caputure from OAV1
cap = cv.VideoCapture("http://bl24i-di-serv-01.diamond.ac.uk:8080/OAV1.mjpg.mjpg")
cap = cv.VideoCapture(oav1)

Check warning on line 155 in src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py

View check run for this annotation

Codecov / codecov/patch

src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py#L155

Added line #L155 was not covered by tests

# Create window named OAV1view and set onmouse to this
cv.namedWindow("OAV1view")
Expand All @@ -47,82 +166,7 @@
while success:
success, frame = cap.read()

# Overlay text and beam centre
cv.ellipse(
frame, (beamX, beamY), (12, 8), 0.0, 0.0, 360, (0, 255, 255), thickness=2
)
# putText(frame,'text',bottomLeftCornerOfText, font, fontScale, fontColor, thickness, lineType)
cv.putText(
frame,
"Key bindings",
(20, 40),
cv.FONT_HERSHEY_COMPLEX_SMALL,
1,
(0, 255, 255),
1,
1,
)
cv.putText(
frame,
"Q / A : go to / set as f0",
(25, 70),
cv.FONT_HERSHEY_COMPLEX_SMALL,
0.8,
(0, 255, 255),
1,
1,
)
cv.putText(
frame,
"W / S : go to / set as f1",
(25, 90),
cv.FONT_HERSHEY_COMPLEX_SMALL,
0.8,
(0, 255, 255),
1,
1,
)
cv.putText(
frame,
"E / D : go to / set as f2",
(25, 110),
cv.FONT_HERSHEY_COMPLEX_SMALL,
0.8,
(0, 255, 255),
1,
1,
)
cv.putText(
frame,
"I / O : in /out of focus",
(25, 130),
cv.FONT_HERSHEY_COMPLEX_SMALL,
0.8,
(0, 255, 255),
1,
1,
)
cv.putText(
frame,
"C : Create CS",
(25, 150),
cv.FONT_HERSHEY_COMPLEX_SMALL,
0.8,
(0, 255, 255),
1,
1,
)
cv.putText(
frame,
"esc : close window",
(25, 170),
cv.FONT_HERSHEY_COMPLEX_SMALL,
0.8,
(0, 255, 255),
1,
1,
)
cv.imshow("OAV1view", frame)
update_ui(frame)

Check warning on line 169 in src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py

View check run for this annotation

Codecov / codecov/patch

src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py#L169

Added line #L169 was not covered by tests

k = cv.waitKey(1)
if k == 113: # Q
Expand Down Expand Up @@ -165,3 +209,7 @@

# Clear cameraCapture instance
cap.release()


if __name__ == "__main__":
start_viewer()

Check warning on line 215 in src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py

View check run for this annotation

Codecov / codecov/patch

src/mx_bluesky/I24/serial/fixed_target/i24ssx_moveonclick.py#L215

Added line #L215 was not covered by tests
7 changes: 7 additions & 0 deletions src/mx_bluesky/I24/serial/parameters/constants.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
from pathlib import Path

OAV_CONFIG_FILES = {
"zoom_params_file": "/dls_sw/i24/software/gda/config/xml/jCameraManZoomLevels.xml",
"oav_config_json": "/dls_sw/i24/software/daq_configuration/json/OAVCentring.json",
"display_config": "/dls_sw/i24/software/gda_versions/var/display.configuration",
}
OAV1_CAM = "http://bl24i-di-serv-01.diamond.ac.uk:8080/OAV1.mjpg.mjpg"

PARAM_FILE_PATH = Path("src/mx_bluesky/I24/serial/parameters").expanduser().resolve()
PARAM_FILE_PATH_FT = (
Path("src/mx_bluesky/I24/serial/parameters/fixed_target").expanduser().resolve()
Expand Down
Empty file.
66 changes: 66 additions & 0 deletions tests/I24/serial/fixed_target/test_moveonclick.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from unittest.mock import ANY, MagicMock, call, patch

import cv2 as cv
import pytest
from bluesky.run_engine import RunEngine
from dodal.beamlines import i24
from dodal.devices.oav.oav_detector import OAV

from mx_bluesky.I24.serial.fixed_target.i24ssx_moveonclick import (
_read_zoom_level,
onMouse,
update_ui,
)


@pytest.fixture
def fake_oav() -> OAV:
return i24.oav(fake_with_ophyd_sim=True)


@pytest.mark.parametrize(
"beam_position, expected_1J, expected_2J",
[
((15, 10), "#1J:-90", "#2J:60"),
((100, 150), "#1J:-600", "#2J:900"),
((475, 309), "#1J:-2850", "#2J:1854"),
((638, 392), "#1J:-3828", "#2J:2352"),
],
)
@patch("mx_bluesky.I24.serial.fixed_target.i24ssx_moveonclick.caput")
@patch("mx_bluesky.I24.serial.fixed_target.i24ssx_moveonclick.get_beam_centre_from_oav")
def test_onMouse_gets_beam_position_and_sends_correct_str(
fake_get_beam_pos,
fake_caput,
beam_position,
expected_1J,
expected_2J,
):
fake_get_beam_pos.side_effect = [beam_position]
onMouse(cv.EVENT_LBUTTONUP, 0, 0, "", "")
assert fake_caput.call_count == 2
fake_caput.assert_has_calls(
[
call(ANY, expected_1J),
call(ANY, expected_2J),
]
)


@patch("mx_bluesky.I24.serial.fixed_target.i24ssx_moveonclick.cv")
@patch("mx_bluesky.I24.serial.fixed_target.i24ssx_moveonclick.get_beam_centre_from_oav")
def test_update_ui_uses_correct_beam_centre_for_ellipse(fake_beam_pos, fake_cv):
mock_frame = MagicMock()
fake_beam_pos.side_effect = [(15, 10)]
update_ui(mock_frame)
fake_cv.ellipse.assert_called_once()
fake_cv.ellipse.assert_has_calls(
[call(ANY, (15, 10), (12, 8), 0.0, 0.0, 360, (0, 255, 255), thickness=2)]
)


def test_read_zoom_level(fake_oav):
fake_oav.zoom_controller.level.sim_put("3.0")
RE = RunEngine(call_returns_result=True)
zoom_level = RE(_read_zoom_level(fake_oav)).plan_result
assert zoom_level == 3.0