Over 20 years designing, building, and automating industrial and vehicle systems — SolidWorks CAD through to PLC programming, on projects from a single fix to full production lines.
| TITLE | Mechanical Design & Automation |
| DRAWN | R. DAVIS |
| SCALE | N.T.S. |
| SHEET | 1 OF 1 |
| REV | A |
The design and control work is still done properly, by hand, to the same regulations as always — the AI layer sits on top, speeding up iteration and catching things sooner.
Mechanical design and PLC programming aren't handled separately — the same person carries a project from the CAD model to the control logic that runs it, all to PUWER, LOLER, and Machinery Regulation (EU) 2023/1230.
A working portfolio — add a sheet for each project as it's completed.
Final specification from a real Genesis session, taken through all eight stages — two modulating intake vents and two boost fans, switchable between PI(D) target control and the original hysteresis range mode, with food-probe alerts, low-fuel detection and battery-aware shutdown over BLE and home Wi-Fi. Design complete and reviewed; bench validation not yet built.
| 0 · INTAKE | Closed |
| 1 · DESCRIPTION OF OPERATION | Closed — final spec confirmed by client |
| 2 · PLC LOGIC | Closed, pending client sign-off on the logic itself |
| 3 · I/O DEFINITION | Closed — every I/O traces to Stage 2 |
| 4 · BENCH VALIDATION | Open — rigs designed, not yet built |
| 5 · HARDWARE ARCHITECTURE | Closed with flags — IP68 servo & fan sourcing still open |
| 6 · FIRMWARE TRANSLATION | Closed — ESP32-C6, ESP-IDF, control code verified against the ST |
| 7 · REVIEW & ITERATION | Closed — every Stage 1 requirement traced through |
| 8 · COST & TIME ESTIMATE | Closed |
(* =====================================================================
BBQ VENT & FAN CONTROLLER — GENESIS STAGE 2 PLC LOGIC (rev C, FINAL SPEC)
Two modulating intake vents, two boost fans, TARGET (PI(D)) and RANGE
(hysteresis) control modes, food-probe alerts, low-fuel detection,
battery-aware shutdown. Never compiled or run — see Stage 4.
===================================================================== *)
(* ---------------------------------------------------------------------
FB: PI(D) controller for vent position, output 0..100 %
Derivative on measurement; integrator clamped (anti-windup);
bumpless initialisation to the current vent position.
--------------------------------------------------------------------- *)
FUNCTION_BLOCK PID_Vent
VAR_INPUT
SP : REAL; (* target temperature, deg C *)
PV : REAL; (* pit temperature, deg C *)
Kp : REAL; (* % vent per deg C *)
Ti_s : REAL; (* integral time, s (0 = no integral) *)
Td_s : REAL; (* derivative time, s *)
dt_s : REAL; (* sample interval, s *)
Init : BOOL; (* TRUE = bumpless start from InitOut *)
InitOut : REAL; (* current vent position, % *)
END_VAR
VAR_OUTPUT
Out : REAL;
END_VAR
VAR
I : REAL;
PrevPV : REAL;
E : REAL;
D : REAL;
U : REAL;
END_VAR
E := SP - PV;
IF Init THEN
I := InitOut - Kp * E;
PrevPV := PV;
END_IF;
IF Ti_s > 0.0 THEN
I := I + Kp * dt_s / Ti_s * E;
END_IF;
IF I > 100.0 THEN I := 100.0; ELSIF I < 0.0 THEN I := 0.0; END_IF;
D := -Kp * Td_s * (PV - PrevPV) / dt_s;
PrevPV := PV;
U := Kp * E + I + D;
IF U > 100.0 THEN U := 100.0; ELSIF U < 0.0 THEN U := 0.0; END_IF;
Out := U;
END_FUNCTION_BLOCK
(* ---------------------------------------------------------------------
FB: one vent channel — servo + closed-end position sensor
Checks position only where the single sensor can prove it:
target <= 0.5 % -> sensor must read closed
target >= 10 % -> sensor must read NOT closed
0.5..10 % -> no check (sensor ambiguous near closed)
On a failed check: back off to 50 %, re-approach once, then fault.
--------------------------------------------------------------------- *)
FUNCTION_BLOCK VentChannel
VAR_INPUT
Demand : REAL; (* 0 = closed (bleed) .. 100 = fully open *)
AtClosed : BOOL; (* TRUE = vent at closed end *)
MoveTime : TIME; (* allowed time for a full stroke *)
END_VAR
VAR_OUTPUT
ServoPos : REAL; (* position command to servo, % *)
Moving : BOOL;
PosFault : BOOL; (* "Vent N failed to reach position" *)
FullyOpen : BOOL; (* settled at >= 99.5 % with no fault *)
END_VAR
VAR
Step : INT := 1; (* 0 settled, 1 moving, 2 back-off, 3 re-approach *)
Target : REAL;
FirstScan : BOOL := TRUE;
MoveTmr : TON;
PositionOK : BOOL;
END_VAR
IF FirstScan THEN
Target := Demand;
FirstScan := FALSE;
END_IF;
IF ABS(Demand - Target) > 0.1 THEN
Target := Demand;
MoveTmr(IN := FALSE);
Step := 1;
END_IF;
IF Target <= 0.5 THEN
PositionOK := AtClosed;
ELSIF Target >= 10.0 THEN
PositionOK := NOT AtClosed;
ELSE
PositionOK := TRUE;
END_IF;
CASE Step OF
0: ServoPos := Target;
1: ServoPos := Target;
MoveTmr(IN := TRUE, PT := MoveTime);
IF MoveTmr.Q THEN
MoveTmr(IN := FALSE);
IF PositionOK THEN
PosFault := FALSE;
Step := 0;
ELSE
Step := 2;
END_IF;
END_IF;
2: ServoPos := 50.0; (* back off *)
MoveTmr(IN := TRUE, PT := MoveTime);
IF MoveTmr.Q THEN
MoveTmr(IN := FALSE);
Step := 3;
END_IF;
3: ServoPos := Target; (* single retry *)
MoveTmr(IN := TRUE, PT := MoveTime);
IF MoveTmr.Q THEN
MoveTmr(IN := FALSE);
PosFault := NOT PositionOK; (* warning only; keep commanding target *)
Step := 0;
END_IF;
END_CASE;
Moving := Step <> 0;
FullyOpen := (Target >= 99.5) AND (Step = 0) AND NOT PosFault;
END_FUNCTION_BLOCK
(* ---------------------------------------------------------------------
MAIN PROGRAM — modes, both control strategies, fan boost, alarm band,
low fuel, food probes, battery shutdown, servo power switching, LED.
Full I/O list and tuning table are in the Genesis project document —
condensed here for the works sheet.
--------------------------------------------------------------------- *)
PROGRAM BBQ_Vent_Fan_Control
VAR_INPUT
(* From app: BLE or home Wi-Fi *)
CmdStart, CmdStop : BOOL;
ControlMode : INT := 1; (* 1 = TARGET, 2 = RANGE *)
PitTarget : REAL := 110.0;
AlarmLow, AlarmHigh : REAL := 100.0, 125.0;
RangeLow, RangeHigh : REAL := 105.0, 120.0;
Food1Enable, Food2Enable: BOOL;
Food1Target, Food2Target: REAL := 95.0, 95.0;
CriticalVentPos : REAL := 0.0; (* vent position at 5% battery *)
(* From hardware *)
PitTemp, Food1Temp, Food2Temp : REAL;
PitProbeOpen, Food1ProbeOpen, Food2ProbeOpen : BOOL;
V1_AtClosed, V2_AtClosed : BOOL;
BatteryPct : REAL;
END_VAR
VAR_OUTPUT
Vent1Pos, Vent2Pos : REAL;
ServoPowerEn : BOOL; (* servo rail on only while moving *)
Fan1On, Fan2On : BOOL; (* per-vent interlock: never without its vent fully open *)
ShutdownReq : BOOL;
ModeState : INT; (* 0 IDLE, 1 MONITORING, 2 SHUTDOWN *)
StartRejected : BOOL;
Fault_PitProbeDisconnected, Fault_PitReadingImplausible : BOOL;
Fault_Food1Probe, Fault_Food2Probe : BOOL;
Fault_Vent1Position, Fault_Vent2Position : BOOL;
Warn_BatteryLow, Alert_BatteryCritical : BOOL;
Alert_PitHigh, Alert_PitLow, Alert_LowFuel : BOOL;
Alert_Food1Near, Alert_Food1Done : BOOL;
Alert_Food2Near, Alert_Food2Done : BOOL;
StatusLEDOut : BOOL; (* off / steady / 1 Hz blink on fault *)
END_VAR
VAR
State : INT := 0; (* not retained across power loss *)
VentDemand : REAL := 100.0;
Kp : REAL := 4.0; Ti_s : REAL := 600.0;
MoveTime : TIME := T#3S; FanDelay : TIME := T#3M;
LowFuelWindow : TIME := T#10M; LowFuelMinDrop : REAL := 2.0;
PID : PID_Vent;
Vent1, Vent2 : VentChannel;
(* internals: sample timer, probe-jump check, fan/band/low-fuel
timers, shutdown timer, servo-off timer, LED blink timer — see
the full listing in the Genesis project document *)
END_VAR
(* Pit probe validity: open-circuit OR out of plausible range OR
a jump > 25 deg C in one 1 s sample *)
Fault_PitProbeDisconnected := PitProbeOpen;
Fault_PitReadingImplausible := NOT PitProbeOpen
AND ((PitTemp < -20.0) OR (PitTemp > 600.0) /* OR PitJump */);
(* Mode control: IDLE -> MONITORING on App START, guarded by valid
settings, a healthy pit probe and battery >= 5%. SHUTDOWN pre-empts
everything once battery stays below 5% for 5 s. *)
CASE State OF
0: (* IDLE: vents 100%, fans off *)
VentDemand := 100.0;
IF CmdStart AND NOT CmdStop THEN
(* SettingsOK AND PitProbeOK AND battery >= 5% -> State := 1
else -> StartRejected := TRUE *)
END_IF;
1: (* MONITORING: TARGET runs PID_Vent every 1 s sample; RANGE
is the open-below-Low / closed-above-High hysteresis.
Either mode drives FAN BOOST once both vents are fully
open and the pit is still below target/Low for FanDelay.
A pit probe fault holds the vents and stops the fans,
with automatic resume once the probe is healthy again. *)
;
2: (* SHUTDOWN: vents move to CriticalVentPos, fans stop, a
final alert goes out, ShutdownReq after 15 s *)
;
END_CASE;
(* Vents: one VentChannel FB each, closed-end position check with
one back-off-and-retry. Servo rail switched on only while moving,
+0.5 s, to save battery. *)
Vent1(Demand := VentDemand, AtClosed := V1_AtClosed, MoveTime := MoveTime);
Vent2(Demand := VentDemand, AtClosed := V2_AtClosed, MoveTime := MoveTime);
Vent1Pos := Vent1.ServoPos; Vent2Pos := Vent2.ServoPos;
(* Fans: per-vent interlock — a fan never runs unless its own vent
has reached fully open *)
Fan1On := (State = 1) AND Vent1.FullyOpen /* AND FanReq */;
Fan2On := (State = 1) AND Vent2.FullyOpen /* AND FanReq */;
(* Food probes: near/done alerts in any state, fault on disconnect *)
Alert_Food1Done := Food1Enable AND NOT Food1ProbeOpen AND (Food1Temp >= Food1Target);
Alert_Food2Done := Food2Enable AND NOT Food2ProbeOpen AND (Food2Temp >= Food2Target);
END_PROGRAM
A structured, staged process for replacing a PLC with a custom-built controller — starting from a genuine blank slate and ending in a fully proven, documented design.
An illustrative walk-through of the tool — step through it below with a sample system (a tank fill with a pump interlock). Your own system gets asked through the same process before anything's drawn.
That's the logic worked out — and it's already clear this isn't a small job. Interlocks, fault behaviour, the physical build, getting it actually running on real hardware — that's the part that needs a proper conversation, not a demo.
Try it for realA digital twin dashboard that reads straight out of the SolidWorks model and drives it against a live PLC in real time, through a single master tag register — no manual re-entry between CAD and control.
The front end works — this is a real dashboard driving a real PLC, not a mock-up. The self-serve version isn't open yet, so for now it's delivered the same way the rest of my work is: hands-on, project by project.
Ask about thisAlready a client? Access your project space — files, comments, and progress in one place.
Client loginSend over what you're working with — a sketch, a spec, or just a description of the problem. I'll look it over and reply with next steps. If you'd rather talk it through first, you can book a call once you've sent your enquiry.
Got it — I'll look over what you've described. If you'd rather not wait for a reply, grab a slot directly:
Book a call