The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Canon SX230HS Microscope and Close-up Macro Adapters

The deal was, if my Shop Assistant repaired my pocket camera, she could have it. She did, which meant I lost the ability to take pix through the microscope. While I was conjuring up a replacement, it occurred to me that I should also build a gadget to hold a close-up lens in front of the camera for tighter macro shots that don’t quite require a microscope’s magnification.

The solid model of the microscope adapter:

Microscope mount - solid model
Microscope mount – solid model

The close-up macro adapter, with an LED ring light around the snout:

LED Ring mount - solid model
LED Ring mount – solid model

They have a common camera mounting plate, with a hex recess for a 1/4-20 nut that mates with a standard tripod screw and some support material sticking up through the hole for the screw that holds the camera to the plate:

Mounting plate - solid model - top view
Mounting plate – solid model – top view

The main tube glues into the plate’s cutout and is long enough to accommodate the fully extended lens turret, with four shallow holes for filament snippet locating pins to align the snout:

Main tube - solid model - bottom view
Main tube – solid model – bottom view

An exploded view shows how everything fits together, with the stud below the camera representing its tripod mounting screw:

LED Ring mount - solid model - exploded view
LED Ring mount – solid model – exploded view

More details on the parts will appear over the next few days, but here’s the view through the macro adapter:

Dahlia through macro adapter
Dahlia through macro adapter

Yeah, some slight vignetting, but overall it’s pretty good.

The OpenSCAD source code that builds both adapters:

// Close-up lens mount & Microscope adapter for Canon SX230HS camera
// Ed Nisley KE4ZNU - Nov 2011

Mount = "Eyepiece";			// End result: LEDRing Eyepiece

Layout = "Show";			// Assembly: Show
							// Parts: Plate Tube LEDRing Camera Eyepiece
							// Build Plates: Build1..4

Gap = 12;					// between "Show" objects

include </home/ed/Thing-O-Matic/lib/MCAD/units.scad>
include </home/ed/Thing-O-Matic/Useful Sizes.scad>
include </home/ed/Thing-O-Matic/lib/visibone_colors.scad>

//-------
//- Extrusion parameters must match reality!
//  Print with +1 shells, 3 solid layers, 0.2 infill

ThreadThick = 0.33;
ThreadWidth = 2.0 * ThreadThick;

HoleFinagle = 0.2;
HoleFudge = 1.02;

function HoleAdjust(Diameter) = HoleFudge*Diameter + HoleFinagle;

Protrusion = 0.1;			// make holes end cleanly

function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);

//-------
// Dimensions

// doublet lens

LensDia = 25.0;
LensRad = LensDia/2;
LensClearance = 0.2;

LensEdge = 6.7;
LensThick = 8.6;
LensRimThick = IntegerMultiple((2.0 + LensThick),ThreadThick);

// LED ring light

LEDRingOD = 50.0;
LEDRingID = 36.0;
LEDBoardThick = 1.5;
LEDThick = 4.0;
LEDRingClearance = 0.5;
LEDWireHoleDia = 3.0;

// microscope eyepiece

EyepieceOD = 30.0;
EyepieceID = 24.0;
EyepieceLength = 25.0;

// camera
// Origin at base of [0] ring, Z+ along lens axis, X+ toward bottom, Y+ toward left

CameraBodyWidth = 2*10.6;							// 2 x center-to-curve edge
CameraBaseWidth = 15.5;								// flat part of bottom front to back
CameraBaseRadius = (CameraBodyWidth - CameraBaseWidth)/2;	// edge rounding
CameraBaseLength = 60.0;							// centered on lens axis
CameraBaseHeight = 55.0;							// main body height
CameraBaseThick = 0.9;								// downward from lens ring

echo(str("Camera base radius: ",CameraBaseRadius));

TripodHoleOffset = -19.0;							// mount screw wrt lens centerline
TripodHoleDia = Clear025_20;						// clearance hole

TripodScrewHeadDia = 14.5;							// recess for screw mounting camera
TripodScrewHeadRad = TripodScrewHeadDia/2;
TripodScrewHeadThick = 3.0;

// main lens tube

TubeDia = 		[53.0,	44.0,	40.0,	37.6];		// lens rings, [0] is fixed to body
TubeLength = 	[8.1,	20.6,	17.6,	12.7];

TubeEndClearance = 2.0;								// camera lens end to tube end
TubeEndThickness = IntegerMultiple(1.5,ThreadThick);
TubeInnerClearance = 0.5;

