ACU Agent

The Antenna Control Unit (ACU) is an industrial PC with VxWorks installed. It is used for readout of encoder measurements and control of telescope platforms.

usage: python3 agent.py [-h] [--acu-config ACU_CONFIG]
                        [--exercise-plan EXERCISE_PLAN] [--no-processes]
                        [--ignore-axes {el,az,third} [{el,az,third} ...]]
                        [--disable-idle-reset] [--min-el MIN_EL]
                        [--max-el MAX_EL] [--avoid-sun AVOID_SUN]
                        [--fov-radius FOV_RADIUS]
                        [--named-positions NAMED_POSITIONS [NAMED_POSITIONS ...]]

Agent Options

--acu-config
--exercise-plan
--no-processes

Default: False

--ignore-axes

Possible choices: el, az, third

One or more axes to ignore.

--disable-idle-reset

Disable idle_reset, even for LAT.

Default: False

--min-el

Override the minimum el defined in platform config.

--max-el

Override the maximum el defined in platform config.

--avoid-sun

Pass 0 or 1 to disable or enable Sun avoidance. Overrides the platform default config.

--fov-radius

Override the default field-of-view (radius in degrees) for Sun avoidance purposes.

--named-positions

Define named positions, for go_to_named; e.g. ‘home=180,60’.

Dependencies

The soaculib package must be installed to use this Agent. This can be installed via:

$ pip install 'soaculib @ git+https://github.com/simonsobs/soaculib.git@master'

Additionally, socs should be installed with the acu group:

$ pip install -U socs[acu]

Configuration File Examples

Below are configuration examples for the ocs config file and for soaculib.

OCS Site Config

To configure the ACU Agent we need to add a block to the ocs configuration file. An example configuration block using all availabile arguments is below:

{'agent-class': 'ACUAgent',
 'instance-id': 'acu-satp1',
 'arguments': [['--acu-config', 'satp1']],
 }

soaculib

We additionally need to add a block to the soaculib configuration file. An example configuration block is below:

'satp1': {
    'base_url': 'http://192.168.1.111:8100',
    'readonly_url': 'http://192.168.1.111:8110',
    'dev_url': 'http://192.168.1.111:8080',
    'interface_ip': '192.168.1.110',
    'motion_waittime': 5.0,
    'streams': {
        'main': {
            'acu_name': 'PositionBroadcast',
            'port': 10004,
            'schema': 'v2'
        },
        'ext': {
            'acu_name': 'PositionBroadcastExt',
            'port': 10005,
            'active': False,
        },
    },
    'status': {
        'status_name': 'Datasets.StatusSATPDetailed8100',
        },

    'platform': 'satp',
    'motion_limits': {
        'azimuth': {
            'lower': -90.0,
            'upper': 480.0,
        },
        'elevation': {
            'lower': 20.0,
            'upper': 50.0,
        },
        'boresight': {
            'lower': 0.0,
            'upper': 360.,
        },
        'acc': (8./1.88),
    },
}

Sun Avoidance

The Sun’s position, and the potential danger of the Sun to the equipment, is monitored and reported by the monitor_sun Process. If enabled to do so, this Process can trigger the escape_sun_now Task, which will cause the platform to move to a Sun-safe position.

The parameters used by an Agent instance for Sun Avoidance are determined like this:

  • Default parameters for each platform (LAT and SATP) are in the Agent code.

  • On start-up the default parameters for platform are modified according to any command-line parameters passed in by the user.

  • Some parameters can be altered using the command line.

The avoidance policy is defined by a few key parameters and concepts; please see the descriptions of sun_dist, sun_time, exclusion_radius, and more in the socs.agents.acu.avoidance module documentation.

The exclusion_radius can be configured from the Agent command line, and also through the update_sun Task.

