From 7441c2537f1320667cc51d55cbdb926fe467fc7e Mon Sep 17 00:00:00 2001 From: Brian Koopman Date: Thu, 3 Aug 2023 16:36:33 -0400 Subject: [PATCH 1/2] Add boresight rotation to move_to() --- src/sorunlib/acu.py | 21 ++++++++++++++++++++- tests/test_acu.py | 36 ++++++++++++++++++++++++++++++++++++ tests/util.py | 11 +++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 tests/util.py diff --git a/src/sorunlib/acu.py b/src/sorunlib/acu.py index 2b19fb9..592455e 100644 --- a/src/sorunlib/acu.py +++ b/src/sorunlib/acu.py @@ -2,13 +2,32 @@ from sorunlib._internal import check_response -def move_to(az, el): +def move_to(az, el, boresight=None): """Move telescope to specified coordinates. Args: az (float): destination angle for the azimuthal axis el (float): destination angle for the elevation axis + boresight (float, optional): destination angle for boresight rotation + on SAT platforms + + Raises: + RuntimeError: If boresight is passed to a non-satp platform. """ + # Az/El motion resp = run.CLIENTS['acu'].go_to(az=az, el=el) check_response(resp) + + # Boresight motion (satp only) + if boresight is None: + return + + # Check platform type + resp = run.CLIENTS['acu'].monitor.status() + platform = resp.session['data']['PlatformType'] + if platform == "satp": + resp = run.CLIENTS['acu'].set_boresight(target=boresight) + check_response(resp) + else: + raise RuntimeError(f"Platform type {platform} does not support boresight motion") diff --git a/tests/test_acu.py b/tests/test_acu.py index 5585c41..e79bc87 100644 --- a/tests/test_acu.py +++ b/tests/test_acu.py @@ -5,9 +5,28 @@ from unittest.mock import MagicMock, patch +import ocs from ocs.ocs_client import OCSReply from sorunlib import acu +from util import create_session + + +def create_acu_client(platform_type): + """Create an ACU client with mock monitor Process session.data. + + Args: + platform_type (str): Either 'satp' or 'ccat'. + + """ + acu_client = MagicMock() + session = create_session('monitor') + session.data = {'PlatformType': platform_type} + reply = OCSReply(ocs.OK, 'msg', session.encoded()) + acu_client.monitor.status = MagicMock(return_value=reply) + + return acu_client + def mocked_clients(test_mode): clients = {'acu': MagicMock(), @@ -23,6 +42,23 @@ def test_move_to(): acu.run.CLIENTS['acu'].go_to.assert_called_with(az=180, el=60) +@patch('sorunlib.create_clients', mocked_clients) +def test_move_to_boresight(): + acu.run.initialize(test_mode=True) + acu.run.CLIENTS['acu'] = create_acu_client('satp') + acu.move_to(180, 60, 20) + acu.run.CLIENTS['acu'].go_to.assert_called_with(az=180, el=60) + acu.run.CLIENTS['acu'].set_boresight.assert_called_with(target=20) + + +@patch('sorunlib.create_clients', mocked_clients) +def test_move_to_boresight_lat(): + acu.run.initialize(test_mode=True) + acu.run.CLIENTS['acu'] = create_acu_client('ccat') + with pytest.raises(RuntimeError): + acu.move_to(180, 60, 20) + + @patch('sorunlib.create_clients', mocked_clients) def test_move_to_failed(): acu.run.initialize() diff --git a/tests/util.py b/tests/util.py new file mode 100644 index 0000000..82c6df5 --- /dev/null +++ b/tests/util.py @@ -0,0 +1,11 @@ +from unittest import mock + +from ocs.ocs_agent import OpSession + + +def create_session(op_name): + """Create an OpSession with a mocked app for testing.""" + mock_app = mock.MagicMock() + session = OpSession(1, op_name, app=mock_app) + + return session From 93bf6146f7e626389947bbcf3b096af91b49c330 Mon Sep 17 00:00:00 2001 From: Brian Koopman Date: Tue, 8 Aug 2023 13:50:03 -0400 Subject: [PATCH 2/2] Split boresight control to separate command --- src/sorunlib/acu.py | 22 ++++++++++++---------- tests/test_acu.py | 9 ++++----- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/sorunlib/acu.py b/src/sorunlib/acu.py index 592455e..8854467 100644 --- a/src/sorunlib/acu.py +++ b/src/sorunlib/acu.py @@ -2,32 +2,34 @@ from sorunlib._internal import check_response -def move_to(az, el, boresight=None): +def move_to(az, el): """Move telescope to specified coordinates. Args: az (float): destination angle for the azimuthal axis el (float): destination angle for the elevation axis - boresight (float, optional): destination angle for boresight rotation - on SAT platforms - - Raises: - RuntimeError: If boresight is passed to a non-satp platform. """ # Az/El motion resp = run.CLIENTS['acu'].go_to(az=az, el=el) check_response(resp) - # Boresight motion (satp only) - if boresight is None: - return +def set_boresight(target): + """Move the third axis to a specific target angle. + + Args: + target (float): destination angle for boresight rotation + + Raises: + RuntimeError: If boresight is passed to a non-satp platform. + + """ # Check platform type resp = run.CLIENTS['acu'].monitor.status() platform = resp.session['data']['PlatformType'] if platform == "satp": - resp = run.CLIENTS['acu'].set_boresight(target=boresight) + resp = run.CLIENTS['acu'].set_boresight(target=target) check_response(resp) else: raise RuntimeError(f"Platform type {platform} does not support boresight motion") diff --git a/tests/test_acu.py b/tests/test_acu.py index e79bc87..be5ee23 100644 --- a/tests/test_acu.py +++ b/tests/test_acu.py @@ -43,20 +43,19 @@ def test_move_to(): @patch('sorunlib.create_clients', mocked_clients) -def test_move_to_boresight(): +def test_set_boresight(): acu.run.initialize(test_mode=True) acu.run.CLIENTS['acu'] = create_acu_client('satp') - acu.move_to(180, 60, 20) - acu.run.CLIENTS['acu'].go_to.assert_called_with(az=180, el=60) + acu.set_boresight(20) acu.run.CLIENTS['acu'].set_boresight.assert_called_with(target=20) @patch('sorunlib.create_clients', mocked_clients) -def test_move_to_boresight_lat(): +def test_set_boresight_lat(): acu.run.initialize(test_mode=True) acu.run.CLIENTS['acu'] = create_acu_client('ccat') with pytest.raises(RuntimeError): - acu.move_to(180, 60, 20) + acu.set_boresight(20) @patch('sorunlib.create_clients', mocked_clients)