Stellar ControlMission control · by Stellar Systems v0.1.0

Operations

Modes and Parameters

Parameters of the components, modes of operation, the value of each parameter per target and mode, the current mode of a target, and configure in procedures.

A component exposes parameters: on-board settings such as the rate of a transmitter or the anode voltage of a TCU. The topology declares the modes of operation (Nominal, Survival…) and gives each target the value of its parameters in each mode. Every target has a current mode; the procedure statement configure applies a mode on board, and the ground chain (driver, transport, gateway) receives the parameters of the current mode, so that a ground modem can follow the rate of the spacecraft.

The pieces live in four places:

WhereWhat
Catalogueparameters of a component: type, unit, range, and how each is set (set) and read back (readback, tolerance)
Topologymodes, and per target parameters (value per mode) and overrides (by environment)
Proceduresconfigure <role> for <mode>, and param <path> [in <Mode>] in expressions
OperationsThe current mode of each target in the stellar_modes bucket; stellar mode, stellar parameters and the API
flowchart LR
    cat["Catalogue<br/>parameters: set, readback"] --> conf
    topo["Topology<br/>modes, values per target"] --> conf
    conf["configure sat for Survival<br/>(send setters, expect readbacks)"] --> kv[("stellar_modes<br/>current mode")]
    op["Operator<br/>stellar mode / PUT"] --> kv
    kv --> rec["Reconciler<br/>bindings: mode + parameters"]
    rec --> chain["Driver, transport, gateway<br/>LinkContext.mode, .parameters"]
    kv --> exe["Executor<br/>param in the current mode"]

Parameters in the catalogue#

A component declares its parameters under parameters, like the arguments of a telecommand. From the example catalogue (packages/platform-v3/catalogue.yaml):

YAML
components:
  tcu:
    instances: tcu_id
    measures:
      mode: {type: tcu_operating_mode}
      anode_voltage:
        raw: u16
        type: f32
        unit: V
        calibration: {polynomial: [0.0, 0.005]}
        limits: {soft: [5 V, 280 V], hard: [0 V, 300 V]}
      # … other measures
    telecommands:
      # … ping, standby, safe_mode
      set_mode:
        args:
          mode: {type: tcu_operating_mode}
        verify: [echo, {mode: args.mode, within: 10s}]
      set_anode_voltage:
        args:
          voltage: {type: f32, unit: V, range: [0 V, 300 V]}
          ramp: {type: f32, unit: V/s, range: [1 V/s, 50 V/s], default: 10 V/s}
        verify: [echo]
    parameters:
      operating_mode:
        description: Operating mode of the TCU.
        type: tcu_operating_mode
        set: {telecommand: set_mode, arg: mode}
        readback: mode
      anode_voltage:
        description: Anode voltage, read back within the noise of the measure.
        type: f32
        unit: V
        range: [0 V, 300 V]
        tolerance: 2 V
        set: {telecommand: set_anode_voltage, arg: voltage}
        readback: anode_voltage
      anode_ramp:
        description: Rate at which the anode voltage is reached.
        type: f32
        unit: V/s
        range: [1 V/s, 50 V/s]
        set: {telecommand: set_anode_voltage, arg: ramp}
  • set names the telecommand of the component that sets the parameter and the argument that carries its value. Several parameters may share one setter, each through its own argument (anode_voltage and anode_ramp both go through set_anode_voltage).
  • readback names the measure (or derived measure) of the component that reads it back; tolerance bounds the gap accepted on a numeric readback.
  • A multi-instance component has one parameter per instance: tcu[TCU1].anode_voltage.

The full reference of the keys and their checks is in Telecommands and Verification.

Modes and values in the topology#

topology.yaml declares the modes, in their order, and exactly one default: the mode of a target whose mode was never set.

YAML
modes:
  Nominal: {description: TCUs powered and ready to fire, default: true}
  Survival: {description: TCUs safe and anodes off}

Each target gives the value of its parameters: one value for every mode, or a table by mode, possibly partial. A key names the parameter as procedures do (tcu[TCU1].anode_voltage; the component is left out on a platform of one component). On a multi-instance component, a key without instance (tcu.anode_voltage) holds for every instance; the key of an instance (tcu[TCU2].anode_voltage) wins for that instance.