When Sun Avoidance is active (active_avoidance is True), the following will be enforced:

  • When a user initiates the go_to Task, the target point of the motion will be checked. If it is not Sun-safe, the Task will exit immediately with an error. If the Task cannot find a set of moves that are Sun-safe and that do not violate other requirements (azimuth and elevation limits; the el_dodging policy), then the Task will exit with error. The move may be executed as a series of separate legs (e.g. the Task may move first to an intermediate elevation, then slew in azimuth, then continue to the final elevation) rather than simulataneously commanding az and el motion.

  • When a user starts the generate_scan Process, the sweep of the scan will be checked for Sun-safety, and the Process will exit with error if it is not. Furthermore, any movement required prior to starting the scan will be checked in the same way as for the go_to Task.

  • If the platform, at any time, enters a position that is not Sun-safe, then an Escape will be Initiated. During an Escape, any running go_to or generate_scan operations will be cancelled, and further motions are blocked. The platform will be driven to a position at due North or due South. The current elevation of the platform will be preserved, unless that is not Sun-safe (in which case lower elevations will be attempted). The Escape feature is active, even when motions are not in progress, as long as the monitor_sun Process is running. However – the Escape operation requires that the platform be in Remote operation mode, with no persistent faults.

Exercisor Mode

The agent can run itself through various motion patterns, using the Process exercise. This process is only visible if the agent is invoked with the --exercise-plan argument and a path to the exercise plan config file. Here is an example config file:

satp1:
  settings:
    use_boresight: false
  steps:
  - type: 'elnod'
    repeat: 2
  - type: 'grid'
    duration: 3600
  - type: 'schedule'
    files:
      - /path/to/schedule1.txt
      - /path/to/schedule2.txt
    duration: 3600
    dwell_time: 600
  - type: 'grease'
    duration: 900

Note that the root level may contain multiple entries; the key corresponds to the ACU config block name, which would correspond to the ACU agent --acu-config argument.

The exercisor writes some diagnostic and timing information to a feed called activity.

Agent API

class socs.agents.acu.agent.ACUAgent(agent, acu_config='guess', exercise_plan=None, startup=False, ignore_axes=None, disable_idle_reset=False, min_el=None, max_el=None, avoid_sun=None, fov_radius=None, named_positions=None)[source]

Agent to acquire data from an ACU and control telescope pointing with the ACU.

Parameters:
  • acu_config (str) – The configuration for the ACU, as referenced in aculib.configs. Default value is ‘guess’.

  • exercise_plan (str) – The full path to a scan config file describing motions to cycle through on the ACU. If this is None, the associated process and feed will not be registered.

  • startup (bool) – If True, immediately start the main monitoring processes for status and UDP data.

  • ignore_axes (list of str) – List of axes to “ignore”. “ignore” means that the axis will not be commanded. If a user requests an action that would otherwise move the axis, it is not moved but the action is assumed to have succeeded. The values in this list should be drawn from “az”, “el”, and “third”.

  • disable_idle_reset (bool) – If True, don’t auto-start idle_reset process for LAT.

  • min_el (float) – If not None, override the default configured elevation lower limit.

  • max_el (float) – If not None, override the default configured elevation upper limit.

  • avoid_sun (bool) – If set, override the default Sun avoidance setting (i.e. force enable or disable the feature).

  • fov_radius (float) – If set, override the default Sun avoidance radius (i.e. the radius of the field of view, in degrees, to use for Sun avoidance purposes).

  • named_positions (list of str) – Names and target positions to register for use with go_to_named task. If provided, each entry in the list should be of the form “name=az,el” with az and el parseable as floats; e.g. “home=180,45.1”.

idle_reset()[source]

Process - To prevent LAT from going into Survival mode, do something on the command interface every so often. (The default inactivity timeout is 1 minute.)

monitor()[source]

Process - Refresh the cache of SATP ACU status information and report it on the ‘acu_status’ and ‘acu_status_influx’ HK feeds.

Summary parameters are ACU-provided time code, Azimuth mode, Azimuth position, Azimuth velocity, Elevation mode, Elevation position, Elevation velocity, Boresight mode, and Boresight position.

The session.data of this process is a nested dictionary. Here’s an example:

{
  "StatusDetailed": {
    "Time": 81.661170959322,
    "Year": 2023,
    "Azimuth mode": "Stop",
    "Azimuth commanded position": -20.0012,
    "Azimuth current position": -20.0012,
    "Azimuth current velocity": 0.0002,
    "Azimuth average position error": 0,
    "Azimuth peak position error": 0,
    "Azimuth computer disabled": false,
    ...
  },
  "Status3rdAxis": {
    "3rd axis Mode": "Stop",
    "3rd axis commanded position": 77,
    "3rd axis current position": 77,
    "3rd axis computer disabled": "No Fault",
    ...
  },
  "StatusResponseRate": 19.237531827325963,
  "PlatformType": "satp",
  "IgnoredAxes": [],
  "NamedPositions": {
    "home": [
      180,
      40
    ]
  },
  "DefaultScanParams": {
    "az_speed": 2.0,
    "az_accel": 1.0,
  },
  "connected": True,
}

