Skip to content

Commit

Permalink
Merge branch 'main' into 50_choose-detector
Browse files Browse the repository at this point in the history
  • Loading branch information
noemifrisina committed Nov 8, 2023
2 parents d86f0e6 + 9a36e6d commit ba0b5f8
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 83 deletions.
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)

zoom_level = RE(_read_zoom_level(oav)).plan_result

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


# 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()
# Use xraycentering as context, not super relevant here.
oav_params = OAVParameters("xrayCentring", **oav_config)

return _get_beam_centre(oav, oav_params)


# 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 @@ def onMouse(event, x, y, flags, param):
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)

# Create window named OAV1view and set onmouse to this
cv.namedWindow("OAV1view")
Expand All @@ -47,82 +166,7 @@ def onMouse(event, x, y, flags, param):
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)

k = cv.waitKey(1)
if k == 113: # Q
Expand Down Expand Up @@ -165,3 +209,7 @@ def onMouse(event, x, y, flags, param):

# Clear cameraCapture instance
cap.release()


if __name__ == "__main__":
start_viewer()
7 changes: 7 additions & 0 deletions src/mx_bluesky/I24/serial/parameters/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ class SSXType(Enum):
EXTRUDER = "Serial Jet"


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

0 comments on commit ba0b5f8

Please sign in to comment.