A water turret that soaks the neighbourhood cat off your flowerbed — and never soaks your own.
Motion-triggered sprinklers can't tell cats apart. They fire at your cat, at the postman, at a carrier bag. So you turn them off, and the flowerbed goes back to being a litter tray.
CatStopper is the design for a vision-guided version: a cheap 3D-printed water turret that aims, a camera that watches the garden, and a policy layer whose default answer is don't fire. It is built on the Bambu Lab CyberBrick Water Turret — an off-the-shelf RC kit — with the radio control replaced by a vision loop.
Status: design kit, not yet code. The architecture, hardware interface, calibration method and safety model are fully specified here. Firmware and host software are not written yet — see Roadmap.
flowchart LR
subgraph garden [Garden]
WC[Wide camera]
CC[Chokepoint camera]
T[Turret · 3 servos · 3 LEDs · watchdog]
end
subgraph server [Home server]
D[Detector]
R[Re-ID · DINOv2 + k-NN]
P[Policy · fire or hold]
L[(Decision log + training crops)]
end
OCC[Occupancy · both cats in]
WC -->|detect + track| D
D --> R
CC -->|close-range ID| R
R --> P
OCC -->|gate| P
P -->|UDP / ESP-NOW| T
WC -.->|LED bearing + water stream| P
P --> L
Three ideas carry the whole design:
1. The turret is a dumb actuator. No camera, no Pi, no compute on it — three servos, three LEDs, and a watchdog. Everything on the CyberBrick's rotating disc must be self-contained and wireless, because any wire crossing the rotation axis kills the infinite pan. Keeping the brain off the turret is what preserves it.
2. The turret's own LEDs are its encoder. Pan is a continuous-rotation servo with no feedback, so the turret cannot know which way it faces. Instead of adding an encoder, the wide camera watches the turret blink a known pattern on its WS2812s and frame-differences it out of the garden clutter. Bearing for free, zero hardware.
3. Don't derive the geometry — learn it by firing. A water stream in flight
is a bright moving line against a static background, so every shot is a free
measurement. Fire 8–12 calibration shots and least-squares fit
(bearing, tilt) → landing pixel directly. That single fit absorbs position,
height, ground slope and ballistics at once, so a sloppy homography and an
uneven lawn stop mattering. Pick the turret up, put it somewhere else, and it
re-solves itself.
Full reasoning in docs/design.md.
This is the part that matters, and it drives every threshold in the system.
| Outcome | Cost |
|---|---|
| Soaking an intruder | The goal |
| Missing an intruder | ≈ Nothing — deterrence is cumulative; a cat hit on 3 visits in 10 still learns |
| Soaking your own cat | The only outcome that actually matters |
The costs are wildly asymmetric, so the system is tuned to need high confidence that a target is not yours, and to hold fire on every ambiguity. It misses a lot of intruders. That is the correct trade.
- Night is a free-fire window. Your cats are indoors after dark, so any cat is an intruder and no identification is needed — which conveniently deletes the hardest imaging problem (mono IR, no colour, a 50-pixel target) exactly where it was worst. Cats are crepuscular, so this covers most intrusion.
- Free-fire is gated on a positive assertion, never a clock. Default state is cats out → hold fire; you assert "both in" with a button, NFC tag or Home Assistant toggle, and the assertion auto-expires at first light. Forget to tap it and you lose a night of coverage, which costs nothing. The opposite default costs you a wet cat.
- Any human anywhere in frame hard-inhibits the trigger.
- Ambiguity holds fire — track merges, splits and occlusions invalidate identity until something re-crosses a chokepoint.
- Shadow mode first. Run the full pipeline with the trigger disabled for a fortnight and log every decision with the frame that caused it. You get a measured false-positive rate instead of a hoped-for one, and the misses become your training set.
Full policy in docs/safety.md.
The kit is unmodified. CatStopper replaces the CyberBrick transmitter with a host program speaking the same channels.
| Channel | Function | Semantics | Servo |
|---|---|---|---|
| PWM1 | Pan | Velocity, 90 = stop, 360° continuous |
PG002 → pinion → ring gear |
| PWM2 | Tilt | Absolute angle, 90 = level |
PG001 180°, trunnion-geared |
| PWM3 | Trigger | 0 = fire, 20 = idle (powers on at 90) |
PG001 presses the gun's trigger |
| LED1 / LED2 | 3× WS2812 | Effects: Idle / Tracking / Fire | — |
| MOTOR1, MOTOR2, PWM4 | Free |
Tilt being absolute is the lucky break — you can command a real elevation angle for ballistics instead of feeling your way toward it. Pan being velocity is the hard part, and is why the LED bearing trick exists.
Wiring, bill of materials and the rotating-disc constraint: docs/hardware.md.
Nothing here is built yet. Ordered so each stage is independently testable, and so the safety-critical piece lands first.
- Core firmware — UDP listener on the ESP32-C3, three channels, LED
state machine, and the watchdog. Write this before the tracker: a
velocity-commanded pan that loses its command stream spins forever and
winds the water tube until it tears out of the gun. No packet in 300 ms →
PWM1=90,PWM3=20. - Bench harness — drive the turret against a moving hand indoors, dry, before anything holds water.
- Detection + tracking on the wide camera, with decoupled loop rates (heavy detector at 5–10 fps, servo loop at 30 fps+ with a cheap interpolating tracker — tie them together and it will hunt).
- LED bearing recovery and the fire-to-calibrate fit.
- Policy layer — occupancy assertion, geofence, human veto, shadow-mode logging.
- Daytime re-ID — frozen DINOv2/CLIP embeddings + k-NN on chokepoint crops. Only after the night path has earned it on logged data.
- Not the turret model. The printed parts, assembly instructions and channel config belong to MaKim's MakerWorld model and Bambu Lab, and are not redistributed here. Buy or print the kit from source. This repo documents the interface to it.
- Not a cat-harming device. It is a jet of water — the same deterrent as a garden hose, aimed better and used less often. If you cannot accept occasionally soaking the wrong cat, do not build it.
- Check what's legal where you live before pointing anything at animals or over a boundary, and site it so it can only ever fire onto your own ground.
This design came out of a single evening's conversation with Claude Code, kept in full at docs/design-conversation.md — including the two places the first answer was wrong and got corrected by the assembly instructions.
MIT — see LICENSE.