NAV
python

Satellite Bus API

The Satellite Bus API allows Space Services Customers to access spacecraft position and attitude data in near real-time and to issue dynamic pointing commands. The API is exposed through the Spire Linux Agent.

Example Usage

Instantiation

import time
from oort_sdk_client.api.sdk_api import SdkApi
from oort_sdk_client.models import (
  AdcsCommandRequest, AdcsTarget, AdcsCommandResponse, AdcsHk,
  AdcsResponse, TfrsResponse
)

agent = SdkApi()

The SDK must be initialized before using it. All ADCS API operations performed through methods on the SdkApi object.

The following examples assume this code is present.

TFRS

TFRS (Time-Frequency Reference System) provides a highly accurate clock and position reading.

Age check

start = time.time()

tfrs_data = agent.get_tfrs()
# if the tfrs data isn't current, there may be some issue with
# the data feeds
if tfrs_data.age > 5:
    print("TFRS data is too old, aborting.")
    exit(1)

time_diff = tfrs_data.utc_time - start
print("TFRS time is {}, local time is {} difference {}"
     .format(tfrs_data.utc_time, start, time_diff))
print("TFRS ECEF position is "
      "{t.ecef_pos_x}, {t.ecef_pos_y}, {t.ecef_pos_z}"
     .format(t=tfrs_data))

TFRS data is typically updated once per second. The age field indicates how long it has been since the Agent has received an update from the TFRS. It is not uncommon or a serious error for an update to occasionally be lost, but multiple updates getting lost may indicate a larger issue.

If the TFRS data is more than a few seconds old, discretion is advised before relying on it.

The code here checks the TFRS timestamp against the system clock and displays the difference, as well as displaying the position reported.

ADCS

ADCS (Attitude Determination And Control System) is a satellite subsystem that provides accurate attitude information about the spacecraft as well as a mechanism to re-orient the spacecraft.

The ADCS API provided by Spire Space Services allows customer payloads to access current attitude information and, if applicable, the ability to maneuver the spacecraft. In order for ADCS commands to take effect, a LEASE_ADCS must have been scheduled. Without this, the payload commands will never be acted on.

Reading current ADCS data

adcs_data = agent.get_adcs()

target_area = {"lat": (-40, -30), "lon": (140,170)}

# if the current location is not over the target area, quit
print("Latitude: {:.2f}  Longitude {:.2f}"
      .format(adcs_data.hk.lat_deg, adcs_data.hk.lon_deg))
if not ((target_area['lat'][0] <= adcs_data.hk.lat_deg <= target_area['lat'][1]) and 
        (target_area['lon'][0] <= adcs_data.hk.lon_deg <= target_area['lon'][1])):
    print("Satellite is outside the requested area.  Exiting.")
    exit(1)

Using the get_adcs interface, the spacecraft surface position (i.e., the position directly beneath the satellite) can be obtained. This can be used for annotating data collections, or to check if the spacecraft is within specified geographic boundaries.

In this example, if the current position is not between 140 and 170 degrees east longitude and between 30 and 40 degrees south latitude, the job will exit.

Commanding a spacecraft maneuver

command = AdcsCommandRequest(command="NADIR", aperture="GOPRO")

command_result = agent.command_adcs(command)

if command_result.status != "OK":
    print("ADCS command failed: {}".format(command_result.reason))
    exit(1)
else:
    feedback_mode = result.mode
    print("ADCS switching to mode {}".format(feedback_mode))
    mode_set = False  # see below

A maneuver can be requested using the command_adcs method.
A maneuver is always performed relative to a named aperture, which is an antenna, imager, or other instrument that needs to be pointed in the specified direction.

The result should always be checked to ensure that there were no errors in the request itself, and that the command was acknowledged and acted on by the control systems.

In addition, when the command is successful, the result will indicate the physical command mode that the control system will use. This command mode can be used for validating that the requested operation is the current in progress operation. (see below)

In this example, the satellite is commanded to NADIR orientation relative to the GOPRO aperture. Stated differently, "point the camera straight down."

Refer to your ICD for valid aperture names.

Maneuver tracking

while True:
    adcs_data = agent.get_adcs()

    print("Pointing error: {:.2f} degrees".format(
          adcs_data.hk.control_error_angle_deg))
    if adcs_data.hk.control_error_angle_deg < 0.5:
        print("Desired pointing accuracy achieved")
        break
    # wait for time to pass
    time.sleep(1)

When a maneuver is commanded, the spacecraft orientation cannot change instantly. The spacecraft's moment of inertia as well as its previous orientation limits how quickly a requested orientation can be attained. It is expected that it can take as much as 3 minutes for a orientation change to complete.