TubeInnerLength = TubeLength[0] + TubeLength[1] + TubeLength[2] + TubeLength[3] +
				  TubeEndClearance;
TubeOuterLength = TubeInnerLength + TubeEndThickness;

TubeID = TubeDia[0] + TubeInnerClearance;
TubeOD = TubeID + 6*ThreadWidth;
TubeWall = (TubeOD - TubeID)/2;
TubeSides = 48;

echo(str("Main tube outer length: ",TubeOuterLength));
echo(str("          ID: ",TubeID," OD: ",TubeOD," wall: ",TubeWall));

// camera mounting base

BaseWidth = IntegerMultiple((CameraBaseWidth + 2*CameraBaseRadius),ThreadThick);
BaseLength = 60.0;
BaseThick = IntegerMultiple((1.0 + Nut025_20Thick + CameraBaseThick),ThreadThick);

// LED ring mount

LEDBaseThick = IntegerMultiple(2.0,ThreadThick);	// base under lens + LED ring
LEDBaseRimWidth = IntegerMultiple(6.0,ThreadWidth);
LEDBaseRimThick = IntegerMultiple(LensThick,ThreadThick);

LEDBaseOD = max((LEDRingOD + LEDRingClearance + LEDBaseRimWidth),TubeOD);

echo(str("LED Ring OD: ",LEDBaseOD));

// alignment pins between tube and LED ring / microscope eyepiece

AlignPins = 4;
AlignPinOD = 2.9;
AlignPinCircleDia = TubeOD - 2*TubeWall - 2*AlignPinOD;		// 2*PinOD -> more clearance

//-------

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=HoleAdjust(FixDia)/2,h=Height,$fn=Sides);
}

module ShowPegGrid(Space = 10.0,Size = 1.0) {

  Range = floor(50 / Space);

	for (x=[-Range:Range])
	  for (y=[-Range:Range])
		translate([x*Space,y*Space,Size/2])
		  %cube(Size,center=true);

}

//-------

//- Camera body segment
//	Including lens base and peg for tripod hole access
//	Z=0 at edge of lens base ring, X=0 along lens axis

module CameraBody() {

  translate([0,0,-CameraBaseThick])
	rotate(90)
	  union() {
		translate([0,0,(CameraBaseHeight/2 + CameraBaseRadius)])
		  minkowski() {
			cube([CameraBaseWidth,
				  (CameraBaseLength + 2*Protrusion),
				  CameraBaseHeight],center=true);
			rotate([90,0,0])
			  cylinder(r=CameraBaseRadius,h=Protrusion,$fn=8);
		  }

		translate([0,0,(TubeDia[0]/2 + CameraBaseThick)])
		  rotate([0,90,0])
			rotate(180/TubeSides)
			  cylinder(r=(TubeDia[0]/2 + CameraBaseThick),
					  h=(CameraBodyWidth/2 + Protrusion),
					  $fn=TubeSides);

		translate([CameraBodyWidth/2,0,(TubeDia[0]/2 + CameraBaseThick)])
		  rotate([0,90,0])
			cylinder(r=TubeDia[0]/2,h=TubeLength[0]);

		translate([(TubeLength[0] + CameraBodyWidth/2),
				  0,(TubeDia[0]/2 + CameraBaseThick)])
		  rotate([0,90,0])
			cylinder(r=TubeDia[1]/2,h=TubeLength[1]);

		translate([(TubeLength[0] + TubeLength[1] + CameraBodyWidth/2),
				  0,(TubeDia[0]/2 + CameraBaseThick)])
		  rotate([0,90,0])
			cylinder(r=TubeDia[2]/2,h=TubeLength[2]);

		translate([(TubeLength[0] + TubeLength[1] + TubeLength[2] + CameraBodyWidth/2),
				  0,(TubeDia[0]/2 + CameraBaseThick)])
		  rotate([0,90,0])
			cylinder(r=TubeDia[3]/2,h=TubeLength[3]);

		translate([0,TripodHoleOffset,-BaseThick])
		  PolyCyl(TripodHoleDia,(BaseThick + 2*Protrusion));

	  }
}

//- Main tube

module Tube() {