In the case of an SATP, the Status3rdAxis is not populated (the Boresight info can be found in StatusDetailed). In the case of the LAT, the corotator info is queried separately and stored under Status3rdAxis.

broadcast(auto_enable=True)[source]

Process - Read UDP data from the port specified by self.acu_config, decode it, and publish to HK feeds. Full resolution (200 Hz) data are written to feed “acu_udp_stream” while 1 Hz decimated are written to “acu_broadcast_influx”. The 1 Hz decimated output are also stored in session.data.

Parameters:

auto_enable (bool) – If True, the Process will try to configure and (re-)enable the UDP stream if at any point the stream seems to drop out.

Notes

The session.data looks like this (this is for a SATP running with servo details in the UDP output):

{
  "Time": 1679499948.8234625,
  "Corrected_Azimuth": -20.00112176010607,
  "Corrected_Elevation": 50.011521050839434,
  "Corrected_Boresight": 29.998428712246067,
  "Raw_Azimuth": -20.00112176010607,
  "Raw_Elevation": 50.011521050839434,
  "Raw_Boresight": 29.998428712246067,
  "Azimuth_Current_1": -0.000384521484375,
  "Azimuth_Current_2": -0.0008331298828125,
  "Elevation_Current_1": 0.003397979736328125,
  "Boresight_Current_1": -0.000483856201171875,
  "Boresight_Current_2": -0.000105743408203125,
  "Azimuth_Vel_1": -0.000002288818359375,
  "Azimuth_Vel_2": 0,
  "Az_Vel_Act": -0.0000011444091796875,
  "Az_Vel_Des": 0,
  "Az_Vffw": 0,
  "Az_Pos_Des": -20.00112176010607,
  "Az_Pos_Err": 0
}
go_to(az, el, end_stop=False)[source]

Task - Move the telescope to a particular point (azimuth, elevation) in Preset mode. When motion has ended and the telescope reaches the preset point, it returns to Stop mode and ends.

Parameters:
  • az (float) – destination angle for the azimuth axis

  • el (float) – destination angle for the elevation axis

  • end_stop (bool) – put the telescope in Stop mode at the end of the motion

set_boresight(target, end_stop=False)[source]

Task - Move the telescope to a particular third-axis angle.

Parameters:
  • target (float) – destination angle for boresight rotation

  • end_stop (bool) – put axes in Stop mode after motion

go_to_named(target, end_stop=True)[source]

Task - Move the telescope to a named position, e.g. “home”, that has been configured through command line args.

Parameters:
  • target (str) – name of the target position.

  • end_stop (bool) – put axes in Stop mode after motion

set_speed_mode(speed_mode)[source]

Task - Set the ACU Speed Mode. This affects motion when in Preset mode, such as when using go_to in this Agent. It should not affect the speed of scans done in ProgramTrack mode.

Parameters:

speed_mode (str) – ‘high’ or ‘low’.

Notes

The axes must be in Stop mode for this to work. This task will return an error if the command appears to have failed.

The actual speed and acceleration settings for the “high” and “low” (perhaps called “aux”) settings must be configured on the ACU front panel.

set_scan_params(az_speed=None, az_accel=None, reset=False))[source]

Task - Update the default scan parameters, used by generate_scan if not passed explicitly.

Parameters:
  • az_speed (float, optional) – The azimuth scan speed.

  • az_accel (float, optional) – The (average) azimuth acceleration at turn-around.

  • reset (bool, optional) – If True, reset all params to default values before applying any updates passed explicitly here.

clear_faults()[source]

Task - Clear any axis faults.

stop_and_clear(all_axes=False)[source]

Task - Change the azimuth, elevation, and 3rd axis modes to Stop; also clear the ProgramTrack stack.

Parameters:

all_axes (bool) – Send Stop to all axes, even ones user has requested to be ignored.

fromfile_scan(filename, adjust_times=True, azonly=True)[source]

Task - Upload and execute a scan pattern from numpy file.

