Machines
Assembly machines combine multiple components into finished products. From simple bolt tightening to multi-station sub-assemblies, mastering assembly automation means coordinating timing, force, torque, presence detection, and quality verification across every single step.
Run a complete assembly line. Each station processes one operation per cycle. Watch station states, force curves, and reject logic in real time.
Every assembly machine β regardless of complexity β follows a consistent architectural model: a series of workstations, each performing one discrete operation on a product carrier (pallet or nest). The product moves from station to station via a transfer system. Understanding this model lets you design, commission, and troubleshoot any assembly line.
// Typical 4-station inline assembly machine
// Station 1: Load base component
// Station 2: Insert pin (press-fit)
// Station 3: Apply torque (screwdriving)
// Station 4: Vision check + unload
// Each station has its own:
// - Presence sensor (part here?)
// - Process actuators (press, driver, camera)
// - End-of-cycle signal (done + OK/NOK)
// - Reject/pass output to transfer system
VAR
station_ready : ARRAY[1..4] OF BOOL;
station_done : ARRAY[1..4] OF BOOL;
station_ok : ARRAY[1..4] OF BOOL;
part_present : ARRAY[1..4] OF BOOL;
transfer_running: BOOL;
cycle_count : DINT := 0;
reject_count : DINT := 0;
END_VAR
A 4-station machine runs one cycle every 8 seconds. Station 3 (screwdriving) takes 11 seconds. What is the bottleneck, and what is the actual cycle time?
Press-fit operations insert one component into another by interference fit. The PLC monitors press force vs. position in real time. A good press curve rises smoothly as the part seats. A sudden spike = collision or wrong part. A flat line = missing component or failed tooling. Force/torque data must be logged for every cycle β this is your primary quality evidence.
// Press-fit force monitoring (Structured Text)
VAR
press_position : REAL; // mm, from encoder
press_force : REAL; // N, from load cell
force_min : REAL := 800.0; // N minimum at seat
force_max : REAL := 2500.0; // N maximum allowed
seat_position : REAL := 18.5; // mm expected seat depth
press_result : INT := 0; // 0=idle,1=ok,2=low,3=high,4=collision
END_VAR
// Called every scan during active press
IF press_position >= seat_position THEN
IF press_force < force_min THEN
press_result := 2; // Under-force: missing part or wrong fit
ELSIF press_force > force_max THEN
press_result := 3; // Over-force: wrong part or obstruction
ELSE
press_result := 1; // OK
END_IF;
END_IF;
// Collision detection (force spikes before seat position)
IF press_force > force_max AND press_position < seat_position - 2.0 THEN
press_result := 4; // Collision β stop immediately!
END_IF;
During a press cycle, force reaches 2800 N at position 12 mm, but the seat position is 18.5 mm. What result code is set, and what should the machine do?
Screwdriving stations need torque AND angle monitoring to confirm a good joint. Torque alone can pass a cross-threaded screw. Angle alone can miss a stripped thread. The "torque + angle window" method: the fastener must reach target torque AND be within min/max angle range. Many modern screwdrivers return both values as analog or fieldbus signals.
// Torque + Angle screwdriving verification
VAR
measured_torque : REAL; // Nm
measured_angle : REAL; // degrees
target_torque : REAL := 4.5; // Nm
torque_tol : REAL := 0.5; // Β±Nm
angle_min : REAL := 280.0; // degrees
angle_max : REAL := 360.0; // degrees
screw_result : STRING;
END_VAR
// Evaluate after driver signals complete
IF (measured_torque >= target_torque - torque_tol) AND
(measured_torque <= target_torque + torque_tol) AND
(measured_angle >= angle_min) AND
(measured_angle <= angle_max) THEN
screw_result := 'OK';
ELSIF measured_torque > target_torque + torque_tol THEN
screw_result := 'OVER_TORQUE'; // Possible cross-thread or seized
ELSIF measured_torque < target_torque - torque_tol THEN
screw_result := 'UNDER_TORQUE'; // Possibly not seated
ELSIFF measured_angle < angle_min THEN
screw_result := 'ANGLE_LOW'; // Thread stripped or wrong screw
ELSE
screw_result := 'ANGLE_HIGH'; // Obstruction or wrong part
END_IF;
Torque = 4.3 Nm (target 4.5 Β±0.5 Nm). Angle = 295Β°. Is this screw OK?
Before releasing a product from any station, you must verify all operations completed correctly. Simple presence sensors confirm a component exists; vision systems verify position, orientation, correct part, and surface quality. Both must be integrated into the station logic β a "present but wrong" part is worse than a missing part because it may pass undetected.
// Multi-sensor presence check before station release
VAR
pin_present : BOOL; // Inductive sensor β metal pin seated
clip_present : BOOL; // Capacitive sensor β plastic clip
label_ok : BOOL; // Vision camera β label correct & readable
gasket_ok : BOOL; // Vision β gasket present, no folds
station_release : BOOL;
station_fault : STRING;
END_VAR
station_release := FALSE;
station_fault := '';
IF NOT pin_present THEN
station_fault := 'MISSING_PIN';
ELSIF NOT clip_present THEN
station_fault := 'MISSING_CLIP';
ELSIF NOT label_ok THEN
station_fault := 'LABEL_FAULT';
ELSIF NOT gasket_ok THEN
station_fault := 'GASKET_FAULT';
ELSE
station_release := TRUE; // All checks passed
END_IF;
// Log result either way
IF station_release THEN
cycle_count := cycle_count + 1;
ELSE
reject_count := reject_count + 1;
// Divert to reject lane, alert operator
END_IF;
pin_present=TRUE, clip_present=TRUE, label_ok=FALSE, gasket_ok=TRUE. What is station_fault, and does the product get released?
Each station runs its own state machine: IDLE β CLAMP β PROCESS β VERIFY β RELEASE β RESET. Never skip states, never combine them. This structure makes the code predictable, safe, and easy to extend. The transfer system only advances when ALL stations signal RELEASE simultaneously.
// Single station state machine (ST, runs every PLC scan)
VAR
st_state : INT := 0;
st_timer : TON;
END_VAR
CASE st_state OF
0: // IDLE β wait for part
IF part_present AND transfer_stopped THEN
clamp_close := TRUE;
st_state := 1;
END_IF;
1: // CLAMP β wait for clamp confirmed
IF clamp_confirmed THEN
st_timer(IN:=FALSE);
st_state := 2;
ELSIF clamp_timeout THEN
fault_code := 'CLAMP_TIMEOUT';
st_state := 99; // Fault state
END_IF;
2: // PROCESS (e.g. press, screw, weld)
process_start := TRUE;
IF process_done THEN
process_start := FALSE;
st_state := 3;
END_IF;
3: // VERIFY all sensors
IF all_sensors_ok THEN
product_result := 'OK';
st_state := 4;
ELSE
product_result := 'NOK';
st_state := 4; // Still release β machine handles NOK routing
END_IF;
4: // RELEASE β signal transfer system
clamp_close := FALSE;
station_done := TRUE;
IF transfer_advancing THEN
station_done := FALSE;
st_state := 0;
END_IF;
99: // FAULT β operator intervention needed
alarm_active := TRUE;
IF fault_reset AND NOT fault_present THEN
alarm_active := FALSE;
st_state := 0;
END_IF;
END_CASE;
The station is in state 2 (PROCESS). The operator opens the guard door, which de-energises the safety relay and kills all outputs. When the door closes and outputs are restored, what state should the machine resume in, and why?
Every NOK product must be physically separated and its data retained. This requires: a divert mechanism (pneumatic gate, push-off pin, separate lane), a unique carrier ID (barcode or RFID pallet tag), and a database write linking carrier ID to all station results. Traceability is not optional in regulated industries β it is a legal requirement.
// Reject management + traceability data structure
TYPE AssemblyRecord :
STRUCT
carrier_id : DWORD; // Pallet/nest RFID tag
timestamp : STRING[20];
st1_result : STRING[8]; // 'OK' / 'NOK' / 'SKIP'
st2_force : REAL; // Actual press force N
st2_result : STRING[8];
st3_torque : REAL; // Actual torque Nm
st3_angle : REAL; // Actual angle deg
st3_result : STRING[8];
st4_vision : STRING[8];
final_result : STRING[8]; // 'OK' only if ALL stations OK
END_STRUCT
END_TYPE
// Reject gate control
IF current_record.final_result = 'NOK' THEN
reject_gate := TRUE; // Open divert gate
st_timer(IN:=TRUE, PT:=T#2s);
IF st_timer.Q THEN
reject_gate := FALSE; // Close after product passes
st_timer(IN:=FALSE);
END_IF;
END_IF;
// Write record to database (via OPC-UA or fieldbus)
// db_write(record := current_record);
A product passes Station 1 (OK) and Station 2 (OK) but fails Station 3 (NOK). Station 4 vision check passes. What is final_result?