  difference() {
	cylinder(r=TubeOD/2,h=TubeOuterLength,$fn=TubeSides);

	translate([0,0,TubeEndThickness])
	  PolyCyl(TubeID,(TubeInnerLength + Protrusion),TubeSides);

	translate([0,0,-Protrusion]) {
	  if (Mount == "LEDRing")
		cylinder(r=LensRad,h=(TubeEndThickness + 2*Protrusion));
	  if (Mount == "Eyepiece")
		cylinder(r=EyepieceID/2,h=(TubeEndThickness + 2*Protrusion));
	}

	for (Index = [0:AlignPins-1])
	  rotate(Index*90)
		translate([(AlignPinCircleDia/2),0,-ThreadThick])
		  rotate(180)			// flat sides outward
			PolyCyl(AlignPinOD,TubeEndThickness);
  }

}

//- Base plate

module BasePlate() {

  union() {
	difference() {
		linear_extrude(height=BaseThick)
		  hull() {
			translate([-(BaseLength/2 - BaseWidth/2),0,0])
			  circle(BaseWidth/2);
			translate([ (BaseLength/2 - BaseWidth/2),0,0])
			  circle(BaseWidth/2);
			translate([0,(0.75*BaseLength),0])
			  circle(BaseWidth/2);
		  }

		translate([0,0,BaseThick])
		  CameraBody();

		translate([0,(TubeOuterLength + CameraBodyWidth/2),
				  (BaseThick + TubeDia[0]/2)])
		  rotate([90,0,0])
			PolyCyl(TubeOD,TubeOuterLength,$fn=TubeSides);

		translate([0,0,3*ThreadThick])
		  PolyCyl((Nut025_20Dia*sqrt(3)/2),2*Nut025_20Thick,6);	// dia across hex flats

		translate([0,0,-Protrusion])
		  PolyCyl(Clear025_20,(BaseThick + 2*Protrusion));

		translate([TripodHoleOffset,0,3*ThreadThick])
		  PolyCyl((Nut025_20Dia*sqrt(3)/2),2*Nut025_20Thick,6);	// dia across hex flats

		translate([TripodHoleOffset,0,-Protrusion])
		  PolyCyl(Clear025_20,(BaseThick + 2*Protrusion));

		translate([-TripodHoleOffset,0,-Protrusion])
		  PolyCyl(TripodScrewHeadDia,(TripodScrewHeadThick + Protrusion));

	}

	translate([-TripodHoleOffset,0,0]) {				// support for tripod screw hole
	  for (Index=[0:3])
		rotate(Index*45)
		  translate([-ThreadWidth,-TripodScrewHeadRad,0])
			cube([2*ThreadWidth,TripodScrewHeadDia,TripodScrewHeadThick]);

	  cylinder(r=0.4*TripodScrewHeadRad,h=(BaseThick - CameraBaseThick),$fn=9);
	}
  }
}

//- LED mounting ring

module LEDRing() {

  difference() {
	cylinder(r=LEDBaseOD/2,h=LensRimThick,$fn=48);

	translate([0,0,-Protrusion])
	  PolyCyl((LensDia + LensClearance),
			  (LensRimThick + 2*Protrusion));

	translate([0,0,LEDBaseRimThick])
	  difference() {
		PolyCyl(LEDBaseOD,LensThick);
		PolyCyl(LEDRingID,LensThick);
	  }

	translate([0,0,LEDBaseThick])
	  difference() {
		PolyCyl((LEDRingOD + LEDRingClearance),LensThick);
		cylinder(r1=HoleAdjust(LEDRingID - LEDRingClearance)/2,
				 r2=HoleAdjust(LensDia + LensClearance)/2 + 2*ThreadWidth,
				 h=LensThick);
	  }

	for (Index = [0:AlignPins-1])
	  rotate(Index*90)
		translate([(AlignPinCircleDia/2),0,-ThreadThick])
		  rotate(180)			// flat sides outward
			PolyCyl(AlignPinOD,LEDBaseThick);

	rotate(45)
	  translate([0,LEDRingID/2,(LEDBaseThick + 1.2*LEDWireHoleDia/2)])
		rotate([0,-90,0])			// flat side down
		  rotate([-90,0,0])
			PolyCyl(LEDWireHoleDia,2*LEDBaseRimWidth);
  }

}

//- Microscope eyepiece adapter

module EyepieceMount() {

  difference() {
	cylinder(r1=TubeOD/2,
			 r2=(EyepieceOD + 8*ThreadWidth)/2,
			 h=EyepieceLength,
			 $fn=TubeSides);

	translate([0,0,-Protrusion])
	  PolyCyl(EyepieceOD,(EyepieceLength + 2*Protrusion));

	for (Index = [0:AlignPins-1])
	  rotate(Index*90)
		translate([(AlignPinCircleDia/2),0,-ThreadThick])
		  rotate(180)			// flat sides outward
			PolyCyl(AlignPinOD,6*ThreadThick);
  }

}

