A complete industrial control and data pipeline: an Allen-Bradley-style PLC owns machine safety and sequencing, an Aerotech-style three axis stage handles precision positioning, a C#/WPF supervisory application orchestrates the cycle, and every part is traceable in SQL with OEE reporting.
The point of the project is the architecture, not hardware ownership. The load-bearing claim is:
Safety and sequencing live in the PLC. Precision positioning lives in the motion controller. The supervisory application coordinates and records, and it never owns safety.
The HMI speaks genuine OPC UA over TCP to a separate process running a real fixed-period scan engine. The supervisory application cannot tell it is talking to a simulator, which is the whole point of the seam.
Station.Core can request a clamp, but the PLC decides. The clamp rung is:
XIC(C_ClampRequest) XIC(S_MotionPermissive) XIC(I_PartPresent) OTE(O_ClampSolenoid);Losing the permissive drops the solenoid on the very next scan without the supervisory request
changing at all. The E-stop latch is set on first scan and on any chain break, and clears only when
the chain is restored and a reset is issued, so the machine is never self-starting after a power
cycle. Recovering from an emergency stop forces a return to Offline and a full re-home; a
recoverable fault only returns to Idle.
Station.sln
src/
Station.Core/ domain, StationStateMachine, CycleOrchestrator, driver interfaces
Station.Plc/ OpcUaPlcDriver: session, subscriptions, tag map
Station.Motion/ trapezoidal profiles, coordinated moves, simulated stage and metrology
Station.Data/ schema.sql, seed.sql, Dapper repositories, OeeCalculator
Station.Hmi/ WPF + MVVM dashboard (entry point)
sim/
SoftPlc/ scan engine + safety chain + OPC UA server
ladder/ ladder.L5X (Studio 5000 import format, 16 rungs)
aeroscript/ home.ascript, inspect.ascript (Automation1)
tests/
Station.Core.Tests/ SoftPlc.Tests/ Station.Motion.Tests/ Station.Data.Tests/
Station.Plc.IntegrationTests/ live OPC UA session against a hosted soft PLC
Station.EndToEnd.Tests/ full production runs across every layer
Requires the .NET 8 SDK. Nothing else needs installing: the database is SQLite and the PLC and stage are simulated.
dotnet build Station.sln
dotnet test Station.sln
dotnet run --project sim/SoftPlc # terminal 1: the controller
dotnet run --project src/Station.Hmi # terminal 2: the supervisory applicationThe soft PLC console is interactive when attached to a terminal:
| key | action |
|---|---|
e |
toggle the emergency stop |
l |
toggle the light curtain |
g |
toggle the guard door |
r |
safety reset |
s / x |
cycle start / stop pushbuttons |
The HMI connects automatically on start. Pick an operator and recipe, set a part count, press Start, then break the light curtain from the PLC console and watch motion halt, the permissive lamp drop and the station latch out.
SELECT c.PartSerial, c.CycleTimeMs, c.Passed, m.FeatureName,
m.CommandedX, m.ActualX, m.FollowingErrorMm, m.MeasuredMm, m.NominalMm
FROM Cycles c JOIN Measurements m ON m.CycleId = c.CycleId
ORDER BY c.CompletedAt DESC;Measurements stores commanded and actual stage position, which is what makes the position
accuracy figure real rather than decorative.
OEE is the genuine three factor product computed in OeeCalculator from StateHistory and Cycles:
Availability (run time / planned time) x Performance (ideal cycle time x count / run time) x
Quality (good / total). Time in Offline is excluded from planned production; time in Faulted and
EmergencyStopped counts as downtime.