It is recommended that after a command is issued, adcs is periodically polled to wait for the requested orientation to be achieved;
control_error_angle_deg, which is the difference between the current measured orientation and the requested orientation, is ideal to check.

The maneuver can be disrupted in certain cases; see below for errors to check for.

Performing an observation after a maneuver

# NOTE: The `Imager` interface is used here for illustration
# only.  Refer to your ICD for the available interfaces.
from spire.imager import Imager, ACTION, BURST_3
imager = Imager()
image = imager.capture(mode=ACTION, best_shot_selector=BURST_3)
adcs_data = agent.get_adcs()
image.annotate(pos=adcs_data.r_ecef, orientation=adcs_data.qcf)

Once the desired orientation has been attained, payload observations can be performed. Measurements from ADCS may be used to annotate the observations, so that they can be accurately matched up to earth positions in post-processing.

NOTE: The Imager interface is used here for illustration only. Refer to your ICD for the available interfaces.

Clean up and deliver

agent.command_adcs(AdcsCommandRequest("IDLE"))

from oort_sdk_client.models import SendFileRequest, TTLParams, SendOptions
filerequest = SendFileRequest(
    destination="ground", filepath=image.get_file(), topic="gopro",
    options=SendOptions(TTLParams(urgent=1800, bulk=86400*14)))
send_response = agent.send_file(filerequest)
print("File sent with UUID {}".format(send_response.uuid))

exit(0)

After observations have been completed, ADCS can be commanded back to IDLE mode. This is not required and will be done automatically at the end of a payload window, but is suggested as an optimization of spacecraft activity.

Any created files to be sent to the ground can be transferred using the data pipeline API, which uses the same SdkApi interface as an entry point.

Error Situations

A maneuver can be interrupted for various reasons. It is recommended to check for these situations to be able to take appropriate recovery actions and/or log the situations for later analysis.

These error checks should be included in the Maneuver tracking loop above.

Satellite moves out of position

    adcs_data = agent.get_adcs()
    if not ((target_area['lat'][0] <= adcs_data.hk.lat_deg <= target_area['lat'][1]) and 
            (target_area['lon'][0] <= adcs_data.hk.lon_deg <= target_area['lon'][1])):
        print("Satellite has left the area.  Exiting.")
        agent.command_adcs(AdcsCommandRequest("IDLE"))
        exit(1)

The satellite is moving around the earth at close to 8km/s. The satellite may leave the target area before attaining the desired orientation. This case can be monitored by checking that the lat_deg and lon_deg values remain within their intended bounds.

This example checks the same condition tested at the beginning of the operation.

Maneuver taking too long

    current_tfrs_data = agent.get_tfrs()
    if current_tfrs_data.utc_time - tfrs_data.utc_time > 180:
        print("Command taking too long.  Exiting.")
        agent.command_adcs(AdcsCommandRequest("IDLE"))
        exit(1)

The satellite does take time to physically change orientation. It is recommended to wait up to 3 minutes while polling. If the desired state is not reached within this time frame, we recommend aborting the operation and logging appropriate information to identify the problem.

Note the reuse of tfrs_data obtained above.

Control override

    if mode_set:
        if adcs_data.hk.acs_mode_active != feedback_mode:
            print("ADCS command has been preempted ({}).  Exiting."
                  .format(adcs_data.hk.acs_mode_active))
            agent.command_adcs(AdcsCommandRequest("IDLE"))
            exit(1)
    else:
        if adcs_data.hk.acs_mode_active != feedback_mode:
            print("ADCS mode request has not been updated, waiting")
            time.sleep(1)
            continue
        else:
            mode_set = True

The satellite control systems may determine that another maneuver has a higher priority, for example to address a spacecraft fault. This can usually be detected by the active mode being changed while waiting for a maneuver to complete.

Is is important to note that due to the data feed mechanism the command mode reported in the get_adcs result will lag behind a successful command by a few seconds, and the command mode being different immediately afterward is expected. It is only an override situation if the command mode switches away from the physical mode indicated in the command result after it has already switched into that physical mode.

Reference - Methods

Instantiation

The client needs to be instantiated before it is used.

from oort_sdk_client.api.sdk_api import SdkApi

agent = SdkApi()

SdkAPI

Create a new Spire Linux Agent Client.

TfrsGet

from oort_sdk_client.models import TfrsResponse

resp = agent.get_tfrs()

print("TFRS time reading is {}".format(resp.utc_time))

Gets the most recent time and position reading from TFRS.

Return value

Type Description
TfrsResponse Contains the TFRS reading

AdcsGet

from oort_sdk_client.models import AdcsResponse

resp = agent.get_adcs()

