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 |