ReferenceControlArcHow ToTest Sequences

Test Sequences

Build automated test sequences with stages, timing, and abort handling

Test sequences are ordered procedures that step through stages: pressurize, hold, fire, shutdown. Arc sequences handle this naturally with stages, transitions, and concurrent monitoring for abort conditions.

Basic Sequence

A minimal sequence with idle, active, and complete states:

sequence main {
    stage idle {
        // Wait for operator to start
        0 -> press_vlv_cmd
    }

    stage active {
        1 -> press_vlv_cmd,
        ox_pt_1 > 500 => next
    }

    stage complete {
        0 -> press_vlv_cmd
    }
}

start_cmd => main

Wire start_cmd to a button in Console. When clicked, the sequence moves from idle to active, opens the valve, waits for pressure to reach 500, then closes the valve and stops.

The entry point start_cmd => main triggers the sequence when the channel receives a truthy value (non-zero). Create start_cmd as a u8 virtual channel in Synnax, then wire it to a button in your Console schematic.

Timed Stages

Use wait to add delays between stages:

sequence main {
    stage pressurize {
        1 -> press_vlv_cmd,
        ox_pt_1 > 500 => next
    }

    stage hold {
        // Keep valve open, wait 30 seconds
        1 -> press_vlv_cmd,
        wait{duration=30s} => next
    }

    stage depressurize {
        0 -> press_vlv_cmd,
        ox_pt_1 < 50 => next
    }

    stage complete {
        0 -> press_vlv_cmd
    }
}

start_cmd => main

The sequence pressurizes to 500 psi, holds for 30 seconds, then depressurizes.

Abort Handling

Real test sequences need abort capability. List abort conditions first in each stage (line order determines priority):

sequence main {
    stage pressurize {
        // ABORT CONDITIONS FIRST
        ox_pt_1 > 700 => abort,           // over-pressure
        abort_btn => abort,                // operator abort

        // Normal operations
        1 -> press_vlv_cmd,
        ox_pt_1 > 500 => next
    }

    stage hold {
        ox_pt_1 > 700 => abort,
        abort_btn => abort,

        1 -> press_vlv_cmd,
        wait{duration=30s} => next
    }

    stage depressurize {
        abort_btn => abort,

        0 -> press_vlv_cmd,
        ox_pt_1 < 50 => next
    }

    stage complete {
        0 -> press_vlv_cmd
    }
}

sequence abort {
    stage safing {
        0 -> press_vlv_cmd,
        0 -> fuel_vlv_cmd,
        0 -> igniter_cmd
    }
}

start_cmd => main
emergency_stop => abort

The abort sequence closes all valves and disables actuators. Both the automated conditions and the emergency_stop channel can trigger it.

Always put abort conditions before normal operation flows in each stage. When multiple one-shot transitions (=>) are true simultaneously, the first one listed wins. Safety conditions should always have priority.

Conditional Progression

Advance based on multiple conditions being satisfied:

sequence main {
    stage verify {
        // Check all systems ready
        ox_pt_1 > 100 and ox_pt_1 < 200 and fuel_pt_1 > 100 => next,

        // Timeout if conditions not met
        wait{duration=10s} => timeout
    }

    stage pressurize {
        ox_pt_1 > 700 => abort,
        abort_btn => abort,

        1 -> press_vlv_cmd,
        ox_pt_1 > 500 => next
    }

    stage hold {
        // ... rest of sequence
    }

    stage timeout {
        // Handle timeout condition
        0 -> press_vlv_cmd
    }
}

The verify stage waits until both pressure readings are in range. If they don’t reach the required values within 10 seconds, the sequence moves to a timeout stage instead.

Rate-Limited Pressurization

Control the pressurization rate to avoid thermal shock or mechanical stress:

func rate_monitor{dt_ms f64, max_rate f64} (value f64) u8 {
    prev $= 0.0
    d := value - prev
    prev = value

    dt_s := dt_ms / 1000.0
    if dt_s <= 0 {
        return 0
    }

    rate := d / dt_s

    // Check magnitude
    if rate < 0 {
        rate = 0.0 - rate
    }

    if rate > max_rate {
        return 1
    }
    return 0
}

sequence main {
    stage pressurize {
        // Abort conditions
        ox_pt_1 > 700 => abort,
        ox_pt_1 -> rate_monitor{dt_ms=50.0, max_rate=100.0} -> ox_rate_high,
        ox_rate_high => abort,
        abort_btn => abort,

        // Pressurize slowly by pulsing the valve
        interval{period=100ms} -> press_valve_pulse{},

        ox_pt_1 > 500 => next
    }

    // ... rest of sequence
}

The rate monitor triggers an abort if pressure rises faster than 100 psi/second.

Complete Test Stand Sequence