print("ADCS lat, lon is {}, {}".format(resp.hk.lat_deg, resp.hk.lon_deg))

Gets the most recent spacecraft attitude reading from ADCS.

Return value

Type Description
AdcsResponse AdcsResponse Object

AdcsCommand

from oort_sdk_client.models import AdcsCommandRequest

request = AdcsCommandRequest(
    command="NADIR", aperture="IPI")

response = agent.command_adcs(request)
print("Response status: {}".format(response.status))
if response.status != "OK":
    print("Reason: {}".format(response.reason))
else:
    print("Command mode: {}".format(response.mode))

Send a command to ADCS

Arguments

Type Description
AdcsCommandRequest AdcsCommandRequest Object

Return value

Type Description
AdcsCommandResponse Result of the command

Reference - Data Structures

TfrsResponse

TFRS reading

Members

Name Type Description
age int Time in seconds since the last reading
utc_time int Unix epoch timestamp
ecef_pos_x int ECEF X Position
ecef_pos_y int ECEF Y Position
ecef_pos_z int ECEF Z Position
ecef_vel_x int ECEF X Velocity
ecef_vel_y int ECEF Y Velocity
ecef_vel_z int ECEF Z Velocity

AdcsResponse

ADCS Reading

Members

Name Type Description
mode string Current ACS mode
age int Time in seconds since the last reading
hk AdcsHk Detailed attitude information

AdcsCommandRequest

An ADCS command to request a particular attitude.

Members

Name Type Description
command string The command to send. Required.
aperture string The aperture to base the command on. Required for TRACK and NADIR commands.
target AdcsTarget The target to use for the command. Required for TRACK command.

AdcsCommandResponse

The response received from a ADCS command.

Members

Name Type Description
status string Status of the request (OK or FAIL)
reason string Reason why a request failed.
mode string Updated current AcsMode

AdcsTarget

A target.

Members

Name Type Description
lat number Latitude in degrees
lon number Longitude in degrees

AdcsCommandMode

A command mode to be sent to ADCS.

Type Notes
string Supported commands are IDLE, NADIR, and TRACK
command description
IDLE Do nothing; return to the initial configuration specified on the window
NADIR point straight down
TRACK point at a specified point on the earth's surface

AcsMode

A command mode received from ADCS via feedback.

Type Notes
string The expected values include NADIRPOINTYAW, LATLONTRACK, and NOOP. Other values are possible, but anything other than these indicate an ADCS control mode not relevant to payload operations.

Aperture

Aperture (imager, antenna, etc) name to use in ADCS pointing requests

Type Notes
string Max length = 24 characters

Refer to your ICD for valid names.

AdcsHk

Detailed ADCS reading.

Members

Name Type Description
control_error_angle_deg number Absolute control error angle
acs_mode_active string Active ACS mode
euler_angles Adcs_euler_t Current attitude in the LVLH (orbit) frame in degrees for Roll, Pitch, Yaw
control_error_q Adcs_quat_t Feedback on quaternion error
lat_deg number Subsatellite latitude, in degrees
lon_deg number Subsatellite longitude, in degrees
q_bo_est Adcs_quat_t Estimated spacecraft attitude quaternion in the orbit (lvlh) frame
latlontrack_lat number Latitude used for ground target tracking
latlontrack_lon number Longitude used for ground target tracking
lease_active number Flag if a lease is currently active
eclipse_flag number Sunlit/eclipse status of spacecraft
q_bi_est Adcs_quat_t Estimated spacecraft attitude quaternion in the inertial coordinate frame
r_eci Adcs_xyz_float_t Estimated spacecraft position in ECI frame
altitude number Estimated altitude of satellite in meters
latlontrack_body_vector Adcs_xyz_float_t Body vector used to point at ground targets
omega_bo_est Adcs_xyz_float_t Body rate estimate in orbit frame
acs_mode_cmd string Commanded ACS mode
v_eci Adcs_xyz_float_t Estimated spacecraft velocity in ECI frame
qcf Adcs_quat_t Control frame quaternion
lease_time_remaining integer Time remaining in current ADCS lease
unix_timestamp number Unix epoch time
omega_bi_est Adcs_xyz_float_t Body rate estimate in inertial frame
control_error_omega Adcs_xyz_float_t Feedback on rate error
r_ecef Adcs_xyz_float_t Estimated spacecraft position in ECEF frame

Adcs_xyz_float_t

A 3-element (x, y, z) vector

Members

Name Type
x number
y number
z number

Adcs_quat_t

ADCS quaternion

Members

Name Type
q1 number
q2 number
q3 number
q4 number

Adcs_euler_t

ADCS Euler angles -- roll, pitch, yaw

Members

Name Type
roll number
pitch number
yaw number