Chapter 1 / 36

Start with the machine

Turn a vague machine request into observable behaviour before opening the editor.

Here is the job. Where would you start?

An operator puts a carton at the near end of a belt. There is a photoeye there, PE1, and another at the far end, PE2. The request is short:

“Press Start to bring one carton to the far sensor. Stop there. Wait for the next cycle.”

A teaching transfer station with a PLC cabinet, entry and arrival photoeyes, a carton and a driven belt
The first job. Find the two observations, the operator request and the actuator. The illustration introduces the equipment; the signal diagram below defines exactly what the program knows.

You know how to write an IF. You might already know how a contact and a coil work. But the request has not told you which IF or which rung to write. That is the part we will practise.

Start on paper. Write Q_Belt in the middle. It is the output that asks the drive to run the belt. Around it, leave space for four answers: what allows it, what keeps it going, what finishes it, and what interrupts it. Those answers will become your program. You can learn the spelling of the instructions as you go.

The workbench above is this exact machine. Open it and leave the first draft's rules off. Change inputs, advance a scan, and look at the carton. Later, add each rule and watch the code change. You are not trying to guess an answer from four options. You are deciding what the machine is allowed to do and testing that decision.

The first twenty minutes

Imagine sitting down with an empty editor and that one-sentence request. Resist the urge to type IF Start. You are missing several decisions, and syntax will not make them for you.

Put a line under each phrase of the request. Beside it, write the question it leaves unanswered. This is what an experienced programmer is doing when they appear to be taking a long time to write a short program.

Words in the briefWhat you need to askDecision for this teaching job
Press StartHold it, or press and release it?A fresh press requests one complete transfer.
One cartonHow do we know a carton is available?PE1 must be active when the request is accepted.
To the far sensorWhat counts as completion?PE2 becomes active while the accepted move is in progress.
Stop thereWhat if arrival and Stop appear together?Stop wins. Record an interrupted cycle, not a successful delivery.
WaitWhat if Start is still held when the carton is removed?Stay stopped. Removal is not a new command.
Next cycleWho says the station is ready again?Acknowledge delivery, establish pickup, release Start, then accept a new press.

These answers are chosen requirements, not properties of PLCs. A different customer could choose a different acknowledgement process. The professional habit is to expose the decision, agree it, and test it. Do not hide it inside a convenient rung.

Now put an asterisk beside anything that the physical equipment cannot prove. Our two photoeyes can show that a carton is at either end. They cannot identify the carton, measure its exact position between sensors, prove that a belt is not slipping, or tell you whether somebody removed it halfway through. Keep those limits on the page. They tell you where a timeout can detect missing progress and where another sensor might be necessary.

If you cannot finish one of those sentences, write a question in the design record. That is progress. A guessed answer that makes the program compile is still a guessed machine.

First: name what you can command

For this small job there is one ordinary control output: the belt-run request. Write its name, destination and meaning.

NameGoes toTRUE meansFALSE means
Q_BeltDrive run inputRequest belt motionRemove the run request

Notice the word request. It is possible to request motion while the drive is faulted, the belt is jammed or the motor is disconnected. A command does not prove that anything moved. Later we will supervise the drive's actual response. For now, do not label this variable “MotorRunning”.

This first row prevents a common muddle: mixing an action, an observation and a permission into one Boolean called “Motor”. You need all three meanings. Give them different names.

Second: find the facts that justify the command

Point to the real thing that supplies each fact. For our teaching station:

FactWhere it comes fromWhy we need it
AtPickupPE1A carton is available when we accept a cycle
AtDropPE2The requested move has reached its destination
DriveReadyDrive statusThe drive can accept an ordinary run request
StartButtonOperator inputSomeone requests a cycle
StopButtonOperator inputSomeone requests an interruption

We have chosen teaching assumptions: a carton starts at PE1, both sensors detect the carton when TRUE, and DriveReady remains supervised during travel. Your real machine might use different wiring or different readiness semantics. Put those differences in the signal map; do not quietly compensate for them halfway down the sequence.

Signal roles around the carton conveyor: requests and sensor evidence enter the controller; memory and continuous permissions justify a single belt command
Read this from the machine inward. Blue identifies observations and requests; gold identifies remembered decisions; green identifies the command. Q_Belt is deliberately separate from proof that the carton moved. Open the drawing to inspect it at full size.

