MECHANICAL DESIGN & AUTOMATION
Mechanical design & automation, Leeds / Wakefield

From your imagination to a running machine.

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.

TITLEMechanical Design & Automation
DRAWNR. DAVIS
SCALEN.T.S.
SHEET1 OF 1
REVA
B.Eng (Hons) Mechanical Engineering & Design — AutoCAD 2D/3D certified — SolidWorks Expert
SOLIDWORKS Associate — Mechanical Design SOLIDWORKS Professional — Mechanical Design SOLIDWORKS Professional — Drawing Tools SOLIDWORKS Professional — Sheet Metal SOLIDWORKS Professional — Weldments
⊢ 20+ YRS ⊣
20+
Years in mechanical design & automation
⊢ SCALE ⊣
£400K
Largest individual projects delivered
⊢ TEAM ⊣
25
Largest team led on a single project
⊢ RESULT ⊣
10–20%
Typical sustained cost reduction achieved
DESIGN IT. AUTOMATE IT.

Now with agentic AI in the loop.

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 designSolidWorks, FEA
PLC automationSiemens, Schneider
Compliance & testingPUWER, LOLER, Machinery Regulation (EU) 2023/1230
Agentic AI layer
Faster iterationDraft to review, same day
Autonomous diagnosticsCatch clashes before build
Predictive maintenanceFlag drift before failure
WHAT I DO

Design and automation, under one roof.

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.

Metal fabrication design
Design & manufacturing
R&D
FEA & motion analysis
Flow analysis
PLC & automation
WORKS

Recent plates.

A working portfolio — add a sheet for each project as it's completed.

Automatic BBQ vent & fan controller

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.

DWG NO. 001 · REV C · FINAL SPECIFICATION
DWG NO. 001 · REV C · STAGES 0–8 STATUS
0 · INTAKEClosed
1 · DESCRIPTION OF OPERATIONClosed — final spec confirmed by client
2 · PLC LOGICClosed, pending client sign-off on the logic itself
3 · I/O DEFINITIONClosed — every I/O traces to Stage 2
4 · BENCH VALIDATIONOpen — rigs designed, not yet built
5 · HARDWARE ARCHITECTUREClosed with flags — IP68 servo & fan sourcing still open
6 · FIRMWARE TRANSLATIONClosed — ESP32-C6, ESP-IDF, control code verified against the ST
7 · REVIEW & ITERATIONClosed — every Stage 1 requirement traced through
8 · COST & TIME ESTIMATEClosed
Nothing on this sheet is physically proven — a complete, reviewed design, not a validated one.
DWG NO. 001 · REV C · STAGE 2 STATE DIAGRAM
State diagram — automatic BBQ vent and fan controller
DWG NO. 001 · REV C · PLC LOGIC (STRUCTURED TEXT, IEC 61131-3) — PID_Vent · VentChannel · BBQ_Vent_Fan_Control
(* =====================================================================
   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
GENESIS
What is Genesis?

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.

  • Behaviour is defined and signed off before any logic is written
  • Every input and output comes straight from that confirmed logic — nothing speculative
  • Proven on a low-cost bench rig before any real hardware is designed
  • Nothing invented — every part, price, and standard cited is checked and current
  • Ends in one master document — logic, wiring, BOM, schematic, firmware — yours outright
Let there be logic.

Describe your machine. Watch it become control logic.

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.

1. Describe
2. Logic diagram
3. ST draft
4. Next steps
GENESIS
What starts this system running?
YOU
An operator presses start, once the tank is confirmed empty.
GENESIS
Understood. If the level sensor fails mid-fill, should the pump stop and hold, or stop and alarm for reset?
YOU
Stop and alarm — nobody should restart it without checking.
[IDLE] --start & tank empty--> [FILLING] --level = high--> [FULL] [FILLING] --sensor fault--> [ALARM] --manual reset--> [IDLE] [FULL] --drain cmd--> [DRAINING] --level = low--> [IDLE]
IF Start AND TankEmpty THEN
  State := FILLING;
  PumpIn := TRUE;
END_IF
IF State = FILLING AND SensorFault THEN
  State := ALARM;
  PumpIn := FALSE;
END_IF
…
Full draft unlocked after enquiry

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 real
This section shows a fixed example. Try the real thing with your own system.
MISSION CONTROL

Live SolidWorks, bridged to real PLC hardware.

A 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.

TAG REGISTER
128 mapped
PLC LINK
Modbus TCP
SOLIDWORKS SYNC
Live
CYCLE STATE
Running
PRELIMINARY
NOT FOR PUBLIC USE

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 this
STATUS  ·  In development  ·  Available today as an engineering service

Already a client? Access your project space — files, comments, and progress in one place.

Client login
START A PROJECT

Tell me about it.

What happens next

Send 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.

EMAIL   r.davis175@tiscali.co.uk
PHONE   07971 253875
BASED   Leeds / Wakefield, UK

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