Parameters:
  • filename (str) – full path to desired numpy file. File should contain an array of shape (5, nsamp) or (7, nsamp). See Note.

  • adjust_times (bool) – If True (the default), the track timestamps are interpreted as relative times, only, and the track will be formatted so the first point happens a few seconds in the future. If False, the track times will be taken at face value (even if the first one is, like, 0).

  • azonly (bool) – If True, the elevation part of the track will be uploaded but the el axis won’t be put in ProgramTrack mode. It might be put in Stop mode though.

Notes

The columns in the numpy array are:

  • 0: timestamps, in seconds.

  • 1: azimuth, in degrees.

  • 2: elevation, in degrees.

  • 3: az_vel, in deg/s.

  • 4: el_vel, in deg/s.

  • 5: az_flags (2 if last point in a leg; 1 otherwise.)

  • 6: el_flags (2 if last point in a leg; 1 otherwise.)

It is acceptable to omit columns 5 and 6.

generate_scan(az_endpoint1, az_endpoint2, az_speed=None, az_accel=None, el_endpoint1=None, el_endpoint2=None, el_speed=None, num_scans=None, start_time=None, wait_to_start=None, step_time=None, az_start='end', az_drift=None, az_only=True, scan_upload_length=None)[source]

Process - Scan generator, currently only works for constant-velocity az scans with fixed elevation.

Parameters:
  • az_endpoint1 (float) – first endpoint of a linear azimuth scan

  • az_endpoint2 (float) – second endpoint of a linear azimuth scan

  • az_speed (float) – azimuth speed for constant-velocity scan

  • az_accel (float) – turnaround acceleration for a constant-velocity scan

  • el_endpoint1 (float) – first endpoint of elevation motion. In the present implementation, this will be the constant elevation declared at every point in the track.

  • el_endpoint2 (float) – this is ignored.

  • el_speed (float) – this is ignored.

  • num_scans (int or None) – if not None, limits the scan to the specified number of constant velocity legs. The process will exit without error once that has completed.

  • start_time (float or None) – a unix timestamp giving the time at which the scan should begin. The default is None, which means the scan will start immediately (but taking into account the value of wait_to_start).

  • wait_to_start (float) – number of seconds to wait before starting a scan, in the case that start_time is None. The default is to compute a minimum time based on the scan parameters and the ACU ramp-up algorithm; this is typically 5-10 seconds.

  • step_time (float) – time, in seconds, between points on the constant-velocity parts of the motion. The default is None, which will cause an appropriate value to be chosen automatically (typically 0.1 to 1.0).

  • az_start (str) – part of the scan to start at. To start at one of the extremes, use ‘az_endpoint1’, ‘az_endpoint2’, or ‘end’ (same as ‘az_endpoint1’). To start in the midpoint of the scan use ‘mid_inc’ (for first half-leg to have positive az velocity), ‘mid_dec’ (negative az velocity), or ‘mid’ (velocity oriented towards endpoint2).

  • az_drift (float) – if set, this should be a drift velocity in deg/s. The scan extrema will move accordingly. This can be used to better follow compact sources as they rise or set through the focal plane.

  • az_only (bool) – if True (the default), then only the Azimuth axis is put in ProgramTrack mode, and the El axis is put in Stop mode.

  • scan_upload_length (float) – number of seconds for each set of uploaded points. If this is not specified, the track manager will try to use as short a time as is reasonable.

Notes

Note that all parameters are optional except for az_endpoint1 and az_endpoint2. If only those two parameters are passed, the Process will scan between those endpoints, with the elevation axis held in Stop, indefinitely (until Process .stop method is called)..

monitor_sun()[source]

Process - Monitors and reports the position of the Sun; maintains a Sun Safety Map for verifying that moves and scans are Sun-safe; triggers a “Sun escape” if the boresight enters an unsafe position.

The monitoring functions are always active (as long as this process is running). But the escape functionality must be explicitly enabled (through the default platform configuration, command line arguments, or the update_sun task).

Session data looks like this:

