Much as board games can model complex decision making of real-world situations,
a frivolous technology project can illustrate a surprising range of real-world
engineering tradeoffs.
This post documents the decision-making in a truly frivolous project...
Cosmo in the prime of her Badness.
My cat has a lengthy history of bringing me "gifts."
Cat owners quickly discover that cats do this. However,
Cosmo was especially prolific and would bring gifts of the
four-legged scurrying variety, almost always at night and often
still very much scurrying.
Her record is four rats in one night, all live.
Dead rodents are unpleasant; still-scurrying are much worse.
They take up residence in your house unless you finish the job that she didn't!
And take up residence they did.
I picked up a package of biscuits in the kitchen one day,
and a rat jumped out!
Yes, true story.
The solution was simple: don't have a cat
bad kitties lose their indoor-outdoor priveleges at night!
And lest you think perhaps the rats found a way in on their own...
...what's that in her mouth?!
Apparently, it got away from her on her first ascent of the ramps.
Yes. I have more video evidence like this, and I lost count of how many live rats she gifted
me.
Some context
My basement is technically a cellar because it is only
accessible from outside the house.
That is, no interior door (suitable for people) connects the main living space
to the basement.
The cellar door is outside in the back of the house
and down a covered stairwell.
My basement entrance is outside, making it a cellar(?)
Notice the cat flap in the cellar door?
Cat infrastructure
Cosmo does have a direct route from the main floor to the
cellar: her own personal, semi-secret door built into a bookcase leading
to a series of ramps to the cellar floor. (When she was young she frequently
came through the bookcase flap as if she was shot out of a cannon, startling
guests.
Thus, her name.)
Way too much trouble for a cat.
I built it when I was younger and had (more of) the misguided priorities of youth.
I did have some defensible motivations, though.
I did need more shelf space, and I wanted to avoid:
a litterbox in the house and everything that goes with that, and
putting a cat flap in my front or back house doors.
Back to Cosmo
The solution was simple: keep her from reentering the main floor of the
house at night by making the cat flap in the bookcase one-way.
I had anticipated this might be necessary even before the rat situation
and installed a
Cat Mate 4-Way-Locking Cat Flap.
(I bought mine over a decade ago, but they don't appear to have changed.)
The "locks" allow you to theoretically make the door one-way, but
all they actually do is control which direction(s) the flap can
be pushed.
I would set the bookshelf flap to be "one-way" outbound in the
evening, and Cosmo could leave the house and come and go from the cellar
but not reenter the main floor.
Theoretically...
An off-the-shelf solution that wasn't
It worked briefly, but
Cosmo quickly learned that she could still enter by pulling the
flap, usually making a house-waking racket because her first few attempts
would fail, and the flap would bang down on the frame and be amplified by the
acoustics of the wooden bookcase it's built into.
Ok, fine. We'll just evict her lure her outside with food and
physically block that hole in the floor, so she absolutely can not reenter
the house at night but can still come and go from the cellar.
(Don't worry: she has plush digs in the cellar.)
Incidentally, the Cat Mate flaps are great, really well built, and I
would recommend them with the caveat that whether or not the "one-way"
feature works depends on your cat's IQ.
Years pass
Being an elderly cat now, she is never eager to leave her living room
bed in the evening.
Even food does not necessarily lure her out.
And now we have a new reason to keep her out: she seems to need
to announce her return when she reenters.
She yowls...loudly.
Yes, every time she reenters.
Yes, multiple times at night.
I think the technical term is caterwauling.
I would rather let her stay inside until she is ready to leave on her own.
If she stayed inside (and quiet!), that's fine, too.
But she won't.
She's a cat—that is, nocturnal.
Her "litterbox" is the entire outside world, and there is still hunting to do...
The best solution is clear, but it's too late: don't have pets.
Sorry, son. I do like cats, but when Cosmo ceases to
voom we're done.
Scoping requirements
Right now I need a genuine one-way door,
a cat valve.
I really do have better things to do, but this situation has become
enough of a nuisance to motivate a(n admittedly ridiculous) project.
I have a place to control her access to the house:
the top landing of her kitty ramps.
And it's convenient since it's entirely out of the way
of our living space.
...meaning, whatever I build, it has no aesthetic requirements!
The future home of a Star Trek-esque sliding door...for a friggin' cat.
The road not taken
I can imagine an entirely passive (unpowered), cat flap which would
actually latch when it closes that could be mounted in that portal on the
top landing of her ramps (between those 2x4's).
It would require some sort of (manual) arming mechanism since I only want
the lock-out to occur at night.
I believe such a mechanism could probably be printed on my
FlashForge, too.
This would hypothetically solve my cat-shaped problem with minimal complexity,
"hypothetically" because I said I can imagine,
not that I've done the design work.
And it would have to survive kitty rage.
Initial design decisions & mission creep
Lingering doubt about the feasibility of a strictly passive mechanism
and the lure of opening and closing her door at the touch of a button—
that's the mission creep— led me to take the other road: a powered door.
I didn't put a lot of thought into the actual door/barrier design.
The 34cm wide x 30cm high space allowed for a ≤17cm sliding panel to
cover a ≤15cm opening with 1cm overlap, and this seemed both simplest
and probably most reliable.
A panel sliding behind (on the interior side of) a fixed wall
arguably gives Cosmo the least "attack surface" for her prying claws,
a serious merit that would not apply to any conventional hinged door.
I committed early to a sliding door design.
Whatever sort of linkage is used, a
reversible motor and associated electrical drive circuitry
is certainly the easiest way to move something back and forth.
Since the goal is automatically closing the door when the cat
exits, detecting/inferring the cat's exit is necessary.
Finally, something needs to integrate the multiple sensors
and actuators.
Design
So pet-management-motivated sub-projects include at least:
mechanical design for a panel driven by some sort of linear motion actuator
A chain/belt and pulley assembly in which the door is attached to the chain/belt (similar, but not identical, to a garage door)
Rack and pinion struck me as requiring more precision than one should attempt
in a plywood-and-2x4 context.
Directly coupling a (gear reduced) motor to a screw is trivial, so I went
with this dangerous option.
It's dangerous because a panel driven by a lead-screw,
even with a small-ish 12V motor, can exert enough force on an obstacle to
constitute a kitty guillotine!
The 300RPM motor I used and the pitch of the lead screw yield a door
speed of only ≈1cm/s, so I'm sure she'll get out
of the way, but I'm not going to risk finding a pinched pet.
This mechanical choice will need a safety cutoff,
so I'll be paying for the mechanical simplicity of a directly-driven
lead-screw actuator with a bit more complexity in other parts (electronics
and/or software).
Engineering tradeoffs!
The door hangs from the lead screw by a nut mounted in this 3D-printed
fixture.
Above is an early print before I recognized the fixture should include
a tab to press the limit switches seen below.
The door (2mm birch plywood) simply hangs from this, so it take very
little force and, thus, a very light-duty motor, to move it.
The motor's shaft fits in the coupler (blue cylinder) on the
left to drive the lead-screw directly.
The other end of the lead-screw is carried by a flange-block bearing,
just the edge of which is visible behind the door.
Control
The fundamental decision in a controller (of anything) is between
open-loop
and
closed-loop.
open-loop = optimistic control ≠ optimal control
Open-loop is simplier but usually optimistic, and optimistic engineering isn't
engineering.
Open loop control relies on a model which in this case is simply
the easily-calculated (or measured) linear relationship between motor speed and
door travel (≈1cm/s).
By simply powering the motor for an appropriate period of
time the door would be moved a predictable distance...predictable
but not necessarily precise.
Electrical fluctuations could result in small deviations each time the
door is opened or closed.
If the deviations were centrally and symmetrically
distributed (e.g. normal) they would cancel each other out over time,
so the door would remain within safe operating bounds.
Alternatively, biases in the control circuits, software, or physics of
the motor, could skew the errors which in turn could cause the door's
left and right "rest" positions to shift.
Essentially, with open-loop control the controller
never positively "knows" what state the controlled system is in.
Incidentally, this also implies the system must be powered-up in a known
state which could be mighty inconvenient.
Feedback closes the loop
If you look inside your 3D printer you will likely see not only a lead-screw
carrying something (probably the print bed), but also
limit switches at
either end of something's range of travel.
The switches provide feedback: when pressed they send electrical
signals to the controller that indicate exactly (within a few millimeters)
where the moving part is.
Obviously, this is applicable to my door.
Better still, I used SPDT
switches which, in the unpressed position, close the circuit of the
corresponding motor control input and open it in the pressed position,
thereby disconnecting the motor input .
That is, the limit switches perform two functions simultaneously.
When a switch is pressed:
power to the motor is cut off independently from the controller, and
a signal is sent to the controller indicating
the limiting position has been reached.
A tab on top of the nut fixture presses the switches at either side.
The vertical tab hits limit switches to limit the door's linear travel,
shown above prior to installation.
FreeCAD of the nut mount fixture.
The tabs at the corners are something I add to prints to pry them off
the print bed. They could be cut off the final product after printing.
Using clamps to test-fit the position of the limit switch mount.
Motor mount
And here's the reason I favored a lead-screw approach:
no little precision required.
A
Greartisan DC 12V 300RPM
motor drives the lead screw directly.
That chunk of right-angled aluminum to which the motor mount is attached?
It's the dashboard mount for a car stereo salvaged from an old Chrysler.
FreeCAD for an adjustable motor mount to fit the Greartisan DC 12V 300RPM.
The motor mount provides 2 dimensions of freedom, rotational and radial,
thanks to that oval hole, so
the motor and lead-screw assembly can be loosely installed (with some parts
temporarily clamped into place),
allowed to find it's own least-stress position then screwed/bolted into that
position. No high-precision tolerances required!
The 2mm birch plywood panel is lightweight, it hangs from the lead screw,
and it is not in contact with the platform beneath it.
The only (linear) friction comes from the panel lightly brushing against a
block at its bottom which prevents the panel from being pushed like a flap.
As a result, very little force is required to move the panel, so the motor
mount is, in turn, under very little stress...which is why the weak-looking
5mm thick PLA print suffices.
An H-bridge is a standard circuit for reversibly driving a DC motor.
It converts
3.3V very low-current GPIO signals to the 12V and higher-current levels
(and current directions) required by the motor.
Yes, I could have used any number of motor driver ICs, but to stay in touch with my
discrete component roots, I overbuilt one with Darlington pair BJTs.
...and good I did, because a hiccup in final wiring got those TIP12x's
hotter than an IC would have withstood. 🤦
Red and black wires are 12V power,
white wires connect to the motor, and blue and brown are control.
A logical high voltage (3.3V) on the blue wire turns the motor on one direction; high on the brown wire turns the motor on the other direction.
Importantly, the motor runs only as long as one of those wires is logic 1,
so whatever is driving those inputs must hold that voltage as long as
required to move the door the intended distance.
(And, btw, blue and brown should never be simultaneously high!)
Speaking of salvage, above are speaker and antenna connector
blocks from an old receiver my son and I disassembled.
With a little coercion they fit the hole pitch of an Adafruit prototyping board.
This is how the Raspberry Pi 4 is connected to motor, sensors and power.
Yes, it's ugly, but this is a one-off, not a product.
Proximity detection
As explained above, because the door is actually capable of injuring a cat,
I need a sensor to trigger motor cutoff (or perhaps reversal) if Cosmo is
near the portal.
This
IR emitter/detector pair is reliable and trivial to use in practice.
The emitter is just wired to 5V, always-on.
The detector (with a pull-up resistor) can drive a 3.3V logic input directly.
Exit detection
Detecting the cat's exit is central to the entire goal of automating this
problem away.
The current approach relies on two assumptions:
In the evening before I go to bed Cosmo is inside.
Overnight nothing but Cosmo would move or cause movement inside the cellar
between her portal and the exterior cat flap.
If Cosmo commences her noctural rounds before I sleep, I close the door
using its UI, and that's that: I am the detector!
So assumption #1 can be treated as valid.
Below is one of multiple reasons assumption #2 is definitely not valid.
If it's not clear in these (full resolution) images, that's a raccoon
entering my cellar, not Cosmo exiting (left).
It left just seconds later followed by Cosmo who I'm guessing
surprised it from one of her high perches.
Fortunately, years of footage suggest raccoon intrusions are rare, though
it has happened more than once.
Fortunately, events invalidating assumption #2, including but not
limited to raccoon intrusions, are rare enough that the
inference:
any movement in the cellar between her portal and the exterior cat
flap ⇒ Cosmo is exiting
...is a model that is definitely wrong, but nonetheless useful.
Incidentally, in all video footage I've collected, I have never seen
her leave the living room for the cellar without immediately
proceeding outside. This regularity in her behavior also supports the
inference.
Methods of detecting movement abound:
IR beam break sensors placed across the exterior cat flap
mercury switch(es) that sense(s) tilt of the exterior cat flap
IR beam break sensors anywhere along her path to the exterior catflap
PIR sensors anywhere along her path to the exterior catflap
motion sensing in a video stream
...and probably more.
Here's where mission creep #2 occurred, which also explains my having
the raccoon image above.
It wasn't part of the initial requirements, but a video record of creature
comings and goings in the cellar could be (and has been) useful, not only
to learn of bandit intrusions but also to monitor whether or not Cosmo is
still bringing in gifts.
So motion detection was accomplished through video.
In 2025 (when this is being written) the knee-jerk response to the raccoon
false-positives for many of my ilk would be
"put a bird on it"
throw some AI/ML at it.
I have lots of true positive video data of Cosmo exiting with which to
train up a suitable model (though relatively little false positive),
I have no doubt that it's feasible,
it would complement, not replace, my current approach,
and I might even pursue it some day as an exercise.
But that's not for this post.
KISS!
...or, maybe, keep it simple by keeping it stupid.
Another advantage of video-based motion detection is that is works
at a distance.
Ideally door closure shouldn't commence until Cosmo is a safe distance
away from the "guillotine" and clearly headed outside.
Using video I can monitor the exit with a camera near the rest of the
assembly, ≈3m away from the exterior cat flap.
(see below).
Otherwise, if sensors were mounted at/on/near the exterior
cat flap, I would have to string wires to them or "escalate" the
project with Bluetooth LE.
So video was wasn't purely mission creep.
It added software requirements while removing hardware, often a good tradeoff.
...in the broadest sense means hooking up disparate systems so that they
cooperate to achieve some goal(s).
In this context, it means connecting the sensors and effectors, as inputs
and outputs, to a
controller implementing
a state machine representing door and motor states.
If there is no signal processing required it could be as little as some
logic gates or my favorite little
workhorse
which in a single chip can replace a bushel of 74xx's and more.
In this case mission creep has essentially made the decision: video-based
motion detection requires software.
It doesn't require software running on a CPU—it
could be accomplished by firmware on a microcontroller, but
I would certainly prefer to use a cheap webcam, it's Linux drivers, and
V4L2
over writing my own video firmware for a μC!
Additionally, by "button" control of the door, I didn't mean a physical
button (though that would be possible, too).
It's 2025; I meant a screen button on the universal remote control
that is my phone.
That means, however the UI is implemented, I need a network stack on the
controller, ideally including WiFi, with which my phone can communicate.
Skipping to the punchline, I used a
Raspberry Pi 4
running Voidlinux
and two daemons
I wrote, catvalve and camomon.
Ultimately, catvalve is the controller/integrator. It:
generates left/right motor control signals based on the input signals
contains a minimalist HTTP server that provides the UI for button control of the door (and more)
A phone screenshot of the HTML UI...the whole UI.
Does that mean you wrote an HTTP server?!
Yes, and ill-advised as that might sound, it's no more difficult than
developing a walled garden app.
I only need my C compiler, not the monstrous toolchains (and monetization tech) for Android/iOS.
In fact, it's probably even easier than dotting all the i's and crossing all the t's
of Apache's configuration!
An exhaustive HTTP implementation with all bells and whistles
is, well, Apache,
and I'm not writing that!
A severely constrained HTTP implementation with only those capabilities
required to support a single (itself simple) application is trivial.
For example, mine only accepts one connection because it's only for use on the
household LAN.
It serves exactly one web page shown above.
It only needs to parse a couple URL encoded parameters to trigger GPIO signals
to run the motor.
Installing Apache or Nginx for this would be absurd.
Lighttpd or
Quark might make sense,
but even they are much more than I need.
Moreover, the same loop and ppoll
call that monitors file descriptors for HTTP requests can simultaneously
monitor (and handle) GPIO events!
Very simple!
The finished installation (with the door closed).
Notice the IR emitter/detector pair, the emitter mounted just left of the door
and the detector on the post on the right side of the platform.
The beam crosses the top landing diagonally to insure she can't be anywhere
on the top platform (outside the door) without breaking the IR beam!
An old Logitech C270 webcam currently clamped in place (top right corner of picture)
watches both the vicinity of the cellar door and the top landing
of Cosmo's ramps (below).
Again: yes, it's ugly because it's a one-off, not a product.
The webcam's view overlayed with
motion-detection regions (left)
and pixels actually used in the computations (right).
Motion in either region is logged and frames saved, but only
motion in the red region triggers door closure.
Camomon monitors video from a webcam.
When it detects motion (in specific regions), it signals catvalve,
"signals" in the Unix IPC sense with
kill(...,SIGUSR1)
because they're running on the same computer.
If "Motion-triggered door closure" is enabled within catvalve,
receipt of that signal closes the door.
In more detail,
camomon grabs still images from the webcam at ≈10Hz.
The webcam, of course, provides color video, but camomon only
uses the luminance of the
YUYV
output which is why the above
images are grayscale.
It computes Pearson correlation coefficient (ρ)
between sets of corresponding pixels in every pair of successive video frames.
If nothing is changing in the field of view (and assuming an illuminated scene),
ρ → 1.0.
Correlation coefficients below some threshold <1.0 indicate successive
frames are different, motion of something in the field of view is the most
likely explanation, and in this context the motion is probably
Cosmo.
Changes in sunlight levels/shadows, insects flying near the camera,
and, of course, raccoons all cause false-positive detections.
For efficiency, ρ is computed on a sparse subset of pixels
within specified polygonal regions of its field of view in the correlation
computations.
The subsets are those pixels that lie at the intersections of a configurable
grid.
Motion in either polygon (red or green) is logged and the (under-correlated
pair of) frames are saved as still images.
Only motion in the red polygon (above) triggers the
signal to catvalve (and thus door closure), because I want to
insure Cosmo is as far as possible from the "guillotine" when it closes.
Logging in the green polygon was used to confirm that the IR beam break
sensors "watching" diagonally across the platform in front of the door
were reliably detecting her presence.
That is, the times of movement in the green polygon and log records of the
IR beam being broken should also be correlated.
I only want automatic door closure at night, but there is no need
to give either program temporal awareness when I can just have
cron launch camomon.
This is the Unix philosophy in practice.
This does imply, however, that I need to insure the host is running a
properly configured ntpd.
There is always more one could say, but you get the idea.
Circuit diagrams, FreeCAD files and software are
here.