What if PE2 does not exist? Then “stop at PE2” is not a decision the program can make. A timer cannot conjure that observation. You would need another way to establish position—perhaps an encoder or a different sensor—or the requirement would need to change. Finding that gap now is more useful than writing twenty rungs around an imagined input.

Third: decide what must be remembered

Ask the operator to press and release Start. Should the belt stop as soon as the finger leaves the button? For this job, no. The press requests a complete move. Something must remember that the request was accepted.

Compare these two jobs carefully:

JobWhat determines the output?Useful starting pattern
Light a lamp while a sensor is activePresent conditionsA Boolean expression or a rung
Run while an operator holds a jog buttonPresent request and permissivesA gated Boolean expression
Accept Start and finish a move after releaseAn accepted request plus later evidenceMemory, with a defined clearing rule
Clamp, extend, retract, then releaseSeveral remembered phases with different evidenceA state sequence

Do not use a state machine because it sounds professional. Use one when naming the phases makes the decision easier to explain. Our one-carton job benefits from four names because the motor can be off for three different reasons: waiting for a request, finished, or interrupted.

Here is a quick proof. After a carton arrives, remove it from PE2. The sensor becomes FALSE. Should the belt run? No: the accepted job is finished. At an earlier moment, while a carton was travelling toward PE2, that same FALSE input meant “keep moving”. The sensor value alone cannot answer the question. The history matters.

Decision tree choosing present-condition logic, one remembered fact or named states according to whether history and phase order change the answer
A method for choosing a method. Ask whether two different histories could need different outputs with the same present inputs. That question tells you whether you need memory. Several distinct remembered phases suggest a state model.

Fourth: name the states and write on the arrows

Use these states for the exercise:

StateWhat it remembersBelt request
IDLENo move has been acceptedOff
MOVINGA move was accepted and has not finishedOn, subject to its continuous permissives
DELIVEREDThe arrival was observedOff
INTERRUPTEDThe accepted work did not finish normallyOff

Write an arrow from IDLE to MOVING. On it, put the conditions that permit acceptance: a fresh Start event, a carton at pickup, an available drive, no arrival already active, and no Stop request.

Write an arrow from MOVING to DELIVERED. Put AtDrop on that arrow. This is the observation that proves normal completion.

Write an arrow from MOVING to INTERRUPTED. Put Stop, loss of drive readiness, or missing arrival after five seconds on it. Five seconds is the chosen limit of this teaching station. A real limit needs a travel distance, speed range, acquisition delay and a reason for the permitted margin.

The diagram is incomplete until you can leave DELIVERED and INTERRUPTED. Delivery needs acknowledgement and a new carton at pickup. Interruption needs a recovery procedure that reconciles the physical carton, then an eligible reset. Neither clearing a sensor nor removing a fault is a new Start request.

The workbench simplifies recovery: release Start and Stop, restore drive readiness, move the carton back to pickup, then issue a new reset edge. That is a declared model procedure, not a universal machine-recovery rule. A real interrupted carton may need removal, inspection or disposal.

Four-state transfer chart: Idle, Moving, Delivered and Interrupted, with acceptance, arrival, interruption and recovery transitions
Read the arrows before the boxes. Start eligibility belongs on the arrow into MOVING. Arrival belongs on the arrow out. Continuous permissions also gate the final output. Eligible recovery includes restored readiness, a carton at pickup, a clear arrival sensor and released Start and Stop.

Fifth: turn the design into three passes

Now the editor has a specific job. Write the program in three passes.

Pass 1 reads events and updates time. Detect a new Start press. Detect acknowledgement and reset events. Call the travel timer every evaluation, including evaluations where its enable is FALSE.

Pass 2 decides one next state. Begin by assuming the state remains unchanged. Evaluate the current state's exit conditions in their agreed priority order. Store the result as the next state.

Pass 3 assigns the physical output once. Combine the state's request with the conditions that must remain true. Do not scatter writes to Q_Belt through every phase.

The final output decision is short because the earlier design did its work:

Q_Belt := (State = 10) AND DriveReady
          AND NOT AtDrop AND NOT StopButton;

In this example 10 is the numeric value assigned to MOVING. The workbench shows the preceding code that reaches and leaves that state. A target project can use a named enumeration if the controller supports it; the decision does not depend on the chosen number.