A realistic rocket engine test sequence with all the patterns combined:

// Rate monitoring
func pressure_rate{dt_ms f64} (value f64) f64 {
    prev $= 0.0
    d := value - prev
    prev = value
    dt_s := dt_ms / 1000.0
    if dt_s <= 0 {
        return 0.0
    }
    return d / dt_s
}

sequence main {
    // Stage 1: System checkout
    stage checkout {
        ox_pt_1 > 50 => abort,     // tank should be empty
        fuel_pt_1 > 50 => abort,
        abort_btn => abort,

        // All systems nominal, proceed
        wait{duration=2s} => next
    }

    // Stage 2: Pressurize oxidizer
    stage press_ox {
        ox_pt_1 > 650 => abort,
        ox_pt_1 -> pressure_rate{dt_ms=50.0} -> ox_rate,
        ox_rate > 100 => abort,
        abort_btn => abort,

        1 -> ox_press_vlv_cmd,
        ox_pt_1 > 500 => next
    }

    // Stage 3: Pressurize fuel
    stage press_fuel {
        ox_pt_1 > 650 => abort,
        fuel_pt_1 > 450 => abort,
        abort_btn => abort,

        1 -> ox_press_vlv_cmd,    // maintain ox pressure
        1 -> fuel_press_vlv_cmd,
        fuel_pt_1 > 350 => next
    }

    // Stage 4: Pre-fire hold
    stage hold {
        ox_pt_1 > 650 => abort,
        fuel_pt_1 > 450 => abort,
        ox_pt_1 < 400 => abort,   // pressure decay = leak
        fuel_pt_1 < 250 => abort,
        abort_btn => abort,

        1 -> ox_press_vlv_cmd,
        1 -> fuel_press_vlv_cmd,
        wait{duration=5s} => next
    }

    // Stage 5: Ignition
    stage ignite {
        ox_pt_1 > 650 => abort,
        fuel_pt_1 > 450 => abort,
        abort_btn => abort,

        1 -> ox_press_vlv_cmd,
        1 -> fuel_press_vlv_cmd,
        1 -> igniter_cmd,

        // Wait for combustion confirmation
        chamber_tc_1 > 500 => next,

        // Ignition timeout
        wait{duration=3s} => ignition_fail
    }

    // Stage 6: Main run
    stage main_run {
        ox_pt_1 > 700 => abort,
        fuel_pt_1 > 500 => abort,
        chamber_tc_1 > 2000 => abort,
        abort_btn => abort,

        1 -> ox_press_vlv_cmd,
        1 -> fuel_press_vlv_cmd,
        1 -> ox_main_vlv_cmd,
        1 -> fuel_main_vlv_cmd,
        0 -> igniter_cmd,

        wait{duration=10s} => next
    }

    // Stage 7: Shutdown
    stage shutdown {
        // Controlled shutdown sequence
        0 -> ox_main_vlv_cmd,
        0 -> fuel_main_vlv_cmd,
        wait{duration=1s} => next
    }

    // Stage 8: Depressurize
    stage depress {
        0 -> ox_press_vlv_cmd,
        0 -> fuel_press_vlv_cmd,
        1 -> ox_vent_vlv_cmd,
        1 -> fuel_vent_vlv_cmd,

        ox_pt_1 < 20 and fuel_pt_1 < 20 => next
    }

    // Stage 9: Complete
    stage complete {
        0 -> ox_vent_vlv_cmd,
        0 -> fuel_vent_vlv_cmd
    }

    // Stage: Ignition failure
    stage ignition_fail {
        0 -> igniter_cmd,
        1 => abort
    }
}

sequence abort {
    stage safing {
        // Close all valves immediately
        0 -> ox_press_vlv_cmd,
        0 -> fuel_press_vlv_cmd,
        0 -> ox_main_vlv_cmd,
        0 -> fuel_main_vlv_cmd,
        0 -> igniter_cmd,

        // Open vents
        1 -> ox_vent_vlv_cmd,
        1 -> fuel_vent_vlv_cmd
    }
}

// Entry points
start_cmd => main
emergency_stop => abort

Sequence Design Tips

List abort conditions first. Line order determines priority. Safety conditions should always win over normal operations.

Use multiple abort thresholds. A pressure of 600 psi might be a warning, but 700 psi triggers an immediate abort.

Add timeouts. Sequences that wait indefinitely for conditions can hang. Use wait to set maximum durations and transition to error stages.

Keep stages focused. Each stage should have one primary purpose. Split complex operations into multiple stages for clarity and easier debugging.

Monitor continuously. While waiting for one condition, continue checking abort conditions. All flows in a stage run concurrently.

Test abort paths. Simulate abort conditions during development to verify the system reaches a safe state. The abort sequence is the most important part of your automation.