YAML
targets:
  sim-1:
    platform: platform-v3@1.4.0
    environments: [SIM, AIT]
    parameters:
      tcu.operating_mode: {Nominal: STANDBY, Survival: SAFE_MODE}
      tcu.anode_voltage: {Nominal: 200 V, Survival: 0 V}
      tcu[TCU2].anode_voltage: {Nominal: 180 V}
      tcu.anode_ramp: 50 V/s
  flatsat-1:
    platform: platform-v3@1.4.0
    environments: [AIT, IVV]
    parameters:
      tcu.operating_mode: {Nominal: STANDBY, Survival: SAFE_MODE}
      tcu.anode_voltage: {Nominal: 200 V, Survival: 0 V}
      tcu.anode_ramp: 20 V/s
    # IVV qualifies the flatsat at a lower voltage.
    overrides:
      IVV:
        parameters:
          tcu.anode_voltage: {Nominal: 150 V}

On sim-1, tcu[TCU2].anode_voltage is 180 V in Nominal and, since its own table has no Survival, 0 V in Survival from the key without instance. On flatsat-1, tcu.anode_voltage in Nominal is 150 V in IVV and 200 V in AIT. The topology rules are on Targets.

Which value applies#

The value of a parameter of a target, in a mode and an environment, is looked up in this order:

  1. the key as written (with its instance): the override of the environment, then the value of the target;
  2. for a parameter of an instance without a value of its own: the key without instance, again override first, then the value of the target.

So an override of tcu.anode_voltage does not change an instance that has its own value in the same mode, such as tcu[TCU2].anode_voltage on sim-1: override the key of the instance for that.

The current mode#

The current mode of each target lives in the KV bucket stellar_modes, under the name of the target: the mode, when it was set, who set it, and the run that set it. A target whose mode was never set (or whose stored mode is no longer declared by the topology) is in the default mode.

It changes in two ways:

  • A run, at the end of a successful configure: the event mode_changed is logged, and the record names the run.
  • An operator, who declares the mode after something that happened outside the MCS, such as an autonomous switch of the spacecraft to survival. Declaring a mode sends nothing to the target.
Shell
stellar mode sim-1               # sim-1: Nominal (default)
                                 # modes: Nominal, Survival
stellar mode sim-1 Survival      # declare the mode, as the operator of --as

The web console shows it in the tab Parameters of a target, where an operator can declare another mode (see Web Console). The API offers the same (tag modes):

RequestResult
GET /v1/targets/{target}/modeModeView: mode, default, modes, since, by, run
PUT /v1/targets/{target}/mode with {"mode": "Survival"}Sets the mode, answers the new ModeView

PUT needs the identity of the operator (X-Stellar-User or a token, else 400 api::anonymous), refuses a mode the topology does not declare (422 mode::unknown) and a target held by a run (409 mode::target-held: its runs set its mode). An unknown target answers 404 api::unknown-target.

Parameters of a target#

stellar parameters <target> lists the parameters of a target: their value in the current mode, their value in each mode, and their readback with its last sample.

text
$ stellar parameters sim-1
sim-1: mode Nominal, environment SIM
tcu[TCU1].operating_mode  "STANDBY"  [Nominal="STANDBY", Survival="SAFE_MODE"]  read "STANDBY" ok
tcu[TCU1].anode_voltage  200.0 V  [Nominal=200.0, Survival=0.0]  read 199.4 ok
tcu[TCU1].anode_ramp  50.0 V/s  [Nominal=50.0, Survival=50.0]
…

The tab Parameters of a target in the web console shows the same table, read again every 5 s, the readbacks marked ✓ or ✗. --environment picks the environment of the overrides; by default, a target engaged in a single environment is read in it, and a target engaged in several without overrides. The API is GET /v1/targets/{target}/parameters?environment=…, answering a ParametersView: for each parameter its name, unit, value in the current mode, values by mode, set (the setter telecommand) and readback (measure, current sample, and matches: whether the sample has the value of the mode within the tolerance; null without a sample or a value). Codes: 404 api::unknown-target, 422 api::unknown-environment (the target is not engaged in it), 503 api::no-catalogue.

Applying a mode: configure#

In a step, configure <role> for <mode> applies a mode to the target of the role. From packages/platform-v3-steps/operations.proc:

text
procedure "Enter survival"
  uses sat: platform-v3

  step "Configure survival"
    configure sat for Survival

procedure "Enter nominal"
  uses sat: platform-v3

  step "Configure nominal"
    configure sat for Nominal
    check sat.tcu[TCU1].anode_voltage is param sat.tcu[TCU1].anode_voltage +/- 2 V

