← SHEET 02 · ASSEMBLIES EL-002

Folding-Stair Actuator Controller

ELHW
LIVE DRAWING — HOVER OR DRAG TO CRANK · BUILT FROM THE REAL PLANT PARAMETERS
PART NOEL-002
MATL / SYSTEMESP32 · BTS7960 · 12V LINEAR ACTUATOR
TOOLSArduino IDE · Wokwi · C++

The drive electronics for HW-002, the folding parallelogram staircase already welded, installed, and in daily use in my split-level bedroom. That project ended with two manual latches; this one replaces them with an ESP32 + BTS7960 H-bridge driving a self-locking 12V linear actuator, with limit switches for the two end-stops and current sensing to soft-stop the ramp if the mechanism meets an obstruction instead of grinding through it.

OVERVIEW & MOTIVATION

HW-002’s build notes flagged motorized deployment as planned future work: “size a self-locking 12V linear actuator for motorized deployment against the ~1251 mm rail geometry and 900 mm rise.” This project is that sizing exercise carried through to a working control design — a five-state firmware (STOWED / DEPLOYING / DEPLOYED / STOWING / FAULT), soft-start/soft-stop PWM ramping so the linkage never gets a hard jolt of torque, limit switches that define the two valid end positions, and current-threshold obstruction detection so a foot, a dropped object, or a binding hinge stops the actuator instead of stalling the motor or bending the linkage. The self-locking actuator choice matters as much as the electronics: it holds the stair’s position with zero holding current, so a power cut mid-stroke can’t let a partially-deployed stair free-fall.

COMPONENTS & BOM

REFCOMPONENTSPECROLE
U1ESP32 DevKit-CESP32-WROOM-32, Arduino core 3.xruns the state machine, PWM ramp, ADC
U2BTS7960 module43A dual half-bridge, RPWM/LPWM/R_EN+L_ENdrives the 12V linear actuator
M112V linear actuatorself-locking (leadscrew/worm), stroke sized to rail travelmotorizes HW-002’s deploy/stow swing
U3ACS712 current sensorratiometric Hall-effect, in series with 12V B+obstruction/stall detection for soft-stop
SW1Limit switch — deployednormally-open, rail end-stopmarks full-deploy travel limit
SW2Limit switch — stowednormally-open, rail end-stopmarks full-stow travel limit
SW3Pushbutton — deploymomentary, INPUT_PULLUPcommands DEPLOYING
SW4Pushbutton — stowmomentary, INPUT_PULLUPcommands STOWING
D1Status LED5 mm + 220R series resistorstate indicator (off / slow-blink / solid / fast-blink)
PSU112V supplysized to actuator stall current + margin, fusedactuator power rail, routed through U3

WIRING

BTN DEPLOY BTN STOW STATUS LED ESP32 DEVKIT-C BTS7960 H-BRIDGE ACS712 CURRENT SENSE 12V SUPPLY 12V LINEAR ACTUATOR (SELF-LOCKING) LIMIT — DEPLOYED LIMIT — STOWED VIN 3V3 GND VCC GND VCC GND GND / RETURN SIGD18 SIGD19 D2+ D25RPWM D26LPWM D27R_EN+L_EN D34OUT D32LIM D33LIM M++ M-- B+ B+
ESP32 PINNETPERIPHERAL PIN
GPIO25 (D25)RPWMBTS7960 RPWM (forward/extend PWM)
GPIO26 (D26)LPWMBTS7960 LPWM (reverse/retract PWM)
GPIO27 (D27)DRV_ENBTS7960 R_EN + L_EN (tied together)
GPIO32 (D32)LIM_DEPLOYEDlimit switch, deployed end-stop
GPIO33 (D33)LIM_STOWEDlimit switch, stowed end-stop
GPIO18 (D18)BTN_DEPLOYdeploy pushbutton
GPIO19 (D19)BTN_STOWstow pushbutton
GPIO2 (D2)STATUS_LEDstatus LED (via 220R)
GPIO34 (D34)CURRENT_SENSEACS712 OUT (analog)
3V3ACS712 VCC (kept at 3.3V so its output stays inside the ESP32 ADC range)
VIN (5V)BTS7960 VCC (logic supply)
GNDcommon return — ESP32, BTS7960, ACS712, switches, 12V supply

CONTROL LOGIC

Five states — STOWED, DEPLOYING, DEPLOYED, STOWING, FAULT — driven by two buttons and two limit switches, with the actuator PWM ramped rather than switched, and an obstruction watchdog running only once the ramp is fully up to cruise speed (so ramp-up inrush current never false-triggers a stall):