Read the expression aloud: “Request the belt while the accepted move is active, the drive is ready, arrival has not been detected, and Stop is absent.” Every phrase points back to a requirement. If you cannot explain a term that way, investigate it before adding another one.

Make the smallest wrong program fail

Try this tempting shortcut:

Q_Belt := StartButton AND NOT AtDrop;

Press Start, let the carton leave pickup, then release Start. The belt stops between sensors. The shortcut forgot the accepted job.

Try the opposite shortcut:

Q_Belt := NOT AtDrop;

It runs before anyone has asked for a cycle. It also starts again when a delivered carton is removed. It has no idea what “one carton per request” means.

These examples are useful because each failure names missing information. The first needs remembered intent. The second needs both intent and a completion state. You do not fix either by adding a mysterious delay.

Four-scan comparison showing that direct Start logic stops on button release while a remembered transfer remains active until arrival
The smallest useful test. Scan 2 distinguishes the two programs. A successful demonstration with Start held down cannot reveal this mistake. Predict both output rows before following the trace.

In the workbench, switch on only the memory rule and run the four tests. Then add Stop priority, fresh-Start acceptance and the arrival watchdog. Read the changed source after each addition. Which condition appeared? In which pass? Which test now distinguishes the two drafts?

Keep five artifacts beside the program

You do not need an elaborate document for this exercise. You do need five small artifacts another person can read:

  1. The output contract: what the command physically requests.
  2. The rule list: acceptance, continuous permission, normal completion and interruption.
  3. The signal map: where the necessary evidence actually comes from.
  4. The state-and-transition table: remembered purpose and the conditions on each arrow.
  5. The test histories: inputs over time and the expected state and output.

These are the route from a machine sentence to code. You will refine them throughout the book. A second actuator, a network peer or an analog measurement adds work to the route; it does not remove the route.

Ordinary control examples here are teaching models. Protective safety functions, electrical stopping arrangements and real recovery procedures need their own engineering and validation. Keep that boundary visible when moving from a browser exercise to equipment.

The complete first program

Here are the decisions assembled into one program. Trace each assignment back to the artifacts above. The declarations start in INTERRUPTED, so a cold start requires the declared recovery check before a fresh Start can be accepted. The interactive workbench begins at an already established IDLE condition to let you compare drafts quickly; that is a different starting condition, not an automatic restart policy.

The listing uses local teaching signals. Bind and verify physical I/O in the target project. State values are non-retained here; an actual controller's startup and retention configuration must match the agreed recovery design. This is ordinary control, not a protective safety function.

PROGRAM Transfer
VAR
  StartButton, StopButton, DriveReady : BOOL;
  AtPickup, AtDrop, AckButton, ResetButton : BOOL;
  StartPulse, AckPulse, ResetPulse : BOOL;
  StartWasDown, AckWasDown, ResetWasDown : BOOL := TRUE;
  State : INT := 90;
  NextState : INT;
  Q_Belt : BOOL := FALSE;
  TravelWatch : TON;
END_VAR