{
  "timestamp": 1698848292.5579932,
  "active_avoidance": false,
  "disable_until": 0,
  "block_motion": false,
  "recompute_req": false,
  "next_drill": null,
  "safety_map_kw": {
    "sun_time_shift": 0
  },
  "policy": {
    "exclusion_radius": 20,
    "el_horizon": 10,
    "min_sun_time": 1800,
    "response_time": 7200,
    "min_az": -90,
    "max_az": 450,
    "min_el": 18.5,
    "max_el": 90
  },
  "sun_pos": {
    "map_exists": true,
    "map_is_old": false,
    "map_ref_time": 1698848179.1123455,
    "platform_azel": [
      90.0158,
      20.0022
    ],
    "sun_radec": [
      216.50815789438036,
      -14.461844389380719
    ],
    "sun_azel": [
      78.24269024936028,
      60.919554369324096
    ],
    "sun_dist": 41.75087242151837,
    "sun_safe_time": 71760
  },
  "avoidance": {
    "safety_unknown": false,
    "warning_zone": false,
    "danger_zone": false,
    "escape_triggered": false,
    "escape_active": false,
    "last_escape_time": 0,
    "sun_is_real": true,
    "platform_is_moveable": true
  }
}

In debugging, the Sun position might be falsified. In that case the “sun_pos” subtree will contain an entry like this:

"WARNING": "Fake Sun Position is in use!",

and “avoidance”: “sun_is_real” will be set to false. (No other functionality is changed when using a falsified Sun position; flags are computed and actions decided based on the false position.)

update_sun(session, params)[source]
update_sun(reset=None, enable=None, temporary_disable=None,

escape=None, avoidance_radius=None, shift_sun_hours=None)

Task - Update Sun monitoring and avoidance parameters.

All arguments are optional.

Parameters:
  • reset (bool) – If True, reset all sun_params to the platform defaults. (The “defaults” includes any overrides specified on Agent command line.)

  • enable (bool) – If True, enable active Sun avoidance. If avoidance was temporarily disabled it is re-enabled. If False, disable active Sun avoidance (non-temporarily).

  • temporary_disable (float) – If set, disable Sun avoidance for this number of seconds.

  • escape (bool) – If True, schedule an escape drill for 10 seconds from now.

  • avoidance_radius (float) – If set, change the FOV radius (degrees), for Sun avoidance purposes, to this number.

  • shift_sun_hours (float) – If set, compute the Sun position as though it were this many hours in the future. This is for debugging, testing, and work-arounds. Pass zero to cancel.

escape_sun_now()[source]

Task - Take control of the platform, and move it to a Sun-Safe position. This will abort/stop any current go_to or generate_scan, identify the safest possible path to North or South (without changing elevation, if possible), and perform the moves to get there.

exercise(starting_index=0)[source]

Process - Run telescope platform through some pre-defined motions.

For historical reasons, this does not command agent functions internally, but rather instantiates a client and calls the agent as though it were an external entity.

Example Clients

Below is an example client demonstrating a go-to task followed by a scan. Note that all tasks and the generate_scan process can be run while the data acquisition processes are running:

from ocs.matched_client import MatchedClient

def upload_track(scantype, testing, azpts, el, azvel, acc, ntimes):
    acu_client = MatchedClient('acu1')
    acu_client.go_to.start(az=azpts[0], el=el, wait=1)
    acu_client.go_to.wait()
    acu_client.run_specified_scan.start(scantype=scantype, testing=testing, azpts=azpts, el=el, azvel=azvel, acc=acc, ntimes=ntimes)
    acu_client.run_specified_scan.wait()

if __name__ == '__main__':
    upload_track('linear_turnaround_sameends', True, (120., 160.), 35., 1., 4, 3)

Supporting APIs

drivers (Scanning support)

socs.agents.acu.drivers.DAY = 86400

The number of seconds in a day.

socs.agents.acu.drivers.constant_velocity_scanpoints(azpts, el, azvel, acc, ntimes)[source]

Produces lists of times, azimuths, elevations, azimuthal velocities, elevation velocities, azimuth motion flags, and elevation motion flags for a finitely long azimuth scan with constant velocity. Scan begins at the first azpts value.

Parameters:
  • azpts (2-tuple) – The endpoints of motion in azimuth, where the first point is the start position of the scan.

  • el (float) – The elevation that is maintained throughout the scan

  • azvel (float) – Desired speed of the azimuth motion in degrees/sec

  • acc (float) – The turnaround acceleration in degrees/sec^2

  • ntimes (int) – Number of times to travel between the endpoints. ntimes = 1 corresponds to a scan from, ex., left to right, and does not return to left.

