CNC 3018-Pro: Probe Camera Case for Logitch QuickCam Pro 5000

The ball-shaped Logitch QuickCam Pro 5000 has a rectangular PCB, so conjuring a case wasn’t too challenging:

Probe Camera Case - Logitech QuickCam Pro 5000 - bottom
Probe Camera Case – Logitech QuickCam Pro 5000 – bottom

That’s more-or-less matte black duct tape to cut down reflections.

The top side has a cover made from scuffed acrylic scrap:

Probe Camera Case - Logitech QuickCam Pro 5000 - top
Probe Camera Case – Logitech QuickCam Pro 5000 – top

The corners are slightly rounded to fit under the screw heads holding it in place.

The solid model shows off the internal ledge positioning the PCB so the camera lens housing rests on the floor:

3018 Probe Camera Mount - solid model
3018 Probe Camera Mount – solid model

The notch lets the cable out, while keeping it in one place and providing some strain relief.

I though if a camera was recognized by V4L2 and worked with VLC, it was good to go:

Logitech QuickCam Pro 5000 - short focus
Logitech QuickCam Pro 5000 – short focus

Regrettably, it turns out the camera has a pixel format incompatible with the Python opencv interface used by bCNC. This may have something to do with running the code on a Raspberry Pi, rather than an x86 box.

The camera will surely come in handy for something else, especially with such a cute case.

The OpenSCAD source code as a GitHub Gist:

// Probe Camera Mount for CNC 3018-Pro Z Axis
// Ed Nisley - KE4ZNU - 2019-08
Layout = "Block"; // [Show,Build,Block]
Support = false;
/* [Hidden] */
ThreadThick = 0.20;
ThreadWidth = 0.40;
HoleWindage = 0.2;
Protrusion = 0.1; // make holes end cleanly
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
ID = 0;
OD = 1;
LENGTH = 2;
inch = 25.4;
//----------------------
// Dimensions
PCB = [45.0,38.0,1.5]; // Logitech QuickCam Pro 5000 ball camera
PCBLip = 1.0; // max non-component border
PCBChamfer = 3.0; // cut along XY axes for corner bevel
PCBClearTop = 15.0; // cables & connectors
PCBClearSides = [0.5,0.5]; // irregular edges & comfort zone
PCBClearBelow = 5.0; // lens support bracket rests on floor
Lens = [11.5,14.2,3.0]; // LENGTH = beyond PCBClearBelow bracket
LensOffset = [-1.5,0.0,0]; // distance from center of board
CableOD = 4.5;
BaseThick = Lens[LENGTH];
Screw = [
3.0,6.8,18.0 // M3 OD=washer, LENGTH=below head
];
RoundRadius = IntegerMultiple(Screw[OD]/2,1.0); // corner rounding
ScrewOC = [PCB.x + 2*sqrt(Screw[OD]),PCB.y + 2*sqrt(Screw[OD])];
echo(str("Screw OC: ",ScrewOC));
Lid = [ScrewOC.x,ScrewOC.y,1.0/16.0 * inch]; // top cover plate
echo(str("Lid: ",Lid));
BlockSize = [ScrewOC.x + 2*RoundRadius,ScrewOC.y + 2*RoundRadius,
BaseThick + PCBClearBelow + PCB.z + PCBClearTop + Lid.z];
echo(str("Block: ",BlockSize));
NumSides = 2*3*4;
//----------------------
// Useful routines
module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes
Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2);
FixDia = Dia / cos(180/Sides);
cylinder(r=(FixDia + HoleWindage)/2,
h=Height,
$fn=Sides);
}
// Basic shapes
// Overall block
module Block() {
difference() {
hull()
for (i=[-1,1], j=[-1,1])
translate([i*ScrewOC.x/2,j*ScrewOC.y/2,0])
cylinder(r=RoundRadius,h=BlockSize.z,$fn=NumSides);
for (i=[-1,1], j=[-1,1]) // corner screws
translate([i*ScrewOC.x/2,j*ScrewOC.y/2,BlockSize.z - Screw[LENGTH]])
cylinder(d=Screw[ID],h=2*Screw[LENGTH],$fn=8); // cylinder = undersized
translate(LensOffset + [0,0,-Protrusion]) // lens body
PolyCyl(Lens[OD],2*BlockSize.z,NumSides);
translate([0,0,BlockSize.z/2 + BaseThick]) // PCB lip on bottom
cube([PCB.x - 2*PCBLip,PCB.y,BlockSize.z],center=true);
translate([0,0,BlockSize.z/2 + BaseThick + PCBClearBelow]) // PCB clearance
cube([PCB.x + 2*PCBClearSides.x,PCB.y + 2*PCBClearSides.y,BlockSize.z],center=true);
translate([0,0,BlockSize.z - Lid.z/2]) // lid recess
cube(Lid + [0,0,Protrusion],center=true);
translate([0,Lid.y/2 - CableOD/2,BaseThick + PCBClearBelow + PCB.z]) // cable exit
hull()
for (j=[-1,1])
translate([0,j*CableOD/4,0])
rotate(180/8)
PolyCyl(CableOD,BlockSize.z,8);
}
}
//- Build it
if (Layout == "Block")
Block();
if (Layout == "Show") {
Block();
}
if (Layout == "Build") {
Block();
}