(* PASS 1: events and elapsed time, evaluated every scan *)
StartPulse := StartButton AND NOT StartWasDown;
StartWasDown := StartButton;
AckPulse := AckButton AND NOT AckWasDown;
AckWasDown := AckButton;
ResetPulse := ResetButton AND NOT ResetWasDown;
ResetWasDown := ResetButton;
TravelWatch(IN := State = 10, PT := T#5s);

(* PASS 2: one decision about remembered work *)
NextState := State;
CASE State OF
  0: (* IDLE *)
    IF StartPulse AND DriveReady AND AtPickup
       AND NOT AtDrop AND NOT StopButton THEN
      NextState := 10;
    END_IF;
  10: (* MOVING: priority is visible in the order *)
    IF StopButton OR NOT DriveReady THEN
      NextState := 90;
    ELSIF AtDrop THEN
      NextState := 20;
    ELSIF TravelWatch.Q THEN
      NextState := 90;
    END_IF;
  20: (* DELIVERED *)
    IF AckPulse AND AtPickup AND NOT AtDrop
       AND NOT StopButton THEN
      NextState := 0;
    END_IF;
  90: (* INTERRUPTED *)
    IF ResetPulse AND DriveReady AND AtPickup
       AND NOT AtDrop AND NOT StopButton
       AND NOT StartButton THEN
      NextState := 0;
    END_IF;
  ELSE
    NextState := 90;
END_CASE;
State := NextState;

(* PASS 3: exactly one writer of the physical request *)
Q_Belt := (State = 10) AND DriveReady
          AND NOT AtDrop AND NOT StopButton;
END_PROGRAM

Read the decisions, not just the instructions

The three previous-button values begin TRUE. A held button at startup therefore cannot masquerade as a fresh press. After the program has observed a released button, a later press can produce an edge. Those detectors run even when the sequence is interrupted.

The timer is called before selecting the next state. Its enable uses the state at the start of this evaluation. An accepted move first enables timing on the following evaluation. Include that ordering, task period and timer resolution when deriving a real travel limit. Five seconds here is an exercise parameter, not an assertion about a real machine's stopping performance.

NextState := State means “keep doing the same work unless a listed transition wins”. The CASE statement selects one branch using the current state, so returning from INTERRUPTED to IDLE does not also run the IDLE branch in the same evaluation. Reset is not Start.

The output uses the updated State and repeats the continuous permissions. It does not use AtPickup, because the carton normally leaves pickup during travel. Putting AtPickup in that final expression would interrupt a correct move as soon as it began.

Prove three things before you add anything

Input historyExpected resultWhat a different result would expose
Establish recovery; press and release Start before arrival.MOVING remains active and Q_Belt stays TRUE.Missing remembered intent or an acceptance-only condition incorrectly used continuously.
While moving, present Stop and arrival together.INTERRUPTED; Q_Belt FALSE.An incorrect priority or another writer of the output.
Keep Start held through arrival, remove the carton, load another and acknowledge.Return to IDLE without motion. Release and press Start to request a new cycle.A level request accidentally standing in for a fresh event.

The next chapters develop fault records, device feedback, modes and richer recovery. Do not silently assume this compact first program already contains them. Its value is that you can explain every line and show exactly which contract it implements.

Try it

A customer changes our station: “The operator should jog the belt forward only while holding Jog. A carton at PE2 must block forward jogging. Auto mode should still deliver one carton per Start.”

Write the first five artifacts. You do not need to implement a complete mode system yet. Identify the two internal requests, the one physical output owner, which request needs memory, and where the mode conditions belong. Give a test in which Jog is held while Auto is selected.

Work through the answer

The two internal requests are AutoRunRequest and JogRequest. Q_Belt remains the one physical command. AutoRunRequest belongs to the remembered Moving phase. JogRequest depends on the current button and Manual mode; it does not need to remember a released button.

JogRequest := ManualMode AND JogButton;
AutoRunRequest := AutoMode AND (State = 10);

Q_Belt := (AutoRunRequest OR JogRequest)
          AND DriveReady AND NOT AtDrop
          AND NOT StopButton;

This is an output-arbitration excerpt, not the whole mode design. The actual mode logic must prevent simultaneous ManualMode and AutoMode and define what happens to an accepted automatic move when the operator changes mode.

The test starts in Auto with no accepted cycle. Hold Jog and keep all physical permissives true. Q_Belt must remain FALSE, because the manual request is gated by ManualMode. That one negative test exposes an ungated jog branch.

Now move to the behaviour contract. We will make the rule list precise enough that two programmers can implement it without inventing different machines.

Now make the decision yourself

Use the chapter’s model on a fresh question, then compare your reasoning with the worked decision.

How this becomes a program

You have the machine request. What goes on the first line?

Move one carton from PE1 to PE2 after a momentary Start. The belt must not start again when someone removes the carton.

PLCVFDPE1 / AtPickupPLC / StateVFD / Q_Belt

Your first artifact

Write the name of the thing you command: Q_Belt. Under it, write the evidence that would justify turning it on. Do not choose a timer or an IF yet.

Open the worked decision
Q_Belt := (State = 10) AND DriveReady
          AND NOT AtDrop AND NOT StopButton;

Why this line belongs here

The output belongs to Moving, not to the Start button. Start asks for a change of state. Arrival and Stop remove the reason to move. That separation is the first useful piece of your program.

Change the task

The customer changes the job to ‘run only while the operator holds the button’. Which memory requirement disappears? Keep the stop and readiness conditions.

Machine notebook experiment

A simplified browser model. Use it to test an idea; it does not execute a vendor PLC runtime.

Request a transfer, then remove one permission. Predict the output before changing a switch.

A request is only one condition. Permission to move must also be true.