//-------
// Build it!

if (Layout != "Show")
  ShowPegGrid();

if (Layout == "Tube")
  Tube();

if (Layout == "LEDRing")
  LEDRing();

if (Layout == "Plate")
  BasePlate();

if (Layout == "Camera")
  CameraBody();

if (Layout == "Eyepiece")
  EyepieceMount();

if (Layout == "Build1")
  translate([0,-BaseLength/3,0])
	BasePlate();

if (Layout == "Build2")
  Tube();

if (Layout == "Build3")
  LEDRing();

if (Layout == "Build4")
  EyepieceMount();

if (Layout == "Show") {
  translate([0,TubeOuterLength,TubeDia[0]/2]) {
	rotate([90,0,0])
	  color(LTC) Tube();
	translate([0,Gap,0])
	  rotate([-90,0,0]) {
		if (Mount == "LEDRing")
		  color(OOR) LEDRing();
		if (Mount == "Eyepiece")
		  color(OOR) EyepieceMount();
	  }
  }

  translate([0,-CameraBodyWidth/2,0])
	color(PG) CameraBody();

  color(PDA)
	render()
	translate([0,-CameraBodyWidth/2,-(BaseThick + Gap)])
	  BasePlate();
}

The original doodles & dimensions:

Close-up Lens Doodles
Close-up Lens Doodles

Comments

11 responses to “Canon SX230HS Microscope and Close-up Macro Adapters”

  1. SX230HS Adapter: Mounting Plate « The Smell of Molten Projects in the Morning Avatar

    […] The Smell of Molten Projects in the Morning « Canon SX230HS Microscope and Close-up Macro Adapters […]

  2. SX230HS Adapter: Macro Lens Snout « The Smell of Molten Projects in the Morning Avatar

    […] macro lens adapter took shape around a nice 25 mm doublet lens from the Box o’ Lenses. The Canon SX230HS has a […]

  3. Vanilla Extract: Commercial Variations « The Smell of Molten Projects in the Morning Avatar

    […] full-frame pix used my new close-up lens gizmo; even with some vignetting the results seem perfectly usable. Normally I crop pix down to the […]

  4. Thing-O-Matic: Small Hole Calibration « The Smell of Molten Projects in the Morning Avatar

    […] macro lens & microscope adapters for the Canon SX230HX camera required a bunch of large and fairly precise circles. The first-pass […]

  5. Canon SX230HS Close-up Adapter: Up-amped LED Ring « The Smell of Molten Projects in the Morning Avatar

    […] a 510 Ω resistor with each of the 180 Ω resistors on the LED ring light around the macro lens holder boosted the LED string current from 15 to 20 mA: LED ring light – paralleled […]

  6. Canon Hack Development Kit for SX230HS « The Smell of Molten Projects in the Morning Avatar

    […] the macro lens adapter and microscope mount work well enough, the relatively small sensor and lens in my Canon SX230HS make for a razor-thin […]

  7. Macro Lens Focus Stacking « The Smell of Molten Projects in the Morning Avatar

    […] by mounting the Canon SX230HS on the macro lens adapter, zooming to about the maximum, fiddling with a ruler to put the end at the closest focus point, and […]

  8. PL605060 Cells: First Charge « The Smell of Molten Projects in the Morning Avatar

    […] to mount it; a case that screws into the tripod socket is obvious, but it would interfere with the macro lens adapter. Of course, I could just print another macro lens adapter with an integral battery case … You […]

  9. Kensington Expert Mouse Trackball: Scroll Ring Aperture Alignment | The Smell of Molten Projects in the Morning Avatar

    […] pix come from the Canon pocket camera mounted on the macro lens / illuminator, handheld with manual focus. The dust speck on the detector is just slightly out of focus, but you […]

  10. Makergear M2: Nozzle Temperature Sensing | The Smell of Molten Projects in the Morning Avatar

    […] Peeling back the tape a bit shows the thermistor against the nozzle, with the glass bead reflecting the LED ringlight around the macro lens adapter: […]

  11. Optical Filament Diameter Sensor Doodles | The Smell of Molten Projects in the Morning Avatar

    […] you can put a macro lens in front of a webcam (like that macro lens holder) and mount it just above the extruder with suitable lighting to give a high-contrast view of the […]