Returns:

(times, azimuths, elevations, azimuth veolicities, elevation velocities, azimuth flags, elevation flags)

Return type:

tuple of lists

socs.agents.acu.drivers.from_file(filename)[source]

Produces properly formatted lists of times, azimuth and elevation locations, azimuth and elevation velocities, and azimuth and elevation motion flags for a finitely long scan from a numpy file. Numpy file must be formatted as an array of arrays in the order [times, azimuths, elevations, azimuth velocities, elevation velocities]

Parameters:

filename (str) – Full path to the numpy file containing scan parameter array

Returns:

(times, azimuths, elevations, azimuth velocities, elevation velocities, azimuth flags, elevation flags)

Return type:

tuple of lists

NOTE: Flags can be set in the numpy file (0=unspecified, 1=constant velocity, 2=last point before turnaround). If flags are not set in the file, all flags are set to 0 to accommodate non-linear scans

socs.agents.acu.drivers.ptstack_format(conctimes, concaz, concel, concva, concve, az_flags, el_flags, group_flag=None, start_offset=0, absolute=False)[source]

Produces a list of lines in the format necessary to upload to the ACU to complete a scan. Params are the outputs of from_file, constant_velocity_scanpoints, or generate_constant_velocity_scan.

Parameters:
  • conctimes (list) – Times starting at 0 for the ACU to reach associated positions

  • concaz (list) – Azimuth positions associated with conctimes

  • concel (list) – Elevation positions associated with conctimes

  • concva (list) – Azimuth velocities associated with conctimes

  • concve (list) – Elevation velocities associated with conctimes

  • az_flags (list) – Flags associated with azimuth motions at conctimes

  • el_flags (list) – Flags associated with elevation motions at conctimes

  • group_flag (list) – If not None, must be a list drawn from [0, 1] where 1 indicates that the point should not be uploaded unless the subsequent point is also immediately uploaded.

  • start_offset (float) – Offset, in seconds, to apply to all timestamps.

  • absolute (bool) – If true, timestamps are taken at face value, and only start_offset is added. If false, then the current time is also added (but note that if the first timestamp is 0, then you will need to also pass start_offset > 0).

Returns:

Lines in the correct format to upload to the ACU. If group_flag was included, then each upload line is returned as a tuple (group_flag, line_text).

Return type:

list

socs.agents.acu.drivers.timecode(acutime, now=None)[source]

Takes the time code produced by the ACU status stream and returns a unix timestamp.

Parameters:
  • acutime (float) – The time recorded by the ACU status stream, corresponding to the fractional day of the year.

  • now (float) – The time, as unix timestamp, to assume it is now. This is for testing, it defaults to time.time().

socs.agents.acu.drivers.generate_constant_velocity_scan(az_endpoint1, az_endpoint2, az_speed, acc, el_endpoint1, el_endpoint2, el_speed=0, num_batches=None, num_scans=None, start_time=None, wait_to_start=10.0, step_time=1.0, batch_size=500, az_start='mid_inc', az_first_pos=None, az_drift=None, ptstack_fmt=True)[source]

Python generator to produce times, azimuth and elevation positions, azimuth and elevation velocities, azimuth and elevation flags for arbitrarily long constant-velocity azimuth scans.