void serviceRamp(unsigned long now) {
  if (activeDir == Dir::NONE) return;
  if (now - lastRampStepMs < RAMP_STEP_MS) return;
  lastRampStepMs = now;
  if (currentDuty < targetDuty) {
    uint16_t next = (uint16_t)currentDuty + RAMP_UP_STEP_DUTY;
    currentDuty = (next >= targetDuty) ? targetDuty : (uint8_t)next;
  } else {
    uint16_t drop = min<uint16_t>(currentDuty, RAMP_DOWN_STEP_DUTY);
    currentDuty -= drop;
  }
  pwmWrite(activeDir, currentDuty);
}

Obstruction detection reads the ACS712 through a design-derived, not bench-measured, scale factor (3.3V-powered ACS712-05B, ~122 mV/A) and only counts a hit once it has held above threshold for OBSTRUCTION_DEBOUNCE_MS:

float readCurrentAmps() {
  float volts = (analogRead(PIN_CURRENT) / 4095.0f) * 3.3f;
  return fabsf((volts - 1.65f) / (122.0f / 1000.0f));
}

A confirmed obstruction ramps the drive to zero, fires a brief reverse “relief” pulse to unbind the linkage, then retries the same direction — up to MAX_RETRIES (2) before the controller gives up and enters FAULT, de-energizing DRV_EN entirely. FAULT only clears on a deliberate 2-second hold of both buttons together, and resumes from whichever limit switch actually reads active rather than assuming a position.

SIMULATION

Wokwi has no BTS7960, ACS712, or linear-actuator part, so diagram.json approximates the rig rather than simulating it literally — the same approach already used for the L298N in this site’s line-follower project and the INA219 in the power-monitor project:

  • BTS7960 — not a Wokwi part. Its three control lines (RPWM, LPWM, R_EN+L_EN) are each broken out to a labeled LED through a 220R resistor, so the ramp and enable logic are visible as brightness/blink without an actual H-bridge behind them.
  • 12V linear actuator — no linear-actuator or plain DC-motor part exists in Wokwi either; its motion is represented indirectly through the RPWM/LPWM LED brightness and by manually toggling the limit-switch pushbuttons to simulate the rail reaching an end-stop.
  • ACS712 — substituted with a potentiometer labeled I stand-in (no ACS712 in Wokwi), wired into GPIO34 exactly like the real sensor’s analog output, so dragging it exercises the same readCurrentAmps() / obstruction-threshold code path.
  • Limit switches and pushbuttons — real wokwi-pushbutton parts, not stand-ins; a limit switch is electrically a momentary contact to ground, identical to a pushbutton.

Steps: open wokwi.com, New Project → ESP32, paste in sketch.ino and diagram.json, press Play. Clicking btnDeploy should ramp ledRpwm up smoothly rather than snapping on; clicking the deployed limit-switch button ramps it back down and the status LED goes solid. Dragging the current-sense potentiometer above threshold and holding it there triggers the retry sequence on the serial monitor, and past MAX_RETRIES trips FAULT (fast LED blink), clearable by holding both buttons for 2 seconds.

STATUS

HW-002 itself is built, welded, and in daily manual use — two hand latches hold it deployed or stowed today. This controller is design and firmware-simulation stage only: the state machine, PWM ramp, and obstruction logic are written and exercised in Wokwi against the substitutions above, but no BTS7960, ACS712, or actuator has been bench-tested, and nothing here is wired to the physical stair yet. OBSTRUCTION_THRESHOLD_A is a datasheet- derived placeholder pending a real bench measurement of the actuator’s no-load and stall current.

USE CASES & APPLICATIONS

The same pattern — limit-switched travel, soft-start/soft-stop ramping, and current-sensed obstruction cutoff — covers most small linear-actuator automation: motorized attic hatches and loft ladders, automatic gate and barrier operators, hospital-bed and recliner positioning actuators, and retractable equipment covers or ramps. Anywhere a linear actuator moves through a space people or objects can be in, current-sensing soft-stop is the cheap, effective substitute for a proper force/torque sensor.

FILES

  • sketch.ino — full ESP32 firmware: state machine, non-blocking PWM ramp, debounced limits/buttons, current-threshold obstruction detection with retry-then-fault logic. Header comment carries the full pinout.
  • diagram.json — Wokwi wiring diagram, pin-identical to the firmware, with the honest part substitutions listed above.
  • README.md — run-in-Wokwi steps, real-build 12V supply sizing notes, and why a self-locking actuator means power-off holding with zero standing current.

← BACK TO ASSEMBLIES

NAME ODILBEK MARIMOV
DWG NO. PF-2026
SHEET 01 / 07
DISCIPLINE ROBOTICS / MECHATRONICS
SCALE 1:1
REV A
THIRD-ANGLE PROJECTION
DATE 2026-07-11
UNITS mm