Printable mounts for two 38×38 mm IP camera boards, side by side, with tilt.
One carrier plate holds both cameras. It drops onto either of two bases: a ballasted desk stand, or a mount that slips over the post of a stacking-ring toy. The pivot is shared, so the head is interchangeable between them.
![]() |
![]() |
| Desk stand, ballasted | Toy-post mount |
Everything prints flat with no supports.
| Part | File | Qty | Size |
|---|---|---|---|
| Head — carrier plate + tilt bracket, one piece | print/headplate.3mf |
1 | 102 × 70 × 29 mm |
| Ballast box | print/box.3mf |
1 | 130 × 100 × 20 mm |
| Lid with pivot ears | print/lid.3mf |
1 | 130 × 100 × 41 mm |
| or toy-post mount (replaces box + lid) | print/mount.3mf |
1 | 108 × 61 × 42 mm |
| Joint | Qty | Fastener |
|---|---|---|
| Camera boards → plate | 8 | M2 standoffs + screws (Ø2.6 clearance holes) |
| Head → ears (pivot) | 2 | M5 × 20 pan head, DIN 967, + M5 flange nut |
| Lid → box (desk stand only) | 6 | M3 × 12, into Ø2.5 pilots |
| Feet (desk stand only) | 4 | Ø12 stick-on rubber pads |
The pivot screw passes through ear (2.8) + gap (0.9) + hub (7.6) = 11.3 mm, leaving 8.7 mm of the 20 mm thread for the flange nut, which sits in free space inboard of the hub. Bores are Ø5.35, so an M5 has 0.35 mm of running clearance.
The lid screws are M3, not M2. The boss pilot is Ø2.50 and an M2 is Ø2.00 — smaller than the hole, so it has nothing to bite and drops straight through. Only the camera boards take M2.
24 radial teeth at 15° on the mating hub and ear faces, clamped by the M5 screw. Holding is geometric first — the teeth interlock — and frictional second, because the screw clamps the Ø26 faces. Tilt sets in 15° detents; loosen the screw to re-aim, nip it up to lock.
![]() |
![]() |
| Level | Tilted up |
Two earlier pivots failed here and are documented so they aren't repeated:
- Printed pins (what this replaces). They broke within days. An M5 screw also clamps hard enough that the detents can't creep, which retired the lock shims the pins needed.
- Pure friction, no teeth. The preload needed is only 6.5 N per side, but 5 mm ears are 311 N/mm, so ±0.15 mm of print tolerance swings preload across ~93 N — anywhere between "falls over" and "cannot be assembled".
- 7.5° / 0.45 mm teeth. Wouldn't hold the cameras horizontal. Not a margin error: at that size the tooth root is 0.47 mm, barely one 0.4 mm extrusion, so the printer laid a rounded bead instead of a tooth. 15° gives a 0.9–1.4 mm root, which prints faithfully.
38×38 modules are 34 × 34 mm between mounting holes — centres 2 mm in from each PCB edge. Confirmed by ANHOYA/SO-ARM101_CAM_holder_38X38mm and BL-M8812EU2.
34 is not a multiple of 2.54, so a perfboard can never place these standoffs correctly — the nearest grid options are 33.02 (1 mm narrow) and 35.56 (1.56 mm wide). Reading the pitch off a perfboard photo is what produced the first plate, whose standoffs splayed outward into a pyramid.
Fill the box with ~300 g of steel shot or M8 nuts across its six compartments before fitting the lid — there's no fill port. The compartments stop a partial fill shifting and moving the centre of mass.
Measured from the meshes (PETG 1.27 g/cm³, 0.6 solid fraction), with 300 g:
| Tilt | CoM height | Total | gf to tip |
|---|---|---|---|
| −30° | 23.1 mm | 524 g | 285 |
| 0° | 21.2 mm | 524 g | 331 |
| +30° | 17.9 mm | 524 g | 426 |
Worst case 260 gf at −60° — a deliberate shove, not a nudge.
Collar and ears deck are a single part, sitting side by side rather than stacked. Both rise from the same plane, so it prints in one orientation with nothing overhanging, needs no screws between them, and the Ø28.4 bore stays open end to end for the camera cable.
Set post_id (28) to your post's diameter — it's the only number to change.
Note the post axis sits 45 mm behind the cameras, so the head cantilevers forward;
structurally that's ~2 N on the socket walls, and any stacking-toy base handles it.
make # all parts as 3MF, into print/
make verify # geometry checks
make renders # regenerate the imagesNeeds openscad on PATH (brew install --cask openscad@snapshot on macOS — the
plain openscad cask is disabled, it fails Gatekeeper).
src/ipcam_stand.scad reads every plate-facing coordinate from
src/ipcam_plate.scad through accessor functions (camera_hole_positions(),
plate_size(), …), so no dimension is written down twice.
make verify runs three checks, in the order they earned their place:
- Mesh validity — read straight from the 3MF: watertight, one shell, on z=0, and genus equal to the through-hole count. Genus caught a plate that silently came out with four of its eight camera holes clipped off by the plate edge.
- Layer sweep — cross-section area must never grow going up. This is the only check that answers can a slicer build this bottom-up. Watertight, single-shell and collision-free all passed on parts that had material starting in mid-air. The checker self-tests first: a vertical cylinder must report zero growth, a 60° cone must report some. An earlier version reported 4.5 mm² on a plain cylinder and was trusted far too long.
- Self-collision by volume —
vol(a) + vol(b) − vol(union)≈ 0, swept across the tilt range.intersection()gave false positives here. It also checks that a non-detent angle does collide, which proves the teeth actually engage.







