StateTick Docs Home →
StateTick
Working with several machines
Composition

One machine, several plans.

A composite is a machine with its own state plan, its own equipment and its own clock. Nothing says a physical machine has to be exactly one of them.

Once you allow more than one, two patterns show up almost immediately — and they are the two things sequence charts usually make awkward. Sections of a machine that genuinely run at the same time. And modes, where the same steel has to obey two entirely different sets of rules depending on who is standing at it.

01

Sections that really do run at the same time

Not interleaved on one scan — separate, at separate rates.

Take a machine with three sections: an infeed that indexes bottles in, a process head that fills them, and an outfeed that takes them away. These are not three phases of one sequence. They are three things happening simultaneously, each with its own idea of urgency.

In StateTick they are three composites. Each one gets its own execution thread and its own period, set where the machine is defined. The infeed servo interlock can look at the world every 2 ms; the fill head, which is waiting on a flow meter, is perfectly comfortable at 20 ms; the outfeed conveyor at 50 ms.

ONE PHYSICAL MACHINE, THREE COMPOSITES Infeed cycle 2 ms Wait → Index → Clear servo interlock lives here Equipment Indexer, Gate, EyeIn own thread Process cycle 20 ms Idle → Fill → Settle waits on a flow meter Equipment Filler1, Filler2, Scale own thread Outfeed cycle 50 ms Run → Accumulate nothing here is urgent Equipment Conveyor, EyeOut own thread No parent sequence owns these. Adding a fourth section does not change the other three.
Three machines, three plans, three clocks. Each is complete on its own — you can open one and understand it without reading the other two.

This is the part that tends to be laborious elsewhere. When parallelism has to be expressed as branches inside one chart, every branch inherits the same scan and the same lifetime, and the chart grows a shape that has more to do with the notation than with the machine. Here, a section is a machine, and a machine is a composite.

A side effect worth having: a section can be switched off at build time. Commissioning the infeed before the outfeed exists is a checkbox, not a comment block wrapped around half the program.

02

They coordinate where you can see it

A machine can wait on another machine's state directly.

Separate machines still need to agree on things. The process head must not start filling while the infeed is mid-index. Normally that agreement is a bit — a flag that means “infeed busy” because everyone involved agreed it does, and which nobody can find the writer of two years later.

Instead, a guard can name the other machine and the state it should be in. IN_STATE('Infeed', 'Clear') is a condition like any other, and it points at something real: if that state is renamed or removed, the reference is caught when the plan is built, not discovered on site.

There is a wider form for when several states count — IN_ANY_STATE('Infeed', 'Clear', 'Idle') — which saves the usual chain of ORs against a hand-maintained list.

THE USUAL WAY Infeed sets a bit, sometimes Process reads the bit, hopefully bInfeedOK meaning by convention Who writes it? When is it cleared? Nothing checks that the answer stayed true. IN STATETICK Infeed Clear a state, not a flag Process Idle → Fill when IN_STATE('Infeed','Clear') read directly The reference points at a real state. Rename it and the plan fails to build.
Same coordination, different substance. The handshake bit carries meaning by agreement; the state reference carries it by construction.
Coming from a PLC

You still have globals when you want them, and they are typed and declared rather than conjured. The point is that timing coordination no longer has to travel through a variable at all. When a machine needs to know where another machine is, it asks that question literally.

03

Automatic and manual as two plans

Not one plan with mode checks scattered through it.

Every real machine has at least two personalities. In automatic it runs a cycle. In manual an operator jogs axes, opens valves and homes things, with a different set of interlocks and a completely different notion of what “safe” means.

Written as one sequence, that becomes mode conditions sprinkled through every step, and a permanent low-grade worry about which combinations were never tried. The two personalities are genuinely different plans, so make them different plans.

Two composites, both looking at the same equipment. One holds the automatic cycle; the other holds jogging and homing. What decides which is live is an abort on each, pointing the other way.

MODE SELECTOR Global.AutoMode Composite — Auto Idle → Index → Fill → Eject ABORT NOT Global.AutoMode → ParkedAuto Composite — Manual Standby → JogAxis → OpenValve ABORT Global.AutoMode → ParkedManual BOTH SEE THE SAME STEEL Indexer · Filler1 · Filler2 · Gate · Conveyor
Two plans over one set of equipment. Each one is aborted by the condition that makes the other one relevant, so exactly one is ever doing anything.

Read either composite on its own and it makes sense end to end. The automatic plan is a clean cycle with no mode checks in it. The manual plan is a set of operator actions with no cycle logic in it. Neither has to reason about the other’s existence beyond that single abort line.

And the abort is not just for modes. The same ladder handles the things that genuinely have to override a plan — guard door open, air pressure lost, e-stop released but not reset. Abort pairs are priority-ordered and the first match wins, so “guard open” can outrank “mode changed” without either of them being written into a state.

04

Handover happens on its own

The abort is held, not latched — which is what makes the switch feel seamless.

The important detail is what an abort is. It is not a jump that fires once. While its condition holds, the machine stays parked in the abort state, running that state normally. The moment the condition stops being true, the abort releases and the plan carries on from there.

So mode switching needs no orchestration. Turn the key to manual and the automatic plan parks itself; the manual plan’s abort clears and it comes alive. Turn it back and the two swap. Nobody wrote a handover sequence, because there isn’t one — there are two conditions that are never true at the same time.

MODE AUTO MANUAL AUTO Auto composite Index → Fill → Eject held in ParkedAuto Index → Fill Manual composite held in ParkedManual JogAxis → OpenValve held in ParkedManual Neither plan is stopped or reset. Each is parked in a state you named, and released by the same condition that parked it.
The switch is instantaneous in both directions and symmetric. There is no window in which both plans are live, and none in which neither is.

Because the parked state is a state you wrote, you decide what parking looks like. ParkedAuto can drop outputs, close a valve, or simply sit there. And because it is a state, the live plan shows the machine sitting in it — which is a considerably better answer to “why is nothing happening?” than an unlit rung.

Two aborts, or one plan with two? Either. A single composite can carry several abort pairs at different priorities, which is often enough for stop and hold. Splitting into two composites is what you reach for when the two behaviours are genuinely different jobs — different steps, different interlocks, different people at the machine.

05

The same idea, twice

Parallel sections and modes look like different problems. They are the same one.

Parallel sections

  • Several composites, all live at once.
  • Each at the period its job needs.
  • They agree by reading each other's states.
  • Adding one does not disturb the rest.

Modes

  • Several composites, one live at a time.
  • Abort decides which, from a plain condition.
  • Handover needs no sequence of its own.
  • Each plan reads cleanly in isolation.

Split by what the machine is doing, not by what the notation allows.

The reason both patterns work is that a composite is cheap and complete. It costs a thread and a period, and it comes with its own plan, its own equipment view and its own abort ladder. So the question stops being “how do I express this in one chart” and becomes the much better question: is this a separate job?

Infeed and outfeed are separate jobs. Automatic and manual are separate jobs. Draw them separately and each one stays small enough to hold in your head — which is, in the end, the only durable way to keep a machine maintainable.

Also worth reading

Machine Paths, Not Scattered Tags — what a composite is made of, and why every signal has an address that says where it lives.

Queues: Batches That Flow Between Stages — when parallel sections need to hand each other data, not just timing.