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

Tracking error fixes #549

Merged
merged 8 commits into from
Aug 19, 2018
Merged
Show file tree
Hide file tree
Changes from 4 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
8 changes: 4 additions & 4 deletions pocs/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ def pointing_error(self):
d_ra = self.pointing.ra - self.header_pointing.ra

self._pointing_error = OffsetError(
d_ra.to(
u.arcsec), d_dec.to(
u.arcsec), mag.to(
u.arcsec))
d_ra.to(u.arcsec),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I read this as just a formatting change, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. It was just annoying me too much as I was trying to understand it.

d_dec.to(u.arcsec),
mag.to(u.arcsec)
)

return self._pointing_error

Expand Down
104 changes: 102 additions & 2 deletions pocs/mount/mount.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ def __init__(self, location, commands=None, *args, **kwargs
self._state = 'Parked'

self.sidereal_rate = ((360 * u.degree).to(u.arcsec) / (86164 * u.second))
self.ra_guide_rate = 0.5 # Sidereal
self.dec_guide_rate = 0.5 # Sidereal
self.ra_guide_rate = 0.9 # Sidereal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does guide rate mean the speed with which we make adjustments to the position between images?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is documented somewhere but the fact that I don't know where and that you have a question here makes that irrelevant.

I want to turn these into properties of the class, which would be more consistent with all these other values and would allow for an easier docstring. - #552

self.dec_guide_rate = 0.9 # Sidereal
self._tracking_rate = 1.0 # Sidereal
self._tracking = 'Sidereal'
self._movement_speed = ''
Expand Down Expand Up @@ -311,6 +311,106 @@ def distance_from_target(self):

return separation

def get_tracking_correction(self, offset_info, pointing_ha):
"""Determine the needed tracking corrections from current position.

Args:
offset_info (`OffsetError`): A named tuple describing the offset
error. See `pocs.images.OffsetError`.
pointing_ha (float): The Hour Angle (HA) of the mount at the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the point here that the mount will do a meridian flip to go from 89 degrees to 91 degrees (90 being pointing to the meridian)? And thus the HA will tell us if we started observing with the cameras on the left or right side of the pier?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some more info in the docstring.

beginning of the observation sequence in degrees. This affects
the direction of the Dec adjustment.

Returns:
dict[tuple]: Offset corrections for each axis:
(arcsec, millisecond, direction).
"""
pier_side = 'east'
if pointing_ha <= 12:
pier_side = 'west'

self.logger.debug("Mount pier side: {}".format(pier_side))

axis_corrections = {
'dec': None,
'ra': None,
}

for axis in axis_corrections.keys():
# find the number of ms and direction for Dec axis
offset = getattr(offset_info, 'delta_{}'.format(axis))
offset_ms = self.get_ms_offset(offset, axis=axis)

if axis == 'dec':
# Determine which direction to move based on direction mount
# is moving (i.e. what side it started on).
if pier_side == 'east':
if offset_ms >= 0:
delta_direction = 'north'
else:
delta_direction = 'south'
else:
if offset_ms >= 0:
delta_direction = 'south'
else:
delta_direction = 'north'
else:
if offset_ms >= 0:
delta_direction = 'west'
else:
delta_direction = 'east'

offset_ms = abs(offset_ms.value)

# Skip short corrections
if offset_ms <= 50:
continue

# Ensure we don't try to move for too long
max_time = 99999

# Correct long offset
if offset_ms > max_time:
offset_ms = max_time

axis_corrections[axis] = (offset, offset_ms, delta_direction)

return axis_corrections

def correct_tracking(self, correction_info, axis_timeout=30.):
""" Make tracking adjustment corrections.

Args:
correction_info (dict[tuple]): Correction info to be applied, see
`get_tracking_correction`.
axis_timeout (float, optional): Timeout for adjustment in each axis,
default 30 seconds.

Raises:
`error.Timeout`: Timeout error.
"""
for axis, corrections in correction_info.items():
offset = corrections[0]
offset_ms = corrections[1]
delta_direction = corrections[2]

self.logger.info("Adjusting {}: {} {:0.2f} ms {:0.2f}".format(
axis, delta_direction, offset_ms, offset))

self.mount.query(
'move_ms_{}'.format(delta_direction),
'{:05.0f}'.format(offset_ms)
)

# Adjust tracking for `axis_timeout` seconds then fail if not done.
start_tracking_time = current_time()
while self.mount.is_tracking is False:
if (current_time() - start_tracking_time).sec > axis_timeout:
raise error.Timeout("Tracking adjustment timeout: {}".format(axis))

self.logger.debug("Waiting for {} tracking adjustment".format(axis))
time.sleep(0.5)


##################################################################################################
# Movement methods
Expand Down
78 changes: 17 additions & 61 deletions pocs/observatory.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import os
import time

from collections import OrderedDict
from datetime import datetime
Expand Down Expand Up @@ -342,67 +341,24 @@ def update_tracking(self):
if self.current_offset_info is not None:
self.logger.debug("Updating the tracking")

# find the number of ms and direction for Dec axis
dec_offset = self.current_offset_info.delta_dec
dec_ms = self.mount.get_ms_offset(dec_offset, axis='dec')
if dec_offset >= 0:
dec_direction = 'north'
else:
dec_direction = 'south'
# Get the pier side of pointing image
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add some more comments? I'm certainly ignorant about what is happening here, and the lack of problem description in the PR isn't helping.

pointing_ha = self.current_observation.pointing_image.header_ha

# find the number of ms and direction for RA axis
ra_offset = self.current_offset_info.delta_ra
ra_ms = self.mount.get_ms_offset(ra_offset, axis='ra')
if ra_offset >= 0:
ra_direction = 'west'
else:
ra_direction = 'east'

dec_ms = abs(dec_ms.value) * 1.5 # TODO(wtgee): Figure out why 1.5
ra_ms = abs(ra_ms.value) * 1.

# Ensure we don't try to move for too long
max_time = 99999

# Correct the Dec axis (if offset is large enough)
if dec_ms > max_time:
dec_ms = max_time

if dec_ms >= 50:
self.logger.info("Adjusting Dec: {} {:0.2f} ms {:0.2f}".format(
dec_direction, dec_ms, dec_offset))
if dec_ms >= 1. and dec_ms <= max_time:
self.mount.query('move_ms_{}'.format(
dec_direction), '{:05.0f}'.format(dec_ms))

# Adjust tracking for up to 30 seconds then fail if not done.
start_tracking_time = current_time()
while self.mount.is_tracking is False:
if (current_time() - start_tracking_time).sec > 30:
raise Exception("Trying to adjust Dec tracking for more than 30 seconds")

self.logger.debug("Waiting for Dec tracking adjustment")
time.sleep(0.1)

# Correct the RA axis (if offset is large enough)
if ra_ms > max_time:
ra_ms = max_time

if ra_ms >= 50:
self.logger.info("Adjusting RA: {} {:0.2f} ms {:0.2f}".format(
ra_direction, ra_ms, ra_offset))
if ra_ms >= 1. and ra_ms <= max_time:
self.mount.query('move_ms_{}'.format(
ra_direction), '{:05.0f}'.format(ra_ms))

# Adjust tracking for up to 30 seconds then fail if not done.
start_tracking_time = current_time()
while self.mount.is_tracking is False:
if (current_time() - start_tracking_time).sec > 30:
raise Exception("Trying to adjust RA tracking for more than 30 seconds")

self.logger.debug("Waiting for RA tracking adjustment")
time.sleep(0.1)
try:
pointing_ha = pointing_ha.value
except AttributeError:
pass

self.logger.debug("Pointing HA: {}".format(pointing_ha))
correction_info = self.mount.get_tracking_correction(
self.current_offset_info,
pointing_ha
)

try:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth putting in a limit, where we don't make a correction if the error is sufficiently low?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It happens back in get_tracking_correction where it checks for anything under 50 ms. Nothing goes into the returned dict so the correct_tracking method then just skips that whole axis.

The 50 ms was determined empirically by me where I noticed when it was shorter than about 40ms it would just happen too quickly and then the system would get stuck waiting. It's also less than 1 pix of movement.

I'll make a note in the docstring to get_tracking_correction about how the values are clipped for min max.

self.mount.correct_tracking(correction_info)
except error.Timeout:
self.logger.warning("Timeout while correcting tracking")

def get_standard_headers(self, observation=None):
"""Get a set of standard headers
Expand Down
7 changes: 0 additions & 7 deletions pocs/tests/bisque/test_mount.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,6 @@ def test_update_location(mount, config):
assert mount.location == location2


# def test_target_coords_below_horizon(mount, target_down):
# mount.initialize()

# assert mount.set_target_coordinates(target_down) is False
# assert mount.get_target_coordinates() is None


def test_target_coords(mount, target):
mount.initialize(unpark=True)

Expand Down
46 changes: 46 additions & 0 deletions pocs/tests/test_ioptron.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
import os
import pytest

from astropy.coordinates import EarthLocation
from astropy import units as u

from pocs.images import OffsetError
from pocs.mount.ioptron import Mount
from pocs.utils.config import load_config


@pytest.fixture
def location():
config = load_config(ignore_local=True)
loc = config['location']
return EarthLocation(lon=loc['longitude'], lat=loc['latitude'], height=loc['elevation'])


@pytest.fixture(scope="function")
def mount(config, location):
try:
del os.environ['POCSTIME']
except KeyError:
pass

config['mount'] = {
'brand': 'bisque',
'template_dir': 'resources/bisque',
}
return Mount(location=location, config=config)


@pytest.mark.with_mount
Expand Down Expand Up @@ -64,3 +89,24 @@ def test_unpark_park(self):
assert self.mount.is_parked is False
self.mount.home_and_park()
assert self.mount.is_parked is True


def test_get_tracking_correction(mount):
pointing_ha = 12
offset_info = OffsetError(
-13.0881456 * u.arcsec,
1.4009 * u.arcsec,
12.154 * u.arcsec
)
correction_info = mount.get_tracking_correction(offset_info, pointing_ha)

dec_info = correction_info['dec']
ra_info = correction_info['ra']

assert dec_info[0].value == pytest.approx(1.4009, rel=1e-2)
assert dec_info[1] == pytest.approx(103.49, rel=1e-2)
assert dec_info[2] == 'south'

assert ra_info[0].value == pytest.approx(-13.09, rel=1e-2)
assert ra_info[1] == pytest.approx(966.84, rel=1e-2)
assert ra_info[2] == 'east'