PackML in practice: keeping modular machine software in sync
12 min read · By the neexo engineering team · Vejle, Denmark
Published: 21 September 2026
Customers ask for PackML because they want a common start, stop and recovery. That does not mean rewriting the whole program. The hard part is making modules wait on the same states. Parent and child have to wait. Optional modules belong in the architecture, not as extra ISA states.
Do we have to rewrite the whole machine in PackML?
Customers start asking for PackML. You have heard the name. It sounds like a full 17-state project and a rewrite of software that already runs the machine.
The requirement is usually more modest. They want start, stop, reset and recovery to mean the same kind of thing from one module to the next, and from one machine to the next on their line. PackML is a framework for that. Process logic, motion and safety stay. The modules get shared states.
You also do not need every state on every module. ANSI/ISA-TR88.00.02-2022 allows a subset for PackML machine and unit modes, and names a minimum set. Nested equipment modules can be smaller. Empty states that nothing in the application uses only add noise.
The work that actually takes time is coordination: who waits, who may Reset, what happens when one station is still aborting. That is where machines drift, and where a BOOL list usually grows.
You do not have to rewrite the whole machine. You do need shared states the relevant modules can wait on.
What goes wrong when modules finish recovery at different times?
Five stations on one machine. One faults. The others keep running or stop on their own timing. The HMI says the machine is ready for Reset because the top program finished. One station is still moving. An operator presses Reset while recovery is still running.
In PackML that looks like this. Infeed, Transport, Process, Inspection and Outfeed are in Execute when a child raises Abort. Infeed reaches Aborted in a few cycles. Transport still has to stop motion. Process stays in Aborting while a station empties or an axis decelerates. The other modules are already Aborted.
If Main treats 'my Aborting code finished' as 'the machine is aborted', Reset starts against a module that has not finished the last step.
That is how the BOOL list grows: ProcessReady, AxisHomed, InfeedResetDone, OutfeedStopped, plus handshakes that only one person remembers. Diagnosis then means hunting bits instead of reading a state. Different modules need different transition times. That is legitimate. The failure is hiding those times in private flags instead of shared states the hierarchy can wait on.
What does PackML actually give the machine?
PackML, in ANSI/ISA-TR88.00.02, is a shared vocabulary for unit and machine states and modes. It came out of packaging through OMAC. The same states are used on other automated machinery when start, stop and recovery have to mean one thing across modules. For a custom machine the origin matters less than this: Stopped, Resetting, Idle, Starting and Execute mean the same kind of thing on Infeed as they do on Process.
Resetting is the acting state that brings a stopped module to a known ready condition. Depending on the application, that may include enabling drives, establishing references or homing axes where the machine safety concept allows this without hazardous motion, returning a mechanism to a known position, and resetting local sequences. On another machine Resetting barely moves anything, because the machine is already at a known ready condition. Those actions are application examples. PackML does not mandate them.
Idle means ready, waiting for Start. Starting is the acting state from ready to running. Typical work includes applying the active job, establishing axis or module sync, starting auxiliaries, and ramping transport. Again, examples. Execute is the defined production behaviour for the active mode.
Stopping is a controlled stop. Aborting is a rapid path to a safe stop after a fault or an Abort command. Clearing leaves Aborted after the cause has been handled and faults have been acknowledged. Completing finishes a cycle from Execute when the mode uses a complete path. Hold and Suspend pause production; they are not the same as Stop or Abort. Abort can be issued from every state except Aborting and Aborted. Stop cannot be issued from Aborting, Aborted, Clearing, Stopping or Stopped. Complete can be issued from Execute, Held and Suspended.
The opening poster is the allowed set. Day to day, production usually runs Stopped, Resetting, Idle, Starting and Execute. Implement the states this machine actually uses. Those states need agreed meaning, so a parent can wait for Resetting to complete instead of a private bit name.
PackML will not fix modules cut in the wrong places, unclear ownership of signals and faults, a weak process, or application motion and sequence logic. It does not replace functional safety. Aborting is a control-state path. An e-stop still trips the safety system.
Why is a state machine in Main not enough?
PackML defines the shared machine states. The parent/child hierarchy described below is a practical modular software architecture for applying those states across a machine. The standard does not require that hierarchy. Real machines with several modules do.
A Main that shows Idle while Process is still Resetting is a misleading dashboard. The machine is the hierarchy, not the top function block.
A typical line is Machine, then Infeed, Transport, Process, Inspection and Outfeed. Each module has local behaviour: sensors, motion, sequences. Each also takes part in those shared states. If only Main speaks PackML, children still finish Abort and Reset on private timing, and you are back to BOOLs.
Nesting is the same rule one level down. Process may own an axis module. Inspection may own a camera station. Those children complete their own transitions and report when they are actually done.
How do parent and child modules stay synchronized?
The child runs its own transition. When the local work is actually done, it signals State Complete. The parent stays in the acting state until the relevant children have completed.
Relevant means children that are in the active hierarchy and configured to take part in that command. A deactivated optional station should not block Reset. A branch that is intentionally left out of sync should not either.
Children will not finish together. Infeed may already be Idle while Process is still Resetting because an axis is referencing. The useful diagnostic is explicit: Main Waiting for Process. Process: Axis reference in progress. Commissioning and service can see the block without opening a cross-reference of flags.
If the parent does not wait, Main will show Idle while a child is still moving. Operators then start a machine that is not ready.
How should Abort, Stop, Start and Reset move through the hierarchy?
Commands need a direction, or every module invents one.
Some commands belong at the parent. Start and Reset are typically issued from above so the hierarchy enters the acting state together. A child that starts itself while siblings are still Idle produces a race.
Some events must travel up. A local Abort on Process should become a machine Abort. Stop often should too. Complete, Hold and Suspend may escalate, depending on the machine.
Children also need a rule for following the parent. If Main goes to Aborting, Process should react even if its own code did not request Abort.
Some PackML libraries name these rules Override, ReactTo and Escalate. The names matter less than the consequences. Override: the parent owns this command; local requests are blocked, though escalation can still occur. ReactTo: the child follows the parent transition. Escalate: a local command is raised to the parent. If a child is neither ReactTo nor Override for a command, it is out of sync and the parent should not wait for it.
How do optional modules join without special cases everywhere?
Keep one software architecture and change which modules are active. Main, Infeed and Outfeed are always present. Printing and Inspection are optional. Printing may itself contain PrintAxis, InkSystem and Dryer.
Machine A marks only. Machine B inspects only. Machine C does both. The optional module still exists in the project. It is not deleted from the code for the short machine. It is either in the active hierarchy or it is not.
If participation is a scatter of IF Config.HasPrinter in Infeed, Main, HMI and the abort handler, every new variant reopens those files.
An explicit activation path is cleaner. The module can sit Deactivated: present in software, not part of the active machine. When the configuration includes it, it goes Activating, then Stopped, and from there into the normal PackML states. The parent does not wait for a deactivated child. Children under Printing follow that branch.
Activating, Deactivating and Deactivated are implementation extensions. They are not states in ISA-TR88.00.02. They exist because Stopped and 'not part of this machine today' are different questions. Should the parent wait? Should it react to Reset? Is the station installed but unused on this order?
Our PackML library uses that Deactivated path so an optional station can exist in the project without sitting in the active machine. The standard names the states. Configuration decides who takes part.
How do we know the architecture is actually ready?
A poster of 17 states does not finish the architecture. Take one Abort or Reset you shipped. If you cannot answer the questions below from that event, the waits are still informal, and the next variant will grow another BOOL list.
- Can each module say whether it is stopped, ready, transitioning or running?
- Does Main know, by name, which module it is waiting for?
- Can service see what blocks Reset or Start without hunting flags?
- Is it clear who may issue Abort, Stop, Start and Reset?
- Can an optional station be left out of this machine without special cases in unrelated code?
- After a child Abort, can you describe how the whole machine ends in one consistent state?
Parent and child already wait in our library
We maintain a PackML framework for modular machines. Parent and child wait on each other. Optional stations join by configuration. The application programmer writes the process.
Engineering and machine softwareFrequently asked questions
Do we have to rewrite the entire machine in PackML?
No. PackML is a shared language for start, stop, reset and recovery. Process logic, motion and safety stay. You implement the states the machine actually uses. Nested modules can be smaller than the unit model. The work is making the relevant modules wait on those states, not replacing every sequence.
Do we need all 17 PackML states?
No. ANSI/ISA-TR88.00.02-2022 allows a subset per PackML machine or unit mode and names a minimum set. A smaller model on nested equipment modules is an architecture choice. Implement the states that match how the machine actually starts, stops, holds and recovers. Empty states that nothing in the application uses only add noise.
Are Activating, Deactivating and Deactivated part of PackML?
No. They are implementation extensions used by some PackML libraries so an optional module can exist in the software without taking part in the active machine. Do not draw them on the official state model, and do not treat them as ISA-TR88 states.
Can we use PackML outside packaging?
Yes, when start, stop, reset and recovery must mean one thing, and modules have to coordinate through them. It is a poor fit when the problem is a single simple sequence with no hierarchy. PackML is not a universal law for every industrial machine.
Does PackML replace functional safety?
No. Aborting is a control-state path that brings the application toward a rapid stop. An emergency stop still trips the safety system. Risk assessment, safety architecture and validated safety functions stay outside the PackML model.
Where should optional modules live in the project?
In the same architecture as the rest of the machine, with an explicit active or inactive participation. Avoid scattering IF Config.HasX through Infeed, abort handling and HMI. Let the optional parent control whether its children join the active hierarchy.
On the next machine, pick one Abort or Reset and write which modules must finish before Main may continue. If that list lives only in someone's head, call us. The library already has the wait.
Contact us