Write a test sequence
Add timeouts, leak checks, rate checks, and ranges to an Arc test sequence.
A test sequence moves hardware through stages, such as pressurize, hold, and vent, and goes to an abort stage when a value is unsafe. This page starts from the sequence that you write in the Arc tutorial, and adds the checks that a real test needs.
Before you start, you need these channels:
Start from the tutorial sequence
This is the sequence from the tutorial, with the channel names above:
import time
sequence press {
stage idle {
0 -> press_vlv_cmd
0 -> vent_vlv_cmd
start_cmd == 1 => pressurize
}
stage pressurize {
1 -> press_vlv_cmd
0 -> vent_vlv_cmd
tank_pt > 450 => abort
abort_cmd == 1 => abort
tank_pt > 300 => hold
}
stage hold {
0 -> press_vlv_cmd
abort_cmd == 1 => abort
time.wait{duration=10s} => vent
}
stage vent {
1 -> vent_vlv_cmd
tank_pt < 5 => idle
}
stage abort {
0 -> press_vlv_cmd
1 -> vent_vlv_cmd
start_cmd == 1 => pressurize
}
}
true => pressThe sequence keeps every stage in one sequence, and true => press keeps it running, so
each click on the start button starts a new run. The tutorial explains each line. For
how stages start and stop, see the
execution model.
Add a timeout
If the press valve sticks closed, pressurize waits forever. Add a timer as the last
transition of the stage:
stage pressurize {
// ...
tank_pt > 300 => hold
time.wait{duration=60s} => abort
}The timer starts again each time pressurize starts. The first true transition in the
code wins, so the safety checks above it still come first.
Add a leak check
In hold, a falling pressure means a leak. Add the over-pressure check and a leak
check:
stage hold {
0 -> press_vlv_cmd
tank_pt > 450 => abort
abort_cmd == 1 => abort
tank_pt < 250 => abort
time.wait{duration=10s} => vent
}The check cannot fire when hold starts, because a stage reacts only to values that
arrive after it starts.
Abort on a fast pressure rise
A pressure that rises too fast can mean a failed regulator. Compute the rate of change
in pressurize, and abort above a limit:
import math
func too_fast(rate f64) bool {
return rate > 50
}
// in stage pressurize:
tank_pt -> math.derivative{} -> too_fast{} => abortmath.derivative gives the change per second, so this check aborts above 50 psi/s. Its
first value after the stage starts is 0. A derivative of a noisy sensor is noisy too:
0.1 psi of noise at 1 kHz is about 100 psi/s. Before you choose the limit, write the
rate to a channel and plot it during a real run:
tank_pt -> math.derivative{} -> tank_pt_rate.
Go from abort to a safe stop
Add a done stage that both vent and abort go to when the tank is empty, and that
waits for the next start:
stage vent {
1 -> vent_vlv_cmd
tank_pt < 5 => done
}
stage abort {
0 -> press_vlv_cmd
1 -> vent_vlv_cmd
tank_pt < 5 => done
}
stage done {
0 -> vent_vlv_cmd
start_cmd == 1 => pressurize
}After an abort, the next click on the start button starts a new run at once. If your
operators must check the hardware first, add a stage that waits for a separate reset
button before done.
Mark each run with a range
A range marks the time of each run, so you can find its data later.
Create the range when pressurize starts, and end it in done:
import ranges
sequence press {
range_key str $= ""
// ...
stage pressurize {
ranges.create{name="Press test", color="#3bc454"} -> range_key
// ...
}
// ...
stage done {
ranges.end{key=range_key}
// ...
}
}range_key is a variable of the sequence. ranges.create stores the key of the new
range in it, and ranges.end reads it when done starts. Each run shows as a range
named Press test. Line plots show only ranges that have a color. For more patterns,
see create ranges in Arc.
The full sequence
import math
import ranges
import time
func too_fast(rate f64) bool {
return rate > 50
}
sequence press {
range_key str $= ""
stage idle {
0 -> press_vlv_cmd
0 -> vent_vlv_cmd
start_cmd == 1 => pressurize
}
stage pressurize {
ranges.create{name="Press test", color="#3bc454"} -> range_key
1 -> press_vlv_cmd
0 -> vent_vlv_cmd
tank_pt > 450 => abort
tank_pt -> math.derivative{} -> too_fast{} => abort
abort_cmd == 1 => abort
tank_pt > 300 => hold
time.wait{duration=60s} => abort
}
stage hold {
0 -> press_vlv_cmd
tank_pt > 450 => abort
abort_cmd == 1 => abort
tank_pt < 250 => abort
time.wait{duration=10s} => vent
}
stage vent {
1 -> vent_vlv_cmd
tank_pt < 5 => done
}
stage abort {
0 -> press_vlv_cmd
1 -> vent_vlv_cmd
tank_pt < 5 => done
}
stage done {
ranges.end{key=range_key}
0 -> vent_vlv_cmd
start_cmd == 1 => pressurize
}
}
true => pressA redeploy during a run starts the sequence again in idle, which closes both valves
with the tank under pressure, and leaves the range of that run open. Stop the test
before you redeploy.
Let an operator take over
The sequence writes at authority 255, the default, so an operator cannot take control of
the valves from a schematic. To let them, add authority 100 after the imports, and
raise the authority to 255 in abort. See
set authority in an Arc automation.