TwinCAT 3 Β· Track 14 Β· one machine, many products

Recipes & Production Data

Real lines almost never make one thing. The same donut machine has to run strawberry rings at 9am, choc-sprinkles at noon, and sugar minis after lunch β€” and the operator changing it over is not a programmer. A recipe is how you let them: a named set of setpoints you swap into the running task without touching a line of code. Pick a product below and watch the machine reconfigure itself.

πŸ“‹ data, not codeπŸ‘· operator-changeableπŸ” repeatable batches
01 Β· The big idea

Same code. Swap the data. Different product.

The sequence never changes: advance the belt β†’ glaze the donut β†’ box them. What changes between products is just numbers β€” glaze colour, dwell time, belt speed, box count. Recipes pull those numbers out of the code and into a working struct the task reads from. Click a recipe: the line keeps running the exact same program, but the loaded setpoints change and the machine follows.

RUN Β· 1 ms task Β· production
βœ“ ACTIVE
Recipe set Β· pick a product to load
Active setpoints Β· what the task reads this cycle
β€· fbDonutStation( Setpoints := Active ) β€” the FB only ever sees Active. Loading a recipe copies one row of the set into it; the FB never knows which product it is.

πŸ‘€ Notice what did not happen: no download, no recompile, no engineer. The yellow setpoints flashed, the belt re-timed, the glaze recoloured β€” a 0.3 s changeover. That gap between "change a product" and "change the program" is the entire reason recipes exist.

02 Β· Anatomy of a recipe

A type, an active copy, and a set

It's three simple pieces. First a type β€” a STRUCT that names every parameter a product needs. Then one active instance the running code reads. Then a set: many filled-in copies, one per product, stored on the controller. Loading = copying the chosen row of the set into the active instance.

// 1 Β· the TYPE β€” every product is shaped like this
TYPE ST_DonutRecipe :
STRUCT
    sGlazeType     : STRING;   // 'strawberry'
    nConveyorSpeed : INT;      // mm/s
    tGlazeDwell    : TIME;     // pour time
    rFryTemp       : REAL;     // Β°C setpoint
    bSprinkles     : BOOL;
    nBoxCount      : INT;      // donuts per box
END_STRUCT
END_TYPE
// 2 Β· the ACTIVE copy the task actually reads
VAR_GLOBAL
    Active : ST_DonutRecipe;        // loaded set
END_VAR

// 3 Β· the SET β€” many products, stored on disk
//    (a file/array of ST_DonutRecipe rows)

// loading is just a copy:
Active := Set[ nChosenProduct ];

// from here the sequence is product-blind:
IF bDonutAtStation THEN
    tDwell( IN:=TRUE, PT:=Active.tGlazeDwell );
END_IF

The stored set is just a table β€” rows are products, columns are the struct fields. This is literally what an operator sees on the HMI. Click any row to load it (it drives the live line above too):

ProductsGlazeTypeSpeedtGlazeDwellrFryTempbSprinklesnBoxCount
03 Β· The machine picks β€” and proves it

The tooling selects the recipe; the barcode confirms it

On a real mixed-reference line, an operator picking from a list is the exception. The machine usually selects its own recipe from a hardware signal β€” and then refuses to run until a second, independent source agrees. This is the pattern worth knowing cold, because it's everywhere in automotive, pharma and food: tool ID in β†’ barcode confirm β†’ cycle-start.

πŸ”§ Channel 1 β€” the tooling tells the machine. Each reference has its own physical fixture / gripper / mould. When it's clamped in, it presents a coded tool ID β€” hardwired ID pins, an RFID tag, or an EtherCAT coupler the bus enumerates. The PLC reads nToolID and auto-loads that reference's recipe. The machine knows what it's set up to make β€” no one typed anything.

πŸ”Ž Channel 2 β€” the barcode proves the part. Knowing the setup isn't enough; the part in front of the tool could be the wrong one. A BCR (barcode reader) scans the incoming part and the PLC compares sScannedRef against the loaded recipe. Agree β†’ cycle-start enabled. Disagree β†’ reject & alarm, before anything is processed.

Try it. Clamp a tool (it auto-loads its recipe and drives the live line up in Β§01), present a part to the reader, then hit Scan. Feed it the wrong box on purpose and watch the machine stop itself.