Parameters:
  • az_endpoint1 (float) – azimuth endpoint for the scan start

  • az_endpoint2 (float) – second azimuth endpoint of the scan

  • az_speed (float) – speed of the constant-velocity azimuth motion

  • acc (float) – turnaround acceleration for the azimuth motion at the endpoints

  • el_endpoint1 (float) – elevation endpoint for the scan start

  • el_endpoint2 (float) – second elevation endpoint of the scan. For constant az scans, this must be equal to el_endpoint1.

  • el_speed (float) – speed of the elevation motion. For constant az scans, set to 0.0

  • num_batches (int or None) – sets the number of batches for the generator to create. Default value is None (interpreted as infinite batches).

  • num_scans (int or None) – if not None, limits the points returned to the specified number of constant velocity legs.

  • start_time (float or None) – a ctime at which to start the scan. Default is None, which is interpreted as starting now + wait_to_start.

  • wait_to_start (float) – number of seconds to wait between start_time and when the scan actually starts. Default is 10 seconds.

  • step_time (float) – time between points on the constant-velocity parts of the motion. Default value is 1.0 seconds. Minimum value is 0.05 seconds.

  • batch_size (int) – number of values to produce in each iteration. Default is 500. Batch size is reset to the length of one leg of the motion if num_batches is not None.

  • az_start (str) – part of the scan to start at. To start at one of the extremes, use ‘az_endpoint1’, ‘az_endpoint2’, or ‘end’ (same as ‘az_endpoint1’). To start in the midpoint of the scan use ‘mid_inc’ (for first half-leg to have positive az velocity), ‘mid_dec’ (negative az velocity), or ‘mid’ (velocity oriented towards endpoint2).

  • az_first_pos (float) – If not None, the first az scan will start at this position (but otherwise proceed in the same starting direction).

  • az_drift (float) – The rate (deg / s) at which to shift the scan endpoints in time. This can be used to better track celestial sources in targeted scans.

  • ptstack_fmt (bool) – determine whether values are produced with the necessary format to upload to the ACU. If False, this function will produce lists of time, azimuth, elevation, azimuth velocity, elevation velocity, azimuth flags, and elevation flags. Default is True.

socs.agents.acu.drivers.plan_scan(az_end1, az_end2, el, v_az=1, a_az=1, az_start=None)[source]

Determine some important parameters for running a ProgramTrack scan with the desired end points, velocity, and mean turn-around acceleration.

These get complicated in the limit of high velocity and narrow scan.

Returns:

A dict with outputs of the calculations. The following items must be considered when generating and posting the track points:

  • ’step_time’: The recommended track point separation, in seconds.

  • ’wait_to_start’: The minimum time (s) between initiating ProgramTrack mode and the first uploaded point’s timestamp.

  • ’init_az’: The az (deg) at which to position the telescope before beginning the scan. This takes into account any “ramp up” that needs to occur and the fact that such ramp up needs to be finished before the ACU starts profiling the first turn-around.

The following dict items provide additional detail / intermediate results:

  • ’scan_start_buffer’: Minimum amount (deg of az) by which to shift the start of the first scan leg in order to satisfy the requirements for az_prep and az_rampup. This ultimately is what can make init_az different from the natural first leg starting point. This parameter is always non-negative.

  • ’turnprep_buffer’: Minimum azimuth travel required for ProgramTrack to prepare a turn-around.

  • ’rampup_buffer’: Minimum azimuth travel required for ProgramTrack to ramp up to the first leg velocity. Degrees, positive.

  • ’rampup_time’: Number of seconds before the first track point where the platform could start moving (as part of smooth acceleration into the initial velocity).

avoidance (Sun Avoidance)

When considering Sun Safety of a boresight pointing, we consider an exclusion zone around the Sun with a user-specified radius. This is called the exclusion_radius or the field-of-view radius.

The Safety of the instrument at any given moment is parametrized by two numbers:

sun_dist

The separation between the Sun and the boresight (az, el), in degrees.

sun_time

The minimum time, in seconds, which must elapse before the current (az, el) pointing of the boresight will lie within the exclusion radius of the Sun.

While the sun_dist is an important indicator of whether the instrument is currently in immediate danger, the sun_time is helpful with looking forward and avoiding positions that will soon be dangerous.

The user-defined policy for Sun Safety is captured in the following settings:

exclusion_radius

The radius, in degres, of a disk centered on the Sun that must be avoided by the boresight.

min_sun_time

An (az, el) position is considered unsafe (danger zone) if the sun_time is less than the min_sun_time. (Expressed in seconds.)

response_time

An (az, el) position is considered vulnerable (warning zone) if the sun_time is less than the response_time. This is intended to represent the maximum amount of time it could take an operator to reach the instrument and secure it, were motion to stall unexpectedly. (Expressed in seconds.)

el_horizon

The elevation (in degrees) below which the Sun may be considered as invisible to the instrument.

el_dodging

This setting affects how point-to-point motions are executed, with respect to what elevations may be used in intermediate legs of the trajectory. When this is False, the platform is restricted to travel only at elevations that lie between the initial and the target elevation. When True, the platform is permitted to travel at other elevations, all the way up to the limits of the platform. Using True is helpful to find Sun-safe trajectories in some circumstances. But False is helpful if excess elevation changes are potentially disturbing to the cryogenics. This setting only affects point-to-point motions; “escape” paths will always consider all available elevations.