The compiler expands configure from the catalogue of the platform of the role:

  1. for each telecommand setting parameters, in the order of the catalogue, and for each instance of its component in the order of the enum of its instances, one send whose parameter arguments take param … in <mode> (the other arguments keep their default);
  2. right after each send, for each of its parameters that has a readback, an expect that the readback measure is the value of the mode (+/- tolerance when declared), within the longest within of the verifications of the setter, or 10 s when it has none;
  3. once all have succeeded, the mode of the target becomes the mode (event mode_changed).

For platform-v3, configure sat for Survival therefore sends, for TCU1 then TCU2 then TCU3, set_mode with mode = SAFE_MODE and expects mode is SAFE_MODE within 10 s; then, for each TCU, set_anode_voltage with voltage = 0 V, ramp = 50 V/s (on sim-1) and expects anode_voltage is 0 V +/- 2 V within 10 s.

These sends follow the rules of every send: a hazardous setter needs its ask operator in the same step, a step with a setter that changes the on-board state is not eligible for retries, and the maximum duration counts every setter and every readback window (see Safety Rules). If a step fails, the mode is not changed.

At the resolution of the run, every parameter a configure sets must have a value on the target in that mode (run::parameter-undefined, 422).

Reading a parameter: param#

In any expression of a procedure, param <role>.<component>[<instance>].<parameter> is the value of the parameter in the current mode of the target, read when the statement is evaluated, in the environment of the run; param … in <Mode> is its value in that mode. It has the type and unit of the parameter, and serves as an argument of a telecommand or in a condition:

text
send set_anode_voltage to sat.tcu[tcu] with voltage = param sat.tcu[tcu].anode_voltage in Nominal
check sat.tcu[TCU1].anode_voltage is param sat.tcu[TCU1].anode_voltage +/- 2 V

The mode is checked at compile time (procedure::unknown-mode). A param … in <Mode> whose instance is known is checked again at the resolution of the run (run::parameter-undefined); otherwise a parameter without value for the target fails the statement at run time. Details are in Expressions.

The ground chain#

The ground segment follows the mode of the target:

  • Each binding the reconciler delivers (stellar_bindings, verb bindings) carries the current mode of its target and its parameters in that mode, plus parameter_environments: the same, overrides applied, for each environment that overrides some. The reconciler watches stellar_modes and delivers the bindings again at each change of mode.
  • The context of a link (LinkContext) gains mode and parameters, resolved for the environment like params. Drivers and transports receive it with each telecommand and each frame, as before.
  • A gateway receives it with each frame (Gateway::send_with in Rust, a send with three arguments in Python) and each time its bindings change (Gateway::configure, @gateway.configure), for instance to set the rate of its modem.
  • LinkContext::parameter("tcu[TCU1].anode_voltage") gives the value of an instance, falling back on the key without instance, as in procedures.

See Writing a Gateway and Writing a Driver.

Diagnostics#

CodeWhereMeaning
catalogue::parameter-typeCatalogueA parameter is a number, bool or an enum value, not bytes nor a duration
catalogue::unknown-setter, catalogue::unknown-setter-argumentCatalogueset names no telecommand of the component, or no argument of it
catalogue::setter-type-mismatchCatalogueThe argument has another type or unit than the parameter
catalogue::duplicate-setterCatalogueThe argument already carries another parameter
catalogue::setter-argument-without-defaultCatalogueA setter has an argument that carries no parameter and has no default
catalogue::unknown-readback, catalogue::readback-type-mismatchCataloguereadback names no measure of the component, or one of another type or unit
catalogue::tolerance-on-non-numeric, catalogue::invalid-toleranceCatalogueA tolerance on a non-numeric parameter, or negative or in the wrong unit
topology::default-modeTopologyNo mode, or several, marked default: true
topology::unknown-parameterTopologyThe key names no parameter of the catalogue of the target
topology::unknown-modeTopologyA value is given for an undeclared mode
topology::invalid-parameter-valueTopologyA value does not fit the parameter: type, unit, range, enum value
topology::unknown-override-environmentTopologyoverrides names an environment the target is not engaged in
procedure::unknown-modeProcedureconfigure … for or param … in names an undeclared mode
procedure::unknown-parameterProcedureparam names no parameter
procedure::nothing-to-configureProcedureThe platform of the role has no parameter with a set
expr::parameter-not-hereCatalogueparam in a catalogue expression: parameters are read in procedures only
run::parameter-undefinedRun requestThe target has no value of a parameter in the mode used
mode::unknown, mode::target-heldAPISee The current mode

Stellar Control · v0.1.0

↑↓ to moveEnter to open