1 Tooling clamped in the machine
2 Part presented to the BCR
β€” present a part β€”
3 PLC verdict Β· cycle interlock
Awaiting scan…
Clamp a tool and present a part, then scan.
// the real pattern: select by tool, then VERIFY before you run
CASE nToolID OF                          // coded tool ID read at the inputs
    1: Active := Set.Strawberry;
    2: Active := Set.Choc;
    3: Active := Set.Sugar;
ELSE
    bToolFault := TRUE;  bCycleEnable := FALSE;   // no/unknown tool β†’ inhibit
END_CASE

IF bScanDone THEN                          // the BCR finished a read
    IF sScannedRef = Active.sRef THEN
        bCycleEnable := TRUE;                  // βœ“ both channels agree β†’ run
    ELSE
        bRejectPart  := TRUE;  bAlarm := TRUE;  // βœ— wrong part for this tooling
    END_IF
END_IF

This is poka-yoke β€” error-proofing. Two independent channels must name the same reference, or the machine won't cycle. Here's every outcome the interlock has to handle:

Tool IDBCR readPLC decisionWhat happens
valid Β· recipe loadedmatches Active.sRefCONFIRMEDbCycleEnable := TRUE β€” run the batch
valid Β· recipe loadeddifferent referenceMISMATCHbRejectPart + bAlarm β€” part ejected
valid Β· recipe loadedno-read / smudgedNO-READre-present / manual entry β€” never assume
none / unknownβ€”NO TOOLbToolFault β€” cycle-start inhibited

Why bother when an operator could just pick it? Because people mis-pick, and a wrong reference is expensive β€” scrapped product, a line stop, a recall in regulated industries. Two-channel verification takes the human out of the critical decision and logs the scanned barcode against the batch, so traceability comes for free. Selection becomes automatic; being right becomes guaranteed.

04 Β· Where recipes live in TwinCAT

On the controller, not in the code

The whole point is that recipes outlive any single download β€” so they are stored as files on the target, edited from the HMI, and loaded at runtime. TwinCAT gives you the Tc2_RecipeManagement library for exactly this: register the variables you want managed, then save and load named recipes that persist on disk. (On TwinCAT HMI you'd use its built-in recipe management instead β€” same idea, prettier front end.)

πŸ‘·
Operator Β· HMI
Picks "Choc Sprinkle" from a list, or edits a value and hits Save. No IDE, no login as engineer.
β†’
πŸ—‚οΈ
Recipe files on disk
Tc2_RecipeManagement stores each named recipe as a file in the boot folder on the controller β€” survives power-off and re-download.
β†’
βš™οΈ
Active struct β†’ task
Load copies the chosen recipe into Active. The 1 ms task reads it next cycle and the machine follows β€” no stop, no download.

⚠️ Recipe β‰  PERSISTENT. PERSISTENT/RETAIN keep the machine's one current state alive across a reboot β€” a single snapshot. A recipe set is a library of many named products you load on demand. Different jobs; people mix them up constantly.

βœ… Validate on load. A recipe is just data β€” and data can be wrong. Range-check every field as you copy it into Active (a 600 Β°C fryer setpoint should be refused, not fried). Recipes move responsibility to the operator, so the code must guard the limits.

05 Β· Why & when it matters

The payoff is changeover, traceability & trust

Reach for recipes the moment a machine makes more than one variant, or the moment the same numbers get typed in twice. Here's what they buy you.

⏱️
Changeover in seconds, by the operator
Switching products becomes "pick from a list", not "call the programmer and download new code". A 20-minute, error-prone changeover collapses into one tap β€” that's reclaimed production time on every switch.
0.3 s
🎯
Every batch is identical
The strawberry ring made today uses byte-for-byte the same setpoints as the one made next month. No "I think the temp was about 180" β€” the recipe is the spec, repeated perfectly.
repeatable
🧾
Traceability for free
Log which recipe ran which batch and you can answer "what settings made lot #4471?" β€” essential for food, pharma and any audited process. The recipe name is your paper trail.
audit-ready
πŸ›‘οΈ
One code base to maintain
Fix a bug in the glaze sequence once and every product inherits it. With copy-pasted per-product programs you'd fix it twelve times and miss one. Data scales; duplicated code rots.
Γ—1
06 Β· Check yourself

Two that catch people out

1 Β· Your donut line must make three products and the operators change it over themselves. What's the right structure?

2 Β· A colleague says "we already have PERSISTENT variables, so we don't need recipe management." Are they right?