A “Sun-safe” position is a pointing of the boresight that currently has a sun_time that meets or exceeds the min_sun_time parameter.

socs.agents.acu.avoidance.DEFAULT_POLICY = {'el_dodging': False, 'el_horizon': 0, 'exclusion_radius': 20, 'max_az': 405, 'max_el': 90, 'min_az': -45, 'min_el': 0, 'min_sun_time': 3600, 'response_time': 14400}

Default policy to apply when evaluating Sun-safety and planning trajectories. Note the Agent code may apply different defaults, based on known platform details.

class socs.agents.acu.avoidance.SunTracker(policy=None, site=None, map_res=0.5, sun_time_shift=None, fake_now=None, compute=True, base_time=None)[source]

Provide guidance on what horizion coordinate positions and trajectories are sun-safe.

Parameters:
  • policy (dict) – Exclusion policy parameters. See module docstring, and DEFAULT_POLICY. The policy should also include {min,max}_{el,az}, giving the limits supported by those axes.

  • site (EarthlySite or None) – Site to use; default is the SO LAT. If not None, pass an so3g.proj.EarthlySite or compatible.

  • map_res (float, deg) – resolution to use for the Sun Safety Map.

  • sun_time_shift (float, seconds) – For debugging and testing, compute the Sun’s position as though it were this manys seconds in the future. If None or zero, this feature is disabled.

  • fake_now (float, seconds) – For debugging and testing, replace the tracker’s computation of the current time (time.time()) with this value. If None, this testing feature is disabled.

  • compute (bool) – If True, immediately compute the Sun Safety Map by calling .reset().

  • base_time (unix timestamp) – Store this base_time and, if compute is True, pass it to .reset().

reset(base_time=None)[source]

Compute and store the Sun Safety Map for a specific timestamp.

This basic computation is required prior to calling other functions that use the Sun Safety Map.

check_trajectory(az, el, t=None, raw=False)[source]

For a telescope trajectory (vectors az, el, in deg), assumed to occur at time t (defaults to now), get the minimum value of the Sun Safety Map traversed by that trajectory. Also get the minimum value of the Sun Distance map.

This requires the Sun Safety Map to have been computed with a base_time in the 24 hours before t.

Returns a dict with entries:

  • 'sun_time': Minimum Sun Safety Time on the traj.

  • 'sun_time_start': Sun Safety Time at first point.

  • 'sun_time_stop': Sun Safety Time at last point.

  • 'sun_dist_min': Minimum distance to Sun, in degrees.

  • 'sun_dist_mean': Mean distance to Sun.

  • 'sun_dist_start': Distance to Sun, at first point.

  • 'sun_dist_stop': Distance to Sun, at last point.

get_sun_pos(az=None, el=None, t=None)[source]

Get info on the Sun’s location at time t. If (az, el) are also specified, returns the angular separation between that pointing and Sun’s center.

show_map(axes=None, show=True)[source]

Plot the Sun Safety Map and Sun Distance Map on the provided axes (a list).

analyze_paths(az0, el0, az1, el1, t=None, plot_file=None, dodging=True)[source]

Design and analyze a number of different paths between (az0, el0) and (az1, el1). Return the list, for further processing and choice.

find_escape_paths(az0, el0, t=None, debug=False)[source]

Design and analyze a number of different paths that move from (az0, el0) to a sun safe position. Return the list, for further processing and choice.

select_move(moves, raw=False)[source]

Given a list of possible “moves”, select the best one. The “moves” should be like the ones returned by analyze_paths.

The best move is determined by first screening out dangerous paths (ones that pass close to Sun, move closer to Sun unnecessarily, violate axis limits, etc.) and then identifying paths that minimize danger (distance to Sun; Sun time) and path length.

If raw=True, a debugging output is returned; see code.

Returns:

(best_move, decisions)

best_move – the element of moves that is safest. If no safe move was found, None is returned.

decisions - List of dicts, in one-to-one correspondence with moves. Each decision dict has entries ‘rejected’ (True or False) and ‘reason’ (string description of why the move was rejected outright).

Return type:

(dict, list)