-
Microscope Stage Positioner
Given the vanishingly small depth of field provided by a cheap USB camera peering through the stereo zoom microscope, I’ve always wanted a better way of moving objects by small increments. The rehabilitated micropositioner didn’t have the right orientation or end effector:

Micropositioner So I rearranged the axis slides and added a small table:

Microscope Stage Positioner That frees up the magnetic base and husky angle bracket, plus a few odds & ends, for future adventures.
The clear base is a random chunk of acrylic, bandsawed to the proper length, then tediously squared and drilled on the Sherline:

Microscope Stage Positioner – base squaring I briefly thought of printing the base, but came to my senses: there are better ways to make big flat surfaces.
The little aluminum table has a nubbly spray coating that came straight from the heap and looks surprisingly good after squaring & drilling. The X axis block puts it below the platform and one screw head above the desk when the Y axis arm sits flat on the acrylic base.
One solid model view arranges things in more-or-less the proper layout to check the alignment:

Microscope Stage Positioner – solid model – Show layout The build layout reduces the platform space:

Microscope Stage Positioner – Slic3r preview You’re looking at four hours of PETG print time at 0.2 mm layer thickness with 15% infill and Hilbert Curve surfaces.
All of the screws have UNF fine-pitch threads (4-48, 6-40, 8-36, stuff like that), so the solid model includes the spacing required to reuse the original screws: those big holes in the Y axis arm end in little clearance holes for the tiny screws. Some of the screws bottom out with barely two millimeters of thread engagement in the slides, while others could jam against the racks. I didn’t want to cut that many screws from my Brownell’s gun screw assortment unless I absolutely had to. So far, so good.
I spent quite a while doodling the layout to convince myself that it would actually work:

Microscope Stage Positioner – layout doodle Memo to self: Next time, use a larger scale!
Although the whole lashup works as intended, those metal hunks are way too heavy for the plastic block that fits between the Z axis drive pillar and the X axis slide: that long Y axis arm drooped toward the front by about 5 mm. A small shim raised the front of the Z axis footprint enough to level the arm, but I think the right answer is a metal upright with a bigger footprint that spreads the load.
All that mass hanging out in mid-air turns the plastic pieces into springs: you can’t keep your fingers on the knobs. Fortunately, everything returns to the same position after you release the knob, so it’s easy to move in precise increments if you close your eyes until the view settles down.
There’s a reason optical equipment uses cast iron, steel, and brass… but I’ll settle for plastic.
The OpenSCAD source code as a GitHub gist:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters// Microscope Stage Positioner // Ed Nisley KE4ZNU January 2016 Layout = "Build"; // Show Build // Base ZStand YMount XMount Gap = 0.0; //- Extrusion parameters must match reality! ThreadThick = 0.25; ThreadWidth = 0.40; HoleWindage = 0.2; Protrusion = 0.1; // make holes end cleanly inch = 25.4; function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit); //———————- // Dimensions SlipFit = 0.1; ZDrive = [26.0,19.6,75.0]; // stationary part of Z drive ZDriveOffset =[0,0,22.0]; // left front corner of stationary Z base ZWall = 4.0; // thickness of edge wrapped around Z columns YStageBlock = [25.0,61.0,17.0]; // Y stage mount + slide YStageOffset = [-6.0,4.0,0.0]; // offset to inner corner of Y stage holder YArm = [10.0,93.0,17.0]; // mount to stationary part of Y stage ZStage = [24.0,9.7,85.0]; // moving part of Z drive ZYArm = [(2*ZWall + ZStage[0]),10.0,YArm[2]]; // attaches to ZStage, same thickness as YArm XStageBlock = [25.0,20.0,12.0]; // X stage mount + slide XStageOffset = [-95.0,-15.0,-26]; // offset to rear left bottom corner of X stage slide XTray = [25,25,5]; // X tray attached to bottom of X mount //———————- // 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); } //– Z Stand module ZStand() { Holes = [12.0,41.5,68.0]; HoleOD = 3.5; HolesOC = 15.0; echo(str("Z Stand holes OC: ",HolesOC)); ZPlate = 6.0; // thickness of Z plate = max screw grab distance ZStandWrap = 2.0; // length of edge wrapped around Z column MaxY = 9.0; MinY = -14.0; difference() { union() { linear_extrude(height=ZDriveOffset[2]) polygon(points=[ [-ZWall,MaxY], // limited by Z slide rack [ZDrive[0] + ZWall,MaxY], [ZDrive[0] + ZWall,MinY], // limited by X slide rack [-ZWall,MinY] ]); linear_extrude(height=(ZDrive[2] + ZDriveOffset[2]),convexity=4) polygon(points=[ [-SlipFit,0], [ZDrive[0] + SlipFit,0.0], [ZDrive[0] + SlipFit,ZStandWrap], [ZDrive[0] + ZWall,ZStandWrap], [ZDrive[0] + ZWall,-ZPlate], [-ZWall,-ZPlate], [-ZWall,ZStandWrap], [-SlipFit,ZStandWrap] ]); } for (i = [0:len(Holes) – 1]) // holes along Z stand translate([ZDrive[0]/2,ZDrive[1]/2,(Holes[i] + ZDriveOffset[2])]) rotate([90,0,0]) PolyCyl(HoleOD,ZDrive[1]); for (i = [-1,1]) // mounting screw holes translate([i*HolesOC/2 + ZDrive[0]/2, // center the holes from side to side (MaxY + MinY)/2, // moby hack to put holes on midline -Protrusion]) PolyCyl(3.5,0.75*ZDriveOffset[2],6); } } //– Y Mounting arm // Polygon origin at inner corner nearest the Z stand column module YMount() { YHoles = [12.0,48.0,84.0]; // mounting holes along Y stage arm, from outside in YScrewLength = 4.0; // screw head to Y stage mount ZStageBase = [(ZDrive[0] – ZStage[0])/2,(ZDrive[1] + ZStage[1]),0.0] – YStageOffset; // local coordinates of Z slide left rear corner ZHoles = [26.5,55.0,71.0]; ZStageWrap = 8.0; // length of edge wrapped around Z stage Trim = ZStageBase[1] – ZStageWrap; union() { difference() { linear_extrude(height=YArm[2],convexity=5) polygon(points=[ [-Trim,0.0], [-YStageBlock[0],0.0], [-YStageBlock[0],-(YArm[1] + SlipFit)], [-(YStageBlock[0] + YArm[0]),-(YArm[1] + SlipFit)], [-(YStageBlock[0] + YArm[0]),Trim], [-Trim,(ZStageBase[1] + ZYArm[1])], [(ZStageBase[0] + ZStage[0]/2),(ZStageBase[1] + ZYArm[1])], [(ZStageBase[0] + ZStage[0] + ZWall),(ZStageBase[1] + 0*ZYArm[1])], [(ZStageBase[0] + ZStage[0] + ZWall),(ZStageBase[1] – ZStageWrap)], [(ZStageBase[0] + ZStage[0] + SlipFit),(ZStageBase[1] – ZStageWrap)], [(ZStageBase[0] + ZStage[0] + SlipFit),ZStageBase[1]], [(ZStageBase[0] – SlipFit),ZStageBase[1]], [(ZStageBase[0] – SlipFit),(ZStageBase[1] – ZStageWrap)], [0.0,(ZStageBase[1] – ZStageWrap)], [0.0,Trim] ]); for (j=[0:len(YHoles) – 1]) { // Y stage mounting screws translate([-(YStageBlock[0] + YScrewLength), (-YArm[1] + YHoles[j] – 2*SlipFit), YArm[2]/2]) rotate([0,-90,0]) rotate(180/6) PolyCyl(5.5,YArm[0],6); translate([-(YStageBlock[0] – Protrusion), (-YArm[1] + YHoles[j] – 2*SlipFit), YArm[2]/2]) rotate([0,-90,0]) rotate(180/6) PolyCyl(2.5,2*YArm[0],6); } } if (true) difference() { linear_extrude(height=ZStage[2],convexity=5) polygon(points=[ [(ZStageBase[0] – ZWall),(ZStageBase[1] + 5.0)], [(ZStageBase[0] + ZStage[0] + ZWall),(ZStageBase[1] + 5.0)], [(ZStageBase[0] + ZStage[0] + ZWall),(ZStageBase[1] – ZStageWrap)], [(ZStageBase[0] + ZStage[0] + SlipFit),(ZStageBase[1] – ZStageWrap)], [(ZStageBase[0] + ZStage[0] + SlipFit),ZStageBase[1]], [(ZStageBase[0] – SlipFit),ZStageBase[1]], [(ZStageBase[0] – SlipFit),(ZStageBase[1] – ZStageWrap)], [(ZStageBase[0] – ZWall),(ZStageBase[1] – ZStageWrap)], ]); for (k=[0:len(ZHoles) – 1]) translate([(ZStageBase[0] + ZStage[0]/2),0.0,ZHoles[k]]) rotate([-90,0,0]) PolyCyl(3.5,2*ZStageBase[1],6); } } } //– X Slide attachment // Origin at left rear bottom of mount module XMount() { XHoles = [6.0,18.0]; // from end of X slide XHolesOffset = 7.0; // from bottom of X slide TrayHolesOC = 10.0; echo(str("Tray holes OC: ",TrayHolesOC)); BlockOAH = XStageBlock[2] – XStageOffset[2] – XTray[2]; // overall height of mount difference() { translate([XStageBlock[0],0,BlockOAH]) rotate([0,90,180]) linear_extrude(height=XStageBlock[0],convexity=2) polygon(points=[ [0,0], [0.0,7.0], [(XStageBlock[2] + SlipFit),7.0], [(XStageBlock[2] + SlipFit),XStageBlock[1]], [BlockOAH,XStageBlock[1]], [BlockOAH,0.0], ]); for (i=[0:len(XHoles) – 1]) // holes for X stage screws translate([XHoles[i],Protrusion,BlockOAH – XStageBlock[2] + XHolesOffset]) rotate([90,0,0]) PolyCyl(3.5,2*7.0,6); for (i=[-1,1]) // holes for tray mount translate([i*TrayHolesOC/2 + XStageBlock[0]/2,-XStageBlock[1]/2,-Protrusion]) PolyCyl(2.5,0.75*(BlockOAH – XStageBlock[2]),6); } } //———————- // Build it if (Layout == "ZStand") ZStand(); if (Layout == "YMount") YMount(); if (Layout == "XMount") XMount(); if (Layout == "Show") { color("lightgreen") ZStand(); color("orange") translate(YStageOffset) YMount(); color("lightblue") translate(XStageOffset + [0,0,-XStageOffset[2]]) XMount(); } if (Layout == "Build") { translate([20,0,0]) ZStand(); translate([YStageBlock[0]/2,0,0]) YMount(); translate([20,-30,0]) XMount(); }