Skip to main content

Protective Stop

Assembled Protective Stop remote with a red stop button, printed enclosure, and Ethernet side pod

OSHWA open source hardware certification mark, UID US002846

Protective Stop is an open hardware remote for robots and automation. A PoE- or USB-powered ESP32-S3 watches a physical stop switch and reports its state to machine-side pstop logic. A STOP message, a wiring fault, or a lost heartbeat causes the machine process to request STOP.

Each machine sets its own heartbeat window; the remote normally transmits halfway through it. The network update rate is therefore configured, not fixed.

This is a protective stop, not an emergency stop. It does not replace a required emergency-stop function, including hardwired power removal where applicable. OSHWA certification covers open source hardware; it is not functional-safety certification.

How it works​

The switch has two normally closed contacts, each wired to a separate GPIO loop and read by one CPU core. Each core builds the full pstop message independently; transmission occurs only when both encoded messages match exactly.

Pressing the switch opens both loops and sends STOP. A broken wire or other fault in one loop makes the cores disagree, while a stalled task or loss of all network paths prevents transmission. In either case, the machine requests STOP when its silence timeout expires.

The wire protocol and machine-side state logic come from vendored pstop_c, which remains unchanged and follows a separate certification track. The surrounding firmware handles sensing, networking, and recovery.

Peers addressed directly over LAN or USB-NCM bypass Tailscale and are not WireGuard-encrypted. Tailscale peers use WireGuard, with DERP relay fallback when a direct path is unavailable. Their sockets are pinned to the tunnel, so losing the VPN causes silence instead of a plaintext downgrade. Ethernet is preferred, with USB-NCM and WiFi available as fallbacks.

Complex scenarios​

One machine can bond several remotes, and the machine runs only while all of them report OK. Which remote may re-arm after a stop depends on roles, arming ownership, and heartbeat timeouts. Multi-remote, single machine walks through two remotes under each combination of stop, drop, and unbond, and gives the number of remotes one machine can hold. Single remote, multiple machines describes how one remote's button and heartbeats reach up to four machines.

What's included​

PathContents
hardware/Editable FreeCAD enclosure, printable files, BOM, wiring, and photographed assembly guide
firmware/ESP-IDF remote firmware and the dual-core sensing/comparison logic
host/Plain-C machine process and its documented configuration
ros2/ROS 2 machine node and messages
components/Embedded networking, USB tether, and pstop_c integration
docs/API, recovery, testing, networking, and safety-case documentation
tools/ and test/Protocol, chaos, soak, flashing, and static-analysis tools (see the tools guide for the uv setup)

Tailscale support uses microlink, an embedded client from Malone Technologies.

ROS Support​

The protective stop machine node is compatible with the following ros2 Distros:

  1. Humble (until May 2027)
  2. Jazzy (until May 2029)
  3. Lyrical (not yet supported, but planned to be supported as soon as possible!)

Build and run​

Quickstart walks a fresh laptop through the whole thing: Tailscale account and key, USB tether, build and flash, the ROS 2 machine node, pairing, and a bench test through STOP and ARM. The short version (ESP-IDF 5.5 required):

cp firmware/sdkconfig.credentials.example firmware/sdkconfig.credentials
$EDITOR firmware/sdkconfig.credentials # Tailscale auth key + admin password
cd firmware && . ~/esp/esp-idf/export.sh
idf.py -DPSTOP_PROFILE=dev build && idf.py -p /dev/ttyACM0 flash # dev profile: bench only

cd ../tools && uv sync # once: the Python environment for flashing and tests, see developing/testing/tools.md
cd ../ros2 && colcon build --packages-up-to protective_stop_machine
ros2 run protective_stop_machine machine_bridge_node
curl -X POST "http://<remote>/api/pstop_peer?ip=<laptop-tailscale-ip>&port=8890"

A plain-C machine process (cd host && make && ./machine_app_runner) is the non-ROS alternative. Later firmware updates go over the authenticated admin API (POST /admin/api/ota). Hardware assembly starts with the hardware guide and the photographed assembly guide.

Timing and arming​

The network update rate and stop-on-silence time are machine-controlled:

remote send interval = clamp(heartbeat_ms / 2, 100 ms, 1000 ms)
stop-on-silence time = heartbeat_ms * max_missed_heartbeats

The default configuration uses a 400 ms heartbeat window and five missed windows, giving a send interval of about 200 ms and a stop-on-silence threshold of about 2 seconds. Integrators should choose values within the validated limits so the timeout fits their process safety time and network conditions.

The machine starts stopped. To arm it, press and hold the switch for at least min_stop_ms (500 ms by default), then release it. Whether a remote may re-arm is the remote's own declared role: a new remote announces stop_only (it can stop a machine but never arm it) until promoted to operator through its authenticated /api/role. The change applies live — an armed machine keeps running when its operator demotes itself, but refuses to re-arm until a remote announcing operator performs the gesture.

Machines optionally restrict who may bond at all with a global allowlist and/or denylist (empty by default = everyone). A refused remote is told so (UNBOND) and stops retrying until an operator asks it to rebond.

One remote can maintain independent sessions with up to four machines. Each machine controls its own heartbeat window, timeout and admission policy.

Testing​

The repository includes host-side protocol tests, fault-injection and chaos ladders, transport soaks, ROS 2 tests, firmware builds, and a MISRA C:2012 pre-check. Start with testing.md; long-run transport testing is documented in connectivity_soak.md.

make -C host test
./tools/misra_check.sh
pre-commit run --all-files

Certification and licensing​

The Protective Stop v1.2 hardware design was OSHWA-certified as open source hardware on August 27, 2026:

  • OSHWA UID: US002846
  • Hardware: CERN-OHL-P-2.0
  • Software and firmware: Apache-2.0
  • Documentation: CC-BY-4.0 unless a file states otherwise

Open source license facts: hardware CERN-OHL-P-2.0, software Apache-2.0, documentation CC-BY-4.0

The source package, licensing map, and mark guidance are summarized in oshwa_certification.md. Full license texts are in LICENSE and LICENSES/.

The design target for the on-demand stop function is SIL 3 under IEC 61508 and PL e under ISO 13849. These are engineering targets, not current functional-safety certifications. The safety case and remaining evidence gaps are tracked in docs/safety/ and open_items.md.

Contributing​

See Contributing for development requirements. Report security issues through the security policy.